build(nrf52): consolidate XIAO QSPI repeater images
This commit is contained in:
1 parent
de82477184
commit
082466f71b
7 files changed
+118
-13
No files matched your search
@@ -216,6 +216,7 @@ jobs:
|
||||
python3 -B test/test_full_logging_resume.py
|
||||
python3 -B test/test_firmware_capabilities.py
|
||||
bash test/test_build_profiles.sh
|
||||
bash test/test_xiao_qspi_combined.sh
|
||||
|
||||
- name: Verify nRF52 UF2-reset CLI coverage
|
||||
run: python3 -B test/test_nrf52_uf2reset_cli.py
|
||||
|
||||
@@ -138,7 +138,7 @@ Options:
|
||||
--firmware-version <version>: Firmware version to embed.
|
||||
--radio-preset <name|number>: Override the USA Cascadia radio default. Stable names are usa-cascadia and target; legacy menu numbers remain accepted.
|
||||
--profile <default|cascade>: Override runtime settings embedded in the firmware (not its feature set).
|
||||
--build-profile <auto|standard|full>: Select feature/partition policy. Auto uses the combined Full MQTT/USB/WiFi recipe when it covers the plain infrastructure target; otherwise it first builds complete LoRa-OTA-capable firmware with a measured-size fallback. Internal-flash nRF52 repeaters and room servers also publish the reduced image for delta-staging headroom. Standard preserves portable images, including the 1.25 MiB slot; full requires the expanded ESP32 recipe.
|
||||
--build-profile <auto|standard|full>: Select feature/partition policy. Auto uses the combined Full MQTT/USB/WiFi recipe when it covers the plain infrastructure target; otherwise it first builds complete LoRa-OTA-capable firmware with a measured-size fallback. Internal-flash nRF52 repeaters and room servers also publish the reduced image for delta-staging headroom; XIAO nRF52 repeaters with external-QSPI staging publish one combined image. Standard preserves portable images, including the 1.25 MiB slot; full requires the expanded ESP32 recipe.
|
||||
--auto|--standard|--full: Short forms of --build-profile.
|
||||
--skip-kiss|--include-kiss: Exclude (default) or include KISS modem targets in bulk builds.
|
||||
--clean|--resume: Clean output or resume existing Option 3/FULL-only artifacts.
|
||||
@@ -353,12 +353,16 @@ for section, options in data:
|
||||
*_repeater|*_repeater_|*_repeatr|*_repeatr_|*_room_server|*_room_server_|*_room_svr|*_room_svr_) ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
# SolarXiao 30S/33S repeater and room-server roles already use matched
|
||||
# external QSPI staging, so their normal full-sensor image is
|
||||
# install-capable. A second lean no-external-sensors target provides no
|
||||
# additional OTA capability.
|
||||
# XIAO nRF52840 repeaters with raw-QSPI staging and the reserved
|
||||
# bootloader scratch region keep sensors, packet logging, and LoRa OTA
|
||||
# in their normal image. Do not publish a redundant reduced sibling.
|
||||
if is_xiao_qspi_combined_repeater_target "$env_name"; then
|
||||
continue
|
||||
fi
|
||||
# Leave SolarXiao room-server inventory unchanged; these roles are not
|
||||
# part of the XIAO repeater consolidation.
|
||||
case "${env_name,,}" in
|
||||
solarxiao_30s_repeater|solarxiao_33s_repeater|solarxiao_30s_room_server|solarxiao_33s_room_server) continue ;;
|
||||
solarxiao_30s_room_server|solarxiao_33s_room_server) continue ;;
|
||||
esac
|
||||
ota_env="${env_name%_}_lora_ota_no_external_sensors"
|
||||
PIO_ENV_COMPLETE_OTA_BASE_BY_NAME["$ota_env"]="$env_name"
|
||||
@@ -2080,6 +2084,22 @@ is_lora_ota_only_target() {
|
||||
[[ "$target_lc" == *lora_ota* ]]
|
||||
}
|
||||
|
||||
is_xiao_qspi_combined_repeater_target() {
|
||||
local env_name=$1
|
||||
|
||||
[ "${PIO_ENV_PLATFORM_BY_NAME[$env_name]:-}" = "NRF52_PLATFORM" ] \
|
||||
&& [ "${PIO_ENV_BOARD_BY_NAME[$env_name]:-}" = "seeed-xiao-afruitnrf52-nrf52840" ] \
|
||||
&& [ "${PIO_ENV_QSPI_OTA_BY_NAME[$env_name]:-0}" = "1" ] \
|
||||
&& { [[ "${env_name,,}" == *_repeater ]] \
|
||||
|| [[ "${env_name,,}" == *_repeater_ ]]; }
|
||||
}
|
||||
|
||||
is_xiao_qspi_canonical_repeater_build() {
|
||||
is_xiao_qspi_combined_repeater_target "$1" \
|
||||
&& [ "$BUILD_PROFILE_FOR_TARGET" = "standard" ] \
|
||||
&& [ -z "$FIRMWARE_FILENAME_INFIX" ]
|
||||
}
|
||||
|
||||
is_lora_ota_no_external_sensors_target() {
|
||||
local target_lc=${1,,}
|
||||
[[ "$target_lc" == *lora_ota_no_external_sensors ]]
|
||||
@@ -3138,7 +3158,8 @@ record_application_expectation() {
|
||||
declare_full_logging_application_contract() {
|
||||
local env_name=$1
|
||||
BUILD_APPLICATION_EXPECTATIONS=()
|
||||
if requires_full_usb_packet_logging "$env_name"; then
|
||||
if requires_full_usb_packet_logging "$env_name" \
|
||||
|| is_xiao_qspi_canonical_repeater_build "$env_name"; then
|
||||
# Inspect the packaged application, not an ELF debug/symbol string. The
|
||||
# settings alone can exist in debug-only builds with packet logging absent.
|
||||
record_application_expectation "logging.usb.packets" \
|
||||
@@ -3179,7 +3200,9 @@ declare_build_capability_contract() {
|
||||
if [ "$env_platform" = "NRF52_PLATFORM" ] && ! is_kiss_modem_target "$env_name"; then
|
||||
# Prove the real DFU service is linked, not merely a generic OTA CLI stub.
|
||||
record_build_expectation "ota.update.bluetooth" "_ZN6BLEDfu5beginEv"
|
||||
if is_lora_ota_build "$env_name" && ! is_companion_build "$env_name"; then
|
||||
if { is_lora_ota_build "$env_name" \
|
||||
|| is_xiao_qspi_canonical_repeater_build "$env_name"; } \
|
||||
&& ! is_companion_build "$env_name"; then
|
||||
# nRF52 applies mOTA in its bootloader, so the ESP32 decoder marker is
|
||||
# absent. The checker also verifies the packaged app's EndF/storage layout.
|
||||
record_build_expectation "ota.update.lora" "invalid in-place patch geometry"
|
||||
@@ -3209,7 +3232,8 @@ declare_build_capability_contract() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if is_lora_ota_build "$env_name"; then
|
||||
if is_lora_ota_build "$env_name" \
|
||||
|| is_xiao_qspi_canonical_repeater_build "$env_name"; then
|
||||
record_build_expectation "ota.cli" "OTA: status"
|
||||
fi
|
||||
|
||||
@@ -4077,7 +4101,8 @@ write_build_capability_manifest() {
|
||||
)
|
||||
local item
|
||||
|
||||
if requires_wireless_self_update "$env_name"; then
|
||||
if requires_wireless_self_update "$env_name" \
|
||||
|| is_xiao_qspi_canonical_repeater_build "$env_name"; then
|
||||
checker_args+=(--require-ota)
|
||||
fi
|
||||
if [ "$env_platform" = "ESP32_PLATFORM" ]; then
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
source build.sh
|
||||
|
||||
fail() { echo "test_xiao_qspi_combined: $*" >&2; exit 1; }
|
||||
|
||||
# Use the resolved PlatformIO recipes, not a board-name allowlist: each
|
||||
# canonical XIAO repeater must retain the internal bootloader scratch bank,
|
||||
# raw external-QSPI OTA staging, and packet logging in one application.
|
||||
init_project_context
|
||||
BUILD_PROFILE_FOR_TARGET=standard
|
||||
BUILD_PROFILE_EFFECTIVE=standard
|
||||
FIRMWARE_FILENAME_INFIX=""
|
||||
DISABLE_DEBUG=0
|
||||
PACKET_LOGGING_OVERRIDE=""
|
||||
MESHDEBUG_OVERRIDE=""
|
||||
MQTT_BRIDGE_OVERRIDE=""
|
||||
|
||||
for target in \
|
||||
Xiao_nrf52_repeater \
|
||||
ikoka_handheld_nrf_e22_30dbm_repeater \
|
||||
ikoka_nano_nrf_22dbm_repeater \
|
||||
ikoka_nano_nrf_30dbm_repeater \
|
||||
ikoka_nano_nrf_33dbm_repeater \
|
||||
ikoka_stick_nrf_22dbm_repeater \
|
||||
ikoka_stick_nrf_30dbm_repeater \
|
||||
ikoka_stick_nrf_33dbm_repeater \
|
||||
solarxiao_30S_repeater \
|
||||
solarxiao_33S_repeater; do
|
||||
is_supported_build_env "$target" || fail "$target is missing"
|
||||
is_xiao_qspi_canonical_repeater_build "$target" \
|
||||
|| fail "$target lost its combined-image classification"
|
||||
if is_supported_build_env "${target}_lora_ota_no_external_sensors"; then
|
||||
fail "$target still publishes a redundant lean OTA sibling"
|
||||
fi
|
||||
if get_reduced_lora_ota_target "$target" >/dev/null; then
|
||||
fail "$target still falls back to a reduced OTA sibling"
|
||||
fi
|
||||
pio_env_option_contains "$target" board_build.ldscript \
|
||||
nrf52840_s140_v7_xiao_bootloader_ota.ld \
|
||||
|| fail "$target lost its 40 KiB internal bootloader scratch reservation"
|
||||
pio_env_option_contains "$target" board_upload.maximum_size 757760 \
|
||||
|| fail "$target lost its internal application size limit"
|
||||
pio_env_option_contains "$target" build_flags OTA_QSPI_BOOTLOADER_UPDATE=1 \
|
||||
|| fail "$target lost its OTAFIX bootloader-update layout"
|
||||
pio_env_option_contains "$target" build_flags OTA_QSPI_STORE=1 \
|
||||
|| fail "$target lost external-QSPI OTA staging"
|
||||
pio_env_option_contains "$target" build_flags MESH_PACKET_LOGGING=1 \
|
||||
|| fail "$target lost packet logging"
|
||||
is_lora_ota_build "$target" || fail "$target lost LoRa OTA"
|
||||
|
||||
BUILD_CAPABILITIES=()
|
||||
BUILD_REDUCTIONS=()
|
||||
BUILD_EXPECTATIONS=()
|
||||
BUILD_APPLICATION_EXPECTATIONS=()
|
||||
declare_build_capability_contract "$target" NRF52_PLATFORM
|
||||
expectations=" ${BUILD_EXPECTATIONS[*]} "
|
||||
application=" ${BUILD_APPLICATION_EXPECTATIONS[*]} "
|
||||
[[ "$expectations" == *"ota.update.lora=invalid in-place patch geometry"* ]] \
|
||||
|| fail "$target no longer proves its LoRa OTA receiver"
|
||||
[[ "$expectations" == *"ota.cli=OTA: status"* ]] \
|
||||
|| fail "$target no longer proves its OTA CLI"
|
||||
[[ "$application" == *"logging.usb.packets=%s: %s, len=%d (type=%d, route=%s, payload_len=%d)"* ]] \
|
||||
|| fail "$target no longer verifies packaged packet logging"
|
||||
[[ "$application" == *"logging.usb.control=OK - USB logging %s (saved)"* ]] \
|
||||
|| fail "$target no longer verifies the packaged USB logging control"
|
||||
done
|
||||
|
||||
# This consolidation is specific to the external-QSPI XIAO repeater layout.
|
||||
is_xiao_qspi_combined_repeater_target Xiao_nrf52_room_server \
|
||||
&& fail "non-QSPI room server was incorrectly consolidated"
|
||||
is_xiao_qspi_combined_repeater_target RAK_4631_repeater \
|
||||
&& fail "unrelated repeater was incorrectly consolidated"
|
||||
|
||||
echo "test_xiao_qspi_combined: OK"
|
||||
@@ -99,6 +99,7 @@ build_flags = ${ikoka_handheld_nrf.build_flags}
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D LORA_TX_POWER=20
|
||||
-D MESH_PACKET_LOGGING=1
|
||||
build_src_filter = ${ikoka_handheld_nrf.build_src_filter}
|
||||
+<../examples/simple_repeater/*.cpp>
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ build_flags =
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
; -D MESH_PACKET_LOGGING=1
|
||||
-D MESH_PACKET_LOGGING=1
|
||||
; -D MESH_DEBUG=1
|
||||
build_src_filter = ${ikoka_nano_nrf.build_src_filter}
|
||||
+<../examples/simple_repeater/*.cpp>
|
||||
|
||||
@@ -135,7 +135,7 @@ build_flags =
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
; -D MESH_PACKET_LOGGING=1
|
||||
-D MESH_PACKET_LOGGING=1
|
||||
; -D MESH_DEBUG=1
|
||||
build_src_filter = ${ikoka_stick_nrf.build_src_filter}
|
||||
+<helpers/ui/SSD1306Display.cpp>
|
||||
|
||||
@@ -101,7 +101,7 @@ build_flags =
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
; -D MESH_PACKET_LOGGING=1
|
||||
-D MESH_PACKET_LOGGING=1
|
||||
; -D MESH_DEBUG=1
|
||||
build_src_filter = ${Xiao_nrf52.build_src_filter}
|
||||
+<../examples/simple_repeater/*.cpp>
|
||||
@@ -231,6 +231,7 @@ build_flags =
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D MESH_PACKET_LOGGING=1
|
||||
-D WITH_RS232_BRIDGE=Serial1
|
||||
-D WITH_RS232_BRIDGE_UART=1
|
||||
-D WITH_RS232_BRIDGE_RX=PIN_SERIAL1_RX
|
||||
|
||||
Reference in new issue
Block a user