fix: preserve complete companion build profiles

This commit is contained in:
mikecarper committed 2026-08-25 23:47:40 -07:00
1 parent 9bc95a60fe
commit 83e402bd4d
6 files changed
+169 -21

No files matched your search

+37 -12
View File
@@ -2448,9 +2448,19 @@ declare_build_capability_contract() {
if is_companion_radio_full_target "$env_name"; then
record_build_expectation "companion.temp_radio" "tempradio"
record_build_expectation "companion.ota_cli" "ota folder"
record_build_expectation "companion.usb" "+++MESHCORE-TERM-START"
record_build_expectation "companion.bluetooth" \
"Companion: starting Bluetooth"
if is_nrf52_companion_radio_full_target "$env_name" \
|| is_esp32_dual_cdc_companion_radio_full_target "$env_name"; then
record_build_expectation "companion.dedicated_usb_logging" \
"get usb.logging"
fi
if [ "$env_platform" = "ESP32_PLATFORM" ]; then
record_build_expectation "companion.network_terminal" \
"Full Companion terminal listening"
"USB currently owns the Full Companion terminal"
record_build_expectation "companion.wifi_ota_seeder" \
"OTA seeder listening on :"
record_build_expectation "web.webconfig" "start webconfig"
else
record_build_expectation "companion.usb_mota_source" "ota folder on"
@@ -2729,6 +2739,29 @@ append_platformio_extra_script() {
export PLATFORMIO_EXTRA_SCRIPTS
}
apply_lora_ota_flag_order_fix() {
local env_name=$1
local pio_env_name=$2
if ! is_lora_ota_build "$env_name" \
&& ! is_companion_radio_full_target "$env_name"; then
unset MESHCORE_FORCE_LORA_OTA
return 0
fi
# A few legacy recipes deliberately finish with -UENABLE_OTA. PlatformIO
# retains that raw undefine after externally supplied definitions, so an OTA
# overlay can otherwise advertise its controls while compiling out the
# protocol implementation. Remove the legacy undefine before flags are
# parsed for every OTA overlay, not just for one platform or role.
if pio_env_option_contains "$pio_env_name" build_flags "-UENABLE_OTA"; then
export MESHCORE_FORCE_LORA_OTA=1
append_platformio_extra_script "pre:scripts/force_lora_ota.py"
else
unset MESHCORE_FORCE_LORA_OTA
fi
}
apply_nrf52_lora_ota_build_recipe() {
local env_name=$1
local pio_env_name=$2
@@ -2753,17 +2786,6 @@ apply_nrf52_lora_ota_build_recipe() {
append_platformio_extra_script "post:tools/mota/pio_endf.py"
fi
# A few feature-rich legacy environments deliberately end their own flags
# with -UENABLE_OTA. PlatformIO build_unflags cannot remove a trailing -U,
# so a pre-script must make the intentional OTA overlay authoritative for
# both compilation and the EndF geometry hook.
if pio_env_option_contains "$pio_env_name" build_flags "-UENABLE_OTA"; then
export MESHCORE_FORCE_LORA_OTA=1
append_platformio_extra_script "pre:scripts/force_lora_ota.py"
else
unset MESHCORE_FORCE_LORA_OTA
fi
if supports_nrf52_internal_bootloader_update "$env_name"; then
export MESHCORE_NRF52_INTERNAL_BOOTLOADER_UPDATE=1
else
@@ -2904,6 +2926,8 @@ apply_companion_radio_full_profile() {
if requires_esp32_companion_full_ota_fallback "$pio_env_name"; then
append_platformio_build_unflags "-DMAX_CONTACTS=350 -DMAX_CONTACTS=160 -DMAX_GROUP_CHANNELS=40 -DOFFLINE_QUEUE_SIZE=512 -DOFFLINE_QUEUE_SIZE=256 -DOFFLINE_QUEUE_SIZE=128"
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DMAX_CONTACTS=100 -DMAX_GROUP_CHANNELS=8 -DOFFLINE_QUEUE_SIZE=16"
record_build_reduction \
"companion.capacity limited to 100 contacts, 8 channels, and 16 queued frames by measured internal DRAM"
fi
# A few WiFi recipes list only their WiFi implementation instead of the
@@ -3354,6 +3378,7 @@ build_firmware() {
apply_lora_ota_override "$env_name"
apply_logical_ota_tuning_flags "$env_name" "$pio_env_name"
apply_companion_radio_full_profile "$env_name" "$pio_env_name"
apply_lora_ota_flag_order_fix "$env_name" "$pio_env_name"
apply_nrf52_lora_ota_build_recipe "$env_name" "$pio_env_name"
apply_esp32_lora_ota_size_profile "$env_name"
apply_esp32_constrained_companion_size_profile "$env_name"
+5
View File
@@ -104,6 +104,11 @@ available from a canonical image:
interface `02` for plaintext logs.
Its LoRa OTA support is source-only: it can serve a host file to another node
but has no staging store and cannot update itself over LoRa.
Installing an ESP32 Full Companion may require one merged-image erase/flash
to adopt its expanded partition table. Once migrated, later Full Companion
releases use normal app updates. The transport-specific non-Full images stay
available as explicit build targets, but are not canonical release artifacts
when the qualified Full image fits.
The old aliases still work with `build-firmware` and
`build-matching-firmwares`. Dedicated repeater LoRa OTA receiver images are not
+5 -2
View File
@@ -163,8 +163,11 @@ target recipes, but application behavior no longer uses that umbrella as an
unrelated compile guard. In particular, ESP32 WiFi/WebConfig terminal controls
are compiled from their actual WiFi/WebConfig capability, and BLE is always
started before WiFi on any combined ESP32 WiFi+BLE Companion to avoid heap
fragmentation. The build's capability sidecar verifies the Full controls after
linking.
fragmentation. Compile-time prerequisite checks reject inconsistent feature
flags. After linking, the capability sidecar verifies USB, BLE, the OTA CLI,
TempRadio, and each platform's host-folder transport; it also verifies the TCP
terminal, WebConfig, and WiFi seeder on ESP32, plus dedicated logging whenever
the board uses dual CDC.
On 4 MB ESP32 boards, the full target uses a single 3 MB application partition
so WiFi, BLE, WebConfig, and source-only mOTA fit together. The T-Beam 1W Full
+32 -6
View File
@@ -11,11 +11,13 @@
#ifndef COMPANION_FEATURE_OTA_CLI
#define COMPANION_FEATURE_OTA_CLI 1
#endif
#ifndef COMPANION_FEATURE_NETWORK_TERMINAL
#define COMPANION_FEATURE_NETWORK_TERMINAL 1
#endif
#ifndef COMPANION_FEATURE_MEMORY_DIAGNOSTICS
#define COMPANION_FEATURE_MEMORY_DIAGNOSTICS 1
#if defined(ESP32_PLATFORM)
#ifndef COMPANION_FEATURE_NETWORK_TERMINAL
#define COMPANION_FEATURE_NETWORK_TERMINAL 1
#endif
#ifndef COMPANION_FEATURE_MEMORY_DIAGNOSTICS
#define COMPANION_FEATURE_MEMORY_DIAGNOSTICS 1
#endif
#endif
#if defined(MESH_DUAL_CDC_LOGGING)
#ifndef COMPANION_FEATURE_DEDICATED_USB_LOGGING
@@ -48,12 +50,36 @@
#define COMPANION_FEATURE_DEDICATED_USB_LOGGING 0
#endif
#if COMPANION_FEATURE_OTA_CLI && !defined(ENABLE_OTA)
#error "COMPANION_FEATURE_OTA_CLI requires ENABLE_OTA"
#endif
#if COMPANION_FEATURE_NETWORK_TERMINAL && !defined(ENABLE_USB_INTERFACE)
#error "COMPANION_FEATURE_NETWORK_TERMINAL requires ENABLE_USB_INTERFACE"
#endif
#if COMPANION_FEATURE_NETWORK_TERMINAL \
&& !(defined(ESP32_PLATFORM) && defined(WIFI_SSID) \
&& defined(ENABLE_OTA))
#error "COMPANION_FEATURE_NETWORK_TERMINAL requires ESP32 WiFi and the OTA source overlay"
#endif
#if COMPANION_FEATURE_USB_MOTA_SOURCE \
&& !(defined(NRF52_PLATFORM) && defined(OTA_FOLDER_SERIAL) \
&& defined(ENABLE_USB_INTERFACE))
&& defined(ENABLE_USB_INTERFACE) && defined(ENABLE_OTA))
#error "COMPANION_FEATURE_USB_MOTA_SOURCE requires nRF52 USB folder seeding"
#endif
#if COMPANION_FEATURE_MEMORY_DIAGNOSTICS && !defined(ESP32_PLATFORM)
#error "COMPANION_FEATURE_MEMORY_DIAGNOSTICS requires ESP32"
#endif
#if COMPANION_FEATURE_DEDICATED_USB_LOGGING \
&& !(defined(MESH_DUAL_CDC_LOGGING) \
&& defined(ENABLE_USB_INTERFACE))
#error "COMPANION_FEATURE_DEDICATED_USB_LOGGING requires dual-CDC USB"
#endif
#if defined(COMPANION_RADIO_FULL) && !defined(BLE_PIN_CODE)
#error "COMPANION_RADIO_FULL requires the Bluetooth Companion transport"
#endif
+80
View File
@@ -149,4 +149,84 @@ verify_reduced_sensor_flags \
verify_reduced_sensor_flags \
Heltec_t114_repeater_lora_ota_no_external_sensors 0
# A qualified Full Companion is the one canonical release artifact for its
# board. The individual USB/BLE transports remain explicitly buildable, but
# must not be republished beside the Full image.
SUPPORTED_PIO_ENVS=(
Station_G2_companion_radio_usb
Station_G2_companion_radio_ble
Station_G2_companion_radio_wifi
Station_G2_companion_radio_full
)
for env_name in "${SUPPORTED_PIO_ENVS[@]}"; do
PIO_ENV_PLATFORM_BY_NAME[$env_name]=ESP32_PLATFORM
PIO_ENV_BOARD_BY_NAME[$env_name]=station-g2
done
mapfile -t companion_release_targets < <(
print_release_firmware_targets get-companion-firmwares-to-build
)
[ "${#companion_release_targets[@]}" -eq 1 ] \
|| fail "Station G2 release did not collapse transports to one Full Companion"
[ "${companion_release_targets[0]}" = Station_G2_companion_radio_full ] \
|| fail "Station G2 release selected a non-Full Companion artifact"
# A WiFi base's final -UENABLE_OTA must not win over the Full Companion's
# source-only OTA overlay. That mismatch compiles out both the TCP terminal and
# seeder while still leaving a superficially valid binary.
pio_env_option_contains() {
[ "$2" = build_flags ] && [ "$3" = -UENABLE_OTA ]
}
PLATFORMIO_BUILD_FLAGS=""
PLATFORMIO_BUILD_UNFLAGS=""
PLATFORMIO_EXTRA_SCRIPTS=""
unset MESHCORE_FORCE_LORA_OTA
apply_companion_radio_full_profile \
Station_G2_companion_radio_full Station_G2_companion_radio_wifi
apply_lora_ota_flag_order_fix \
Station_G2_companion_radio_full Station_G2_companion_radio_wifi
[ "${MESHCORE_FORCE_LORA_OTA:-}" = 1 ] \
|| fail "ESP32 Full Companion did not force its OTA source overlay"
[[ "$PLATFORMIO_EXTRA_SCRIPTS" == *"pre:scripts/force_lora_ota.py"* ]] \
|| fail "ESP32 Full Companion did not install the OTA flag-order fix"
# The same protection applies to explicitly requested standalone OTA
# transports even though the canonical release publishes the Full replacement.
PIO_ENV_OTA_BY_NAME[Station_G2_companion_radio_wifi]=1
PLATFORMIO_EXTRA_SCRIPTS=""
unset MESHCORE_FORCE_LORA_OTA
apply_lora_ota_flag_order_fix \
Station_G2_companion_radio_wifi Station_G2_companion_radio_wifi
[ "${MESHCORE_FORCE_LORA_OTA:-}" = 1 ] \
|| fail "standalone ESP32 OTA Companion did not force its OTA overlay"
[[ "$PLATFORMIO_EXTRA_SCRIPTS" == *"pre:scripts/force_lora_ota.py"* ]] \
|| fail "standalone ESP32 OTA Companion omitted the OTA flag-order fix"
# Full capability contracts must use functional strings that survive release
# builds with optional debug logging disabled.
BUILD_PROFILE_FOR_TARGET=full
BUILD_CAPABILITIES=()
BUILD_REDUCTIONS=()
BUILD_EXPECTATIONS=()
declare_build_capability_contract \
Station_G2_companion_radio_full ESP32_PLATFORM
expectations=" ${BUILD_EXPECTATIONS[*]} "
[[ "$expectations" == *"companion.network_terminal=USB currently owns the Full Companion terminal"* ]] \
|| fail "ESP32 Full contract uses no stable network-terminal evidence"
[[ "$expectations" == *"companion.wifi_ota_seeder=OTA seeder listening on :"* ]] \
|| fail "ESP32 Full contract omitted the WiFi seeder"
[[ "$expectations" != *"Full Companion terminal listening"* ]] \
|| fail "ESP32 Full contract still depends on optional debug logging"
PIO_ENV_PLATFORM_BY_NAME[RAK_3401_companion_radio_full]=NRF52_PLATFORM
BUILD_CAPABILITIES=()
BUILD_REDUCTIONS=()
BUILD_EXPECTATIONS=()
declare_build_capability_contract \
RAK_3401_companion_radio_full NRF52_PLATFORM
expectations=" ${BUILD_EXPECTATIONS[*]} "
[[ "$expectations" == *"companion.usb_mota_source=ota folder on"* ]] \
|| fail "nRF52 Full contract omitted USB folder seeding"
[[ "$expectations" != *"companion.network_terminal="* ]] \
|| fail "nRF52 Full contract promised an ESP32-only network terminal"
echo "test_build_profiles: OK"
+10 -1
View File
@@ -1,6 +1,12 @@
[Station_G2]
extends = esp32_base
board = station-g2
; MeshCore and the Station G2's source-built dependencies do not throw C++
; exceptions. Removing the otherwise forced exception runtime saves about
; 67 KiB, keeping the complete ordinary repeater inside the deployed 1.25 MiB
; app slot without removing sensors, LoRa OTA, the browser updater, or CLI.
build_unflags =
-fexceptions
; Preserve the original 0x10000/0x150000 dual-OTA layout so app-only updates do
; not require replacing the partition table or erasing an installed G2.
board_build.partitions = default.csv
@@ -11,6 +17,7 @@ board_build.flash_mode = dio
build_flags =
${esp32_base.build_flags}
${sensor_base.build_flags}
-fno-exceptions
-I variants/station_g2
-I src/helpers/ui
-D STATION_G2
@@ -326,7 +333,9 @@ lib_deps =
extends = env:Station_G2_companion_radio_wifi
platform = ${esp32_s3_dual_cdc_full.platform}
board_build.flash_mode = ${esp32_s3_full.board_build.flash_mode}
build_unflags = ${esp32_s3_dual_cdc_full.build_unflags}
build_unflags =
${Station_G2.build_unflags}
${esp32_s3_dual_cdc_full.build_unflags}
build_flags =
${env:Station_G2_companion_radio_wifi.build_flags}
${esp32_s3_dual_cdc_full.build_flags}