Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions .github/workflows/mambo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Experimental Mambo checks
on:
pull_request:
paths:
- '.github/workflows/mambo.yml'
- 'CMakeLists.txt'
- 'CMakePresets.json'
- 'cmake/**'
- 'radio/**'
- 'tools/hwdef_schema.json'
- 'tools/mambo-tests/**'
- 'tools/mambo-flash/**'
- 'pyproject.toml'
- 'uv.lock'
workflow_dispatch:

permissions:
contents: read

jobs:
host:
name: Standalone Mambo board tests
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
- run: cmake -S tools/mambo-tests -B build/mambo-tests
- run: cmake --build build/mambo-tests --parallel 2
- run: ctest --test-dir build/mambo-tests --output-on-failure

firmware:
name: Build default Mambo with external CRSF
runs-on: ubuntu-latest
timeout-minutes: 20
if: |
github.event_name != 'pull_request' ||
!contains(github.event.pull_request.labels.*.name, 'ci: skip-fw')
container:
image: ghcr.io/edgetx/edgetx-dev:latest
volumes:
- ${{ github.workspace }}:/src
steps:
- uses: actions/checkout@v7
with:
submodules: recursive
- uses: astral-sh/setup-uv@v10.0.1
- run: uv sync --locked
- name: Configure the default Mambo build with Lua enabled
run: >-
uv run cmake --preset mambo
-DPython3_EXECUTABLE="$GITHUB_WORKSPACE/.venv/bin/python"
-DLUA=ON -DLUA_COMPILER=ON -DLUA_MIXER=ON
- run: cmake --build build/mambo --target firmware --parallel 4
- name: Check memory boundaries and external CRSF interrupt vectors
run: >-
uv run python tools/mambo-flash/verify_firmware.py
build/mambo/firmware.elf build/mambo/firmware.bin
- name: Validate the offline flashing target (no USB access)
run: cmake --build build/mambo --target flash-plan
- name: Assemble the verified bench-test bundle
run: |
mkdir -p build/mambo/tester-bundle
cp build/mambo/firmware.bin build/mambo/firmware.elf LICENSE build/mambo/tester-bundle/
cp tools/mambo-flash/mambo_flash.py tools/mambo-flash/verify_firmware.py tools/mambo-flash/README.txt build/mambo/tester-bundle/
git rev-parse HEAD > build/mambo/tester-bundle/SOURCE_REVISION.txt
uv run python tools/mambo-flash/mambo_flash.py \
--image build/mambo/firmware.bin --elf build/mambo/firmware.elf \
> build/mambo/tester-bundle/flash-plan.json
- name: Upload the Mambo bench-test bundle
uses: actions/upload-artifact@v7
with:
name: mambo-bench-${{ github.sha }}
path: build/mambo/tester-bundle/
if-no-files-found: error
retention-days: 14
6 changes: 6 additions & 0 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,12 @@
"displayName": "Senduwing H17",
"inherits": "firmware",
"cacheVariables": { "PCB": "H17" }
},
{
"name": "mambo",
"displayName": "TBS Mambo experimental (external CRSF; internal RF disabled)",
"inherits": "firmware",
"cacheVariables": { "PCB": "MAMBO", "BOOTLOADER": false }
}
],
"buildPresets": [
Expand Down
29 changes: 29 additions & 0 deletions cmake/MamboFlash.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Original TBS controller bootloader: USB HID, not STM32 DFU. The application
# allocation and its ELF are checked before the uploader can open USB.
set(MAMBO_FLASH_SCRIPT "${CMAKE_SOURCE_DIR}/tools/mambo-flash/mambo_flash.py")
set(MAMBO_FLASH_RUNNER "${CMAKE_SOURCE_DIR}/cmake/RunMamboFlash.cmake")

foreach(mode IN ITEMS PLAN PROBE FLASH)
if(mode STREQUAL "PLAN")
set(target_name flash-plan)
elseif(mode STREQUAL "PROBE")
set(target_name flash-probe)
else()
set(target_name flash)
endif()
add_custom_target(${target_name}
COMMAND ${CMAKE_COMMAND}
"-DMAMBO_FLASH_MODE=${mode}"
"-DMAMBO_FLASH_PYTHON=${PYTHON_EXECUTABLE}"
"-DMAMBO_FLASH_SCRIPT=${MAMBO_FLASH_SCRIPT}"
"-DMAMBO_FLASH_IMAGE=${CMAKE_BINARY_DIR}/firmware.bin"
"-DMAMBO_FLASH_ELF=${CMAKE_BINARY_DIR}/firmware.elf"
"-DMAMBO_FLASH_LOG_ROOT=${CMAKE_BINARY_DIR}/mambo-flash-logs"
-P "${MAMBO_FLASH_RUNNER}"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
USES_TERMINAL
VERBATIM)
if(NOT mode STREQUAL "PROBE")
add_dependencies(${target_name} firmware)
endif()
endforeach()
42 changes: 42 additions & 0 deletions cmake/RunMamboFlash.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
cmake_minimum_required(VERSION 3.20)

if(NOT MAMBO_FLASH_MODE MATCHES "^(PLAN|PROBE|FLASH)$")
message(FATAL_ERROR "Unknown Mambo flashing mode '${MAMBO_FLASH_MODE}'")
endif()
if(NOT EXISTS "${MAMBO_FLASH_PYTHON}" OR NOT EXISTS "${MAMBO_FLASH_SCRIPT}")
message(FATAL_ERROR "Mambo flashing requires the build Python and HID uploader")
endif()

if(MAMBO_FLASH_MODE STREQUAL "PROBE")
set(args --probe)
else()
set(args --image "${MAMBO_FLASH_IMAGE}" --elf "${MAMBO_FLASH_ELF}")
endif()

if(MAMBO_FLASH_MODE STREQUAL "FLASH")
# Read at build time: setting these must not reconfigure/rebuild the firmware
# after its SHA256 was approved with flash-plan.
set(serial "$ENV{MAMBO_FLASH_SERIAL}")
set(sha256 "$ENV{MAMBO_FLASH_SHA256}")
if(serial STREQUAL "")
message(FATAL_ERROR
"Set MAMBO_FLASH_SERIAL to the controller serial shown by flash-probe. USB not opened.")
endif()
string(LENGTH "${sha256}" hash_length)
if(NOT hash_length EQUAL 64 OR NOT sha256 MATCHES "^[0-9a-fA-F]+$")
message(FATAL_ERROR
"Set MAMBO_FLASH_SHA256 to the approved SHA256 shown by flash-plan. USB not opened.")
endif()
list(APPEND args --execute --expected-serial "${serial}"
--expected-sha256 "${sha256}" --log-root "${MAMBO_FLASH_LOG_ROOT}")
endif()

if(DEFINED ENV{MAMBO_HID_LIBRARY} AND NOT "$ENV{MAMBO_HID_LIBRARY}" STREQUAL "")
list(APPEND args --hid-library "$ENV{MAMBO_HID_LIBRARY}")
endif()

execute_process(COMMAND "${MAMBO_FLASH_PYTHON}" "${MAMBO_FLASH_SCRIPT}" ${args}
RESULT_VARIABLE result)
if(NOT result EQUAL 0)
message(FATAL_ERROR "Mambo ${MAMBO_FLASH_MODE} stopped (exit code ${result}); no automatic retry")
endif()
8 changes: 6 additions & 2 deletions radio/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
include(CMakeForceCompiler)
include(Bitmaps)

set(PCB_TYPES X9LITE X9LITES X7 XLITE XLITES X9D X9D+ X9E X10 X12S PL18 T15PRO T15H7 T18H7 ST16 PA01 TX15 GX15 TX16SMK3 T22 V12 H17 V15)
set(PCB_TYPES X9LITE X9LITES X7 XLITE XLITES X9D X9D+ X9E X10 X12S PL18 T15PRO T15H7 T18H7 ST16 PA01 TX15 GX15 TX16SMK3 T22 V12 H17 V15 MAMBO)
set(RADIO_LANGUAGES CN CZ DA DE EN ES FI FR HE HU IT JP KO NL PL PT RU SE SK TW UA)
set(TTS_LANGUAGES CN CZ DA DE EN ES FI FR HE HU IT JP KO NL PL PT RU SE SK TW UA)

Expand Down Expand Up @@ -116,6 +116,8 @@ elseif(PCB STREQUAL STM32H7S78_DK)
include(targets/stm32h7s78-dk/CMakeLists.txt)
elseif(PCB STREQUAL X9E OR PCB STREQUAL X9D+ OR PCB STREQUAL X9D OR PCB STREQUAL X7 OR PCB STREQUAL X9LITE OR PCB STREQUAL X9LITES OR PCB STREQUAL XLITE OR PCB STREQUAL XLITES)
include(targets/taranis/CMakeLists.txt)
elseif(PCB STREQUAL MAMBO)
include(targets/mambo/CMakeLists.txt)
else()
message(FATAL_ERROR "Unknown PCB '${PCB}'")
endif()
Expand Down Expand Up @@ -819,7 +821,9 @@ else()
)
endif()

