From 6ff61b3e04ec583f679db658772fe6ed37315e69 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Sat, 2 Dec 2023 21:47:52 +0100 Subject: [PATCH] Pico W: Initial Wi-Fi support (#2980) * Pico W: Initial WiFi support: connects, but freezes after a while * Update arduino-pico core to fix hang with Wi-Fi * Add `picow` to workflow since it's different from `pico` now --- .github/workflows/main_matrix.yml | 1 + arch/nrf52/nrf52.ini | 2 +- arch/portduino/portduino.ini | 1 + arch/rp2040/rp2040.ini | 6 +- arch/stm32/stm32wl5e.ini | 2 +- src/graphics/Screen.cpp | 11 +- src/main.cpp | 11 +- src/mesh/NodeDB.cpp | 2 +- src/mesh/api/WiFiServerAPI.h | 2 +- src/mesh/http/ContentHandler.cpp | 2 +- src/mesh/http/ContentHandler.h | 3 +- src/mesh/http/ContentHelper.cpp | 4 +- src/mesh/http/WebServer.cpp | 4 +- src/mesh/{http => wifi}/WiFiAPClient.cpp | 194 +++++++++++++---------- src/mesh/{http => wifi}/WiFiAPClient.h | 4 +- src/modules/AdminModule.h | 6 +- src/mqtt/MQTT.cpp | 2 +- src/platform/esp32/main-esp32.cpp | 2 +- src/sleep.cpp | 2 +- variants/rpipicow/platformio.ini | 6 +- variants/rpipicow/variant.h | 6 +- 21 files changed, 154 insertions(+), 119 deletions(-) rename src/mesh/{http => wifi}/WiFiAPClient.cpp (94%) rename src/mesh/{http => wifi}/WiFiAPClient.h (79%) diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 6b6ff1ad7..e53c35bd2 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -123,6 +123,7 @@ jobs: matrix: include: - board: pico + - board: picow - board: rak11310 uses: ./.github/workflows/build_rpi2040.yml with: diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini index 1a3631420..5da571cce 100644 --- a/arch/nrf52/nrf52.ini +++ b/arch/nrf52/nrf52.ini @@ -11,7 +11,7 @@ build_flags = -Isrc/platform/nrf52 build_src_filter = - ${arduino_base.build_src_filter} - - - - - - - - + ${arduino_base.build_src_filter} - - - - - - - - - lib_deps= ${arduino_base.lib_deps} diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini index 8b4ab5d4b..c4b6d5377 100644 --- a/arch/portduino/portduino.ini +++ b/arch/portduino/portduino.ini @@ -10,6 +10,7 @@ build_src_filter = - - - + - - - - diff --git a/arch/rp2040/rp2040.ini b/arch/rp2040/rp2040.ini index 38acde1e0..7674fbd52 100644 --- a/arch/rp2040/rp2040.ini +++ b/arch/rp2040/rp2040.ini @@ -1,8 +1,8 @@ ; Common settings for rp2040 Processor based targets [rp2040_base] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git#0c33219f53faa035e188925ea1324f472e8b93d2 +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#612de5399d68b359053f1307ed223d400aea975c extends = arduino_base -platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.2.2 +platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#d2461a14ad5aa920e44508d236c2f459e3befbf8 board_build.core = earlephilhower board_build.filesystem_size = 0.5m @@ -12,7 +12,7 @@ build_flags = -D__PLAT_RP2040__ # -D _POSIX_THREADS build_src_filter = - ${arduino_base.build_src_filter} - - - - - - - - + ${arduino_base.build_src_filter} - - - - - - - - lib_ignore = BluetoothOTA diff --git a/arch/stm32/stm32wl5e.ini b/arch/stm32/stm32wl5e.ini index f563eec18..cac7110f2 100644 --- a/arch/stm32/stm32wl5e.ini +++ b/arch/stm32/stm32wl5e.ini @@ -13,7 +13,7 @@ build_flags = -DVECT_TAB_OFFSET=0x08000000 build_src_filter = - ${arduino_base.build_src_filter} - - - - - - - - - - - - + ${arduino_base.build_src_filter} - - - - - - - - - - - - - board_upload.offset_address = 0x08000000 upload_protocol = stlink diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 2e144e41a..e75a432d4 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -45,7 +45,7 @@ along with this program. If not, see . #ifdef ARCH_ESP32 #include "esp_task_wdt.h" -#include "mesh/http/WiFiAPClient.h" +#include "mesh/wifi/WiFiAPClient.h" #include "modules/esp32/StoreForwardModule.h" #endif @@ -1618,12 +1618,19 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Failed"); } else if (WiFi.status() == WL_IDLE_STATUS) { display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Idle ... Reconnecting"); - } else { + } +#ifdef ARCH_ESP32 + else { // Codes: // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-reason-code display->drawString(x, y + FONT_HEIGHT_SMALL * 1, WiFi.disconnectReasonName(static_cast(getWifiDisconnectReason()))); } +#else + else { + display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Unkown status: " + String(WiFi.status())); + } +#endif display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName)); diff --git a/src/main.cpp b/src/main.cpp index 5cea142bc..b3671c020 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -32,9 +32,6 @@ #include // #include -#include "mesh/eth/ethClient.h" -#include "mesh/http/WiFiAPClient.h" - #ifdef ARCH_ESP32 #include "mesh/http/WebServer.h" #include "nimble/NimbleBluetooth.h" @@ -48,10 +45,12 @@ NRF52Bluetooth *nrf52Bluetooth; #if HAS_WIFI #include "mesh/api/WiFiServerAPI.h" +#include "mesh/wifi/WiFiAPClient.h" #endif #if HAS_ETHERNET #include "mesh/api/ethServerAPI.h" +#include "mesh/eth/ethClient.h" #endif #include "mqtt/MQTT.h" @@ -835,11 +834,15 @@ void setup() #ifndef ARCH_PORTDUINO // Initialize Wifi +#if HAS_WIFI initWifi(); +#endif +#if HAS_ETHERNET // Initialize Ethernet initEthernet(); #endif +#endif #ifdef ARCH_ESP32 // Start web server thread. @@ -938,4 +941,4 @@ void loop() mainDelay.delay(delayMsec); } // if (didWake) LOG_DEBUG("wake!\n"); -} \ No newline at end of file +} diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index cb5c27b49..bb079e5c0 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -21,7 +21,7 @@ #include #ifdef ARCH_ESP32 -#include "mesh/http/WiFiAPClient.h" +#include "mesh/wifi/WiFiAPClient.h" #include "modules/esp32/StoreForwardModule.h" #include #include diff --git a/src/mesh/api/WiFiServerAPI.h b/src/mesh/api/WiFiServerAPI.h index 11b494d23..e436a177d 100644 --- a/src/mesh/api/WiFiServerAPI.h +++ b/src/mesh/api/WiFiServerAPI.h @@ -22,4 +22,4 @@ class WiFiServerPort : public APIServerPort explicit WiFiServerPort(int port); }; -void initApiServer(int port = 4403); +void initApiServer(int port = 4403); \ No newline at end of file diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 2ea2a76a5..4ca37a256 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -5,7 +5,7 @@ #include "main.h" #include "mesh/http/ContentHelper.h" #include "mesh/http/WebServer.h" -#include "mesh/http/WiFiAPClient.h" +#include "mesh/wifi/WiFiAPClient.h" #include "mqtt/JSON.h" #include "power.h" #include "sleep.h" diff --git a/src/mesh/http/ContentHandler.h b/src/mesh/http/ContentHandler.h index 903d5ee08..987e3ffef 100644 --- a/src/mesh/http/ContentHandler.h +++ b/src/mesh/http/ContentHandler.h @@ -1,5 +1,4 @@ #pragma once - void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer); // Declare some handler functions for the various URLs on the server @@ -34,4 +33,4 @@ class HttpAPI : public PhoneAPI protected: /// Check the current underlying physical link to see if the client is currently connected virtual bool checkIsConnected() override { return true; } // FIXME, be smarter about this -}; +}; \ No newline at end of file diff --git a/src/mesh/http/ContentHelper.cpp b/src/mesh/http/ContentHelper.cpp index 249dcbde6..8f283932b 100644 --- a/src/mesh/http/ContentHelper.cpp +++ b/src/mesh/http/ContentHelper.cpp @@ -1,6 +1,6 @@ #include "mesh/http/ContentHelper.h" -//#include -//#include "main.h" +// #include +// #include "main.h" void replaceAll(std::string &str, const std::string &from, const std::string &to) { diff --git a/src/mesh/http/WebServer.cpp b/src/mesh/http/WebServer.cpp index 2b045c0be..7814f2c29 100644 --- a/src/mesh/http/WebServer.cpp +++ b/src/mesh/http/WebServer.cpp @@ -2,7 +2,7 @@ #include "NodeDB.h" #include "graphics/Screen.h" #include "main.h" -#include "mesh/http/WiFiAPClient.h" +#include "mesh/wifi/WiFiAPClient.h" #include "sleep.h" #include #include @@ -210,4 +210,4 @@ void initWebServer() } else { LOG_ERROR("Web Servers Failed! ;-( \n"); } -} +} \ No newline at end of file diff --git a/src/mesh/http/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp similarity index 94% rename from src/mesh/http/WiFiAPClient.cpp rename to src/mesh/wifi/WiFiAPClient.cpp index cc8d4b168..06573fd60 100644 --- a/src/mesh/http/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -1,17 +1,22 @@ -#include "mesh/http/WiFiAPClient.h" +#include "mesh/wifi/WiFiAPClient.h" #include "NodeDB.h" #include "RTC.h" #include "concurrency/Periodic.h" #include "configuration.h" #include "main.h" #include "mesh/api/WiFiServerAPI.h" -#include "mesh/http/WebServer.h" #include "mqtt/MQTT.h" #include "target_specific.h" -#include #include #include +#ifndef ARCH_RP2040 +#include "mesh/http/WebServer.h" +#include #include +static void WiFiEvent(WiFiEvent_t event); +#else +#include +#endif #ifndef DISABLE_NTP #include @@ -19,8 +24,6 @@ using namespace concurrency; -static void WiFiEvent(WiFiEvent_t event); - // NTP WiFiUDP ntpUDP; @@ -44,78 +47,6 @@ Syslog syslog(syslogClient); Periodic *wifiReconnect; -static int32_t reconnectWiFi() -{ - const char *wifiName = config.network.wifi_ssid; - const char *wifiPsw = config.network.wifi_psk; - - if (config.network.wifi_enabled && needReconnect) { - - if (!*wifiPsw) // Treat empty password as no password - wifiPsw = NULL; - - needReconnect = false; - - // Make sure we clear old connection credentials - WiFi.disconnect(false, true); - LOG_INFO("Reconnecting to WiFi access point %s\n", wifiName); - - delay(5000); - - if (!WiFi.isConnected()) { - WiFi.begin(wifiName, wifiPsw); - } - } - -#ifndef DISABLE_NTP - if (WiFi.isConnected() && (((millis() - lastrun_ntp) > 43200000) || (lastrun_ntp == 0))) { // every 12 hours - LOG_DEBUG("Updating NTP time from %s\n", config.network.ntp_server); - if (timeClient.update()) { - LOG_DEBUG("NTP Request Success - Setting RTCQualityNTP if needed\n"); - - struct timeval tv; - tv.tv_sec = timeClient.getEpochTime(); - tv.tv_usec = 0; - - perhapsSetRTC(RTCQualityNTP, &tv); - lastrun_ntp = millis(); - - } else { - LOG_DEBUG("NTP Update failed\n"); - } - } -#endif - - if (config.network.wifi_enabled && !WiFi.isConnected()) { - return 1000; // check once per second - } else { - return 300000; // every 5 minutes - } -} - -bool isWifiAvailable() -{ - - if (config.network.wifi_enabled && (config.network.wifi_ssid[0])) { - return true; - } else { - return false; - } -} - -// Disable WiFi -void deinitWifi() -{ - LOG_INFO("WiFi deinit\n"); - - if (isWifiAvailable()) { - WiFi.disconnect(true); - WiFi.mode(WIFI_MODE_NULL); - LOG_INFO("WiFi Turned Off\n"); - // WiFi.printDiag(Serial); - } -} - static void onNetworkConnected() { if (!APStartupComplete) { @@ -158,7 +89,9 @@ static void onNetworkConnected() syslog.enable(); } +#ifndef ARCH_RP2040 initWebServer(); +#endif initApiServer(); APStartupComplete = true; @@ -169,6 +102,89 @@ static void onNetworkConnected() mqtt->reconnect(); } +static int32_t reconnectWiFi() +{ + const char *wifiName = config.network.wifi_ssid; + const char *wifiPsw = config.network.wifi_psk; + + if (config.network.wifi_enabled && needReconnect) { + + if (!*wifiPsw) // Treat empty password as no password + wifiPsw = NULL; + + needReconnect = false; + + // Make sure we clear old connection credentials +#ifdef ARCH_ESP32 + WiFi.disconnect(false, true); +#else + WiFi.disconnect(false); +#endif + LOG_INFO("Reconnecting to WiFi access point %s\n", wifiName); + + delay(5000); + + if (!WiFi.isConnected()) { + WiFi.begin(wifiName, wifiPsw); + } + } + +#ifndef DISABLE_NTP + if (WiFi.isConnected() && (((millis() - lastrun_ntp) > 43200000) || (lastrun_ntp == 0))) { // every 12 hours + LOG_DEBUG("Updating NTP time from %s\n", config.network.ntp_server); + if (timeClient.update()) { + LOG_DEBUG("NTP Request Success - Setting RTCQualityNTP if needed\n"); + + struct timeval tv; + tv.tv_sec = timeClient.getEpochTime(); + tv.tv_usec = 0; + + perhapsSetRTC(RTCQualityNTP, &tv); + lastrun_ntp = millis(); + + } else { + LOG_DEBUG("NTP Update failed\n"); + } + } +#endif + + if (config.network.wifi_enabled && !WiFi.isConnected()) { + return 1000; // check once per second + } else { +#ifdef ARCH_RP2040 + onNetworkConnected(); // will only do anything once +#endif + return 300000; // every 5 minutes + } +} + +bool isWifiAvailable() +{ + + if (config.network.wifi_enabled && (config.network.wifi_ssid[0])) { + return true; + } else { + return false; + } +} + +// Disable WiFi +void deinitWifi() +{ + LOG_INFO("WiFi deinit\n"); + + if (isWifiAvailable()) { +#ifdef ARCH_ESP32 + WiFi.disconnect(true, false); +#else + WiFi.disconnect(true); +#endif + WiFi.mode(WIFI_OFF); + LOG_INFO("WiFi Turned Off\n"); + // WiFi.printDiag(Serial); + } +} + // Startup WiFi bool initWifi() { @@ -177,10 +193,10 @@ bool initWifi() const char *wifiName = config.network.wifi_ssid; const char *wifiPsw = config.network.wifi_psk; - createSSLCert(); - +#ifndef ARCH_RP2040 + createSSLCert(); // For WebServer esp_wifi_set_storage(WIFI_STORAGE_RAM); // Disable flash storage for WiFi credentials - +#endif if (!*wifiPsw) // Treat empty password as no password wifiPsw = NULL; @@ -189,17 +205,17 @@ bool initWifi() getMacAddr(dmac); snprintf(ourHost, sizeof(ourHost), "Meshtastic-%02x%02x", dmac[4], dmac[5]); - WiFi.mode(WIFI_MODE_STA); + WiFi.mode(WIFI_STA); WiFi.setHostname(ourHost); - WiFi.onEvent(WiFiEvent); - WiFi.setAutoReconnect(true); - WiFi.setSleep(false); if (config.network.address_mode == meshtastic_Config_NetworkConfig_AddressMode_STATIC && config.network.ipv4_config.ip != 0) { WiFi.config(config.network.ipv4_config.ip, config.network.ipv4_config.gateway, config.network.ipv4_config.subnet, - config.network.ipv4_config.dns, - config.network.ipv4_config.dns); // Wifi wants two DNS servers... set both to the same value + config.network.ipv4_config.dns); } +#ifndef ARCH_RP2040 + WiFi.onEvent(WiFiEvent); + WiFi.setAutoReconnect(true); + WiFi.setSleep(false); // This is needed to improve performance. esp_wifi_set_ps(WIFI_PS_NONE); // Disable radio power saving @@ -218,7 +234,7 @@ bool initWifi() wifiDisconnectReason = info.wifi_sta_disconnected.reason; }, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED); - +#endif LOG_DEBUG("JOINING WIFI soon: ssid=%s\n", wifiName); wifiReconnect = new Periodic("WifiConnect", reconnectWiFi); } @@ -229,6 +245,7 @@ bool initWifi() } } +#ifndef ARCH_RP2040 // Called by the Espressif SDK to static void WiFiEvent(WiFiEvent_t event) { @@ -369,8 +386,9 @@ static void WiFiEvent(WiFiEvent_t event) break; } } +#endif uint8_t getWifiDisconnectReason() { return wifiDisconnectReason; -} +} \ No newline at end of file diff --git a/src/mesh/http/WiFiAPClient.h b/src/mesh/wifi/WiFiAPClient.h similarity index 79% rename from src/mesh/http/WiFiAPClient.h rename to src/mesh/wifi/WiFiAPClient.h index 0c08c567b..6625d3e46 100644 --- a/src/mesh/http/WiFiAPClient.h +++ b/src/mesh/wifi/WiFiAPClient.h @@ -5,7 +5,7 @@ #include #include -#ifdef ARCH_ESP32 +#if defined(HAS_WIFI) && !defined(ARCH_PORTDUINO) #include #endif @@ -19,4 +19,4 @@ void deinitWifi(); bool isWifiAvailable(); -uint8_t getWifiDisconnectReason(); +uint8_t getWifiDisconnectReason(); \ No newline at end of file diff --git a/src/modules/AdminModule.h b/src/modules/AdminModule.h index eb06e7b83..6ecc88829 100644 --- a/src/modules/AdminModule.h +++ b/src/modules/AdminModule.h @@ -1,7 +1,7 @@ #pragma once #include "ProtobufModule.h" -#ifdef ARCH_ESP32 -#include "mesh/http/WiFiAPClient.h" +#if HAS_WIFI +#include "mesh/wifi/WiFiAPClient.h" #endif /** @@ -50,4 +50,4 @@ class AdminModule : public ProtobufModule void reboot(int32_t seconds); }; -extern AdminModule *adminModule; +extern AdminModule *adminModule; \ No newline at end of file diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 29a634922..a97aa5255 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -7,9 +7,9 @@ #include "mesh/Router.h" #include "mesh/generated/meshtastic/mqtt.pb.h" #include "mesh/generated/meshtastic/telemetry.pb.h" -#include "mesh/http/WiFiAPClient.h" #include "sleep.h" #if HAS_WIFI +#include "mesh/wifi/WiFiAPClient.h" #include #endif #include "mqtt/JSON.h" diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp index 833e058d8..7da41512e 100644 --- a/src/platform/esp32/main-esp32.cpp +++ b/src/platform/esp32/main-esp32.cpp @@ -7,7 +7,7 @@ #include "nimble/NimbleBluetooth.h" #endif #include "BleOta.h" -#include "mesh/http/WiFiAPClient.h" +#include "mesh/wifi/WiFiAPClient.h" #include "meshUtils.h" #include "sleep.h" diff --git a/src/sleep.cpp b/src/sleep.cpp index b0f4aec88..464486d00 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -11,7 +11,7 @@ #ifdef ARCH_ESP32 #include "esp32/pm.h" #include "esp_pm.h" -#include "mesh/http/WiFiAPClient.h" +#include "mesh/wifi/WiFiAPClient.h" #include "rom/rtc.h" #include #include diff --git a/variants/rpipicow/platformio.ini b/variants/rpipicow/platformio.ini index 3228e4c24..4c8cf992d 100644 --- a/variants/rpipicow/platformio.ini +++ b/variants/rpipicow/platformio.ini @@ -8,8 +8,10 @@ upload_protocol = picotool build_flags = ${rp2040_base.build_flags} -DRPI_PICO -Ivariants/rpipicow - -DDEBUG_RP2040_PORT=Serial -DHW_SPI1_DEVICE -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m0plus" + -fexceptions # for exception handling in MQTT +build_src_filter = ${rp2040_base.build_src_filter} + lib_deps = - ${rp2040_base.lib_deps} \ No newline at end of file + ${rp2040_base.lib_deps} + ${networking_base.lib_deps} \ No newline at end of file diff --git a/variants/rpipicow/variant.h b/variants/rpipicow/variant.h index abbd1c465..c48b901ac 100644 --- a/variants/rpipicow/variant.h +++ b/variants/rpipicow/variant.h @@ -4,6 +4,10 @@ #define ARDUINO_ARCH_AVR +#ifndef HAS_WIFI +#define HAS_WIFI 1 +#endif + #define USE_SH1106 1 // default I2C pins: @@ -46,4 +50,4 @@ #define SX126X_RESET LORA_RESET #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 -#endif +#endif \ No newline at end of file