From 96c21a3f34bc5e79112b2924419f5788322f505b Mon Sep 17 00:00:00 2001 From: Bogdan Ivanus Date: Wed, 10 Sep 2025 17:59:17 +0300 Subject: [PATCH 1/2] ZEP-55: Implemented WiFi.scan() functionality. --- libraries/WiFi/src/WiFi.cpp | 52 ++++++++++++++++++++--------- libraries/WiFi/src/WiFi.h | 66 +++++++++++++++++++++++++++++++++++++ loader/llext_exports.c | 1 + 3 files changed, 104 insertions(+), 15 deletions(-) diff --git a/libraries/WiFi/src/WiFi.cpp b/libraries/WiFi/src/WiFi.cpp index 5a6d2912..23781709 100644 --- a/libraries/WiFi/src/WiFi.cpp +++ b/libraries/WiFi/src/WiFi.cpp @@ -2,6 +2,8 @@ WiFiClass WiFi; +WiFiClass *WiFiClass::instance = nullptr; + String WiFiClass::firmwareVersion() { #if defined(ARDUINO_PORTENTA_C33) return "v1.5.0"; @@ -18,21 +20,30 @@ int WiFiClass::begin(const char *ssid, const char *passphrase, wl_enc_type secur sta_config.ssid_length = strlen(ssid); sta_config.psk = (const uint8_t *)passphrase; sta_config.psk_length = strlen(passphrase); - // TODO: change these fields with scan() results - sta_config.security = WIFI_SECURITY_TYPE_PSK; - sta_config.channel = WIFI_CHANNEL_ANY; - sta_config.band = WIFI_FREQ_BAND_2_4_GHZ; - sta_config.bandwidth = WIFI_FREQ_BANDWIDTH_20MHZ; - int ret = net_mgmt(NET_REQUEST_WIFI_CONNECT, sta_iface, &sta_config, - sizeof(struct wifi_connect_req_params)); - if (ret) { - return false; - } - NetworkInterface::begin(false, NET_EVENT_WIFI_MASK); - if (blocking) { - net_mgmt_event_wait_on_iface(sta_iface, NET_EVENT_WIFI_CONNECT_RESULT, NULL, NULL, NULL, - K_FOREVER); + + // Register the Wi-Fi event callback + net_mgmt_init_event_callback(&wifiCb, scanEventDispatcher, + NET_EVENT_WIFI_SCAN_RESULT | NET_EVENT_WIFI_SCAN_DONE); + + net_mgmt_add_event_callback(&wifiCb); + + (void)scanNetworks(); + + // Check if the network we were seekin was found and attempt to connect to it + if (getSoughtNetworkFound() != true) { + int ret = net_mgmt(NET_REQUEST_WIFI_CONNECT, sta_iface, &sta_config, + sizeof(struct wifi_connect_req_params)); + if (ret) { + return false; + } + + NetworkInterface::begin(false, NET_EVENT_WIFI_MASK); + if (blocking) { + net_mgmt_event_wait_on_iface(sta_iface, NET_EVENT_WIFI_CONNECT_RESULT, NULL, NULL, NULL, + K_FOREVER); + } } + return status(); } @@ -79,7 +90,18 @@ int WiFiClass::status() { } int8_t WiFiClass::scanNetworks() { - // TODO: borrow code from mbed core for scan results handling + resultCount = 0u; + setScanSequenceFinished(false); + setSoughtNetworkFound(false); + + // Trigger a new scan + net_mgmt(NET_REQUEST_WIFI_SCAN, sta_iface, nullptr, 0u); + + // Wait for the scan to finish. This is by design a blocking call + while (getScanSequenceFinished() != true) + ; + + return resultCount; } char *WiFiClass::SSID() { diff --git a/libraries/WiFi/src/WiFi.h b/libraries/WiFi/src/WiFi.h index 739b5bb3..bfd5abc4 100644 --- a/libraries/WiFi/src/WiFi.h +++ b/libraries/WiFi/src/WiFi.h @@ -3,6 +3,9 @@ #include "utility/wl_definitions.h" #include +// Max number of scan results to store +#define MAX_SCAN_RESULTS 20 + #define NET_EVENT_WIFI_MASK \ (NET_EVENT_WIFI_CONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_RESULT | \ NET_EVENT_WIFI_AP_ENABLE_RESULT | NET_EVENT_WIFI_AP_DISABLE_RESULT | \ @@ -31,6 +34,62 @@ class WiFiClass : public NetworkInterface { String firmwareVersion(); + static void scanEventDispatcher(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, + struct net_if *iface) { + if (instance != nullptr) { + instance->handleScanEvent(cb, mgmt_event, iface); + } + } + + void handleScanEvent(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, + struct net_if *iface) { + if (mgmt_event == NET_EVENT_WIFI_SCAN_RESULT) { + const struct wifi_scan_result *entry = + reinterpret_cast(cb->info); + if (resultCount < MAX_SCAN_RESULTS) { + memcpy(&scanResults[resultCount], entry, sizeof(struct wifi_scan_result)); + resultCount++; + + // for each new result found, compare network name with desired one + if (!memcmp(entry->ssid, sta_config.ssid, entry->ssid_length)) { + // if a match is found, add missing info to config before attempting to connect + sta_config.security = entry->security; + sta_config.channel = entry->channel; + sta_config.band = entry->band; + sta_config.bandwidth = WIFI_FREQ_BANDWIDTH_20MHZ; + + setSoughtNetworkFound(true); + } + } + } + + if (mgmt_event == NET_EVENT_WIFI_SCAN_DONE) { + setScanSequenceFinished(true); + + if (resultCount = 0) { + printk("No networks found.\n"); + } + } + } + + void setScanSequenceFinished(bool scanFinished) { + scanSequenceFinished = scanFinished; + } + + void setSoughtNetworkFound(bool networkFound) { + soughtNetworkFound = networkFound; + } + + bool getScanSequenceFinished(void) { + return scanSequenceFinished; + } + + bool getSoughtNetworkFound(void) { + return soughtNetworkFound; + } + + static WiFiClass *instance; + private: struct net_if *sta_iface = nullptr; struct net_if *ap_iface = nullptr; @@ -39,6 +98,13 @@ class WiFiClass : public NetworkInterface { struct wifi_connect_req_params sta_config; struct wifi_iface_status sta_state = {0}; + + struct wifi_scan_result scanResults[MAX_SCAN_RESULTS]; + uint8_t resultCount; + struct net_mgmt_event_callback wifiCb; + + bool soughtNetworkFound = false; + bool scanSequenceFinished = false; }; extern WiFiClass WiFi; diff --git a/loader/llext_exports.c b/loader/llext_exports.c index 7941a00b..607052dd 100644 --- a/loader/llext_exports.c +++ b/loader/llext_exports.c @@ -113,6 +113,7 @@ FORCE_EXPORT_SYM(tls_credential_add); FORCE_EXPORT_SYM(net_if_get_wifi_sta); FORCE_EXPORT_SYM(net_if_get_wifi_sap); FORCE_EXPORT_SYM(net_mgmt_NET_REQUEST_WIFI_CONNECT); +FORCE_EXPORT_SYM(net_mgmt_NET_REQUEST_WIFI_SCAN); FORCE_EXPORT_SYM(net_mgmt_NET_REQUEST_WIFI_IFACE_STATUS); FORCE_EXPORT_SYM(net_mgmt_NET_REQUEST_WIFI_AP_ENABLE); #endif From d93ba64c10142963897408a0256b8c1bfc75ce2c Mon Sep 17 00:00:00 2001 From: Bogdan Ivanus Date: Tue, 16 Sep 2025 17:23:00 +0300 Subject: [PATCH 2/2] ZEP-55: WiFi: try to connect using default connection parameters Device will try to connect using default connection parameters, if an SSID and a password were provided, even if the scan was unsuccessful. --- .../examples/WiFiWebClient/WiFiWebClient.ino | 4 +-- libraries/WiFi/src/WiFi.cpp | 26 +++++++++++++++---- libraries/WiFi/src/WiFi.h | 4 +-- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/libraries/WiFi/examples/WiFiWebClient/WiFiWebClient.ino b/libraries/WiFi/examples/WiFiWebClient/WiFiWebClient.ino index 0231e88c..b9d7c82e 100644 --- a/libraries/WiFi/examples/WiFiWebClient/WiFiWebClient.ino +++ b/libraries/WiFi/examples/WiFiWebClient/WiFiWebClient.ino @@ -50,8 +50,8 @@ void setup() { Serial.println(ssid); // Connect to WPA/WPA2 network. Change this line if using open or WEP network: status = WiFi.begin(ssid, pass); - // wait 3 seconds for connection: - delay(3000); + // wait 6 seconds for connection: + delay(6000); } Serial.println("Connected to wifi"); printWifiStatus(); diff --git a/libraries/WiFi/src/WiFi.cpp b/libraries/WiFi/src/WiFi.cpp index 23781709..8eafaae0 100644 --- a/libraries/WiFi/src/WiFi.cpp +++ b/libraries/WiFi/src/WiFi.cpp @@ -12,8 +12,8 @@ String WiFiClass::firmwareVersion() { #endif } -int WiFiClass::begin(const char *ssid, const char *passphrase, wl_enc_type security, - bool blocking) { +int begin(const char *ssid, const char *passphrase, + wifi_security_type security = WIFI_SECURITY_TYPE_NONE, bool blocking = true) { sta_iface = net_if_get_wifi_sta(); netif = sta_iface; sta_config.ssid = (const uint8_t *)ssid; @@ -21,16 +21,32 @@ int WiFiClass::begin(const char *ssid, const char *passphrase, wl_enc_type secur sta_config.psk = (const uint8_t *)passphrase; sta_config.psk_length = strlen(passphrase); + // The user might provide the security type as well + if (security != WIFI_SECURITY_TYPE_NONE) { + sta_config.security = security; + } else { + sta_config.security = WIFI_SECURITY_TYPE_PSK; + } + sta_config.channel = WIFI_CHANNEL_ANY; + sta_config.band = WIFI_FREQ_BAND_2_4_GHZ; + sta_config.bandwidth = WIFI_FREQ_BANDWIDTH_20MHZ; + // Register the Wi-Fi event callback net_mgmt_init_event_callback(&wifiCb, scanEventDispatcher, NET_EVENT_WIFI_SCAN_RESULT | NET_EVENT_WIFI_SCAN_DONE); net_mgmt_add_event_callback(&wifiCb); - (void)scanNetworks(); + // If the network we are scanning for is found, the connection parameters will be updated + // automatically; + (void)scanNetworks(); // This is a blocking function call + + // Attempt to connect with either default parameters, or the updated ones after the scan + // completed + if ((sta_config.ssid != NULL) && (sta_config.ssid_length != 0u) && (sta_config.psk != NULL) && + (sta_config.psk_length != 0u)) - // Check if the network we were seekin was found and attempt to connect to it - if (getSoughtNetworkFound() != true) { + { int ret = net_mgmt(NET_REQUEST_WIFI_CONNECT, sta_iface, &sta_config, sizeof(struct wifi_connect_req_params)); if (ret) { diff --git a/libraries/WiFi/src/WiFi.h b/libraries/WiFi/src/WiFi.h index bfd5abc4..b5bd052f 100644 --- a/libraries/WiFi/src/WiFi.h +++ b/libraries/WiFi/src/WiFi.h @@ -20,8 +20,8 @@ class WiFiClass : public NetworkInterface { ~WiFiClass() { } - int begin(const char *ssid, const char *passphrase, wl_enc_type security = ENC_TYPE_UNKNOWN, - bool blocking = true); + int begin(const char *ssid, const char *passphrase, + wifi_security_type security = WIFI_SECURITY_TYPE_NONE, bool blocking = true); bool beginAP(char *ssid, char *passphrase, int channel = WIFI_CHANNEL_ANY, bool blocking = false);