if(CPU_FAMILY STREQUAL STM32)
if(CPU_FAMILY STREQUAL STM32 AND PCB STREQUAL MAMBO)
include(${CMAKE_SOURCE_DIR}/cmake/MamboFlash.cmake)
elseif(CPU_FAMILY STREQUAL STM32)
# FIRMWARE_QSPI boards can only be firmware-flashed via flash-uf2 below;
# the bootloader doesn't expose external QSPI/XSPI flash as a DFU segment.
if(NOT FIRMWARE_QSPI)
Expand Down
12 changes: 12 additions & 0 deletions radio/src/boards/generic_stm32/analog_inputs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
#include "flysky_gimbal_driver.h"

#include "hal.h"
#if defined(RADIO_MAMBO)
#include "targets/mambo/gimbals.h"
#endif

#if defined(USE_ADS79XX)
#include "ads79xx.h"
Expand Down Expand Up @@ -59,6 +62,9 @@ static_assert(n_inputs <= MAX_ANALOG_INPUTS, "Too many analog inputs");
static bool adc_init()
{
bool success = stm32_hal_adc_init(_ADC_adc, n_ADC, _ADC_inputs, _ADC_GPIOs, n_GPIO);
#if defined(RADIO_MAMBO)
mamboGimbalsInit();
#endif
#if defined(USE_ADS79XX)
if (n_ADC_spi > 0) ads79xx_init(&_ADC_spi[0]);
#endif
Expand All @@ -67,6 +73,9 @@ static bool adc_init()

static void adc_deinit()
{
#if defined(RADIO_MAMBO)
mamboGimbalsDeinit();
#endif
stm32_hal_adc_deinit(_ADC_adc, n_ADC);
}

Expand All @@ -89,6 +98,9 @@ static void adc_wait_completion()
if (n_ADC_spi > 0) ads79xx_adc_wait_completion(&_ADC_spi[0], _ADC_inputs);
#endif
stm32_hal_adc_wait_completion(_ADC_adc, n_ADC, _ADC_inputs, n_inputs);
#if defined(RADIO_MAMBO)
mamboGimbalsRead();
#endif
#if defined(SIXPOS_SWITCH_INDEX)
sixPosUpdateFromAdc();
#endif
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
INCLUDE stm32f40x/extra_sections.ld
21 changes: 21 additions & 0 deletions radio/src/boards/generic_stm32/linker/mambo/layout.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* Application-only allocation. Never include original bootloader/RF bytes. */
STACK_ADDRESS = ORIGIN(CCM) + LENGTH(CCM);
MAIN_STACK_SIZE = 1024;
BOOTLOADER_SIZE = 0;
MIN_HEAP_SIZE = 0;
HEAP_ADDRESS = ORIGIN(RAM) + LENGTH(RAM);

MEMORY
{
FLASH (rx) : ORIGIN = 0x0800C000, LENGTH = 720K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 84K
CCM (xrw) : ORIGIN = 0x10000400, LENGTH = 63K
}

REGION_ALIAS("REGION_BOOTLOADER", FLASH);
REGION_ALIAS("REGION_ISR_VECT", FLASH);
REGION_ALIAS("REGION_TEXT", FLASH);
REGION_ALIAS("REGION_TEXT_STORAGE", FLASH);
REGION_ALIAS("REGION_DATA", CCM);
REGION_ALIAS("REGION_BSS", CCM);
REGION_ALIAS("REGION_RAM", RAM);
5 changes: 5 additions & 0 deletions radio/src/boards/generic_stm32/module_ports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,10 +349,15 @@ static void _sport_set_inverted(uint8_t enable)
stm32_usart_rx_inversion(&sportUSART, !enable);
stm32_usart_tx_inversion(&sportUSART, !enable);
#endif
#else
#if defined(TELEMETRY_INVERTER_ACTIVE_HIGH)
gpio_write(TELEMETRY_TX_REV_GPIO, enable);
gpio_write(TELEMETRY_RX_REV_GPIO, enable);
#else
gpio_write(TELEMETRY_TX_REV_GPIO, !enable);
gpio_write(TELEMETRY_RX_REV_GPIO, !enable);
#endif
#endif
}

static void _sport_init_inverter()
Expand Down
Loading