From 759a35fc4f8e26ffef176a7aa8a566f2a268bdb2 Mon Sep 17 00:00:00 2001 From: mikecarper Date: Fri, 14 Aug 2026 15:16:03 -0700 Subject: [PATCH] Fix complete firmware matrix builds --- build.sh | 12 +++---- examples/simple_repeater/MyMesh.cpp | 45 +++++++++++++++++++------- examples/simple_repeater/MyMesh.h | 9 ++++++ src/Dispatcher.h | 6 ++++ variants/meshtracker_x1/platformio.ini | 2 ++ variants/rak3x72/platformio.ini | 15 +++++++++ variants/tiny_relay/platformio.ini | 15 +++++++++ variants/wio-e5-dev/platformio.ini | 8 +++++ variants/wio-e5-mini/platformio.ini | 15 +++++++++ 9 files changed, 109 insertions(+), 18 deletions(-) diff --git a/build.sh b/build.sh index 5e9e3bf3..6ace1ace 100755 --- a/build.sh +++ b/build.sh @@ -1971,11 +1971,12 @@ requires_esp32_companion_full_ota_fallback() { } requires_dram_limited_neighbors() { - # These classic ESP32 MQTT observers keep their persistent neighbor and MQTT - # discovery tables in internal DRAM. Their GPS, TLS, and OTA state leave too - # little linker margin for the protocol maximum, even when PSRAM is present. + # These targets cannot hold the protocol-maximum neighbor table. Classic + # 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. case "${1,,}" in - tbeam_sx1262_repeater_observer_mqtt|tbeam_sx1262_room_server_observer_mqtt|tbeam_sx1276_repeater_observer_mqtt|tbeam_sx1276_room_server_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 } @@ -2173,8 +2174,7 @@ apply_repeater_neighbor_capacity() { fi # Repeater discovery uses one-byte indexes, so 254 is the largest usable - # table. Keep the two classic T-Beam MQTT observers at their measured safe - # capacity; their 254-entry builds leave less than 256 bytes of DRAM margin. + # table. Keep explicitly constrained targets at their measured safe capacity. if requires_dram_limited_neighbors "$env_name"; then max_neighbours=$DRAM_LIMITED_MAX_NEIGHBOURS append_platformio_build_unflags "-DMAX_NEIGHBOURS=8 -DMAX_NEIGHBOURS=254" diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 9ec0e430..1a9cf548 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -990,13 +990,15 @@ bool MyMesh::allowPacketForward(const mesh::Packet *packet) { // other forwarding gate has accepted the packet. Quota is then spent only // for a message this repeater will actually retransmit. #if !defined(PORTABLE_MQTT_OBSERVER) +#if MESH_ENABLE_FLOOD_GROUP_MODERATION if (packet->isRouteFlood() && shouldBlockFloodGroupTextForward(packet)) return false; +#endif if (packet->isRouteFlood()) commitFloodPacketFilterRates(packet); // Normal path mode accepts clock evidence only from packets this node would // forward. Edge mode observes verified evidence on the receive path instead, // so repeat off and other forwarding filters do not hide a single upstream // path from a node at the edge of the network. -#if !defined(PORTABLE_MQTT_OBSERVER) +#if !defined(PORTABLE_MQTT_OBSERVER) && MESH_ENABLE_CLOCK_SYNC if (!clock_sync_mesh_edge_enabled) recordAcceptedFloodClockSample(packet); #endif #endif @@ -2551,7 +2553,7 @@ void MyMesh::onAdvertRecv(mesh::Packet *packet, const mesh::Identity &id, uint32 // Mesh calls this hook only after verifying the advert's Ed25519 signature. // Edge mode observes it here rather than in allowPacketForward(), because // forwarding can be disabled on a receive-only edge node. -#if !defined(PORTABLE_MQTT_OBSERVER) +#if !defined(PORTABLE_MQTT_OBSERVER) && MESH_ENABLE_CLOCK_SYNC if (clock_sync_mesh_edge_enabled && isClockSyncCollectionActive()) { uint8_t source_id[4]; mesh::Utils::sha256(source_id, sizeof(source_id), id.pub_key, PUB_KEY_SIZE); @@ -2570,7 +2572,7 @@ void MyMesh::onAdvertRecv(mesh::Packet *packet, const mesh::Identity &id, uint32 } void MyMesh::onGroupPacketRecv(mesh::Packet* packet) { -#if !defined(PORTABLE_MQTT_OBSERVER) +#if !defined(PORTABLE_MQTT_OBSERVER) && MESH_ENABLE_CLOCK_SYNC // The base Mesh calls this for every unseen, structurally valid group packet // before the forwarding decision. Public-channel decryption below also // verifies its MAC, so unrelated or forged channel packets are ignored. @@ -2986,7 +2988,9 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc sizeof(flood_channel_direct_scopes)); memset(flood_channel_scope_requirements, 0, sizeof(flood_channel_scope_requirements)); +#if MESH_ENABLE_FLOOD_GROUP_MODERATION memset(flood_group_moderation, 0, sizeof(flood_group_moderation)); +#endif #if MESH_ENABLE_FLOOD_RULE_ENGINE flood_policy_has_embedded_sections = false; flood_channel_data_rule_slot = 0xFF; @@ -3177,8 +3181,10 @@ void MyMesh::begin(FILESYSTEM *fs) { loadFloodChannelScopes(); #endif loadFloodChannelScopeRequirements(); +#if MESH_ENABLE_FLOOD_GROUP_MODERATION loadFloodGroupModeration(); -#if !defined(PORTABLE_MQTT_OBSERVER) +#endif +#if MESH_ENABLE_CLOCK_SYNC loadClockSyncPrefs(); #endif #endif @@ -8327,6 +8333,8 @@ void MyMesh::deleteFloodChannelScopeRequirement(const char* args, } } +#if MESH_ENABLE_FLOOD_GROUP_MODERATION + static bool parseFloodModerationPath(const char* text, uint8_t& hash_size, uint8_t& path_hops, uint8_t path[FLOOD_GROUP_MODERATION_PATH_BYTES_MAX]) { memset(path, 0, FLOOD_GROUP_MODERATION_PATH_BYTES_MAX); @@ -8475,6 +8483,8 @@ bool MyMesh::saveFloodGroupModeration() { return success; } +#endif + bool MyMesh::decodeFloodGroupPlainText(const mesh::Packet* packet, const uint8_t* secret, uint8_t key_len, uint32_t& timestamp, char* sender, size_t sender_len) const { if (sender != NULL && sender_len > 0) sender[0] = 0; @@ -8509,6 +8519,8 @@ bool MyMesh::decodeFloodGroupPlainText(const mesh::Packet* packet, const uint8_t return true; } +#if MESH_ENABLE_FLOOD_GROUP_MODERATION + bool MyMesh::shouldBlockFloodGroupTextForward(const mesh::Packet* packet) { if (packet == NULL || !packet->isRouteFlood() || packet->getPayloadType() != PAYLOAD_TYPE_GRP_TXT || packet->payload_len <= PATH_HASH_SIZE + CIPHER_MAC_SIZE) return false; @@ -8849,7 +8861,9 @@ void MyMesh::deleteFloodGroupModeration(const char* args, char* reply) { } } -#if !defined(PORTABLE_MQTT_OBSERVER) +#endif + +#if !defined(PORTABLE_MQTT_OBSERVER) && MESH_ENABLE_CLOCK_SYNC void MyMesh::loadClockSyncPrefs() { clock_sync_mesh_enabled = CLOCK_SYNC_MESH_DEFAULT_ENABLED != 0; @@ -9489,9 +9503,9 @@ void MyMesh::formatClockSyncStatus(const char* args, char* reply, size_t reply_l #else -// Portable MQTT observers use their bridge's NTP source. Omitting the mesh -// consensus implementation keeps these legacy-slot images update-compatible; -// FULL MQTT images retain both NTP and mesh clock synchronization. +// Portable MQTT observers use their bridge's NTP source. Flash-constrained +// repeaters can also omit mesh consensus while retaining manual clock setting +// and scheduled radio changes. static const char* clockSyncMeshSuppressionName(uint8_t source) { (void)source; return "unavailable"; @@ -10474,13 +10488,18 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, ClientInfo* sender, char * } else if (commandFamilyMatches(command, "del flood.rule")) { deleteFloodPacketFilter(command + strlen("del flood.rule"), reply); #endif - } else if (commandFamilyMatches(command, "get flood.moderation")) { + } +#if MESH_ENABLE_FLOOD_GROUP_MODERATION + else if (commandFamilyMatches(command, "get flood.moderation")) { formatFloodGroupModeration(command + strlen("get flood.moderation"), reply); } else if (commandFamilyMatches(command, "set flood.moderation")) { setFloodGroupModeration(command + strlen("set flood.moderation"), reply); } else if (commandFamilyMatches(command, "del flood.moderation")) { deleteFloodGroupModeration(command + strlen("del flood.moderation"), reply); - } else if (commandFamilyMatches(command, "get clock.sync.status")) { + } +#endif +#if MESH_ENABLE_CLOCK_SYNC + else if (commandFamilyMatches(command, "get clock.sync.status")) { formatClockSyncStatus(command + strlen("get clock.sync.status"), reply, 160); } else if (strcmp(command, "get clock.sync") == 0) { formatClockSyncStatus("", reply, 160); @@ -10613,7 +10632,9 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, ClientInfo* sender, char * sprintf(reply, "OK - clock sync requires %u samples", (unsigned int)required); } } - } else if (memcmp(command, "setperm ", 8) == 0) { // format: setperm {pubkey-hex} {permissions-int8} + } +#endif + else if (memcmp(command, "setperm ", 8) == 0) { // format: setperm {pubkey-hex} {permissions-int8} char* hex = &command[8]; char* sp = strchr(hex, ' '); // look for separator char if (sp == NULL) { @@ -11120,7 +11141,7 @@ void __attribute__((noinline)) MyMesh::servicePostMeshLoop() { uint32_t now = millis(); uptime_millis += now - last_millis; last_millis = now; -#if !defined(PORTABLE_MQTT_OBSERVER) +#if !defined(PORTABLE_MQTT_OBSERVER) && MESH_ENABLE_CLOCK_SYNC checkGpsClockSyncOverride(); checkClockSync(); #endif diff --git a/examples/simple_repeater/MyMesh.h b/examples/simple_repeater/MyMesh.h index 71c920d3..b1e4856b 100644 --- a/examples/simple_repeater/MyMesh.h +++ b/examples/simple_repeater/MyMesh.h @@ -210,6 +210,9 @@ struct NeighbourInfo { #define FLOOD_CHANNEL_SCOPE_REQUIRE_SLOTS FLOOD_CHANNEL_SCOPE_SLOTS #endif +#ifndef MESH_ENABLE_FLOOD_GROUP_MODERATION + #define MESH_ENABLE_FLOOD_GROUP_MODERATION 1 +#endif #ifndef FLOOD_GROUP_MODERATION_SLOTS #define FLOOD_GROUP_MODERATION_SLOTS 16 #endif @@ -219,6 +222,10 @@ struct NeighbourInfo { #define FLOOD_GROUP_MODERATION_HOPS_ALL 0xFF #define FLOOD_GROUP_MODERATION_RATE_UNLIMITED 0xFFFF +#ifndef MESH_ENABLE_CLOCK_SYNC + #define MESH_ENABLE_CLOCK_SYNC 1 +#endif + #ifndef CLOCK_SYNC_SAMPLE_SLOTS #define CLOCK_SYNC_SAMPLE_SLOTS 16 #endif @@ -399,7 +406,9 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks [FLOOD_PACKET_FILTER_SCOPE_NAME_LEN]; FloodChannelScopeRequireEntry flood_channel_scope_requirements[FLOOD_CHANNEL_SCOPE_REQUIRE_SLOTS]; +#if MESH_ENABLE_FLOOD_GROUP_MODERATION FloodGroupModerationEntry flood_group_moderation[FLOOD_GROUP_MODERATION_SLOTS]; +#endif uint64_t recv_pkt_filter_match_mask; #if MESH_ENABLE_FLOOD_RULE_ENGINE bool flood_policy_has_embedded_sections; diff --git a/src/Dispatcher.h b/src/Dispatcher.h index e8f42621..a48700a6 100644 --- a/src/Dispatcher.h +++ b/src/Dispatcher.h @@ -116,6 +116,12 @@ public: virtual bool supportsRxPowerSaving() const { return false; } virtual bool setRxPowerSaving(bool enabled, uint32_t rx_us, uint32_t sleep_us) { return !enabled; } + virtual bool supportsRxPowerSavingRfRxDisable() const { return false; } + virtual bool setRxPowerSavingRfRxDisabled(bool disabled) { + (void)disabled; + return false; + } + virtual bool isRxPowerSavingRfRxDisabled() const { return false; } /** * \brief Attempts to change the radio modulation parameters without waiting. diff --git a/variants/meshtracker_x1/platformio.ini b/variants/meshtracker_x1/platformio.ini index 2194d48d..74986661 100644 --- a/variants/meshtracker_x1/platformio.ini +++ b/variants/meshtracker_x1/platformio.ini @@ -135,3 +135,5 @@ lib_deps = ${MeshTracker_X1.lib_deps} extends = MeshTracker_X1 build_src_filter = ${MeshTracker_X1.build_src_filter} +<../examples/kiss_modem/> +lib_deps = ${MeshTracker_X1.lib_deps} + stevemarple/MicroNMEA @ ^2.0.6 diff --git a/variants/rak3x72/platformio.ini b/variants/rak3x72/platformio.ini index 9e66b70d..ed940bef 100644 --- a/variants/rak3x72/platformio.ini +++ b/variants/rak3x72/platformio.ini @@ -24,10 +24,14 @@ build_flags = ${rak3x72.build_flags} -fno-inline-small-functions ; reduce flash without moving the deployed filesystem boundary -fipa-pta -fmerge-all-constants + -fno-ipa-cp-clone + -fno-partial-inlining -fno-semantic-interposition -fno-unwind-tables -fno-asynchronous-unwind-tables -D LFS_FLASH_TOTAL_SIZE=16384 + -D MESH_ENABLE_CLOCK_SYNC=0 ; preserve the 16 KiB filesystem on this 256 KiB part + -D MESH_ENABLE_FLOOD_GROUP_MODERATION=0 ; keep core routing and radio scheduling in flash -D ADVERT_NAME='"RAK3x72 Repeater"' -D ADMIN_PASSWORD='"password"' -D MAX_NEIGHBOURS=50 @@ -36,7 +40,18 @@ build_src_filter = ${rak3x72.build_src_filter} [env:RAK_3x72_sensor] extends = rak3x72 +build_unflags = -Os build_flags = ${rak3x72.build_flags} + -Oz + -flto + -fno-inline-small-functions + -fipa-pta + -fmerge-all-constants + -fno-ipa-cp-clone + -fno-partial-inlining + -fno-semantic-interposition + -fno-unwind-tables + -fno-asynchronous-unwind-tables -D ADVERT_NAME='"RAK3x72 Sensor"' -D ADMIN_PASSWORD='"password"' build_src_filter = ${rak3x72.build_src_filter} diff --git a/variants/tiny_relay/platformio.ini b/variants/tiny_relay/platformio.ini index 443c744d..9aec4c01 100644 --- a/variants/tiny_relay/platformio.ini +++ b/variants/tiny_relay/platformio.ini @@ -25,10 +25,14 @@ build_flags = ${Tiny_Relay.build_flags} -fno-inline-small-functions ; reduce flash without moving the deployed filesystem boundary -fipa-pta -fmerge-all-constants + -fno-ipa-cp-clone + -fno-partial-inlining -fno-semantic-interposition -fno-unwind-tables -fno-asynchronous-unwind-tables -D LFS_FLASH_TOTAL_SIZE=16384 + -D MESH_ENABLE_CLOCK_SYNC=0 ; preserve the 16 KiB filesystem on this 256 KiB part + -D MESH_ENABLE_FLOOD_GROUP_MODERATION=0 ; keep core routing and radio scheduling in flash -D ADVERT_NAME='"tiny_relay Repeater"' -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 @@ -39,7 +43,18 @@ build_src_filter = ${Tiny_Relay.build_src_filter} [env:Tiny_Relay_sensor] extends = Tiny_Relay +build_unflags = -Os build_flags = ${Tiny_Relay.build_flags} + -Oz + -flto + -fno-inline-small-functions + -fipa-pta + -fmerge-all-constants + -fno-ipa-cp-clone + -fno-partial-inlining + -fno-semantic-interposition + -fno-unwind-tables + -fno-asynchronous-unwind-tables -D ADVERT_NAME='"tiny_relay Sensor"' -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 diff --git a/variants/wio-e5-dev/platformio.ini b/variants/wio-e5-dev/platformio.ini index f71d4411..245339c3 100644 --- a/variants/wio-e5-dev/platformio.ini +++ b/variants/wio-e5-dev/platformio.ini @@ -25,10 +25,14 @@ build_flags = ${lora_e5.build_flags} -fno-inline-small-functions ; reduce flash without moving the deployed filesystem boundary -fipa-pta -fmerge-all-constants + -fno-ipa-cp-clone + -fno-partial-inlining -fno-semantic-interposition -fno-unwind-tables -fno-asynchronous-unwind-tables -D LFS_FLASH_TOTAL_SIZE=16384 + -D MESH_ENABLE_CLOCK_SYNC=0 ; preserve the 16 KiB filesystem on this 256 KiB part + -D MESH_ENABLE_FLOOD_GROUP_MODERATION=0 ; keep core routing and radio scheduling in flash -D LORA_TX_POWER=22 -D ADVERT_NAME='"WIO-E5 Repeater"' -D ADMIN_PASSWORD='"password"' @@ -39,7 +43,9 @@ build_src_filter = ${lora_e5.build_src_filter} [env:wio-e5-repeater_bridge_rs232] extends = lora_e5 board_upload.maximum_size = 245760 ; 240 KiB app, 16 KiB LittleFS +build_unflags = -Os build_flags = ${lora_e5.build_flags} + -Oz -flto -fno-inline-small-functions ; reduce flash without moving the deployed filesystem boundary -fipa-pta @@ -52,6 +58,8 @@ build_flags = ${lora_e5.build_flags} -fno-unwind-tables -fno-asynchronous-unwind-tables -D LFS_FLASH_TOTAL_SIZE=16384 + -D MESH_ENABLE_CLOCK_SYNC=0 ; preserve the 16 KiB filesystem on this 256 KiB part + -D MESH_ENABLE_FLOOD_GROUP_MODERATION=0 ; keep core routing and radio scheduling in flash -D MESH_ENABLE_RECENT_REPEATERS=1 -D LORA_TX_POWER=22 -D ADVERT_NAME='"WIO-E5 Repeater"' diff --git a/variants/wio-e5-mini/platformio.ini b/variants/wio-e5-mini/platformio.ini index 2417b393..f52986cc 100644 --- a/variants/wio-e5-mini/platformio.ini +++ b/variants/wio-e5-mini/platformio.ini @@ -27,12 +27,16 @@ build_flags = ${lora_e5_mini.build_flags} -fno-inline-small-functions ; reduce flash without moving the deployed filesystem boundary -fipa-pta -fmerge-all-constants + -fno-ipa-cp-clone + -fno-partial-inlining -fno-semantic-interposition -fno-unwind-tables -fno-asynchronous-unwind-tables -D RADIO_LIVENESS_SOFT_ONLY=1 ; integrated STM32WL has no separate radio-reset pin -D WIO_E5_MINI_NO_EXTERNAL_SENSORS=1 ; the dedicated sensor env retains BME280 support -D LFS_FLASH_TOTAL_SIZE=16384 + -D MESH_ENABLE_CLOCK_SYNC=0 ; preserve the 16 KiB filesystem on this 256 KiB part + -D MESH_ENABLE_FLOOD_GROUP_MODERATION=0 ; keep core routing and radio scheduling in flash -D MESH_ENABLE_RECENT_REPEATERS=1 -D LORA_TX_POWER=22 -D ADVERT_NAME='"wio-e5-mini Repeater"' @@ -44,7 +48,18 @@ lib_deps = ${stm32_base.lib_deps} [env:wio-e5-mini_sensor] extends = lora_e5_mini +build_unflags = -Os build_flags = ${lora_e5_mini.build_flags} + -Oz + -flto + -fno-inline-small-functions + -fipa-pta + -fmerge-all-constants + -fno-ipa-cp-clone + -fno-partial-inlining + -fno-semantic-interposition + -fno-unwind-tables + -fno-asynchronous-unwind-tables -D LORA_TX_POWER=22 -D ADVERT_NAME='"wio-e5-mini Sensor"' -D ADMIN_PASSWORD='"password"'