-
-
Notifications
You must be signed in to change notification settings - Fork 41
WiFi: add scan() #221
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
WiFi: add scan() #221
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -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); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does his operation remove the |
||||||
|
|
||||||
| // 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); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can pass a pointer to this class to the handler in order to avoid having a static wifiState defined.
Suggested change
|
||||||
|
|
||||||
| // Wait for the scan to finish (this is a blocking call) | ||||||
| while (!wifiState.scanSequenceFinished) | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does it make sense to add a timeout here? if somthing strange happens underneath we may be stuck here |
||||||
| ; | ||||||
|
|
||||||
| 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, | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||
| struct net_if *iface) { | ||||||
| if (mgmt_event == NET_EVENT_WIFI_SCAN_RESULT) { | ||||||
| const struct wifi_scan_result *entry = | ||||||
| reinterpret_cast<const struct wifi_scan_result *>(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; | ||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,8 +1,14 @@ | ||||||
| #include "SocketHelpers.h" | ||||||
| #ifndef WIFI_H | ||||||
| #define WIFI_H | ||||||
|
|
||||||
| #include "SocketHelpers.h" | ||||||
| #include "utility/wl_definitions.h" | ||||||
| #include <zephyr/net/wifi_mgmt.h> | ||||||
|
|
||||||
| // 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(); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the destructor is empty we can write it in this way
Suggested change
|
||||||
|
|
||||||
| ~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 | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this shouldn't be static |
||||||
|
|
||||||
| struct wifi_iface_status sta_state = {0}; | ||||||
| private: | ||||||
| static void scanEventDispatcher(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can define this function in the cpp file only |
||||||
| 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 | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems to be a convoluted name, what do you think about
networkFound?