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/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..732f6e40 100644 --- a/libraries/WiFi/src/WiFi.cpp +++ b/libraries/WiFi/src/WiFi.cpp @@ -1,99 +1,215 @@ #include "WiFi.h" -WiFiClass WiFi; +#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) -String WiFiClass::firmwareVersion() { -#if defined(ARDUINO_PORTENTA_C33) - return "v1.5.0"; -#else - return "v0.0.0"; -#endif +WiFiClass::WiFiClass() { } -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; - } +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); - 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); - } - NetworkInterface::begin(blocking, NET_EVENT_WIFI_MASK); - return status(); + 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); + + 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; + + registerWiFiScanResultCallback([this](const struct wifi_scan_result* result) { + handleScanResult(result); + }); + + registerWiFiScanDoneCallback([this]() { + handleScanDone(); + }); + + wifi(); + + 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 (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); + 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; +} + +void WiFiClass::handleScanResult(const struct wifi_scan_result *entry) { + + printk("Scan result found SSID: %s, Security: %d, Channel: %d, Band: %d\n", + entry->ssid, entry->security, entry->channel, entry->band); + + 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); +} + +void WiFiClass::handleScanDone() { + wifiState.scanSequenceFinished = true; + if (wifiState.resultCount == 0) { + printk("No networks found.\n"); + } +} + +void WiFiClass::triggerWiFiScan() { + printk("Trigger a new scan.\n\r"); + net_mgmt(NET_REQUEST_WIFI_SCAN, wifiState.sta_iface, nullptr, 0u); +} + +bool WiFiClass::isScanFinished() const { + return wifiState.scanSequenceFinished; +} + +bool WiFiClass::isNetworkFound() const { + return wifiState.networkFound; +} + +int WiFiClass::getScanResultCount() const { + return wifiState.resultCount; +} + +const struct wifi_scan_result* WiFiClass::getScanResults() const { + return wifiState.scanResults; } 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 +int8_t WiFiClass::scanNetworks(int timeout_ms) { + triggerWiFiScan(); + + 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 *)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 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 + } +} + +WiFiClass WiFi; diff --git a/libraries/WiFi/src/WiFi.h b/libraries/WiFi/src/WiFi.h index 739b5bb3..a2b6dda1 100644 --- a/libraries/WiFi/src/WiFi.h +++ b/libraries/WiFi/src/WiFi.h @@ -1,44 +1,65 @@ -#include "SocketHelpers.h" +#pragma once +#include "SocketHelpers.h" #include "utility/wl_definitions.h" #include -#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) +#define MAX_SCAN_RESULTS 20u + +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() = default; - ~WiFiClass() { - } + int begin(const char *ssid, const char *passphrase, wl_enc_type security = ENC_TYPE_WPA, + bool blocking = true); - 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); + bool beginAP(char *ssid, char *passphrase, int channel = WIFI_CHANNEL_ANY, + bool blocking = false); - int status(); + void handleScanResult(const struct wifi_scan_result *entry); - int8_t scanNetworks(); + void handleScanDone(); - char *SSID(); - int32_t RSSI(); + void triggerWiFiScan(); - String firmwareVersion(); + bool isScanFinished() const; -private: - struct net_if *sta_iface = nullptr; - struct net_if *ap_iface = nullptr; + bool isNetworkFound() const; - struct wifi_connect_req_params ap_config; - struct wifi_connect_req_params sta_config; + int getScanResultCount() const; - struct wifi_iface_status sta_state = {0}; + const struct wifi_scan_result* getScanResults() const; + + 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: + void handleScanEvent(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, + struct net_if *iface); + + struct WiFiState wifiState; }; extern WiFiClass WiFi; 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