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
This commit is contained in:
GUVWAF 2023-12-02 21:47:52 +01:00 committed by GitHub
parent 9e90b4af02
commit 6ff61b3e04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 154 additions and 119 deletions

View File

@ -123,6 +123,7 @@ jobs:
matrix: matrix:
include: include:
- board: pico - board: pico
- board: picow
- board: rak11310 - board: rak11310
uses: ./.github/workflows/build_rpi2040.yml uses: ./.github/workflows/build_rpi2040.yml
with: with:

View File

@ -11,7 +11,7 @@ build_flags =
-Isrc/platform/nrf52 -Isrc/platform/nrf52
build_src_filter = build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2040> -<mesh/eth/> ${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2040> -<mesh/eth/>
lib_deps= lib_deps=
${arduino_base.lib_deps} ${arduino_base.lib_deps}

View File

@ -10,6 +10,7 @@ build_src_filter =
-<platform/nrf52/> -<platform/nrf52/>
-<platform/stm32wl/> -<platform/stm32wl/>
-<platform/rp2040> -<platform/rp2040>
-<mesh/wifi/>
-<mesh/http/> -<mesh/http/>
-<mesh/eth/> -<mesh/eth/>
-<modules/esp32> -<modules/esp32>

View File

@ -1,8 +1,8 @@
; Common settings for rp2040 Processor based targets ; Common settings for rp2040 Processor based targets
[rp2040_base] [rp2040_base]
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#0c33219f53faa035e188925ea1324f472e8b93d2 platform = https://github.com/maxgerhardt/platform-raspberrypi.git#612de5399d68b359053f1307ed223d400aea975c
extends = arduino_base 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.core = earlephilhower
board_build.filesystem_size = 0.5m board_build.filesystem_size = 0.5m
@ -12,7 +12,7 @@ build_flags =
-D__PLAT_RP2040__ -D__PLAT_RP2040__
# -D _POSIX_THREADS # -D _POSIX_THREADS
build_src_filter = build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/> ${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/> -<mesh/wifi/> -<mesh/http/>
lib_ignore = lib_ignore =
BluetoothOTA BluetoothOTA

View File

@ -13,7 +13,7 @@ build_flags =
-DVECT_TAB_OFFSET=0x08000000 -DVECT_TAB_OFFSET=0x08000000
build_src_filter = build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040> ${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040>
board_upload.offset_address = 0x08000000 board_upload.offset_address = 0x08000000
upload_protocol = stlink upload_protocol = stlink

View File

@ -45,7 +45,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
#include "esp_task_wdt.h" #include "esp_task_wdt.h"
#include "mesh/http/WiFiAPClient.h" #include "mesh/wifi/WiFiAPClient.h"
#include "modules/esp32/StoreForwardModule.h" #include "modules/esp32/StoreForwardModule.h"
#endif #endif
@ -1618,12 +1618,19 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Failed"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Failed");
} else if (WiFi.status() == WL_IDLE_STATUS) { } else if (WiFi.status() == WL_IDLE_STATUS) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Idle ... Reconnecting"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Idle ... Reconnecting");
} else { }
#ifdef ARCH_ESP32
else {
// Codes: // Codes:
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-reason-code // 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, display->drawString(x, y + FONT_HEIGHT_SMALL * 1,
WiFi.disconnectReasonName(static_cast<wifi_err_reason_t>(getWifiDisconnectReason()))); WiFi.disconnectReasonName(static_cast<wifi_err_reason_t>(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)); display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName));

View File

@ -32,9 +32,6 @@
#include <utility> #include <utility>
// #include <driver/rtc_io.h> // #include <driver/rtc_io.h>
#include "mesh/eth/ethClient.h"
#include "mesh/http/WiFiAPClient.h"
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
#include "mesh/http/WebServer.h" #include "mesh/http/WebServer.h"
#include "nimble/NimbleBluetooth.h" #include "nimble/NimbleBluetooth.h"
@ -48,10 +45,12 @@ NRF52Bluetooth *nrf52Bluetooth;
#if HAS_WIFI #if HAS_WIFI
#include "mesh/api/WiFiServerAPI.h" #include "mesh/api/WiFiServerAPI.h"
#include "mesh/wifi/WiFiAPClient.h"
#endif #endif
#if HAS_ETHERNET #if HAS_ETHERNET
#include "mesh/api/ethServerAPI.h" #include "mesh/api/ethServerAPI.h"
#include "mesh/eth/ethClient.h"
#endif #endif
#include "mqtt/MQTT.h" #include "mqtt/MQTT.h"
@ -835,11 +834,15 @@ void setup()
#ifndef ARCH_PORTDUINO #ifndef ARCH_PORTDUINO
// Initialize Wifi // Initialize Wifi
#if HAS_WIFI
initWifi(); initWifi();
#endif
#if HAS_ETHERNET
// Initialize Ethernet // Initialize Ethernet
initEthernet(); initEthernet();
#endif #endif
#endif
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
// Start web server thread. // Start web server thread.

View File

