From a620f38e04a452eecdbc6ebbfab705eadbbd70c2 Mon Sep 17 00:00:00 2001 From: Pixel Perfect Date: Sat, 1 Aug 2026 23:57:39 -0700 Subject: [PATCH] fix(tpager): recover WiFi without rebooting Signed-off-by: Pixel Perfect --- .../MultiTransportCompanionInterface.cpp | 32 +++++++++++++++---- .../esp32/MultiTransportCompanionInterface.h | 5 +++ src/main.cpp | 24 +++++++------- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/helpers/esp32/MultiTransportCompanionInterface.cpp b/src/helpers/esp32/MultiTransportCompanionInterface.cpp index 933b67a5..d9c48af3 100644 --- a/src/helpers/esp32/MultiTransportCompanionInterface.cpp +++ b/src/helpers/esp32/MultiTransportCompanionInterface.cpp @@ -236,8 +236,9 @@ void MultiTransportCompanionInterface::enableBle() { _ble.enable(); #if defined(TLORA_PAGER) // A successful live enable means NimBLE is now resident. Do not let the - // Arduino Wi-Fi event path enter WPA automatically after a later link loss; - // main.cpp detects that state and reboots through the Wi-Fi-first boundary. + // Arduino Wi-Fi event path enter WPA automatically after a later link loss. + // main.cpp first releases NimBLE, then explicitly re-associates and recreates + // BLE after GOT_IP so the same Wi-Fi-first ordering holds without a reboot. // Avoid touching Wi-Fi when it has never been initialised (BLE-only mode). if (WiFi.getMode() != WIFI_MODE_NULL) WiFi.setAutoReconnect(false); #endif @@ -250,18 +251,35 @@ void MultiTransportCompanionInterface::disableBle() { // its cached server pointer. Never call disable() again after that teardown; // a later begin() replaces the cached pointers with a fresh GATT server. if (_ble_begun) _ble.disable(); // stop advertising + drop any connection - // Pager only: if Wi-Fi is genuinely absent, fully release NimBLE so a later - // Wi-Fi enable has the contiguous internal heap esp_wifi_init needs. Other - // boards retain their established resident-stack disable/re-enable behavior. - // While Wi-Fi exists, keep the controller resident on every board. + // Pager only: release NimBLE whenever the user turns Bluetooth off. This + // returns its internal heap and restores Wi-Fi's ordinary reconnect path; + // a later enable recreates the GATT server after Wi-Fi is already stable. + // Other boards retain their established resident-stack disable/re-enable + // behavior. #if defined(TLORA_PAGER) - if (_ble_begun && WiFi.getMode() == WIFI_MODE_NULL) { + if (_ble_begun) { NimBLEDevice::deinit(true); _ble_begun = false; } + if (WiFi.getMode() != WIFI_MODE_NULL) WiFi.setAutoReconnect(true); #endif } +#if defined(TLORA_PAGER) +void MultiTransportCompanionInterface::suspendBleForWifiReconnect() { + // Preserve wifiConfig's BLE preference: this is a short ownership handoff, + // not a user-visible toggle. SerialBLEInterface::begin() replaces the cached + // server pointers after deinit(true), matching the cold enable path above. + if (_ble_begun) { + if (_ble_enabled) _ble.disable(); + NimBLEDevice::deinit(true); + _ble_begun = false; + } + _ble_enabled = false; + if (WiFi.getMode() != WIFI_MODE_NULL) WiFi.setAutoReconnect(true); +} +#endif + bool MultiTransportCompanionInterface::getBlePeerAddress(char* buf, size_t len) const { if (!_ble_begun || !_ble_enabled) { if (buf && len > 0) buf[0] = '\0'; diff --git a/src/helpers/esp32/MultiTransportCompanionInterface.h b/src/helpers/esp32/MultiTransportCompanionInterface.h index cafd9ccf..4139def7 100644 --- a/src/helpers/esp32/MultiTransportCompanionInterface.h +++ b/src/helpers/esp32/MultiTransportCompanionInterface.h @@ -40,6 +40,11 @@ public: void prepareBle(const char* prefix, char* name, uint32_t pin_code); void enableBle() override; void disableBle() override; +#if defined(TLORA_PAGER) + // Tear down the resident controller without changing the saved BLE intent. + // Wi-Fi can then re-associate before enableBle() recreates NimBLE. + void suspendBleForWifiReconnect(); +#endif bool isBleEnabled() const override { return _ble_enabled; } bool isBleStackBegun() const { return _ble_begun; } #if defined(HAS_TDISPLAY_P4) diff --git a/src/main.cpp b/src/main.cpp index 96f5440c..cac1948b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -945,14 +945,14 @@ void loop() { * from the UI (the transition above already covered the on case). */ if (wifiConfigConsumeApplyRequest()) { #if defined(TLORA_PAGER) && defined(BLE_PIN_CODE) - // With NimBLE resident, every explicit credential/reconnect request must - // return through setup. Wi-Fi-only applies stay live: opening the Wi-Fi - // page itself performs a scan/rejoin and must not reboot the device. + // Credential changes need the same Wi-Fi-before-BLE order as boot. Release + // the resident controller without changing the saved BLE intent, apply the + // credentials live, then recreate BLE after the new link reaches GOT_IP. if (wifi_radio_en && wifiConfigHasRuntime() && serial_interface.isBleStackBegun()) { - Serial.println("[wifi] restarting for ordered T-Pager association"); - ui_task.rebootDevice(); - return; + s_pager_ble_after_wifi = wifiConfigGetBleEnabled(); + serial_interface.suspendBleForWifiReconnect(); + Serial.println("[wifi] BLE released for ordered T-Pager association"); } if (wifi_radio_en && !serial_interface.isBleStackBegun()) { WiFi.setAutoReconnect(true); @@ -999,11 +999,13 @@ void loop() { last_wifi_retry_ms = now; #if defined(TLORA_PAGER) && defined(BLE_PIN_CODE) if (serial_interface.isBleStackBegun()) { - // Auto-reconnect is disabled once NimBLE exists. Re-authenticate at - // boot before recreating BLE rather than entering WPA under coex. - Serial.println("[wifi] link lost with BLE resident; restarting for ordered association"); - ui_task.rebootDevice(); - return; + // Auto-reconnect is disabled once NimBLE exists. Release the BLE + // controller first, then use the ordinary retry below; GOT_IP recreates + // BLE once Wi-Fi owns the coexistence path again. This bounds an AP + // outage to transport reconnects instead of a device reboot loop. + s_pager_ble_after_wifi = wifiConfigGetBleEnabled(); + serial_interface.suspendBleForWifiReconnect(); + Serial.println("[wifi] BLE released after link loss; re-associating"); } #endif char ssid[WIFI_CONFIG_SSID_MAX];