diff --git a/cores/arduino/SerialUSB.h b/cores/arduino/SerialUSB.h index 442d28d0..be1377f8 100644 --- a/cores/arduino/SerialUSB.h +++ b/cores/arduino/SerialUSB.h @@ -19,6 +19,7 @@ class SerialUSB_ : public ZephyrSerial { operator bool() override; size_t write(const uint8_t *buffer, size_t size) override; + size_t write(const uint8_t data) override { return write(&data, 1); } void flush() override; protected: diff --git a/libraries/SocketWrapper/WiFi.cpp b/libraries/SocketWrapper/WiFi.cpp index 4290fe2e..882babfe 100644 --- a/libraries/SocketWrapper/WiFi.cpp +++ b/libraries/SocketWrapper/WiFi.cpp @@ -1,3 +1,5 @@ #include "WiFi.h" WiFiClass WiFi; + +WiFiClass* WiFiClass::instance = nullptr; \ No newline at end of file diff --git a/libraries/SocketWrapper/WiFi.h b/libraries/SocketWrapper/WiFi.h index c83846b2..fe64a3fa 100644 --- a/libraries/SocketWrapper/WiFi.h +++ b/libraries/SocketWrapper/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 | \ @@ -16,31 +19,37 @@ class WiFiClass: public NetworkInterface WiFiClass() {} ~WiFiClass() {} - bool begin(const char* ssid, const char* passphrase, wl_enc_type security = ENC_TYPE_UNKNOWN, bool blocking = false) { + int begin(const char* ssid, const char* passphrase, wl_enc_type security = ENC_TYPE_UNKNOWN, bool blocking = true) { 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; - } + // Register the Wi-Fi event callback + net_mgmt_init_event_callback(&wifiCb, scanEventDispatcher, NET_EVENT_WIFI_SCAN_RESULT | NET_EVENT_WIFI_SCAN_DONE); - NetworkInterface::begin(false, NET_EVENT_WIFI_MASK); - if (blocking) { - net_mgmt_event_wait_on_iface(sta_iface, NET_EVENT_WIFI_AP_STA_CONNECTED, NULL, NULL, NULL, K_FOREVER); - } + net_mgmt_add_event_callback(&wifiCb); - return true; + (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(); } bool beginAP(char* ssid, char* passphrase, int channel = WIFI_CHANNEL_ANY, bool blocking = false) { @@ -75,14 +84,14 @@ class WiFiClass: public NetworkInterface } int status() { - struct wifi_iface_status status = { 0 }; - - if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, netif, &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 (status.state >= WIFI_STATE_ASSOCIATED) { + if (sta_state.state >= WIFI_STATE_ASSOCIATED) { return WL_CONNECTED; } else { return WL_DISCONNECTED; @@ -90,16 +99,109 @@ class WiFiClass: public NetworkInterface return WL_NO_SHIELD; } - int8_t scanNetworks() { - // TODO: borrow code from mbed core for scan results handling + uint8_t scanNetworks() { + 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* SSID() { + if (status() == WL_CONNECTED) { + return (char *)sta_state.ssid; + } + return nullptr; + } + + int32_t RSSI() { + if (status() == WL_CONNECTED) { + return sta_state.rssi; + } + return 0; + } + + 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; 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; + struct net_mgmt_event_callback wifiCb; + + bool soughtNetworkFound = false; + bool scanSequenceFinished = false; }; extern WiFiClass WiFi; diff --git a/libraries/SocketWrapper/examples/WiFiWebClient/WiFiWebClient.ino b/libraries/SocketWrapper/examples/WiFiWebClient/WiFiWebClient.ino new file mode 100644 index 00000000..a5687041 --- /dev/null +++ b/libraries/SocketWrapper/examples/WiFiWebClient/WiFiWebClient.ino @@ -0,0 +1,106 @@ +/* + Web client + + This sketch connects to a website (http://example.com) using the WiFi module. + + This example is written for a network using WPA encryption. For + WEP or WPA, change the Wifi.begin() call accordingly. + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + */ + +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key Index number (needed only for WEP) + +int status = WL_IDLE_STATUS; +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +// IPAddress server(93,184,216,34); // IP address for example.com (no DNS) +char server[] = "example.com"; // host name for example.com (using DNS) + +ZephyrClient client; + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the WiFi module: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + // attempt to connect to Wifi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + Serial.println(status); + // wait 3 seconds for connection: + delay(3000); + } + Serial.println("Connected to wifi"); + printWifiStatus(); + + Serial.println("\nStarting connection to server..."); + // if you get a connection, report back via serial: + if (client.connect(server, 80)) { + Serial.println("connected to server"); + // Make a HTTP request: + client.println("GET /index.html HTTP/1.1"); + client.print("Host: "); + client.println(server); + client.println("Connection: close"); + client.println(); + } +} + +void loop() { + // if there are incoming bytes available + // from the server, read them and print them: + while (client.available()) { + char c = client.read(); + Serial.write(c); + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + Serial.println(); + Serial.println("disconnecting from server."); + client.stop(); + + // do nothing forevermore: + while (true); + } +} + +void printWifiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/libraries/SocketWrapper/examples/WiFiWebClient/arduino_secrets.h b/libraries/SocketWrapper/examples/WiFiWebClient/arduino_secrets.h new file mode 100644 index 00000000..0c9fdd55 --- /dev/null +++ b/libraries/SocketWrapper/examples/WiFiWebClient/arduino_secrets.h @@ -0,0 +1,2 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" diff --git a/loader/llext_exports.c b/loader/llext_exports.c index f1370a92..82cec3aa 100644 --- a/loader/llext_exports.c +++ b/loader/llext_exports.c @@ -106,6 +106,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