From 0dcb4b7d19da56e8171bc6d06a3ac9bbb717ead5 Mon Sep 17 00:00:00 2001 From: mikecarper Date: Wed, 29 Jul 2026 13:10:52 -0700 Subject: [PATCH] Expand ESP32 FULL neighbor capacity --- build.sh | 18 ++++++++++------ examples/simple_repeater/MyMesh.cpp | 30 ++++++++++++++++++++++++-- examples/simple_room_server/MyMesh.cpp | 30 ++++++++++++++++++++++++-- 3 files changed, 68 insertions(+), 10 deletions(-) diff --git a/build.sh b/build.sh index 2a6ae1076..b82809bb5 100755 --- a/build.sh +++ b/build.sh @@ -55,6 +55,7 @@ TAG_PREFIX_SENSOR="sensor" SUPPORTED_PLATFORM_PATTERN='ESP32_PLATFORM|NRF52_PLATFORM|STM32_PLATFORM|RP2040_PLATFORM' OUTPUT_DIR="out" ESP32_LORA_OTA_APP_LIMIT=$((0x150000 - 0x10000)) +ESP32_FULL_MAX_NEIGHBOURS=254 FALLBACK_VERSION_PREFIX="dev" FALLBACK_VERSION_DATE_FORMAT='+%Y-%m-%d-%H-%M' @@ -73,8 +74,8 @@ Commands: build-firmware : Build the firmware for the given build target. build-firmwares: Build all firmwares for all targets. build-firmwares-logging-matrix: Build all firmwares in standard, logging, MQTT, FULL ESP32, and FULL ESP32 logging profiles, logging each target under out/build-logs/ and continuing after failures. - build-full-esp32-firmwares: Build only feature-complete ESP32 profiles with LoRa OTA and expanded dual-OTA partitions. - build-full-esp32-logging-firmwares: Build only feature-complete ESP32 profiles with logging, LoRa OTA, and expanded dual-OTA partitions. + build-full-esp32-firmwares: Build only feature-complete ESP32 profiles with 254 neighbors, LoRa OTA, and expanded dual-OTA partitions. + build-full-esp32-logging-firmwares: Build only feature-complete ESP32 profiles with 254 neighbors, logging, LoRa OTA, and expanded dual-OTA partitions. build-matching-firmwares : Build all firmwares for build targets containing the string given for . build-companion-firmwares: Build all companion firmwares for all build targets. build-repeater-firmwares: Build all repeater firmwares for all build targets. @@ -433,7 +434,7 @@ prompt_for_single_target_build_profile() { local options=( "Standard/custom build" - "FULL everything (all features, logging, LoRa OTA, expanded dual-OTA partitions)" + "FULL everything (all features, 254 neighbors, logging, LoRa OTA, expanded dual-OTA partitions)" ) echo "Select the Option 1 build profile:" @@ -452,7 +453,7 @@ prompt_for_single_target_build_profile() { ;; 2) SINGLE_TARGET_FULL_BUILD=1 - echo "Using FULL everything: all features, logging, LoRa OTA, and expanded dual-OTA partitions." + echo "Using FULL everything: all features, 254 neighbors, logging, LoRa OTA, and expanded dual-OTA partitions." return 0 ;; esac @@ -1811,6 +1812,11 @@ apply_esp32_full_size_profile() { append_platformio_build_unflags "-DWEBCONFIG_DISABLED=1" export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UWEBCONFIG_DISABLED -DWIFI_OTA_SEEDER=1" + # Keep ordinary builds at their board-defined neighbor capacity. FULL builds + # use the largest table supported by the one-byte neighbor discovery indexes. + append_platformio_build_unflags "-DMAX_NEIGHBOURS=50 -DMAX_NEIGHBOURS=8" + export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DMAX_NEIGHBOURS=${ESP32_FULL_MAX_NEIGHBOURS}" + # 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. @@ -2526,13 +2532,13 @@ run_full_esp32_profile() { fi if [ "$logging_mode" = "on" ]; then - echo "${profile_label}: building $((${#full_standard_targets[@]} + ${#full_mqtt_targets[@]})) feature-complete ESP32 target(s) with logging and expanded dual-OTA partitions." + echo "${profile_label}: building $((${#full_standard_targets[@]} + ${#full_mqtt_targets[@]})) feature-complete ESP32 target(s) with ${ESP32_FULL_MAX_NEIGHBOURS} neighbors, logging, and expanded dual-OTA partitions." echo "FULL logging artifacts include LoRa OTA and use filename form: name-full-logging-ota-version." MESHDEBUG_OVERRIDE="on" PACKET_LOGGING_OVERRIDE="on" FIRMWARE_FILENAME_INFIX="full-logging" else - echo "${profile_label}: building $((${#full_standard_targets[@]} + ${#full_mqtt_targets[@]})) feature-complete ESP32 target(s) with expanded dual-OTA partitions." + echo "${profile_label}: building $((${#full_standard_targets[@]} + ${#full_mqtt_targets[@]})) feature-complete ESP32 target(s) with ${ESP32_FULL_MAX_NEIGHBOURS} neighbors and expanded dual-OTA partitions." echo "FULL artifacts include LoRa OTA and use filename form: name-full-ota-version." MESHDEBUG_OVERRIDE="off" PACKET_LOGGING_OVERRIDE="off" diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index c19df4561..d2cf477fa 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -8702,8 +8702,27 @@ void MyMesh::finishNeighborDiscover() { char timestamp[40]; MQTTMessageBuilder::formatIsoTimestampForMqtt(getRTCClock()->getCurrentTime(), 0, nullptr, timestamp, sizeof(timestamp)); - char pubkey_hex[MAX_NEIGHBOURS][65]; - MQTTMessageBuilder::NeighborsMessageEntry entries[MAX_NEIGHBOURS]; + struct NeighborPublishWorkspace { + char pubkey_hex[MAX_NEIGHBOURS][65]; + MQTTMessageBuilder::NeighborsMessageEntry entries[MAX_NEIGHBOURS]; + }; +#if defined(ESP_PLATFORM) + auto* publish_workspace = static_cast( + heap_caps_malloc(sizeof(NeighborPublishWorkspace), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT)); +#else + auto* publish_workspace = static_cast( + malloc(sizeof(NeighborPublishWorkspace))); +#endif + if (!publish_workspace) { + neighbor_discover_active = false; + neighbor_discover_count = 0; + if (_cli.getObserverPrefs()->mqtt_neighbors_enabled) { + next_neighbors_publish = futureMillis(_cli.getObserverPrefs()->mqtt_neighbors_interval); + } + return; + } + auto& pubkey_hex = publish_workspace->pubkey_hex; + auto& entries = publish_workspace->entries; uint32_t now_secs = getRTCClock()->getCurrentTime(); for (int i = 0; i < neighbor_discover_count; i++) { @@ -8738,6 +8757,11 @@ void MyMesh::finishNeighborDiscover() { char* json_buf = (char*)malloc(MQTTBridge::NEIGHBORS_JSON_BUFFER_SIZE); #endif if (!json_buf) { +#if defined(ESP_PLATFORM) + heap_caps_free(publish_workspace); +#else + free(publish_workspace); +#endif neighbor_discover_active = false; neighbor_discover_count = 0; if (_cli.getObserverPrefs()->mqtt_neighbors_enabled) { @@ -8763,8 +8787,10 @@ void MyMesh::finishNeighborDiscover() { #if defined(ESP_PLATFORM) heap_caps_free(json_buf); + heap_caps_free(publish_workspace); #else free(json_buf); + free(publish_workspace); #endif neighbor_discover_active = false; diff --git a/examples/simple_room_server/MyMesh.cpp b/examples/simple_room_server/MyMesh.cpp index 1bdbd61ab..29fc8b4d4 100644 --- a/examples/simple_room_server/MyMesh.cpp +++ b/examples/simple_room_server/MyMesh.cpp @@ -2150,8 +2150,27 @@ void MyMesh::finishNeighborDiscover() { char timestamp[40]; MQTTMessageBuilder::formatIsoTimestampForMqtt(getRTCClock()->getCurrentTime(), 0, nullptr, timestamp, sizeof(timestamp)); - char pubkey_hex[MAX_NEIGHBOURS][65]; - MQTTMessageBuilder::NeighborsMessageEntry entries[MAX_NEIGHBOURS]; + struct NeighborPublishWorkspace { + char pubkey_hex[MAX_NEIGHBOURS][65]; + MQTTMessageBuilder::NeighborsMessageEntry entries[MAX_NEIGHBOURS]; + }; +#if defined(ESP_PLATFORM) + auto* publish_workspace = static_cast( + heap_caps_malloc(sizeof(NeighborPublishWorkspace), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT)); +#else + auto* publish_workspace = static_cast( + malloc(sizeof(NeighborPublishWorkspace))); +#endif + if (!publish_workspace) { + neighbor_discover_active = false; + neighbor_discover_count = 0; + if (_cli.getObserverPrefs()->mqtt_neighbors_enabled) { + next_neighbors_publish = futureMillis(_cli.getObserverPrefs()->mqtt_neighbors_interval); + } + return; + } + auto& pubkey_hex = publish_workspace->pubkey_hex; + auto& entries = publish_workspace->entries; uint32_t now_secs = getRTCClock()->getCurrentTime(); for (int i = 0; i < neighbor_discover_count; i++) { @@ -2186,6 +2205,11 @@ void MyMesh::finishNeighborDiscover() { char* json_buf = (char*)malloc(MQTTBridge::NEIGHBORS_JSON_BUFFER_SIZE); #endif if (!json_buf) { +#if defined(ESP_PLATFORM) + heap_caps_free(publish_workspace); +#else + free(publish_workspace); +#endif neighbor_discover_active = false; neighbor_discover_count = 0; if (_cli.getObserverPrefs()->mqtt_neighbors_enabled) { @@ -2211,8 +2235,10 @@ void MyMesh::finishNeighborDiscover() { #if defined(ESP_PLATFORM) heap_caps_free(json_buf); + heap_caps_free(publish_workspace); #else free(json_buf); + free(publish_workspace); #endif neighbor_discover_active = false;