From f769b0cc2f7f67cc34d1adba9c8c01697e99a16c Mon Sep 17 00:00:00 2001 From: Bogdan Ivanus Date: Thu, 30 Oct 2025 18:38:15 +0200 Subject: [PATCH 1/2] WiFI: Implemented WiFI.scan() functionality. 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. ZEP-55: Implemented WiFi.scan() functionality. --- .../examples/WiFiWebClient/WiFiWebClient.ino | 4 +- libraries/WiFi/src/WiFi.cpp | 220 ++++++++++++++---- libraries/WiFi/src/WiFi.h | 39 ++-- loader/llext_exports.c | 1 + 4 files changed, 193 insertions(+), 71 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 f7a57bd1..96fe61de 100644 --- a/libraries/WiFi/src/WiFi.cpp +++ b/libraries/WiFi/src/WiFi.cpp @@ -1,99 +1,217 @@ #include "WiFi.h" -WiFiClass WiFi; +// Static Wi-Fi state instance +struct WiFiState { + struct net_if *sta_iface = nullptr; + struct net_if *ap_iface = nullptr; + struct wifi_connect_req_params ap_config; + 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 = 0; + struct net_mgmt_event_callback wifiCb; + bool soughtNetworkFound = false; + bool scanSequenceFinished = false; +}; -String WiFiClass::firmwareVersion() { -#if defined(ARDUINO_PORTENTA_C33) - return "v1.5.0"; -#else - return "v0.0.0"; -#endif +WiFiClass::WiFiClass() { } +WiFiClass::~WiFiClass() { +} + +// Static instance of Wi-Fi state +struct WiFiState WiFiClass::wifiState; + int WiFiClass::begin(const char *ssid, const char *passphrase, wl_enc_type security, bool blocking) { - sta_iface = net_if_get_wifi_sta(); - netif = sta_iface; - sta_config.ssid = (const uint8_t *)ssid; - 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; + wifi_security_type wifi_security = convert_enc_type_to_security_type(security); + + wifiState.sta_iface = net_if_get_wifi_sta(); + netif = wifiState.sta_iface; + wifiState.sta_config.ssid = (const uint8_t *)ssid; + wifiState.sta_config.ssid_length = strlen(ssid); + wifiState.sta_config.psk = (const uint8_t *)passphrase; + wifiState.sta_config.psk_length = strlen(passphrase); + + // Set Wi-Fi security type if specified + if (wifi_security != WIFI_SECURITY_TYPE_NONE) { + wifiState.sta_config.security = wifi_security; + } else { + wifiState.sta_config.security = WIFI_SECURITY_TYPE_PSK; } - ret = status(); - if (ret != WL_CONNECTED && blocking) { - net_mgmt_event_wait_on_iface(sta_iface, NET_EVENT_WIFI_CONNECT_RESULT, NULL, NULL, NULL, - K_FOREVER); + wifiState.sta_config.channel = WIFI_CHANNEL_ANY; + wifiState.sta_config.band = WIFI_FREQ_BAND_2_4_GHZ; + wifiState.sta_config.bandwidth = WIFI_FREQ_BANDWIDTH_20MHZ; + + // Register the Wi-Fi event callback + net_mgmt_init_event_callback(&wifiState.wifiCb, scanEventDispatcher, + NET_EVENT_WIFI_SCAN_RESULT | NET_EVENT_WIFI_SCAN_DONE); + net_mgmt_add_event_callback(&wifiState.wifiCb); + + // Trigger a network scan + (void)scanNetworks(); // Blocking call + + // Attempt to connect to the network if configuration is valid + if (wifiState.sta_config.ssid && wifiState.sta_config.psk) { + int ret = net_mgmt(NET_REQUEST_WIFI_CONNECT, wifiState.sta_iface, &wifiState.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(wifiState.sta_iface, NET_EVENT_WIFI_CONNECT_RESULT, NULL, + NULL, NULL, K_FOREVER); + } } - NetworkInterface::begin(blocking, NET_EVENT_WIFI_MASK); + return status(); } bool WiFiClass::beginAP(char *ssid, char *passphrase, int channel, bool blocking) { - if (ap_iface != NULL) { - return false; + if (wifiState.ap_iface != nullptr) { + return false; // AP already initialized } - ap_iface = net_if_get_wifi_sap(); - netif = ap_iface; - ap_config.ssid = (const uint8_t *)ssid; - ap_config.ssid_length = strlen(ssid); - ap_config.psk = (const uint8_t *)passphrase; - ap_config.psk_length = strlen(passphrase); - ap_config.security = WIFI_SECURITY_TYPE_PSK; - ap_config.channel = channel; - ap_config.band = WIFI_FREQ_BAND_2_4_GHZ; - ap_config.bandwidth = WIFI_FREQ_BANDWIDTH_20MHZ; - int ret = net_mgmt(NET_REQUEST_WIFI_AP_ENABLE, ap_iface, &ap_config, + + wifiState.ap_iface = net_if_get_wifi_sap(); + netif = wifiState.ap_iface; + wifiState.ap_config.ssid = (const uint8_t *)ssid; + wifiState.ap_config.ssid_length = strlen(ssid); + wifiState.ap_config.psk = (const uint8_t *)passphrase; + wifiState.ap_config.psk_length = strlen(passphrase); + wifiState.ap_config.security = WIFI_SECURITY_TYPE_PSK; + wifiState.ap_config.channel = channel; + wifiState.ap_config.band = WIFI_FREQ_BAND_2_4_GHZ; + wifiState.ap_config.bandwidth = WIFI_FREQ_BANDWIDTH_20MHZ; + + int ret = net_mgmt(NET_REQUEST_WIFI_AP_ENABLE, wifiState.ap_iface, &wifiState.ap_config, sizeof(struct wifi_connect_req_params)); if (ret) { return false; } - enable_dhcpv4_server(ap_iface); + + enable_dhcpv4_server(wifiState.ap_iface); + if (blocking) { - net_mgmt_event_wait_on_iface(ap_iface, NET_EVENT_WIFI_AP_ENABLE_RESULT, NULL, NULL, NULL, - K_FOREVER); + net_mgmt_event_wait_on_iface(wifiState.ap_iface, NET_EVENT_WIFI_AP_ENABLE_RESULT, NULL, + NULL, NULL, K_FOREVER); } + return true; } int WiFiClass::status() { - sta_iface = net_if_get_wifi_sta(); - netif = sta_iface; - if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, netif, &sta_state, + wifiState.sta_iface = net_if_get_wifi_sta(); + netif = wifiState.sta_iface; + if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, netif, &wifiState.sta_state, sizeof(struct wifi_iface_status))) { return WL_NO_SHIELD; } - if (sta_state.state >= WIFI_STATE_ASSOCIATED) { + if (wifiState.sta_state.state >= WIFI_STATE_ASSOCIATED) { return WL_CONNECTED; } else { return WL_DISCONNECTED; } - return WL_NO_SHIELD; } int8_t WiFiClass::scanNetworks() { - // TODO: borrow code from mbed core for scan results handling + wifiState.resultCount = 0u; + wifiState.soughtNetworkFound = false; + wifiState.scanSequenceFinished = false; + + // Trigger a new scan + net_mgmt(NET_REQUEST_WIFI_SCAN, wifiState.sta_iface, nullptr, 0u); + + // Wait for the scan to finish (this is a blocking call) + while (!wifiState.scanSequenceFinished) + ; + + return wifiState.resultCount; +} + +void WiFiClass::scanEventDispatcher(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, + struct net_if *iface) { + // Use the global Wi-Fi state instance to handle the event + if (wifiState.sta_iface != nullptr) { + WiFi.handleScanEvent(cb, mgmt_event, iface); + } +} + +void WiFiClass::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 (wifiState.resultCount < MAX_SCAN_RESULTS) { + memcpy(&wifiState.scanResults[wifiState.resultCount], entry, + sizeof(struct wifi_scan_result)); + wifiState.resultCount++; + + // Compare SSID of the scanned network with the desired network SSID + if (!memcmp(entry->ssid, wifiState.sta_config.ssid, entry->ssid_length)) { + wifiState.sta_config.security = entry->security; + wifiState.sta_config.channel = entry->channel; + wifiState.sta_config.band = entry->band; + wifiState.sta_config.bandwidth = WIFI_FREQ_BANDWIDTH_20MHZ; + + wifiState.soughtNetworkFound = true; + } + } + } + + if (mgmt_event == NET_EVENT_WIFI_SCAN_DONE) { + wifiState.scanSequenceFinished = true; + + if (wifiState.resultCount == 0) { + printk("No networks found.\n"); + } + } } char *WiFiClass::SSID() { if (status() == WL_CONNECTED) { - return (char *)sta_state.ssid; + return (char *)wifiState.sta_state.ssid; } return nullptr; } int32_t WiFiClass::RSSI() { if (status() == WL_CONNECTED) { - return sta_state.rssi; + return wifiState.sta_state.rssi; } return 0; } + +String WiFiClass::firmwareVersion() { +#if defined(ARDUINO_PORTENTA_C33) + return "v1.5.0"; +#else + return "v0.0.0"; +#endif +} + +wifi_security_type WiFiClass::convert_enc_type_to_security_type(wl_enc_type enc_type) { + switch (enc_type) { + case ENC_TYPE_WEP: + return WIFI_SECURITY_TYPE_WEP; + case ENC_TYPE_WPA: + return WIFI_SECURITY_TYPE_WPA_PSK; // Could also map to WPA_AUTO_PERSONAL + case ENC_TYPE_WPA2: + return WIFI_SECURITY_TYPE_PSK; // Could also map to WPA_AUTO_PERSONAL + case ENC_TYPE_WPA3: + return WIFI_SECURITY_TYPE_SAE; // Could also map to SAE_AUTO + case ENC_TYPE_NONE: + return WIFI_SECURITY_TYPE_NONE; + case ENC_TYPE_UNKNOWN: + case ENC_TYPE_AUTO: + return WIFI_SECURITY_TYPE_UNKNOWN; + default: + return WIFI_SECURITY_TYPE_UNKNOWN; // Default case for any undefined or unexpected values + } +} + +// Global Wi-Fi object, uses the static wifiState struct +WiFiClass WiFi; diff --git a/libraries/WiFi/src/WiFi.h b/libraries/WiFi/src/WiFi.h index 739b5bb3..243da05c 100644 --- a/libraries/WiFi/src/WiFi.h +++ b/libraries/WiFi/src/WiFi.h @@ -1,8 +1,14 @@ -#include "SocketHelpers.h" +#ifndef WIFI_H +#define WIFI_H +#include "SocketHelpers.h" #include "utility/wl_definitions.h" #include +// Max number of scan results to store +#define MAX_SCAN_RESULTS 20 + +// Wi-Fi event mask for the various events #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 | \ @@ -11,34 +17,31 @@ class WiFiClass : public NetworkInterface { public: - WiFiClass() { - } + WiFiClass(); + ~WiFiClass(); - ~WiFiClass() { - } - - int begin(const char *ssid, const char *passphrase, wl_enc_type security = ENC_TYPE_UNKNOWN, + int begin(const char *ssid, const char *passphrase, wl_enc_type security = ENC_TYPE_WPA, bool blocking = true); + bool beginAP(char *ssid, char *passphrase, int channel = WIFI_CHANNEL_ANY, bool blocking = false); int status(); - int8_t scanNetworks(); - char *SSID(); int32_t RSSI(); - String firmwareVersion(); + wifi_security_type convert_enc_type_to_security_type(wl_enc_type enc_type); -private: - struct net_if *sta_iface = nullptr; - struct net_if *ap_iface = nullptr; - - struct wifi_connect_req_params ap_config; - struct wifi_connect_req_params sta_config; + static struct WiFiState wifiState; // Static instance to hold Wi-Fi state - struct wifi_iface_status sta_state = {0}; +private: + static void scanEventDispatcher(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, + struct net_if *iface); + void handleScanEvent(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, + struct net_if *iface); }; -extern WiFiClass WiFi; +extern WiFiClass WiFi; // Global Wi-Fi object + +#endif // WIFI_H diff --git a/loader/llext_exports.c b/loader/llext_exports.c index 43aac03a..6f8980ac 100644 --- a/loader/llext_exports.c +++ b/loader/llext_exports.c @@ -115,6 +115,7 @@ FORCE_EXPORT_SYM(tls_credential_get); 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 2116455ef261773d612e7e3c22baa23a4fb60782 Mon Sep 17 00:00:00 2001 From: Bogdan Ivanus Date: Tue, 9 Dec 2025 10:46:15 +0200 Subject: [PATCH 2/2] WiFi: Addressed code review findings. --- libraries/SocketWrapper/SocketHelpers.cpp | 50 +++- libraries/SocketWrapper/SocketHelpers.h | 43 +-- libraries/WiFi/src/WiFi.cpp | 332 +++++++++++----------- libraries/WiFi/src/WiFi.h | 78 +++-- 4 files changed, 284 insertions(+), 219 deletions(-) diff --git a/libraries/SocketWrapper/SocketHelpers.cpp b/libraries/SocketWrapper/SocketHelpers.cpp index da15b3a3..dd090fd4 100644 --- a/libraries/SocketWrapper/SocketHelpers.cpp +++ b/libraries/SocketWrapper/SocketHelpers.cpp @@ -1,4 +1,5 @@ #include "SocketHelpers.h" +#include #include LOG_MODULE_DECLARE(sketch, LOG_LEVEL_NONE); @@ -8,14 +9,13 @@ struct net_dhcpv4_option_callback NetworkInterface::dhcp_cb; void NetworkInterface::event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface) { - int i = 0; - if (mgmt_event != NET_EVENT_IPV4_ADDR_ADD) { - return; - } + // 1. Handle DHCP events first (e.g., NET_EVENT_IPV4_ADDR_ADD) + if (mgmt_event & NET_EVENT_IPV4_ADDR_ADD) { - for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { - char buf[NET_IPV4_ADDR_LEN]; + int i = 0; + for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { + char buf[NET_IPV4_ADDR_LEN]; if (iface->config.ip.ipv4->unicast[i].ipv4.addr_type != NET_ADDR_DHCP) { continue; @@ -34,6 +34,24 @@ void NetworkInterface::event_handler(struct net_mgmt_event_callback *cb, uint64_ } } + // 2. Handle WiFi events + if (mgmt_event == NET_EVENT_WIFI_SCAN_RESULT) { + const struct wifi_scan_result *entry = reinterpret_cast(cb->info); + // Call the registered callback for scan result, if it's set + if (scanResultCallback) { + scanResultCallback(entry); + } + } else if (mgmt_event == NET_EVENT_WIFI_SCAN_DONE) { + // Call the registered callback for scan done, if it's set + if (scanDoneCallback) { + scanDoneCallback(); + } + } + + // 3. Handle [placeholder] events + // ... +} + void NetworkInterface::option_handler(struct net_dhcpv4_option_callback *cb, size_t length, enum net_dhcpv4_msg_type msg_type, struct net_if *iface) { char buf[NET_IPV4_ADDR_LEN]; @@ -58,6 +76,14 @@ int NetworkInterface::dhcp() { return 0; } +int NetworkInterface::wifi() { + net_mgmt_init_event_callback(&mgmt_cb, event_handler, + NET_EVENT_WIFI_SCAN_RESULT | NET_EVENT_WIFI_SCAN_DONE); + net_mgmt_add_event_callback(&mgmt_cb); + + return 0; +} + void NetworkInterface::enable_dhcpv4_server(struct net_if *netif, char *_netmask) { static struct in_addr addr; static struct in_addr netmaskAddr; @@ -191,3 +217,15 @@ void NetworkInterface::setGatewayIP(const IPAddress gateway) { void NetworkInterface::setDnsServerIP(const IPAddress dns_server) { return; // DNS server dynamic configuration is not supported } + +// Initialize static member variables +NetworkInterface::WiFiScanResultCallback NetworkInterface::scanResultCallback = nullptr; +NetworkInterface::WiFiScanDoneCallback NetworkInterface::scanDoneCallback = nullptr; + +void NetworkInterface::registerWiFiScanResultCallback(WiFiScanResultCallback callback) { + scanResultCallback = callback; +} + +void NetworkInterface::registerWiFiScanDoneCallback(WiFiScanDoneCallback callback) { + scanDoneCallback = callback; +} diff --git a/libraries/SocketWrapper/SocketHelpers.h b/libraries/SocketWrapper/SocketHelpers.h index 25210848..fd5b8bb7 100644 --- a/libraries/SocketWrapper/SocketHelpers.h +++ b/libraries/SocketWrapper/SocketHelpers.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -14,28 +15,14 @@ #include #include #include +#include #include + #define DHCP_OPTION_NTP (42) class NetworkInterface { -private: - uint8_t ntp_server[4]; - static struct net_mgmt_event_callback mgmt_cb; - static struct net_dhcpv4_option_callback dhcp_cb; - - static void event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, - struct net_if *iface); - - static void option_handler(struct net_dhcpv4_option_callback *cb, size_t length, - enum net_dhcpv4_msg_type msg_type, struct net_if *iface); - -protected: - struct net_if *netif = nullptr; - int dhcp(); - void enable_dhcpv4_server(struct net_if *netif, char *_netmask = "255.255.255.0"); - public: NetworkInterface() { } @@ -60,4 +47,28 @@ class NetworkInterface { int begin(bool blocking = true, uint32_t additional_event_mask = 0); bool disconnect(); + using WiFiScanResultCallback = std::function; + using WiFiScanDoneCallback = std::function; + + void registerWiFiScanResultCallback(WiFiScanResultCallback callback); + void registerWiFiScanDoneCallback(WiFiScanDoneCallback callback); +protected: + struct net_if *netif = nullptr; + int dhcp(); + int wifi(); + void enable_dhcpv4_server(struct net_if *netif, char *_netmask = "255.255.255.0"); +private: + uint8_t ntp_server[4]; + static struct net_mgmt_event_callback mgmt_cb; + static struct net_dhcpv4_option_callback dhcp_cb; + + + static void event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, + struct net_if *iface); + + static void option_handler(struct net_dhcpv4_option_callback *cb, size_t length, + enum net_dhcpv4_msg_type msg_type, struct net_if *iface); + + static WiFiScanResultCallback scanResultCallback; + static WiFiScanDoneCallback scanDoneCallback; }; diff --git a/libraries/WiFi/src/WiFi.cpp b/libraries/WiFi/src/WiFi.cpp index 96fe61de..732f6e40 100644 --- a/libraries/WiFi/src/WiFi.cpp +++ b/libraries/WiFi/src/WiFi.cpp @@ -1,217 +1,215 @@ #include "WiFi.h" -// Static Wi-Fi state instance -struct WiFiState { - struct net_if *sta_iface = nullptr; - struct net_if *ap_iface = nullptr; - struct wifi_connect_req_params ap_config; - 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 = 0; - struct net_mgmt_event_callback wifiCb; - bool soughtNetworkFound = false; - bool scanSequenceFinished = false; -}; +#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 | \ + NET_EVENT_WIFI_AP_STA_CONNECTED | NET_EVENT_WIFI_AP_STA_DISCONNECTED | \ + NET_EVENT_WIFI_SCAN_RESULT) WiFiClass::WiFiClass() { } -WiFiClass::~WiFiClass() { -} +int WiFiClass::begin(const char *ssid, const char *passphrase, wl_enc_type security, bool blocking) { + wifi_security_type wifi_security = convert_enc_type_to_security_type(security); -// Static instance of Wi-Fi state -struct WiFiState WiFiClass::wifiState; + wifiState.sta_iface = net_if_get_wifi_sta(); + netif = wifiState.sta_iface; + wifiState.sta_config.ssid = (const uint8_t *)ssid; + wifiState.sta_config.ssid_length = strlen(ssid); + wifiState.sta_config.psk = (const uint8_t *)passphrase; + wifiState.sta_config.psk_length = strlen(passphrase); -int WiFiClass::begin(const char *ssid, const char *passphrase, wl_enc_type security, - bool blocking) { - wifi_security_type wifi_security = convert_enc_type_to_security_type(security); + if (wifi_security != WIFI_SECURITY_TYPE_NONE) { + wifiState.sta_config.security = wifi_security; + } else { + wifiState.sta_config.security = WIFI_SECURITY_TYPE_PSK; + } - wifiState.sta_iface = net_if_get_wifi_sta(); - netif = wifiState.sta_iface; - wifiState.sta_config.ssid = (const uint8_t *)ssid; - wifiState.sta_config.ssid_length = strlen(ssid); - wifiState.sta_config.psk = (const uint8_t *)passphrase; - wifiState.sta_config.psk_length = strlen(passphrase); + wifiState.sta_config.channel = WIFI_CHANNEL_ANY; + wifiState.sta_config.band = WIFI_FREQ_BAND_2_4_GHZ; + wifiState.sta_config.bandwidth = WIFI_FREQ_BANDWIDTH_20MHZ; - // Set Wi-Fi security type if specified - if (wifi_security != WIFI_SECURITY_TYPE_NONE) { - wifiState.sta_config.security = wifi_security; - } else { - wifiState.sta_config.security = WIFI_SECURITY_TYPE_PSK; - } + registerWiFiScanResultCallback([this](const struct wifi_scan_result* result) { + handleScanResult(result); + }); - wifiState.sta_config.channel = WIFI_CHANNEL_ANY; - wifiState.sta_config.band = WIFI_FREQ_BAND_2_4_GHZ; - wifiState.sta_config.bandwidth = WIFI_FREQ_BANDWIDTH_20MHZ; - - // Register the Wi-Fi event callback - net_mgmt_init_event_callback(&wifiState.wifiCb, scanEventDispatcher, - NET_EVENT_WIFI_SCAN_RESULT | NET_EVENT_WIFI_SCAN_DONE); - net_mgmt_add_event_callback(&wifiState.wifiCb); - - // Trigger a network scan - (void)scanNetworks(); // Blocking call - - // Attempt to connect to the network if configuration is valid - if (wifiState.sta_config.ssid && wifiState.sta_config.psk) { - int ret = net_mgmt(NET_REQUEST_WIFI_CONNECT, wifiState.sta_iface, &wifiState.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(wifiState.sta_iface, NET_EVENT_WIFI_CONNECT_RESULT, NULL, - NULL, NULL, K_FOREVER); - } - } + registerWiFiScanDoneCallback([this]() { + handleScanDone(); + }); + + wifi(); - return status(); + scanNetworks(); + + if (isNetworkFound()) { + int ret = net_mgmt(NET_REQUEST_WIFI_CONNECT, wifiState.sta_iface, &wifiState.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(wifiState.sta_iface, NET_EVENT_WIFI_CONNECT_RESULT, NULL, NULL, NULL, K_FOREVER); + } + } + + return status(); } bool WiFiClass::beginAP(char *ssid, char *passphrase, int channel, bool blocking) { - if (wifiState.ap_iface != nullptr) { - return false; // AP already initialized - } + if (wifiState.ap_iface != nullptr) { + return false; + } + + wifiState.ap_iface = net_if_get_wifi_sap(); + netif = wifiState.ap_iface; + wifiState.ap_config.ssid = (const uint8_t *)ssid; + wifiState.ap_config.ssid_length = strlen(ssid); + wifiState.ap_config.psk = (const uint8_t *)passphrase; + wifiState.ap_config.psk_length = strlen(passphrase); + wifiState.ap_config.security = WIFI_SECURITY_TYPE_PSK; + wifiState.ap_config.channel = channel; + wifiState.ap_config.band = WIFI_FREQ_BAND_2_4_GHZ; + wifiState.ap_config.bandwidth = WIFI_FREQ_BANDWIDTH_20MHZ; + + int ret = net_mgmt(NET_REQUEST_WIFI_AP_ENABLE, wifiState.ap_iface, &wifiState.ap_config, sizeof(struct wifi_connect_req_params)); + if (ret) { + return false; + } + + enable_dhcpv4_server(wifiState.ap_iface); + + if (blocking) { + net_mgmt_event_wait_on_iface(wifiState.ap_iface, NET_EVENT_WIFI_AP_ENABLE_RESULT, NULL, NULL, NULL, K_FOREVER); + } + + return true; +} - wifiState.ap_iface = net_if_get_wifi_sap(); - netif = wifiState.ap_iface; - wifiState.ap_config.ssid = (const uint8_t *)ssid; - wifiState.ap_config.ssid_length = strlen(ssid); - wifiState.ap_config.psk = (const uint8_t *)passphrase; - wifiState.ap_config.psk_length = strlen(passphrase); - wifiState.ap_config.security = WIFI_SECURITY_TYPE_PSK; - wifiState.ap_config.channel = channel; - wifiState.ap_config.band = WIFI_FREQ_BAND_2_4_GHZ; - wifiState.ap_config.bandwidth = WIFI_FREQ_BANDWIDTH_20MHZ; - - int ret = net_mgmt(NET_REQUEST_WIFI_AP_ENABLE, wifiState.ap_iface, &wifiState.ap_config, - sizeof(struct wifi_connect_req_params)); - if (ret) { - return false; - } +void WiFiClass::handleScanResult(const struct wifi_scan_result *entry) { - enable_dhcpv4_server(wifiState.ap_iface); + printk("Scan result found SSID: %s, Security: %d, Channel: %d, Band: %d\n", + entry->ssid, entry->security, entry->channel, entry->band); - if (blocking) { - net_mgmt_event_wait_on_iface(wifiState.ap_iface, NET_EVENT_WIFI_AP_ENABLE_RESULT, NULL, - NULL, NULL, K_FOREVER); + if (wifiState.resultCount < MAX_SCAN_RESULTS) { + memcpy(&wifiState.scanResults[wifiState.resultCount], entry, + sizeof(struct wifi_scan_result)); + wifiState.resultCount++; } - return true; + if (!memcmp(entry->ssid, wifiState.sta_config.ssid, entry->ssid_length)) { + wifiState.sta_config.security = entry->security; + wifiState.sta_config.channel = entry->channel; + wifiState.sta_config.band = entry->band; + wifiState.sta_config.bandwidth = WIFI_FREQ_BANDWIDTH_20MHZ; + wifiState.networkFound = true; + + printk("Network found and matched SSID: %s\n", entry->ssid); + } else { + + printk("Network did not match SSID: %s\n", entry->ssid); + } + + printk("Scan result - Channel: %d, Band: %d, Security: %d\n", + entry->channel, entry->band, entry->security); } -int WiFiClass::status() { - wifiState.sta_iface = net_if_get_wifi_sta(); - netif = wifiState.sta_iface; - if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, netif, &wifiState.sta_state, - sizeof(struct wifi_iface_status))) { - return WL_NO_SHIELD; - } - if (wifiState.sta_state.state >= WIFI_STATE_ASSOCIATED) { - return WL_CONNECTED; - } else { - return WL_DISCONNECTED; - } +void WiFiClass::handleScanDone() { + wifiState.scanSequenceFinished = true; + if (wifiState.resultCount == 0) { + printk("No networks found.\n"); + } } -int8_t WiFiClass::scanNetworks() { - wifiState.resultCount = 0u; - wifiState.soughtNetworkFound = false; - wifiState.scanSequenceFinished = false; +void WiFiClass::triggerWiFiScan() { + printk("Trigger a new scan.\n\r"); + net_mgmt(NET_REQUEST_WIFI_SCAN, wifiState.sta_iface, nullptr, 0u); +} - // Trigger a new scan - net_mgmt(NET_REQUEST_WIFI_SCAN, wifiState.sta_iface, nullptr, 0u); +bool WiFiClass::isScanFinished() const { + return wifiState.scanSequenceFinished; +} - // Wait for the scan to finish (this is a blocking call) - while (!wifiState.scanSequenceFinished) - ; +bool WiFiClass::isNetworkFound() const { + return wifiState.networkFound; +} - return wifiState.resultCount; +int WiFiClass::getScanResultCount() const { + return wifiState.resultCount; } -void WiFiClass::scanEventDispatcher(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, - struct net_if *iface) { - // Use the global Wi-Fi state instance to handle the event - if (wifiState.sta_iface != nullptr) { - WiFi.handleScanEvent(cb, mgmt_event, iface); - } +const struct wifi_scan_result* WiFiClass::getScanResults() const { + return wifiState.scanResults; } -void WiFiClass::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 (wifiState.resultCount < MAX_SCAN_RESULTS) { - memcpy(&wifiState.scanResults[wifiState.resultCount], entry, - sizeof(struct wifi_scan_result)); - wifiState.resultCount++; - - // Compare SSID of the scanned network with the desired network SSID - if (!memcmp(entry->ssid, wifiState.sta_config.ssid, entry->ssid_length)) { - wifiState.sta_config.security = entry->security; - wifiState.sta_config.channel = entry->channel; - wifiState.sta_config.band = entry->band; - wifiState.sta_config.bandwidth = WIFI_FREQ_BANDWIDTH_20MHZ; - - wifiState.soughtNetworkFound = true; - } - } - } +int WiFiClass::status() { + wifiState.sta_iface = net_if_get_wifi_sta(); + netif = wifiState.sta_iface; + if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, netif, &wifiState.sta_state, sizeof(struct wifi_iface_status))) { + return WL_NO_SHIELD; + } + if (wifiState.sta_state.state >= WIFI_STATE_ASSOCIATED) { + return WL_CONNECTED; + } else { + return WL_DISCONNECTED; + } +} - if (mgmt_event == NET_EVENT_WIFI_SCAN_DONE) { - wifiState.scanSequenceFinished = true; +int8_t WiFiClass::scanNetworks(int timeout_ms) { + triggerWiFiScan(); - if (wifiState.resultCount == 0) { - printk("No networks found.\n"); - } - } + uint32_t start_time = k_uptime_get(); + + while (!isScanFinished() && !isNetworkFound()) { + if (k_uptime_get() - start_time >= timeout_ms) { + printk("Wi-Fi scan timed out.\n"); + break; + } + } + + return getScanResultCount(); } -char *WiFiClass::SSID() { - if (status() == WL_CONNECTED) { - return (char *)wifiState.sta_state.ssid; - } - return nullptr; +char* WiFiClass::SSID() { + if (status() == WL_CONNECTED) { + return (char *)wifiState.sta_state.ssid; + } + return nullptr; } int32_t WiFiClass::RSSI() { - if (status() == WL_CONNECTED) { - return wifiState.sta_state.rssi; - } - return 0; + if (status() == WL_CONNECTED) { + return wifiState.sta_state.rssi; + } + return 0; } String WiFiClass::firmwareVersion() { #if defined(ARDUINO_PORTENTA_C33) - return "v1.5.0"; + return "v1.5.0"; #else - return "v0.0.0"; + return "v0.0.0"; #endif } wifi_security_type WiFiClass::convert_enc_type_to_security_type(wl_enc_type enc_type) { - switch (enc_type) { - case ENC_TYPE_WEP: - return WIFI_SECURITY_TYPE_WEP; - case ENC_TYPE_WPA: - return WIFI_SECURITY_TYPE_WPA_PSK; // Could also map to WPA_AUTO_PERSONAL - case ENC_TYPE_WPA2: - return WIFI_SECURITY_TYPE_PSK; // Could also map to WPA_AUTO_PERSONAL - case ENC_TYPE_WPA3: - return WIFI_SECURITY_TYPE_SAE; // Could also map to SAE_AUTO - case ENC_TYPE_NONE: - return WIFI_SECURITY_TYPE_NONE; - case ENC_TYPE_UNKNOWN: - case ENC_TYPE_AUTO: - return WIFI_SECURITY_TYPE_UNKNOWN; - default: - return WIFI_SECURITY_TYPE_UNKNOWN; // Default case for any undefined or unexpected values - } + switch (enc_type) { + case ENC_TYPE_WEP: + return WIFI_SECURITY_TYPE_WEP; + case ENC_TYPE_WPA: + return WIFI_SECURITY_TYPE_WPA_PSK; // Could also map to WPA_AUTO_PERSONAL + case ENC_TYPE_WPA2: + return WIFI_SECURITY_TYPE_PSK; // Could also map to WPA_AUTO_PERSONAL + case ENC_TYPE_WPA3: + return WIFI_SECURITY_TYPE_SAE; // Could also map to SAE_AUTO + case ENC_TYPE_NONE: + return WIFI_SECURITY_TYPE_NONE; + case ENC_TYPE_UNKNOWN: + case ENC_TYPE_AUTO: + return WIFI_SECURITY_TYPE_UNKNOWN; + default: + return WIFI_SECURITY_TYPE_UNKNOWN; // Default case for any undefined or unexpected values + } } -// Global Wi-Fi object, uses the static wifiState struct WiFiClass WiFi; diff --git a/libraries/WiFi/src/WiFi.h b/libraries/WiFi/src/WiFi.h index 243da05c..a2b6dda1 100644 --- a/libraries/WiFi/src/WiFi.h +++ b/libraries/WiFi/src/WiFi.h @@ -1,47 +1,65 @@ -#ifndef WIFI_H -#define WIFI_H +#pragma once #include "SocketHelpers.h" #include "utility/wl_definitions.h" #include -// Max number of scan results to store -#define MAX_SCAN_RESULTS 20 +#define MAX_SCAN_RESULTS 20u -// Wi-Fi event mask for the various events -#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 | \ - NET_EVENT_WIFI_AP_STA_CONNECTED | NET_EVENT_WIFI_AP_STA_DISCONNECTED | \ - NET_EVENT_WIFI_SCAN_RESULT) +struct WiFiState { + struct net_if *sta_iface = nullptr; + struct net_if *ap_iface = nullptr; + struct wifi_connect_req_params ap_config; + 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 = 0u; + bool networkFound = false; + bool scanSequenceFinished = false; +}; class WiFiClass : public NetworkInterface { public: - WiFiClass(); - ~WiFiClass(); + WiFiClass(); + ~WiFiClass() = default; + + int begin(const char *ssid, const char *passphrase, wl_enc_type security = ENC_TYPE_WPA, + bool blocking = true); + + bool beginAP(char *ssid, char *passphrase, int channel = WIFI_CHANNEL_ANY, + bool blocking = false); + + void handleScanResult(const struct wifi_scan_result *entry); + + void handleScanDone(); + + void triggerWiFiScan(); + + bool isScanFinished() const; - int begin(const char *ssid, const char *passphrase, wl_enc_type security = ENC_TYPE_WPA, - bool blocking = true); + bool isNetworkFound() const; - bool beginAP(char *ssid, char *passphrase, int channel = WIFI_CHANNEL_ANY, - bool blocking = false); + int getScanResultCount() const; - int status(); - int8_t scanNetworks(); - char *SSID(); - int32_t RSSI(); - String firmwareVersion(); - wifi_security_type convert_enc_type_to_security_type(wl_enc_type enc_type); + const struct wifi_scan_result* getScanResults() const; - static struct WiFiState wifiState; // Static instance to hold Wi-Fi state + int status(); + + int8_t scanNetworks(int timeout_ms = 10000); + + char* SSID(); + + int32_t RSSI(); + + String firmwareVersion(); + + wifi_security_type convert_enc_type_to_security_type(wl_enc_type enc_type); private: - static void scanEventDispatcher(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, - struct net_if *iface); - void handleScanEvent(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, - struct net_if *iface); -}; + void handleScanEvent(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, + struct net_if *iface); -extern WiFiClass WiFi; // Global Wi-Fi object + struct WiFiState wifiState; +}; -#endif // WIFI_H +extern WiFiClass WiFi;