@ -21,7 +21,7 @@
#include <pb_encode.h> #include <pb_encode.h>
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
#include "mesh/http/WiFiAPClient.h" #include "mesh/wifi/WiFiAPClient.h"
#include "modules/esp32/StoreForwardModule.h" #include "modules/esp32/StoreForwardModule.h"
#include <Preferences.h> #include <Preferences.h>
#include <nvs_flash.h> #include <nvs_flash.h>

View File

@ -5,7 +5,7 @@
#include "main.h" #include "main.h"
#include "mesh/http/ContentHelper.h" #include "mesh/http/ContentHelper.h"
#include "mesh/http/WebServer.h" #include "mesh/http/WebServer.h"
#include "mesh/http/WiFiAPClient.h" #include "mesh/wifi/WiFiAPClient.h"
#include "mqtt/JSON.h" #include "mqtt/JSON.h"
#include "power.h" #include "power.h"
#include "sleep.h" #include "sleep.h"

View File

@ -1,5 +1,4 @@
#pragma once #pragma once
void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer); void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer);
// Declare some handler functions for the various URLs on the server // Declare some handler functions for the various URLs on the server

View File

@ -2,7 +2,7 @@
#include "NodeDB.h" #include "NodeDB.h"
#include "graphics/Screen.h" #include "graphics/Screen.h"
#include "main.h" #include "main.h"
#include "mesh/http/WiFiAPClient.h" #include "mesh/wifi/WiFiAPClient.h"
#include "sleep.h" #include "sleep.h"
#include <HTTPBodyParser.hpp> #include <HTTPBodyParser.hpp>
#include <HTTPMultipartBodyParser.hpp> #include <HTTPMultipartBodyParser.hpp>

View File

