From a4ac85a0d6b3d392f303e054ab03516933dbec52 Mon Sep 17 00:00:00 2001 From: Michael Graff Date: Fri, 4 Sep 2026 20:57:01 -0500 Subject: [PATCH] Address review findings on WiFi companion support - scope the serial config CLI to RP2040; it was exposing the rescue CLI (cat/rm/erase) on every ESP32 WiFi build, which gates it behind a physical long-press - bound and space out RP2040 rejoins: the core's join busy-waits, so cap it at 5s and retry every 30s instead of every 10s - stamp the reconnect timer in setup(), so the first loop() doesn't tear down an association that is still finishing DHCP - treat stored credentials as a pair, and pass NULL (not "") for an open network - teach build_as_lib.py where SerialWifiInterface moved --- build_as_lib.py | 2 ++ examples/companion_radio/MyMesh.cpp | 5 +++-- examples/companion_radio/main.cpp | 24 ++++++++++++++++++++---- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/build_as_lib.py b/build_as_lib.py index d8e95378e..fbc7c15a7 100644 --- a/build_as_lib.py +++ b/build_as_lib.py @@ -20,10 +20,12 @@ for item in menv.get("CPPDEFINES", []): src_filter.append("+") elif item == "ESP32": src_filter.append("+") + src_filter.append("+") elif item == "NRF52_PLATFORM": src_filter.append("+") elif item == "RP2040_PLATFORM": src_filter.append("+") + src_filter.append("+") # DISPLAY HANDLING elif isinstance(item, tuple) and item[0] == "DISPLAY_CLASS": diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 8550890e1..a8e305a6a 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -2416,8 +2416,9 @@ void MyMesh::loop() { checkCLIRescueCmd(); } else { checkSerialInterface(); -#if defined(WIFI_SSID) && !defined(ENABLE_USB_INTERFACE) - // headless WiFi build: USB serial isn't a companion transport, so use it for config +#if defined(WIFI_SSID) && defined(RP2040_PLATFORM) && !defined(ENABLE_USB_INTERFACE) + // RP2040 WiFi builds are headless and have no way into the rescue CLI (that needs a + // display + long-press), so serve config commands on the otherwise unused USB serial checkCLIRescueCmd(); #endif } diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index f0c12908f..ff0794ab9 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -36,6 +36,12 @@ MultiSerialInterface interface_manager; #ifndef TCP_PORT #define TCP_PORT 5000 #endif + #ifndef WIFI_RETRY_INTERVAL + #define WIFI_RETRY_INTERVAL 30000 // millis between reconnect attempts + #endif + #ifndef WIFI_RETRY_TIMEOUT + #define WIFI_RETRY_TIMEOUT 5000 // RP2040: cap on how long one join may block loop() + #endif #if defined(ESP32) || defined(RP2040_PLATFORM) #include SerialWifiInterface wifi_interface; @@ -209,15 +215,23 @@ void setup() { }); #endif - // stored credentials win over the build-time ones ('set wifi.ssid ' over USB serial) + // stored credentials win over the build-time ones ('set wifi.ssid ' over USB serial). + // they are taken as a pair, so 'set wifi.ssid' alone gives an open-network join, not a + // silent fallback to the build-time password of a different network. if (the_mesh.getNodePrefs()->wifi_ssid[0]) { wifi_ssid = the_mesh.getNodePrefs()->wifi_ssid; wifi_pwd = the_mesh.getNodePrefs()->wifi_pwd; } + if (wifi_pwd[0] == 0) wifi_pwd = NULL; // NULL (not "") selects an open network WIFI_DEBUG_PRINTLN("connecting to %s", wifi_ssid); #if defined(RP2040_PLATFORM) - WiFi.beginNoBlock(wifi_ssid, wifi_pwd); // begin() blocks for up to 2x its 15s timeout + // ponytail: the join itself blocks inside the core (CYW43::begin busy-waits for the + // association), so every attempt stalls the mesh loop. beginNoBlock() only skips the + // extra DHCP wait. Give the first connect a full window, then bound the retries below. + // Upgrade path if the stall ever matters: run WiFi on core1. + WiFi.beginNoBlock(wifi_ssid, wifi_pwd); + last_wifi_reconnect_attempt = millis(); // let DHCP finish before the poll can retry #else WiFi.begin(wifi_ssid, wifi_pwd); #endif @@ -291,10 +305,12 @@ void loop() { } #endif - // Safely attempt to reconnect every 10 seconds if flagged - if (wifi_needs_reconnect && (millis() - last_wifi_reconnect_attempt > 10000)) { + // Safely attempt to reconnect if flagged. On RP2040 each attempt blocks the mesh loop + // for up to WIFI_RETRY_TIMEOUT, so retry less often and cap how long a join may stall. + if (wifi_needs_reconnect && (millis() - last_wifi_reconnect_attempt > WIFI_RETRY_INTERVAL)) { WIFI_DEBUG_PRINTLN("Attempting manual WiFi reconnect to %s (status %d)...", wifi_ssid, WiFi.status()); #if defined(RP2040_PLATFORM) + WiFi.setTimeout(WIFI_RETRY_TIMEOUT); WiFi.beginNoBlock(wifi_ssid, wifi_pwd); // no reconnect() on this platform #else WiFi.disconnect();