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 5a6d2912..f8696d33 100644 --- a/libraries/WiFi/src/WiFi.cpp +++ b/libraries/WiFi/src/WiFi.cpp @@ -1,97 +1,210 @@ #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) { + 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; + } + + 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; -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; - } - 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(); + // 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); + } + } + + return status(); } bool WiFiClass::beginAP(char *ssid, char *passphrase, int channel, bool blocking) { - if (ap_iface != NULL) { - return false; - } - 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, - sizeof(struct wifi_connect_req_params)); - if (ret) { - return false; - } - enable_dhcpv4_server(ap_iface); - if (blocking) { - net_mgmt_event_wait_on_iface(ap_iface, NET_EVENT_WIFI_AP_ENABLE_RESULT, NULL, NULL, NULL, - K_FOREVER); - } - return true; + if (wifiState.ap_iface != nullptr) { + return false; // AP already initialized + } + + 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; } int WiFiClass::status() { - sta_iface = net_if_get_wifi_sta(); - netif = sta_iface; - if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, netif, &sta_state, - sizeof(struct wifi_iface_status))) { - return WL_NO_SHIELD; - } - if (sta_state.state >= WIFI_STATE_ASSOCIATED) { - return WL_CONNECTED; - } else { - return WL_DISCONNECTED; - } - return WL_NO_SHIELD; + 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; + } } 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 nullptr; + if (status() == WL_CONNECTED) { + return (char *)wifiState.sta_state.ssid; + } + return nullptr; } int32_t WiFiClass::RSSI() { - if (status() == WL_CONNECTED) { - return 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"; +#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..01df0343 100644 --- a/libraries/WiFi/src/WiFi.h +++ b/libraries/WiFi/src/WiFi.h @@ -1,44 +1,47 @@ -#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 | \ - NET_EVENT_WIFI_AP_STA_CONNECTED | NET_EVENT_WIFI_AP_STA_DISCONNECTED | \ - NET_EVENT_WIFI_SCAN_RESULT) + (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) class WiFiClass : public NetworkInterface { public: - WiFiClass() { - } - - ~WiFiClass() { - } + WiFiClass(); + ~WiFiClass(); - int begin(const char *ssid, const char *passphrase, wl_enc_type security = ENC_TYPE_UNKNOWN, - bool blocking = true); - bool beginAP(char *ssid, char *passphrase, int channel = WIFI_CHANNEL_ANY, - bool blocking = false); + int begin(const char *ssid, const char *passphrase, + wl_enc_type security = ENC_TYPE_WPA, bool blocking = true); - int status(); + bool beginAP(char *ssid, char *passphrase, int channel = WIFI_CHANNEL_ANY, + bool blocking = false); - int8_t scanNetworks(); + 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); - char *SSID(); - int32_t RSSI(); - - String firmwareVersion(); + static struct WiFiState wifiState; // Static instance to hold Wi-Fi state 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; - - struct wifi_iface_status sta_state = {0}; + 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 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