@ -1,17 +1,22 @@
#include "mesh/http/WiFiAPClient.h" #include "mesh/wifi/WiFiAPClient.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "RTC.h" #include "RTC.h"
#include "concurrency/Periodic.h" #include "concurrency/Periodic.h"
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
#include "mesh/api/WiFiServerAPI.h" #include "mesh/api/WiFiServerAPI.h"
#include "mesh/http/WebServer.h"
#include "mqtt/MQTT.h" #include "mqtt/MQTT.h"
#include "target_specific.h" #include "target_specific.h"
#include <ESPmDNS.h>
#include <WiFi.h> #include <WiFi.h>
#include <WiFiUdp.h> #include <WiFiUdp.h>
#ifndef ARCH_RP2040
#include "mesh/http/WebServer.h"
#include <ESPmDNS.h>
#include <esp_wifi.h> #include <esp_wifi.h>
static void WiFiEvent(WiFiEvent_t event);
#else
#include <ESP8266mDNS.h>
#endif
#ifndef DISABLE_NTP #ifndef DISABLE_NTP
#include <NTPClient.h> #include <NTPClient.h>
@ -19,8 +24,6 @@
using namespace concurrency; using namespace concurrency;
static void WiFiEvent(WiFiEvent_t event);
// NTP // NTP
WiFiUDP ntpUDP; WiFiUDP ntpUDP;
@ -44,78 +47,6 @@ Syslog syslog(syslogClient);
Periodic *wifiReconnect; 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() static void onNetworkConnected()
{ {
if (!APStartupComplete) { if (!APStartupComplete) {
@ -158,7 +89,9 @@ static void onNetworkConnected()
syslog.enable(); syslog.enable();
} }
#ifndef ARCH_RP2040
initWebServer(); initWebServer();
#endif
initApiServer(); initApiServer();
APStartupComplete = true; APStartupComplete = true;
@ -169,6 +102,89 @@ static void onNetworkConnected()
mqtt->reconnect(); 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 // Startup WiFi
bool initWifi() bool initWifi()
{ {
@ -177,10 +193,10 @@ bool initWifi()
const char *wifiName = config.network.wifi_ssid; const char *wifiName = config.network.wifi_ssid;
const char *wifiPsw = config.network.wifi_psk; 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 esp_wifi_set_storage(WIFI_STORAGE_RAM); // Disable flash storage for WiFi credentials
#endif
if (!*wifiPsw) // Treat empty password as no password if (!*wifiPsw) // Treat empty password as no password
wifiPsw = NULL; wifiPsw = NULL;
@ -189,17 +205,17 @@ bool initWifi()
getMacAddr(dmac); getMacAddr(dmac);
snprintf(ourHost, sizeof(ourHost), "Meshtastic-%02x%02x", dmac[4], dmac[5]); snprintf(ourHost, sizeof(ourHost), "Meshtastic-%02x%02x", dmac[4], dmac[5]);
WiFi.mode(WIFI_MODE_STA); WiFi.mode(WIFI_STA);
WiFi.setHostname(ourHost); WiFi.setHostname(ourHost);
WiFi.onEvent(WiFiEvent);
WiFi.setAutoReconnect(true);
WiFi.setSleep(false);
if (config.network.address_mode == meshtastic_Config_NetworkConfig_AddressMode_STATIC && if (config.network.address_mode == meshtastic_Config_NetworkConfig_AddressMode_STATIC &&
config.network.ipv4_config.ip != 0) { config.network.ipv4_config.ip != 0) {
WiFi.config(config.network.ipv4_config.ip, config.network.ipv4_config.gateway, config.network.ipv4_config.subnet, 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);
config.network.ipv4_config.dns); // Wifi wants two DNS servers... set both to the same value
} }
#ifndef ARCH_RP2040
WiFi.onEvent(WiFiEvent);
WiFi.setAutoReconnect(true);
WiFi.setSleep(false);
// This is needed to improve performance. // This is needed to improve performance.
esp_wifi_set_ps(WIFI_PS_NONE); // Disable radio power saving esp_wifi_set_ps(WIFI_PS_NONE); // Disable radio power saving
@ -218,7 +234,7 @@ bool initWifi()
wifiDisconnectReason = info.wifi_sta_disconnected.reason; wifiDisconnectReason = info.wifi_sta_disconnected.reason;
}, },
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED); WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
#endif
LOG_DEBUG("JOINING WIFI soon: ssid=%s\n", wifiName); LOG_DEBUG("JOINING WIFI soon: ssid=%s\n", wifiName);
wifiReconnect = new Periodic("WifiConnect", reconnectWiFi); wifiReconnect = new Periodic("WifiConnect", reconnectWiFi);
} }
@ -229,6 +245,7 @@ bool initWifi()
} }
} }
#ifndef ARCH_RP2040
// Called by the Espressif SDK to // Called by the Espressif SDK to
static void WiFiEvent(WiFiEvent_t event) static void WiFiEvent(WiFiEvent_t event)
{ {
@ -369,6 +386,7 @@ static void WiFiEvent(WiFiEvent_t event)
break; break;
} }
} }
#endif
uint8_t getWifiDisconnectReason() uint8_t getWifiDisconnectReason()
{ {

View File

@ -5,7 +5,7 @@
#include <Arduino.h> #include <Arduino.h>
#include <functional> #include <functional>
#ifdef ARCH_ESP32 #if defined(HAS_WIFI) && !defined(ARCH_PORTDUINO)
#include <WiFi.h> #include <WiFi.h>
#endif #endif

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "ProtobufModule.h" #include "ProtobufModule.h"
#ifdef ARCH_ESP32 #if HAS_WIFI
#include "mesh/http/WiFiAPClient.h" #include "mesh/wifi/WiFiAPClient.h"
#endif #endif
/** /**

View File

@ -7,9 +7,9 @@
#include "mesh/Router.h" #include "mesh/Router.h"
#include "mesh/generated/meshtastic/mqtt.pb.h" #include "mesh/generated/meshtastic/mqtt.pb.h"
#include "mesh/generated/meshtastic/telemetry.pb.h" #include "mesh/generated/meshtastic/telemetry.pb.h"
#include "mesh/http/WiFiAPClient.h"
#include "sleep.h" #include "sleep.h"
#if HAS_WIFI #if HAS_WIFI
#include "mesh/wifi/WiFiAPClient.h"
#include <WiFi.h> #include <WiFi.h>
#endif #endif
#include "mqtt/JSON.h" #include "mqtt/JSON.h"

View File

@ -7,7 +7,7 @@
#include "nimble/NimbleBluetooth.h" #include "nimble/NimbleBluetooth.h"
#endif #endif
#include "BleOta.h" #include "BleOta.h"
#include "mesh/http/WiFiAPClient.h" #include "mesh/wifi/WiFiAPClient.h"
#include "meshUtils.h" #include "meshUtils.h"
#include "sleep.h" #include "sleep.h"

View File

@ -11,7 +11,7 @@
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
#include "esp32/pm.h" #include "esp32/pm.h"
#include "esp_pm.h" #include "esp_pm.h"
#include "mesh/http/WiFiAPClient.h" #include "mesh/wifi/WiFiAPClient.h"
#include "rom/rtc.h" #include "rom/rtc.h"
#include <driver/rtc_io.h> #include <driver/rtc_io.h>
#include <driver/uart.h> #include <driver/uart.h>

View File

@ -8,8 +8,10 @@ upload_protocol = picotool
build_flags = ${rp2040_base.build_flags} build_flags = ${rp2040_base.build_flags}
-DRPI_PICO -DRPI_PICO
-Ivariants/rpipicow -Ivariants/rpipicow
-DDEBUG_RP2040_PORT=Serial
-DHW_SPI1_DEVICE -DHW_SPI1_DEVICE
-L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m0plus" -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} +<mesh/wifi/>
lib_deps = lib_deps =
${rp2040_base.lib_deps} ${rp2040_base.lib_deps}
${networking_base.lib_deps}

View File

@ -4,6 +4,10 @@
#define ARDUINO_ARCH_AVR #define ARDUINO_ARCH_AVR
#ifndef HAS_WIFI
#define HAS_WIFI 1
#endif
#define USE_SH1106 1 #define USE_SH1106 1
// default I2C pins: // default I2C pins: