Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build_as_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
src_filter.append("+<helpers/stm32/*>")
elif item == "ESP32":
src_filter.append("+<helpers/esp32/*>")
src_filter.append("+<helpers/wifi/*>")
elif item == "NRF52_PLATFORM":
src_filter.append("+<helpers/nrf52/*>")
elif item == "RP2040_PLATFORM":
src_filter.append("+<helpers/rp2040/*>")
src_filter.append("+<helpers/wifi/*>")

# DISPLAY HANDLING
elif isinstance(item, tuple) and item[0] == "DISPLAY_CLASS":
Expand Down
21 changes: 21 additions & 0 deletions examples/companion_radio/MyMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
_serial(NULL), telemetry(MAX_PACKET_PAYLOAD - 4), _store(&store), _ui(ui), _iter(0) {
_iter_started = false;
_cli_rescue = false;
cli_command[0] = 0;
offline_queue_len = 0;
app_target_ver = 0;
clearPendingReqs();
Expand Down Expand Up @@ -2050,6 +2051,21 @@ void MyMesh::checkCLIRescueCmd() {
_prefs.ble_pin = atoi(&config[4]);
savePrefs();
Serial.printf(" > pin is now %06d\n", _prefs.ble_pin);
#ifdef WIFI_SSID
} else if (memcmp(config, "wifi.ssid ", 10) == 0) {
StrHelper::strncpy(_prefs.wifi_ssid, &config[10], sizeof(_prefs.wifi_ssid));
savePrefs();
Serial.printf(" > wifi.ssid is now %s (set wifi.pwd too, then reboot)\n", _prefs.wifi_ssid);
} else if (memcmp(config, "wifi.pwd ", 9) == 0) {
StrHelper::strncpy(_prefs.wifi_pwd, &config[9], sizeof(_prefs.wifi_pwd));
savePrefs();
Serial.println(" > wifi.pwd updated (reboot to apply)");
} else if (strcmp(config, "wifi.clear") == 0) {
_prefs.wifi_ssid[0] = 0;
_prefs.wifi_pwd[0] = 0;
savePrefs();
Serial.println(" > wifi config cleared, using build-time credentials (reboot to apply)");
#endif
} else {
Serial.printf(" Error: unknown config: %s\n", config);
}
Expand Down Expand Up @@ -2233,6 +2249,11 @@ void MyMesh::loop() {
checkCLIRescueCmd();
} else {
checkSerialInterface();
#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
}

// is there are pending dirty contacts write needed?
Expand Down
27 changes: 26 additions & 1 deletion examples/companion_radio/NodePrefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class NodePrefs : public ConfigSerializer { // persisted to file
uint8_t autoadd_max_hops = 0; // 0 = no limit, 1 = direct (0 hops), N = up to N-1 hops (max 64)
char default_scope_name[31];
uint8_t default_scope_key[16];
#ifdef WIFI_SSID
char wifi_ssid[33] = {0}; // if empty, the compile-time WIFI_SSID is used
char wifi_pwd[64] = {0};
#endif

private:
class RadioPrefs : public ConfigSerializer { // COPIED from CommonCLI (for now)
Expand Down Expand Up @@ -121,6 +125,20 @@ class NodePrefs : public ConfigSerializer { // persisted to file
};
CompanionPrefs companion;

#ifdef WIFI_SSID
class WiFiPrefs : public ConfigSerializer {
NodePrefs* _parent;
protected:
void structure() override {
def("ssid", _parent->wifi_ssid, sizeof(_parent->wifi_ssid));
def("pwd", _parent->wifi_pwd, sizeof(_parent->wifi_pwd));
}
public:
WiFiPrefs(NodePrefs* parent) : _parent(parent) { }
};
WiFiPrefs wifi;
#endif

protected:
void structure() override {
def("name", node_name, sizeof(node_name));
Expand All @@ -132,9 +150,16 @@ class NodePrefs : public ConfigSerializer { // persisted to file
def("gps", gps);
def("repeat", repeat);
def("comp", companion);
#ifdef WIFI_SSID
def("wifi", wifi);
#endif
}
public:
NodePrefs() : radio(this), gps(this), companion(this) {
NodePrefs() : radio(this), gps(this), companion(this)
#ifdef WIFI_SSID
, wifi(this)
#endif
{
node_name[0] = 0;
default_scope_name[0] = 0;
memset(default_scope_key, 0, sizeof(default_scope_key));
Expand Down
70 changes: 59 additions & 11 deletions examples/companion_radio/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,14 @@ MultiSerialInterface interface_manager;
#ifndef TCP_PORT
#define TCP_PORT 5000
#endif
#ifdef ESP32
// include esp32 wifi interface
#include <helpers/esp32/SerialWifiInterface.h>
#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 <helpers/wifi/SerialWifiInterface.h>
SerialWifiInterface wifi_interface;
#else
#error "SerialWifiInterface is not defined for this platform"
Expand Down Expand Up @@ -108,9 +113,12 @@ void halt() {
}

/* WIFI RECONNECT TRACKERS */
#if defined(ESP32) && defined(WIFI_SSID)
#ifdef WIFI_SSID
bool wifi_needs_reconnect = false;
unsigned long last_wifi_reconnect_attempt = 0;
const char* wifi_ssid = WIFI_SSID; // replaced by stored prefs, if set
const char* wifi_pwd = WIFI_PWD;
bool wifi_was_connected = false;
#endif

void setup() {
Expand Down Expand Up @@ -192,6 +200,7 @@ void setup() {

// add wifi interface
#ifdef WIFI_SSID
#if defined(ESP32)
board.setInhibitSleep(true); // prevent sleep when WiFi is active
WiFi.setAutoReconnect(true);

Expand All @@ -204,8 +213,28 @@ void setup() {
wifi_needs_reconnect = false;
}
});
#endif

WiFi.begin(WIFI_SSID, WIFI_PWD);
// stored credentials win over the build-time ones ('set wifi.ssid <x>' 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)
// 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
wifi_interface.begin(TCP_PORT);
interface_manager.addInterface(InterfaceType::WiFi, &wifi_interface);
#endif
Expand Down Expand Up @@ -262,12 +291,31 @@ void loop() {
#endif
}

#if defined(ESP32) && defined(WIFI_SSID)
// Safely attempt to reconnect every 10 seconds if flagged
if (wifi_needs_reconnect && (millis() - last_wifi_reconnect_attempt > 10000)) {
WIFI_DEBUG_PRINTLN("Attempting manual WiFi reconnect...");
WiFi.disconnect();
WiFi.reconnect();
#ifdef WIFI_SSID
// RP2040 has no WiFi event callbacks, so poll the link state instead
#if defined(RP2040_PLATFORM)
wifi_needs_reconnect = (WiFi.status() != WL_CONNECTED);
if (wifi_was_connected == wifi_needs_reconnect) { // link state changed
wifi_was_connected = !wifi_needs_reconnect;
if (wifi_was_connected) {
WIFI_DEBUG_PRINTLN("connected, listening on %s:%d", WiFi.localIP().toString().c_str(), TCP_PORT);
} else {
WIFI_DEBUG_PRINTLN("link lost");
}
}
#endif

// 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();
WiFi.reconnect();
#endif
last_wifi_reconnect_attempt = millis();
}
#endif
Expand Down
1 change: 1 addition & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ build_flags = ${arduino_base.build_flags}
-D ESP32_PLATFORM
; -D ESP32_CPU_FREQ=80 ; change it to your need
build_src_filter = ${arduino_base.build_src_filter}
+<helpers/wifi/*.cpp>

[esp32_ota]
lib_deps =
Expand Down
30 changes: 16 additions & 14 deletions variants/rpi_picow/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -81,20 +81,22 @@ lib_ignore = BLE
; lib_deps = ${rpi_picow.lib_deps}
; densaugeo/base64 @ ~1.4.0

; [env:PicoW_companion_radio_wifi]
; extends = rpi_picow
; build_flags = ${rpi_picow.build_flags}
; -D MAX_CONTACTS=100
; -D MAX_GROUP_CHANNELS=8
; -D WIFI_DEBUG_LOGGING=1
; -D WIFI_SSID='"myssid"'
; -D WIFI_PWD='"mypwd"'
; ; -D MESH_PACKET_LOGGING=1
; ; -D MESH_DEBUG=1
; build_src_filter = ${rpi_picow.build_src_filter}
; +<../examples/companion_radio/*.cpp>
; lib_deps = ${rpi_picow.lib_deps}
; densaugeo/base64 @ ~1.4.0
[env:PicoW_companion_radio_wifi]
extends = rpi_picow
build_flags = ${rpi_picow.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D WIFI_DEBUG_LOGGING=1
-D WIFI_SSID='"myssid"'
-D WIFI_PWD='"mypwd"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${rpi_picow.build_src_filter}
+<helpers/wifi/*.cpp>
+<../examples/companion_radio/*.cpp>
lib_deps = ${rpi_picow.lib_deps}
densaugeo/base64 @ ~1.4.0
lib_ignore = BLE

[env:PicoW_terminal_chat]
extends = rpi_picow
Expand Down