diff --git a/build.sh b/build.sh index 0d2df280d..c9612f01b 100755 --- a/build.sh +++ b/build.sh @@ -2641,6 +2641,24 @@ requires_dram_limited_neighbors() { # ESP32 MQTT observers exhaust internal DRAM, while the 256 KiB STM32WL # targets exhaust their fixed application region because initialized table # storage is part of the image. + # These measured classic ESP32 LoRa OTA images fall below the required + # 8 KiB static reserve at 254 neighbors. Use their board-declared 50-entry + # tables when the OTA manager is included. + case "${1,,}" in + generic_e22_sx1262_repeater_lora_ota_no_external_sensors|\ + generic_e22_sx1268_repeater_lora_ota_no_external_sensors|\ + heltec_v2_repeater_lora_ota_no_external_sensors|\ + meshadventurer_sx1262_repeater_lora_ota_no_external_sensors|\ + meshadventurer_sx1268_repeater_lora_ota_no_external_sensors|\ + tbeam_sx1262_repeater_lora_ota_no_external_sensors|\ + tbeam_sx1276_repeater_lora_ota_no_external_sensors) + return 0 ;; + generic_e22_sx1262_repeater|generic_e22_sx1268_repeater|\ + heltec_v2_repeater|meshadventurer_sx1262_repeater|\ + meshadventurer_sx1268_repeater|tbeam_sx1262_repeater|\ + tbeam_sx1276_repeater) + if [ "$ESP32_FULL_BUILD" = "1" ]; then return 0; fi ;; + esac # # Classic ESP32 bridge targets only need the lower limit when the expanded # FULL profile also enables packet logging. Keep their ordinary and @@ -2662,6 +2680,8 @@ requires_dram_limited_neighbors() { esac fi case "${1,,}" in + lilygo_tlora_v2_1_1_6_repeater_observer_mqtt_) + return 0 ;; tbeam_sx1262_repeater_observer_mqtt|tbeam_sx1262_room_server_observer_mqtt|tbeam_sx1276_repeater_observer_mqtt|tbeam_sx1276_room_server_observer_mqtt|rak_3x72_repeater|tiny_relay_repeater|wio-e5-mini_repeater|wio-e5-repeater_bridge_rs232|wio-e5_repeater) return 0 ;; *) return 1 ;; esac @@ -2993,6 +3013,7 @@ declare_build_capability_contract() { apply_esp32_lora_ota_size_profile() { local env_name=$1 + local max_neighbours=$ESP32_FULL_MAX_NEIGHBOURS if [ "$BUILD_PROFILE_FOR_TARGET" != "standard" ] \ || ! requires_esp32_portable_app_slot "$env_name"; then @@ -3018,12 +3039,18 @@ apply_esp32_lora_ota_size_profile() { || requires_esp32_field_browser_ota "$env_name"; then # The no-external-sensors image is also the self-updatable field image. Keep # manual browser OTA available on every ESP32 family through the compact - # uploader, the complete role CLI, and the full one-byte neighbor-index - # range. MeshCore and this source-built dependency set do not use C++ + # uploader, the complete role CLI, and the target's safe neighbor capacity. + # MeshCore and this source-built dependency set do not use C++ # exceptions, so omit their otherwise forced runtime tables instead of # dropping WiFi OTA, LoRa OTA, USB seeding, or CLI commands. - append_platformio_build_unflags "-DDISABLE_WIFI_OTA=1 -DMAX_NEIGHBOURS=50 -DMAX_NEIGHBOURS=8 -fexceptions" - export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UDISABLE_WIFI_OTA -DLIGHTWEIGHT_WIFI_OTA=1 -DMAX_NEIGHBOURS=${ESP32_FULL_MAX_NEIGHBOURS} -fno-exceptions" + append_platformio_build_unflags "-DDISABLE_WIFI_OTA=1 -DMAX_NEIGHBOURS=8 -fexceptions" + if requires_dram_limited_neighbors "$env_name"; then + max_neighbours=$DRAM_LIMITED_MAX_NEIGHBOURS + append_platformio_build_unflags "-DMAX_NEIGHBOURS=254" + else + append_platformio_build_unflags "-DMAX_NEIGHBOURS=50" + fi + export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UDISABLE_WIFI_OTA -DLIGHTWEIGHT_WIFI_OTA=1 -DMAX_NEIGHBOURS=${max_neighbours} -fno-exceptions" record_build_capability "web.lightweight_browser_ota" else append_platformio_build_unflags "-DLIGHTWEIGHT_WIFI_OTA=1" @@ -3090,6 +3117,32 @@ apply_esp32_full_size_profile() { fi export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DMAX_NEIGHBOURS=${max_neighbours}" + case "${env_name,,}" in + tbeam_sx1262_repeater_observer_mqtt|tbeam_sx1276_repeater_observer_mqtt) + # MQTT/TLS plus OTA left only 3.3 KiB of static-region headroom with + # 63 rules. Retain the complete rule engine with a 31-entry table. + append_platformio_build_unflags "-DFLOOD_PACKET_FILTER_SLOTS=63" + export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFLOOD_PACKET_FILTER_SLOTS=31" + record_build_reduction \ + "mesh.flood_rules limited to 31 by measured internal DRAM; complete rule engine retained" + ;; + generic_e22_sx1262_repeater_bridge_espnow|\ + generic_e22_sx1268_repeater_bridge_espnow|\ + heltec_v2_repeater_bridge_espnow|\ + lilygo_tlora_v2_1_1_6_repeater_bridge_espnow|\ + meshadventurer_sx1262_repeater_bridge_espnow|\ + meshadventurer_sx1268_repeater_bridge_espnow|\ + tbeam_sx1262_repeater_bridge_espnow|\ + tbeam_sx1276_repeater_bridge_espnow) + if [ "${PACKET_LOGGING_OVERRIDE,,}" = "on" ]; then + append_platformio_build_unflags "-DFLOOD_PACKET_FILTER_SLOTS=63" + export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFLOOD_PACKET_FILTER_SLOTS=47" + record_build_reduction \ + "mesh.flood_rules limited to 47 by measured internal DRAM; complete rule engine retained" + fi + ;; + esac + # Restore the full ElegantOTA implementation only when the target already # declares its dependency. Some ESP32-C6 targets intentionally have no # compatible ElegantOTA library and retain their target WiFi-OTA setting. @@ -3540,9 +3593,9 @@ apply_companion_radio_full_profile() { meshadventurer_sx1262_companion_radio_full|\ meshadventurer_sx1268_companion_radio_full) append_platformio_build_unflags "-DMAX_CONTACTS=160 -DMAX_GROUP_CHANNELS=40 -DOFFLINE_QUEUE_SIZE=128" - export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DMAX_CONTACTS=160 -DMAX_GROUP_CHANNELS=30 -DOFFLINE_QUEUE_SIZE=64" + export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DMAX_CONTACTS=100 -DMAX_GROUP_CHANNELS=30 -DOFFLINE_QUEUE_SIZE=16" record_build_reduction \ - "companion.capacity limited to 160 contacts, 30 channels, and 64 queued frames by measured internal DRAM" + "companion.capacity limited to 100 contacts, 30 channels, and 16 queued frames by measured internal DRAM" ;; *) if requires_esp32_companion_full_ota_fallback "$pio_env_name"; then diff --git a/docs/companion_offline_queue.md b/docs/companion_offline_queue.md index a3b406ff4..ae973d991 100644 --- a/docs/companion_offline_queue.md +++ b/docs/companion_offline_queue.md @@ -15,13 +15,13 @@ A reboot clears it. | RP2040 | 256 | | STM32 | 16 | | Known constrained classic ESP32 target override | 128 | -| Meshadventurer Full Companion | 64 | +| Meshadventurer Full Companion | 16 | | Constrained Full ESP32 fallback | 16 | An explicit target `OFFLINE_QUEUE_SIZE` overrides the platform default. The Heltec V2 and TLora V2 Full Companion profiles, for example, use 16 frames so their combined WiFi, BLE, and LoRa mOTA image retains enough internal DRAM. -Meshadventurer SX1262 and SX1268 Full Companion use 64 frames together with 160 +Meshadventurer SX1262 and SX1268 Full Companion use 16 frames together with 100 contacts and 30 group channels; their ordinary transport-specific images keep 128 frames and 40 channels. diff --git a/docs/companion_radio_full.md b/docs/companion_radio_full.md index 8d5dd61f0..7b14da2d2 100644 --- a/docs/companion_radio_full.md +++ b/docs/companion_radio_full.md @@ -314,9 +314,9 @@ partition layout. Other boards with 8 MB or more retain dual application partitions. Heltec V2 and TLora V2 use 100 contacts, 8 group channels, and a 16-frame offline queue in this combined profile because of internal DRAM limits. Meshadventurer -SX1262 and SX1268 retain 160 contacts, use 30 group channels, and use a -64-frame queue. That is the smallest measured reduction which cleared their -classic ESP32 internal-DRAM link limit; their ordinary transport-specific +SX1262 and SX1268 use 100 contacts, 30 group channels, and a 16-frame queue. +These capacities preserve the required 8 KiB static internal-DRAM reserve +alongside MOTA and all Full transports; their ordinary transport-specific images retain 160 contacts, 40 channels, and 128 queued frames. Full Companions normally retain 256 pending Companion message frames. ESP32 diff --git a/docs/full_companion_features.md b/docs/full_companion_features.md index 9fca32f90..3722d331c 100644 --- a/docs/full_companion_features.md +++ b/docs/full_companion_features.md @@ -161,3 +161,8 @@ and the board's matching BLE-DFU-capable bootloader/SoftDevice. USB remains the fallback when the installed bootloader does not support that procedure. Bluetooth DFU updates the Companion; the separate Bluetooth MOTA source service feeds packages to other mesh nodes. + +For OTAFIX installations, use the exact board/storage profile from +[OTAFIX 2.4.5](https://github.com/mikecarper/Adafruit_nRF52_Bootloader_OTAFIX/releases/tag/0.11.0-OTAFIX2.4.5). +Its release notes cover the Bluetooth reconnect fix and upgrades from older +bootloaders, including the special UF2-drive precautions for version 2.4.3. diff --git a/docs/releases/1.17.1.5.md b/docs/releases/1.17.1.5.md index e0288da55..f7975b861 100644 --- a/docs/releases/1.17.1.5.md +++ b/docs/releases/1.17.1.5.md @@ -31,6 +31,15 @@ application slots and OTA metadata; nRF52 Bluetooth qualification checks the linked DFU service and its application ZIP. LoRa installation on nRF52 still requires the exact matching OTAFIX bootloader and storage arrangement. +Classic ESP32 capacity limits are recorded in each artifact's capability +manifest. Generic E22, Heltec V2, Meshadventurer, and T-Beam OTA repeaters, +plus the TLora MQTT repeater, use 50 neighbors where needed to preserve the +required internal RAM reserve. +T-Beam MQTT repeater profiles retain the full rule engine with 31 flood rules; +constrained classic ESP32 ESP-NOW bridges with logging use 47. +Meshadventurer Full uses 100 contacts, 30 group channels, and a 16-frame +offline queue while retaining its MOTA and transport features. + Since 1.17.1.4, this branch also includes USB session and contact-persistence fixes, automatic nRF52 ExtraFS recovery, improved Indicator setup/display handling, compressed MOTA transport, and measured ESP32 memory limits. @@ -62,3 +71,5 @@ the matrix unsuccessful and must be resolved before publication. `--allow-no-ota` is an explicit development override for cable-only infrastructure. Those outputs do not belong in this OTA-required release. Use a separate output directory when changing the radio or settings profile. +Use a fresh release output directory after changing the source revision or +firmware version so packaging cannot mix old and new binaries. diff --git a/test/test_release_ota_policy.sh b/test/test_release_ota_policy.sh index a1093bead..37afd6350 100644 --- a/test/test_release_ota_policy.sh +++ b/test/test_release_ota_policy.sh @@ -38,4 +38,54 @@ fi resolve_command_targets build-firmware rp_companion_radio_usb >/dev/null [ "${#RESOLVED_BUILD_TARGETS[@]}" = 1 ] || fail "explicit USB Companion was rejected" +# The portable OTA overlay and the final neighbor overlay must agree: an +# earlier build_unflags entry removes even a later definition in PlatformIO. +for target in Generic_E22_sx1262_repeater_lora_ota_no_external_sensors \ + Generic_E22_sx1268_repeater_lora_ota_no_external_sensors \ + Heltec_v2_repeater_lora_ota_no_external_sensors \ + Meshadventurer_sx1262_repeater_lora_ota_no_external_sensors \ + Meshadventurer_sx1268_repeater_lora_ota_no_external_sensors \ + Tbeam_SX1262_repeater_lora_ota_no_external_sensors \ + Tbeam_SX1276_repeater_lora_ota_no_external_sensors; do + PIO_ENV_PLATFORM_BY_NAME[$target]=ESP32_PLATFORM + PLATFORMIO_BUILD_FLAGS="" + PLATFORMIO_BUILD_UNFLAGS="" + BUILD_PROFILE_FOR_TARGET=standard + ESP32_FULL_BUILD=0 + apply_esp32_lora_ota_size_profile "$target" + apply_repeater_neighbor_capacity "$target" + [[ "$PLATFORMIO_BUILD_FLAGS" == *"-DMAX_NEIGHBOURS=50"* ]] \ + || fail "$target lost its measured-safe neighbor capacity" + [[ "$PLATFORMIO_BUILD_UNFLAGS" != *"MAX_NEIGHBOURS=50"* ]] \ + || fail "$target removed its selected neighbor capacity" + [[ "$PLATFORMIO_BUILD_FLAGS" == *"-DLIGHTWEIGHT_WIFI_OTA=1"* ]] \ + || fail "$target lost WiFi OTA while fixing its RAM budget" +done + +ESP32_FULL_BUILD=1 +BUILD_PROFILE_FOR_TARGET=full +PACKET_LOGGING_OVERRIDE=on +for pair in Tbeam_SX1262_repeater_observer_mqtt:31 \ + Tbeam_SX1276_repeater_observer_mqtt:31 \ + Generic_E22_sx1262_repeater_bridge_espnow:47 \ + LilyGo_TLora_V2_1_1_6_repeater_bridge_espnow:47 \ + LilyGo_TLora_V2_1_1_6_repeater_observer_mqtt_:default; do + target=${pair%:*} + rules=${pair##*:} + PIO_ENV_PLATFORM_BY_NAME[$target]=ESP32_PLATFORM + PIO_ENV_FULL_BUILD_BY_NAME[$target]=1 + PLATFORMIO_BUILD_FLAGS="" + PLATFORMIO_BUILD_UNFLAGS="" + apply_esp32_full_size_profile "$target" + apply_repeater_neighbor_capacity "$target" + [[ "$PLATFORMIO_BUILD_FLAGS" == *"-DMAX_NEIGHBOURS=50"* \ + && "$PLATFORMIO_BUILD_UNFLAGS" != *"MAX_NEIGHBOURS=50"* ]] \ + || fail "$target lost its Full profile neighbor capacity" + if [ "$rules" != default ]; then + [[ "$PLATFORMIO_BUILD_FLAGS" == *"-DFLOOD_PACKET_FILTER_SLOTS=$rules"* \ + && "$PLATFORMIO_BUILD_UNFLAGS" != *"FLOOD_PACKET_FILTER_SLOTS=$rules"* ]] \ + || fail "$target lost its Full profile rule capacity" + fi +done + echo "test_release_ota_policy: OK"