diff --git a/build_legacy.sh b/build_legacy.sh index 42107fe8a..5d6529f9f 100755 --- a/build_legacy.sh +++ b/build_legacy.sh @@ -3872,7 +3872,8 @@ apply_esp32_iram_advert_storage_profile() { lilygo_tlora_v2_1_1_6_repeater_observer_mqtt|lilygo_tlora_v2_1_1_6_repeater_observer_mqtt_|\ lilygo_tlora_v2_1_1_6_room_server|lilygo_tlora_v2_1_1_6_room_server_|\ lilygo_tlora_v2_1_1_6_room_server_observer_mqtt|lilygo_tlora_v2_1_1_6_room_server_observer_mqtt_|\ - tbeam_sx1262_repeater_observer_mqtt|tbeam_sx1276_repeater_observer_mqtt) + tbeam_sx1262_repeater_observer_mqtt|tbeam_sx1276_repeater_observer_mqtt|\ + tbeam_sx1262_room_server_observer_mqtt|tbeam_sx1276_room_server_observer_mqtt) export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFLOOD_ADVERT_IRAM_WORD_STORAGE=1" ;; esac @@ -3907,7 +3908,8 @@ apply_esp32_full_size_profile() { case "${env_name,,}" in lilygo_tlora_v2_1_1_6_room_server|lilygo_tlora_v2_1_1_6_room_server_|\ - lilygo_tlora_v2_1_1_6_room_server_observer_mqtt|lilygo_tlora_v2_1_1_6_room_server_observer_mqtt_) + lilygo_tlora_v2_1_1_6_room_server_observer_mqtt|lilygo_tlora_v2_1_1_6_room_server_observer_mqtt_|\ + tbeam_sx1262_room_server_observer_mqtt|tbeam_sx1276_room_server_observer_mqtt) # Preserve all 32 Room posts in genuine byte-accessible RTC SLOW memory. # The bounded proof implementation serves the same maximum 4096 leaves # without retaining the legacy 16 KiB leaf cache alongside Room services. diff --git a/examples/simple_room_server/MyMesh.h b/examples/simple_room_server/MyMesh.h index d6c6b499e..338bfd9c6 100644 --- a/examples/simple_room_server/MyMesh.h +++ b/examples/simple_room_server/MyMesh.h @@ -153,9 +153,10 @@ namespace mesh { class RoomJsonWriter; } #if ROOM_POSTS_RTC_SLOW_STORAGE != 0 && ROOM_POSTS_RTC_SLOW_STORAGE != 1 #error "ROOM_POSTS_RTC_SLOW_STORAGE must be 0 or 1" #endif -#if ROOM_POSTS_RTC_SLOW_STORAGE && (!defined(ESP32_PLATFORM) || !defined(LILYGO_TLORA) \ +#if ROOM_POSTS_RTC_SLOW_STORAGE && (!defined(ESP32_PLATFORM) \ + || (!defined(LILYGO_TLORA) && !defined(TBEAM_SX1262) && !defined(TBEAM_SX1276)) \ || !defined(MESHCORE_EXPANDED_PARTITION_PROFILE)) -#error "RTC slow Room posts require the qualified Full TLora ESP32 recipe" +#error "RTC slow Room posts require a qualified Full TLora or Tbeam ESP32 recipe" #endif struct PostInfo { diff --git a/test/test_flood_advert_iram.py b/test/test_flood_advert_iram.py index 5efb58e31..6a074e19b 100644 --- a/test/test_flood_advert_iram.py +++ b/test/test_flood_advert_iram.py @@ -106,7 +106,10 @@ class FloodAdvertIramTests(unittest.TestCase): ('LilyGo_TLora_V2_1_1_6_room_server_observer_mqtt_',True), ('Tbeam_SX1262_repeater_observer_mqtt',True), ('Tbeam_SX1276_repeater_observer_mqtt',True), - ('Tbeam_SX1262_room_server_observer_mqtt',False), + ('Tbeam_SX1262_room_server_observer_mqtt',True), + ('Tbeam_SX1276_room_server_observer_mqtt',True), + ('Tbeam_SX1262_room_server',False), + ('Tbeam_SX1276_room_server',False), ('Tbeam_SX1276_companion_radio_ble',False), ('LilyGo_TLora_V2_1_1_6_companion_radio_ble',False), ('Heltec_Wireless_Tracker_repeater',False), diff --git a/test/test_ota_source_proofs.py b/test/test_ota_source_proofs.py index 6fa61a288..42cca597f 100644 --- a/test/test_ota_source_proofs.py +++ b/test/test_ota_source_proofs.py @@ -129,6 +129,41 @@ int main() { f"-DENV_INCLUDE_BME680_BSEC={sensors}", ]) + def test_tbeam_full_rooms_preserve_maximum_source_and_bounded_ownership(self): + for board in ("TBEAM_SX1262", "TBEAM_SX1276"): + with self.subTest(board=board): + self.check_grouped_equivalence([ + "-DESP32_PLATFORM=1", "-D" + board + "=1", "-DBOARD_HAS_PSRAM=1", + "-DOTA_BOUNDED_SOURCE_PROOFS=1", + ]) + + def test_tbeam_room_budget_changes_only_actual_source_workspace(self): + import sys + sys.path.insert(0, str(ROOT / "scripts")) + from check_firmware_ram import requirements + flags = dict(ENABLE_OTA=1, OTA_HEAP_CONTEXT=1, WITH_MQTT_BRIDGE=1, + ADMIN_PASSWORD="password", BOARD_HAS_PSRAM=1, + DISPLAY_CLASS="SSD1306Display", MESH_ENABLE_ROOM_FLOOD_RULE_ENGINE=1, + MESHCORE_OTA_DEVICE_DEFLATE=1) + for radio in ("SX1262", "SX1276"): + with self.subTest(radio=radio): + target = "Tbeam_" + radio + "_room_server_observer_mqtt" + before = requirements("ESP32_PLATFORM", flags, target) + after = requirements("ESP32_PLATFORM", dict(flags, OTA_BOUNDED_SOURCE_PROOFS=1), target) + self.assertEqual(before["required_heap_bytes"], 212784) + self.assertEqual(after["required_heap_bytes"], 197936) + self.assertEqual(before["required_contiguous_bytes"], 18464) + self.assertEqual(after["required_contiguous_bytes"], 16400) + self.assertEqual(before["components"]["ota_generic_source_buffers"], 18464) + self.assertEqual(after["components"]["ota_generic_source_buffers"], 3616) + before_parts = dict(before["components"]) + after_parts = dict(after["components"]) + before_parts.pop("ota_generic_source_buffers") + after_parts.pop("ota_generic_source_buffers") + self.assertEqual(before_parts, after_parts) + self.assertEqual(before["mqtt"], after["mqtt"]) + self.assertEqual(after_parts["allocation_and_transient_margin"], 16384) + def test_tlora_full_room_preserves_maximum_source_and_bounded_ownership(self): self.check_grouped_equivalence([ "-DESP32_PLATFORM=1", "-DLILYGO_TLORA=1", "-DOTA_BOUNDED_SOURCE_PROOFS=1", diff --git a/test/test_room_rtc_posts.py b/test/test_room_rtc_posts.py index e492b018b..2aae65f6b 100644 --- a/test/test_room_rtc_posts.py +++ b/test/test_room_rtc_posts.py @@ -131,7 +131,12 @@ int main(int argc,char** argv) { (["-DROOM_POSTS_RTC_SLOW_STORAGE=1", "-DNRF52_PLATFORM=1"], False), (["-DROOM_POSTS_RTC_SLOW_STORAGE=1", "-DESP32_PLATFORM=1"], False), (["-DROOM_POSTS_RTC_SLOW_STORAGE=1", "-DESP32_PLATFORM=1", "-DLILYGO_TLORA=1", - "-DMESHCORE_EXPANDED_PARTITION_PROFILE=1"], True)) + "-DMESHCORE_EXPANDED_PARTITION_PROFILE=1"], True), + *((["-DROOM_POSTS_RTC_SLOW_STORAGE=1", "-DESP32_PLATFORM=1", "-D" + board + "=1", + "-DMESHCORE_EXPANDED_PARTITION_PROFILE=1"], True) + for board in ("TBEAM_SX1262", "TBEAM_SX1276")), + *((["-DROOM_POSTS_RTC_SLOW_STORAGE=1", "-DESP32_PLATFORM=1", "-D" + board + "=1"], False) + for board in ("LILYGO_TLORA", "TBEAM_SX1262", "TBEAM_SX1276"))) for flags, valid in cases: with self.subTest(flags=flags): result = subprocess.run([shutil.which("g++") or "clang++", "-std=c++17", "-x", "c++", @@ -139,6 +144,59 @@ int main(int argc,char** argv) { capture_output=True, text=True, timeout=20) self.assertEqual(result.returncode == 0, valid, result.stderr) + def test_only_qualified_full_room_recipes_select_complete_storage_policy(self): + text = (ROOT / "build_legacy.sh").read_text() + functions = [] + for name in ("apply_esp32_full_size_profile", "apply_esp32_iram_advert_storage_profile"): + start = text.index(name + "() {") + functions.append(text[start:text.index("\n}\n", start) + 2]) + targets = { + "Tbeam_SX1262_room_server_observer_mqtt": True, + "Tbeam_SX1276_room_server_observer_mqtt": True, + "LilyGo_TLora_V2_1_1_6_room_server_observer_mqtt_": True, + "Tbeam_SX1262_room_server": False, + "Tbeam_SX1276_room_server": False, + "Tbeam_SX1262_repeater_observer_mqtt": False, + "Tbeam_SX1276_companion_radio_ble": False, + "T_Beam_S3_Supreme_SX1262_room_server_observer_mqtt": False, + "RAK_4631_room_server": False, + } + for full in ("0", "1"): + for supported in ("0", "1"): + for target, selected in targets.items(): + with self.subTest(full=full, supported=supported, target=target): + code = r''' +ESP32_FULL_BUILD="$1" +QUALIFIED="$2" +ESP32_FULL_MAX_NEIGHBOURS=254 +DRAM_LIMITED_MAX_NEIGHBOURS=50 +PLATFORMIO_BUILD_FLAGS="-DEXISTING=1" +declare -A PIO_ENV_FULL_WIFI_OTA_BY_NAME=() +supports_esp32_full_build() { [ "$QUALIFIED" = 1 ]; } +is_room_server_role_target() { [[ "$1" == *room_server* ]]; } +requires_dram_limited_neighbors() { [[ "$1" == Tbeam_SX12* ]]; } +requires_esp32_companion_full_ota_fallback() { return 1; } +append_platformio_build_unflags() { :; } +record_build_reduction() { :; } +''' + "\n".join(functions) + r''' +apply_esp32_full_size_profile "$3" +apply_esp32_iram_advert_storage_profile "$3" +printf "%s" "$PLATFORMIO_BUILD_FLAGS" +''' + result = subprocess.run(["bash", "-c", code, "bash", full, supported, target], + capture_output=True, text=True, check=True, timeout=10) + enabled = full == "1" and supported == "1" and selected + flags = result.stdout.split() + for name in ("ROOM_POSTS_RTC_SLOW_STORAGE", "OTA_BOUNDED_SOURCE_PROOFS"): + self.assertEqual(flags.count("-D" + name + "=1"), int(enabled), result.stdout) + if enabled: + self.assertIn("-DFLOOD_ADVERT_IRAM_WORD_STORAGE=1", flags) + self.assertNotIn("-DFLOOD_PACKET_FILTER_SLOTS=31", flags) + self.assertIn("-DMESH_ENABLE_ROOM_FLOOD_RULE_ENGINE=1", flags) + self.assertIn("-DMAX_NEIGHBOURS=" + ("50" if target.startswith("Tbeam_") else "254"), flags) + self.assertNotIn("-DMAX_UNSYNCED_POSTS", result.stdout) + self.assertNotIn("-DFLOOD_ADVERT_SOURCE_SLOTS", result.stdout) + def test_real_post_fifo_history_reload_maximum_text_and_catchup(self): source, header, bank, initializer, clear, destructor, post = self.sources() fixture = (ROOT / "test/fixtures/room_history_integration/test.cpp").read_text().split("int main()", 1)[0]