From 2a96333aefe9e9cea24e7cd995602e74b48c0d66 Mon Sep 17 00:00:00 2001 From: randogoth Date: Sun, 25 Oct 2026 16:13:41 +0200 Subject: [PATCH] feat: add WiFi access point with HTTP API and patched WiFiNINA --- README.md | 14 +- arduino/libraries/WiFiNINA/CHANGELOG | 62 + arduino/libraries/WiFiNINA/README.adoc | 34 + arduino/libraries/WiFiNINA/STRIX.md | 3 + arduino/libraries/WiFiNINA/keywords.txt | 65 + arduino/libraries/WiFiNINA/library.properties | 10 + arduino/libraries/WiFiNINA/src/WiFi.cpp | 385 +++++ arduino/libraries/WiFiNINA/src/WiFi.h | 281 ++++ arduino/libraries/WiFiNINA/src/WiFiClient.cpp | 362 +++++ arduino/libraries/WiFiNINA/src/WiFiClient.h | 69 + arduino/libraries/WiFiNINA/src/WiFiNINA.h | 25 + .../libraries/WiFiNINA/src/WiFiSSLClient.cpp | 60 + .../libraries/WiFiNINA/src/WiFiSSLClient.h | 45 + arduino/libraries/WiFiNINA/src/WiFiServer.cpp | 119 ++ arduino/libraries/WiFiNINA/src/WiFiServer.h | 49 + .../libraries/WiFiNINA/src/WiFiStorage.cpp | 30 + arduino/libraries/WiFiNINA/src/WiFiStorage.h | 151 ++ arduino/libraries/WiFiNINA/src/WiFiUdp.cpp | 217 +++ arduino/libraries/WiFiNINA/src/WiFiUdp.h | 83 ++ .../WiFiNINA/src/utility/WiFiSocketBuffer.cpp | 104 ++ .../WiFiNINA/src/utility/WiFiSocketBuffer.h | 52 + .../libraries/WiFiNINA/src/utility/debug.h | 95 ++ .../WiFiNINA/src/utility/server_drv.cpp | 520 +++++++ .../WiFiNINA/src/utility/server_drv.h | 69 + .../WiFiNINA/src/utility/spi_drv.cpp | 584 ++++++++ .../libraries/WiFiNINA/src/utility/spi_drv.h | 109 ++ .../WiFiNINA/src/utility/wifi_drv.cpp | 1262 +++++++++++++++++ .../libraries/WiFiNINA/src/utility/wifi_drv.h | 326 +++++ .../libraries/WiFiNINA/src/utility/wifi_spi.h | 203 +++ .../WiFiNINA/src/utility/wl_definitions.h | 77 + .../libraries/WiFiNINA/src/utility/wl_types.h | 57 + arduino/strix/API.md | 29 +- arduino/strix/strix.ino | 459 ++++-- devbox.json | 3 +- 34 files changed, 5867 insertions(+), 146 deletions(-) create mode 100644 arduino/libraries/WiFiNINA/CHANGELOG create mode 100644 arduino/libraries/WiFiNINA/README.adoc create mode 100644 arduino/libraries/WiFiNINA/STRIX.md create mode 100644 arduino/libraries/WiFiNINA/keywords.txt create mode 100644 arduino/libraries/WiFiNINA/library.properties create mode 100644 arduino/libraries/WiFiNINA/src/WiFi.cpp create mode 100644 arduino/libraries/WiFiNINA/src/WiFi.h create mode 100644 arduino/libraries/WiFiNINA/src/WiFiClient.cpp create mode 100644 arduino/libraries/WiFiNINA/src/WiFiClient.h create mode 100644 arduino/libraries/WiFiNINA/src/WiFiNINA.h create mode 100644 arduino/libraries/WiFiNINA/src/WiFiSSLClient.cpp create mode 100644 arduino/libraries/WiFiNINA/src/WiFiSSLClient.h create mode 100644 arduino/libraries/WiFiNINA/src/WiFiServer.cpp create mode 100644 arduino/libraries/WiFiNINA/src/WiFiServer.h create mode 100644 arduino/libraries/WiFiNINA/src/WiFiStorage.cpp create mode 100644 arduino/libraries/WiFiNINA/src/WiFiStorage.h create mode 100644 arduino/libraries/WiFiNINA/src/WiFiUdp.cpp create mode 100644 arduino/libraries/WiFiNINA/src/WiFiUdp.h create mode 100644 arduino/libraries/WiFiNINA/src/utility/WiFiSocketBuffer.cpp create mode 100644 arduino/libraries/WiFiNINA/src/utility/WiFiSocketBuffer.h create mode 100644 arduino/libraries/WiFiNINA/src/utility/debug.h create mode 100644 arduino/libraries/WiFiNINA/src/utility/server_drv.cpp create mode 100644 arduino/libraries/WiFiNINA/src/utility/server_drv.h create mode 100644 arduino/libraries/WiFiNINA/src/utility/spi_drv.cpp create mode 100644 arduino/libraries/WiFiNINA/src/utility/spi_drv.h create mode 100644 arduino/libraries/WiFiNINA/src/utility/wifi_drv.cpp create mode 100644 arduino/libraries/WiFiNINA/src/utility/wifi_drv.h create mode 100644 arduino/libraries/WiFiNINA/src/utility/wifi_spi.h create mode 100644 arduino/libraries/WiFiNINA/src/utility/wl_definitions.h create mode 100644 arduino/libraries/WiFiNINA/src/utility/wl_types.h diff --git a/README.md b/README.md index e8f1339..e84e635 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A portable wireless True Random Number Generator built on an Arduino MKR Vidor 4 ## Design -Entropy comes from FPGA ring oscillators whose sampled timing jitter is XOR-combined into output bits, with no pseudo-random post-processing. A SAMD21 serves the results over USB (WiFi is planned). +Entropy comes from FPGA ring oscillators whose sampled timing jitter is XOR-combined into output bits, with no pseudo-random post-processing. A SAMD21 serves the results over USB, and over HTTP on its own WiFi access point when running without a computer (stationary mode on a charger). - 4 independent generators × 90 ring oscillators. Each generator XORs its rings every 120 MHz clock (spatial) and then several consecutive bits (temporal, default 5): about 24 Mbps per generator. - Separate stream per generator, plus a combined stream of all healthy generators @@ -15,33 +15,33 @@ Entropy comes from FPGA ring oscillators whose sampled timing jitter is XOR-comb - Von Neumann extractor that can be toggled on the stream, statistics and amplifier paths - Raw ring captures and frequency measurement for characterization -The USB protocol is documented in [arduino/strix/API.md](arduino/strix/API.md). +The USB and HTTP API is documented in [arduino/strix/API.md](arduino/strix/API.md). ## Layout - `fpga/rtl/`: Verilog sources; `fpga/sim/`: testbenches; `fpga/src/`: Quartus project - `arduino/strix/`: device firmware - `arduino/strix_capture/`: characterization tool firmware, used by `tools/jitter.py` -- `arduino/libraries/`: `StrixFPGA` (FPGA boot, SPI access, embedded FPGA image) and `VidorBoot` (vendored subset of Arduino's VidorPeripherals) +- `arduino/libraries/`: `StrixFPGA` (FPGA boot, SPI access, embedded FPGA image), `VidorBoot` (vendored subset of Arduino's VidorPeripherals) and `WiFiNINA` (Arduino's library, patched to drive the WiFi module through the FPGA's pin pass-through) - `tools/`: FPGA image converter, jitter and statistics experiments, API check ## Development (Linux) The toolchain is managed by [devbox](https://www.jetify.com/devbox): `arduino-cli`, Intel Quartus Prime Lite (Cyclone 10 LP only, through a Nix flake in `nix/`), Icarus Verilog, Python and Rust. -1. `devbox run setup`: install the Arduino SAMD core and libraries +1. `devbox run setup`: install the Arduino SAMD core (libraries are vendored in `arduino/libraries/`) 2. `devbox run sim`: run the FPGA testbenches 3. `devbox run fpga`: build the FPGA bitstream (about 10 minutes) 4. `devbox run image`: embed the bitstream in the `StrixFPGA` library 5. `devbox run build`, then `devbox run upload`: build and flash the firmware (`PORT` defaults to `/dev/ttyACM0`) 6. `devbox run api-check`: end-to-end check of the USB API -Serial access requires membership in the `dialout` group. For characterization, flash the capture tool with `devbox run upload-capture` and use `devbox run jitter `. `devbox run onod-build` builds the onod3000 test suite used by `jitter output` and `api-check`. +Serial access requires membership in the `dialout` group. If a firmware leaves the board unable to stay on USB, enter the bootloader: hold reset while plugging in, release, then tap reset once quickly. For characterization, flash the capture tool with `devbox run upload-capture` and use `devbox run jitter `. `devbox run onod-build` builds the onod3000 test suite used by `jitter output` and `api-check`. ## TODO -- Serve randomness over WiFi (NINA pass-through in the FPGA is wired, firmware not yet) -- Make Vidor pairable via Bluetooth +- Bluetooth LE for mobile mode (needs a newer WiFi module firmware than the installed 1.0.0) +- WiFi credentials stored on the device instead of compile-time defaults - Battery pack - 3D case diff --git a/arduino/libraries/WiFiNINA/CHANGELOG b/arduino/libraries/WiFiNINA/CHANGELOG new file mode 100644 index 0000000..ad6e784 --- /dev/null +++ b/arduino/libraries/WiFiNINA/CHANGELOG @@ -0,0 +1,62 @@ +WiFiNINA ?.?.? - ????.??.?? + +WiFiNINA 1.8.0 - 2020.11.18 + +* Limit the maximum length of the download URL for the OTA binary since the receive buffer on the nina firmware can't hold more than 128 bytes (#131) +* Introduce WiFiBearSSLClient (offloaded to Nina) (#139) +* Change WIFI_FIRMWARE_LATEST_VERSION to 1.4.2 + +WiFiNINA 1.7.1 - 2020.08.26 + +* Change WIFI_FIRMWARE_LATEST_VERSION to 1.4.1 + +WiFiNINA 1.7.0 - 2020.08.06 + +* Add downloadOTA command to download OTA file and verify length/CRC (#124) (to be used together with nina-fw > arduino/nina-fw@d4a2118) + +WiFiNINA 1.6.0 - 2020.07.13 + +* Adding API to make use of file storage/retieval capability available since nina-fw 1.5.0 (#74) +* Speed up of duration of function ServerDrv::getDataBuf (#84) + +WiFiNINA 1.5.0 - 2019.12.30 + +* Add WiFi.reasonCode() API to retrieve the deauthentication reason code +* Use WIFI_FIRMWARE_LATEST_VERSION in example sketch FW version checks +* Updated firmware updaters for Nano 33 IoT +* Added Nano 33 IoT to explicit targets list +* Added WPA2 Enterprise support: PEAP/MSCHAPv2 (depends on NINA f/w 1.3.0) + +WiFiNINA 1.4.0 - 2019.03.27 + +* Improved connection time, by increasing poll time of checking connection status to 100ms on begin +* Added WiFiClass::setTimeout(...) API to set timeout of begin +* Fixed issue of WiFiServer:available() only reporting the first byte in the WiFiChatServer example + +WiFiNINA 1.3.0 - 2018.11.13 + +* Added Tools/CheckFirmwareVersion example to check NINA firmware version +* Changed examples where required, the server's URL arduino.cc:80 to example.org:80, because http://arduino.cc will be no longer available +* Changed WiFi.end() to not put the reset pin mode in input mode +* Use 1000000 baud for the firmware updater, and added support for the Uno WiFi Rev2 + +WiFiNINA 1.2.0 - 2018.10.05 + +* Changed WiFi.begin(...) not to fail, if not connected in 5 seconds +* Removed retrying to get the host by name if it fails +* Renamed WiFiNINAFirmwareUpdater example to SerialNINAPassthrough +* Added new Firmware Updater Tool sketch (which talks to ESP32 boot ROM) +* Changed firmware version comparison check to < instead of != + +WiFiNINA 1.1.1 - 2018.09.11 + +* Improved byte by byte read performance of sockets by adding a socket buffer + +WiFiNINA 1.1.0 - 2018.08.13 + +* Added support for MKR Vidor 4000 +* Added handling of unknown encryption type in the ScanNetworks example + +WiFiNINA 1.0.0 - 2018.07.11 + +* Initial release diff --git a/arduino/libraries/WiFiNINA/README.adoc b/arduino/libraries/WiFiNINA/README.adoc new file mode 100644 index 0000000..783984f --- /dev/null +++ b/arduino/libraries/WiFiNINA/README.adoc @@ -0,0 +1,34 @@ +// Define the repository information in these attributes +:repository-owner: arduino-libraries +:repository-name: WiFiNINA + += {repository-name} library for Arduino = + +image:https://github.com/{repository-owner}/{repository-name}/workflows/Compile%20Examples/badge.svg["Compile Examples Status", link="https://github.com/{repository-owner}/{repository-name}/actions?workflow=Compile+Examples"] +image:https://github.com/{repository-owner}/{repository-name}/workflows/Spell%20Check/badge.svg["Spell Check Status", link="https://github.com/{repository-owner}/{repository-name}/actions?workflow=Spell+Check"] + +Enables network connection (local and Internet) with the Arduino MKR WiFi 1010, Arduino MKR VIDOR 4000 and Arduino UNO WiFi Rev.2. + +With this library you can instantiate Servers, Clients and send/receive UDP packets through WiFi. The board can connect either to open or encrypted networks (WEP, WPA). The IP address can be assigned statically or through a DHCP. The library can also manage DNS. + +For more information about this library please visit us at +https://www.arduino.cc/en/Reference/{repository-name} + +== License == + +Copyright (c) 2018 Arduino SA. All rights reserved. +Copyright (c) 2011-2014 Arduino LLC. All right reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/arduino/libraries/WiFiNINA/STRIX.md b/arduino/libraries/WiFiNINA/STRIX.md new file mode 100644 index 0000000..93edc94 --- /dev/null +++ b/arduino/libraries/WiFiNINA/STRIX.md @@ -0,0 +1,3 @@ +# WiFiNINA for STRIX + +Arduino's [WiFiNINA](https://github.com/arduino-libraries/WiFiNINA) 1.8.5 (GNU LGPL 2.1 or later, see the source headers), vendored with one change in `src/utility/spi_drv.cpp`: on the MKR Vidor 4000 it drives the NINA module directly through the STRIX FPGA image's pin pass-through (SPI on D8–D10, SS D5, ACK D4, GPIO0 D6, RESETN D7) instead of through Arduino's FPGA peripherals bitstream. diff --git a/arduino/libraries/WiFiNINA/keywords.txt b/arduino/libraries/WiFiNINA/keywords.txt new file mode 100644 index 0000000..2e1f9c6 --- /dev/null +++ b/arduino/libraries/WiFiNINA/keywords.txt @@ -0,0 +1,65 @@ +####################################### +# Syntax Coloring Map For WiFiNINA +####################################### + +####################################### +# Library (KEYWORD1) +####################################### + +WiFi KEYWORD1 +WiFiNINA KEYWORD1 +WiFiUdp KEYWORD1 +WiFiClient KEYWORD1 +WiFiSSLClient KEYWORD1 +WiFiServer KEYWORD1 +WiFiUDP KEYWORD1 + + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +firmwareVersion KEYWORD2 +status KEYWORD2 +reasonCode KEYWORD2 +connect KEYWORD2 +write KEYWORD2 +available KEYWORD2 +config KEYWORD2 +setDNS KEYWORD2 +read KEYWORD2 +flush KEYWORD2 +stop KEYWORD2 +connected KEYWORD2 +begin KEYWORD2 +disconnect KEYWORD2 +macAddress KEYWORD2 +localIP KEYWORD2 +subnetMask KEYWORD2 +gatewayIP KEYWORD2 +SSID KEYWORD2 +BSSID KEYWORD2 +RSSI KEYWORD2 +encryptionType KEYWORD2 +beginPacket KEYWORD2 +endPacket KEYWORD2 +parsePacket KEYWORD2 +remoteIP KEYWORD2 +remotePort KEYWORD2 + +beginAP KEYWORD2 +beginEnterprise KEYWORD2 +setHostname KEYWORD2 +end KEYWORD2 +getTime KEYWORD2 +lowPowerMode KEYWORD2 +noLowPowerMode KEYWORD2 +ping KEYWORD2 +beginMulticast KEYWORD2 +setTimeout KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/arduino/libraries/WiFiNINA/library.properties b/arduino/libraries/WiFiNINA/library.properties new file mode 100644 index 0000000..e11fb11 --- /dev/null +++ b/arduino/libraries/WiFiNINA/library.properties @@ -0,0 +1,10 @@ +name=WiFiNINA +version=1.8.5 +author=Arduino +maintainer=Arduino +sentence=Enables network connection (local and Internet) with the Arduino MKR WiFi 1010, Arduino MKR VIDOR 4000, Arduino UNO WiFi Rev.2 and Nano 33 IoT. +paragraph=With this library you can instantiate Servers, Clients and send/receive UDP packets through WiFi. The board can connect either to open or encrypted networks (WEP, WPA). The IP address can be assigned statically or through a DHCP. The library can also manage DNS. +category=Communication +url=http://www.arduino.cc/en/Reference/WiFiNINA +architectures=* +includes=WiFiNINA.h diff --git a/arduino/libraries/WiFiNINA/src/WiFi.cpp b/arduino/libraries/WiFiNINA/src/WiFi.cpp new file mode 100644 index 0000000..ed5bae0 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/WiFi.cpp @@ -0,0 +1,385 @@ +/* + WiFi.cpp - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "utility/wifi_drv.h" +#include "WiFi.h" + +extern "C" { + #include "utility/wl_definitions.h" + #include "utility/wl_types.h" + #include "utility/debug.h" +} + +WiFiClass::WiFiClass() : _timeout(50000) +{ +} + +void WiFiClass::init() +{ + WiFiDrv::wifiDriverInit(); +} + +const char* WiFiClass::firmwareVersion() +{ + return WiFiDrv::getFwVersion(); +} + +int WiFiClass::begin(const char* ssid) +{ + uint8_t status = WL_IDLE_STATUS; + + if (WiFiDrv::wifiSetNetwork(ssid, strlen(ssid)) != WL_FAILURE) + { + for (unsigned long start = millis(); (millis() - start) < _timeout;) + { + delay(WL_DELAY_START_CONNECTION); + status = WiFiDrv::getConnectionStatus(); + if ((status != WL_IDLE_STATUS) && (status != WL_NO_SSID_AVAIL) && (status != WL_SCAN_COMPLETED)) { + break; + } + } + }else + { + status = WL_CONNECT_FAILED; + } + return status; +} + +int WiFiClass::begin(const char* ssid, uint8_t key_idx, const char *key) +{ + uint8_t status = WL_IDLE_STATUS; + + // set encryption key + if (WiFiDrv::wifiSetKey(ssid, strlen(ssid), key_idx, key, strlen(key)) != WL_FAILURE) + { + for (unsigned long start = millis(); (millis() - start) < _timeout;) + { + delay(WL_DELAY_START_CONNECTION); + status = WiFiDrv::getConnectionStatus(); + if ((status != WL_IDLE_STATUS) && (status != WL_NO_SSID_AVAIL) && (status != WL_SCAN_COMPLETED)) { + break; + } + } + }else{ + status = WL_CONNECT_FAILED; + } + return status; +} + +int WiFiClass::begin(const char* ssid, const char *passphrase) +{ + uint8_t status = WL_IDLE_STATUS; + + // set passphrase + if (WiFiDrv::wifiSetPassphrase(ssid, strlen(ssid), passphrase, strlen(passphrase))!= WL_FAILURE) + { + for (unsigned long start = millis(); (millis() - start) < _timeout;) + { + delay(WL_DELAY_START_CONNECTION); + status = WiFiDrv::getConnectionStatus(); + if ((status != WL_IDLE_STATUS) && (status != WL_NO_SSID_AVAIL) && (status != WL_SCAN_COMPLETED)) { + break; + } + } + }else{ + status = WL_CONNECT_FAILED; + } + return status; +} + +uint8_t WiFiClass::beginAP(const char *ssid) +{ + return beginAP(ssid, 1); +} + +uint8_t WiFiClass::beginAP(const char *ssid, uint8_t channel) +{ + uint8_t status = WL_IDLE_STATUS; + + if (WiFiDrv::wifiSetApNetwork(ssid, strlen(ssid), channel) != WL_FAILURE) + { + for (unsigned long start = millis(); (millis() - start) < _timeout;) + { + delay(WL_DELAY_START_CONNECTION); + status = WiFiDrv::getConnectionStatus(); + if ((status != WL_IDLE_STATUS) && (status != WL_NO_SSID_AVAIL) && (status != WL_SCAN_COMPLETED)) { + break; + } + } + }else + { + status = WL_AP_FAILED; + } + return status; +} + +uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase) +{ + return beginAP(ssid, passphrase, 1); +} + +uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase, uint8_t channel) +{ + uint8_t status = WL_IDLE_STATUS; + + // set passphrase + if (WiFiDrv::wifiSetApPassphrase(ssid, strlen(ssid), passphrase, strlen(passphrase), channel)!= WL_FAILURE) + { + for (unsigned long start = millis(); (millis() - start) < _timeout;) + { + delay(WL_DELAY_START_CONNECTION); + status = WiFiDrv::getConnectionStatus(); + if ((status != WL_IDLE_STATUS) && (status != WL_NO_SSID_AVAIL) && (status != WL_SCAN_COMPLETED)) { + break; + } + } + }else{ + status = WL_AP_FAILED; + } + return status; +} + +uint8_t WiFiClass::beginEnterprise(const char* ssid, const char* username, const char* password) +{ + return beginEnterprise(ssid, username, password, ""); +} + +uint8_t WiFiClass::beginEnterprise(const char* ssid, const char* username, const char* password, const char* identity) +{ + return beginEnterprise(ssid, username, password, identity, ""); +} + +uint8_t WiFiClass::beginEnterprise(const char* ssid, const char* username, const char* password, const char* identity, const char* ca) +{ + uint8_t status = WL_IDLE_STATUS; + + // set passphrase + if (WiFiDrv::wifiSetEnterprise(0 /*PEAP/MSCHAPv2*/, ssid, strlen(ssid), username, strlen(username), password, strlen(password), identity, strlen(identity), ca, strlen(ca) + 1)!= WL_FAILURE) + { + for (unsigned long start = millis(); (millis() - start) < _timeout;) + { + delay(WL_DELAY_START_CONNECTION); + status = WiFiDrv::getConnectionStatus(); + if ((status != WL_IDLE_STATUS) && (status != WL_NO_SSID_AVAIL) && (status != WL_SCAN_COMPLETED)) { + break; + } + } + } else { + status = WL_CONNECT_FAILED; + } + return status; +} + +void WiFiClass::config(IPAddress local_ip) +{ + WiFiDrv::config(1, (uint32_t)local_ip, 0, 0); +} + +void WiFiClass::config(IPAddress local_ip, IPAddress dns_server) +{ + WiFiDrv::config(1, (uint32_t)local_ip, 0, 0); + WiFiDrv::setDNS(1, (uint32_t)dns_server, 0); +} + +void WiFiClass::config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway) +{ + WiFiDrv::config(2, (uint32_t)local_ip, (uint32_t)gateway, 0); + WiFiDrv::setDNS(1, (uint32_t)dns_server, 0); +} + +void WiFiClass::config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet) +{ + WiFiDrv::config(3, (uint32_t)local_ip, (uint32_t)gateway, (uint32_t)subnet); + WiFiDrv::setDNS(1, (uint32_t)dns_server, 0); +} + +void WiFiClass::setDNS(IPAddress dns_server1) +{ + WiFiDrv::setDNS(1, (uint32_t)dns_server1, 0); +} + +void WiFiClass::setDNS(IPAddress dns_server1, IPAddress dns_server2) +{ + WiFiDrv::setDNS(2, (uint32_t)dns_server1, (uint32_t)dns_server2); +} + +void WiFiClass::setHostname(const char* name) +{ + WiFiDrv::setHostname(name); +} + +int WiFiClass::disconnect() +{ + return WiFiDrv::disconnect(); +} + +void WiFiClass::end(void) +{ + WiFiDrv::wifiDriverDeinit(); +} + +uint8_t* WiFiClass::macAddress(uint8_t* mac) +{ + uint8_t* _mac = WiFiDrv::getMacAddress(); + memcpy(mac, _mac, WL_MAC_ADDR_LENGTH); + return mac; +} + +IPAddress WiFiClass::localIP() +{ + IPAddress ret; + WiFiDrv::getIpAddress(ret); + return ret; +} + +IPAddress WiFiClass::subnetMask() +{ + IPAddress ret; + WiFiDrv::getSubnetMask(ret); + return ret; +} + +IPAddress WiFiClass::gatewayIP() +{ + IPAddress ret; + WiFiDrv::getGatewayIP(ret); + return ret; +} + +const char* WiFiClass::SSID() +{ + return WiFiDrv::getCurrentSSID(); +} + +uint8_t* WiFiClass::BSSID(uint8_t* bssid) +{ + uint8_t* _bssid = WiFiDrv::getCurrentBSSID(); + memcpy(bssid, _bssid, WL_MAC_ADDR_LENGTH); + return bssid; +} + +int32_t WiFiClass::RSSI() +{ + return WiFiDrv::getCurrentRSSI(); +} + +uint8_t WiFiClass::encryptionType() +{ + return WiFiDrv::getCurrentEncryptionType(); +} + + +int8_t WiFiClass::scanNetworks() +{ + uint8_t attempts = 10; + uint8_t numOfNetworks = 0; + + if (WiFiDrv::startScanNetworks() == WL_FAILURE) + return WL_FAILURE; + do + { + delay(2000); + numOfNetworks = WiFiDrv::getScanNetworks(); + } + while (( numOfNetworks == 0)&&(--attempts>0)); + return numOfNetworks; +} + +const char* WiFiClass::SSID(uint8_t networkItem) +{ + return WiFiDrv::getSSIDNetoworks(networkItem); +} + +int32_t WiFiClass::RSSI(uint8_t networkItem) +{ + return WiFiDrv::getRSSINetoworks(networkItem); +} + +uint8_t WiFiClass::encryptionType(uint8_t networkItem) +{ + return WiFiDrv::getEncTypeNetowrks(networkItem); +} + +uint8_t* WiFiClass::BSSID(uint8_t networkItem, uint8_t* bssid) +{ + return WiFiDrv::getBSSIDNetowrks(networkItem, bssid); +} + +uint8_t WiFiClass::channel(uint8_t networkItem) +{ + return WiFiDrv::getChannelNetowrks(networkItem); +} + +uint8_t WiFiClass::status() +{ + return WiFiDrv::getConnectionStatus(); +} + +uint8_t WiFiClass::reasonCode() +{ + return WiFiDrv::getReasonCode(); +} + +int WiFiClass::hostByName(const char* aHostname, IPAddress& aResult) +{ + return WiFiDrv::getHostByName(aHostname, aResult); +} + +unsigned long WiFiClass::getTime() +{ + return WiFiDrv::getTime(); +} + +void WiFiClass::lowPowerMode() +{ + WiFiDrv::setPowerMode(1); +} + +void WiFiClass::noLowPowerMode() +{ + WiFiDrv::setPowerMode(0); +} + +int WiFiClass::ping(const char* hostname, uint8_t ttl) +{ + IPAddress ip; + + if (!hostByName(hostname, ip)) { + return WL_PING_UNKNOWN_HOST; + } + + return ping(ip, ttl); +} + +int WiFiClass::ping(const String &hostname, uint8_t ttl) +{ + return ping(hostname.c_str(), ttl); +} + +int WiFiClass::ping(IPAddress host, uint8_t ttl) +{ + return WiFiDrv::ping(host, ttl); +} + +void WiFiClass::setTimeout(unsigned long timeout) +{ + _timeout = timeout; +} +WiFiClass WiFi; diff --git a/arduino/libraries/WiFiNINA/src/WiFi.h b/arduino/libraries/WiFiNINA/src/WiFi.h new file mode 100644 index 0000000..6f92706 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/WiFi.h @@ -0,0 +1,281 @@ +/* + WiFi.h - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WiFi_h +#define WiFi_h + +#define WIFI_FIRMWARE_LATEST_VERSION "1.4.3" + +#include + +extern "C" { + #include "utility/wl_definitions.h" + #include "utility/wl_types.h" +} + +#include "IPAddress.h" +#include "WiFiClient.h" +#include "WiFiSSLClient.h" +#include "WiFiServer.h" +#include "WiFiStorage.h" + +class WiFiClass +{ +private: + + static void init(); + unsigned long _timeout; +public: + WiFiClass(); + + /* + * Get firmware version + */ + static const char* firmwareVersion(); + + + /* Start WiFi connection for OPEN networks + * + * param ssid: Pointer to the SSID string. + */ + int begin(const char* ssid); + + /* Start WiFi connection with WEP encryption. + * Configure a key into the device. The key type (WEP-40, WEP-104) + * is determined by the size of the key (5 bytes for WEP-40, 13 bytes for WEP-104). + * + * param ssid: Pointer to the SSID string. + * param key_idx: The key index to set. Valid values are 0-3. + * param key: Key input buffer. + */ + int begin(const char* ssid, uint8_t key_idx, const char* key); + + /* Start WiFi connection with passphrase + * the most secure supported mode will be automatically selected + * + * param ssid: Pointer to the SSID string. + * param passphrase: Passphrase. Valid characters in a passphrase + * must be between ASCII 32-126 (decimal). + */ + int begin(const char* ssid, const char *passphrase); + + uint8_t beginAP(const char *ssid); + uint8_t beginAP(const char *ssid, uint8_t channel); + uint8_t beginAP(const char *ssid, const char* passphrase); + uint8_t beginAP(const char *ssid, const char* passphrase, uint8_t channel); + + uint8_t beginEnterprise(const char* ssid, const char* username, const char* password); + uint8_t beginEnterprise(const char* ssid, const char* username, const char* password, const char* identity); + uint8_t beginEnterprise(const char* ssid, const char* username, const char* password, const char* identity, const char* ca); + + /* Change Ip configuration settings disabling the dhcp client + * + * param local_ip: Static ip configuration + */ + void config(IPAddress local_ip); + + /* Change Ip configuration settings disabling the dhcp client + * + * param local_ip: Static ip configuration + * param dns_server: IP configuration for DNS server 1 + */ + void config(IPAddress local_ip, IPAddress dns_server); + + /* Change Ip configuration settings disabling the dhcp client + * + * param local_ip: Static ip configuration + * param dns_server: IP configuration for DNS server 1 + * param gateway : Static gateway configuration + */ + void config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway); + + /* Change Ip configuration settings disabling the dhcp client + * + * param local_ip: Static ip configuration + * param dns_server: IP configuration for DNS server 1 + * param gateway: Static gateway configuration + * param subnet: Static Subnet mask + */ + void config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet); + + /* Change DNS Ip configuration + * + * param dns_server1: ip configuration for DNS server 1 + */ + void setDNS(IPAddress dns_server1); + + /* Change DNS Ip configuration + * + * param dns_server1: ip configuration for DNS server 1 + * param dns_server2: ip configuration for DNS server 2 + * + */ + void setDNS(IPAddress dns_server1, IPAddress dns_server2); + + + /* Set the hostname used for DHCP requests + * + * param name: hostname to set + * + */ + void setHostname(const char* name); + + /* + * Disconnect from the network + * + * return: one value of wl_status_t enum + */ + int disconnect(void); + + void end(void); + + /* + * Get the interface MAC address. + * + * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + */ + uint8_t* macAddress(uint8_t* mac); + + /* + * Get the interface IP address. + * + * return: Ip address value + */ + IPAddress localIP(); + + /* + * Get the interface subnet mask address. + * + * return: subnet mask address value + */ + IPAddress subnetMask(); + + /* + * Get the gateway ip address. + * + * return: gateway ip address value + */ + IPAddress gatewayIP(); + + /* + * Return the current SSID associated with the network + * + * return: ssid string + */ + const char* SSID(); + + /* + * Return the current BSSID associated with the network. + * It is the MAC address of the Access Point + * + * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + */ + uint8_t* BSSID(uint8_t* bssid); + + /* + * Return the current RSSI /Received Signal Strength in dBm) + * associated with the network + * + * return: signed value + */ + int32_t RSSI(); + + /* + * Return the Encryption Type associated with the network + * + * return: one value of wl_enc_type enum + */ + uint8_t encryptionType(); + + /* + * Start scan WiFi networks available + * + * return: Number of discovered networks + */ + int8_t scanNetworks(); + + /* + * Return the SSID discovered during the network scan. + * + * param networkItem: specify from which network item want to get the information + * + * return: ssid string of the specified item on the networks scanned list + */ + const char* SSID(uint8_t networkItem); + + /* + * Return the encryption type of the networks discovered during the scanNetworks + * + * param networkItem: specify from which network item want to get the information + * + * return: encryption type (enum wl_enc_type) of the specified item on the networks scanned list + */ + uint8_t encryptionType(uint8_t networkItem); + + uint8_t* BSSID(uint8_t networkItem, uint8_t* bssid); + uint8_t channel(uint8_t networkItem); + + /* + * Return the RSSI of the networks discovered during the scanNetworks + * + * param networkItem: specify from which network item want to get the information + * + * return: signed value of RSSI of the specified item on the networks scanned list + */ + int32_t RSSI(uint8_t networkItem); + + /* + * Return Connection status. + * + * return: one of the value defined in wl_status_t + */ + uint8_t status(); + + /* + * Return The deauthentication reason code. + * + * return: the deauthentication reason code + */ + uint8_t reasonCode(); + + /* + * Resolve the given hostname to an IP address. + * param aHostname: Name to be resolved + * param aResult: IPAddress structure to store the returned IP address + * result: 1 if aIPAddrString was successfully converted to an IP address, + * else error code + */ + int hostByName(const char* aHostname, IPAddress& aResult); + + unsigned long getTime(); + + void lowPowerMode(); + void noLowPowerMode(); + + int ping(const char* hostname, uint8_t ttl = 128); + int ping(const String &hostname, uint8_t ttl = 128); + int ping(IPAddress host, uint8_t ttl = 128); + + void setTimeout(unsigned long timeout); +}; + +extern WiFiClass WiFi; + +#endif diff --git a/arduino/libraries/WiFiNINA/src/WiFiClient.cpp b/arduino/libraries/WiFiNINA/src/WiFiClient.cpp new file mode 100644 index 0000000..b8ec61d --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/WiFiClient.cpp @@ -0,0 +1,362 @@ +/* + WiFiClient.cpp - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +extern "C" { + #include "utility/wl_definitions.h" + #include "utility/wl_types.h" + #include "string.h" + #include "utility/debug.h" +} + + +#include "utility/server_drv.h" +#include "utility/wifi_drv.h" +#include "utility/WiFiSocketBuffer.h" + +#include "WiFi.h" +#include "WiFiClient.h" + +uint16_t WiFiClient::_srcport = 1024; + +WiFiClient::WiFiClient() : _sock(NO_SOCKET_AVAIL), _retrySend(true) { +} + +WiFiClient::WiFiClient(uint8_t sock) : _sock(sock), _retrySend(true) { +} + +int WiFiClient::connect(const char* host, uint16_t port) { + IPAddress remote_addr; + if (WiFi.hostByName(host, remote_addr)) + { + return connect(remote_addr, port); + } + return 0; +} + +int WiFiClient::connect(IPAddress ip, uint16_t port) { + if (_sock != NO_SOCKET_AVAIL) + { + stop(); + } + + _sock = ServerDrv::getSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startClient(uint32_t(ip), port, _sock); + + unsigned long start = millis(); + + // wait 4 second for the connection to close + while (!connected() && millis() - start < 10000) + delay(1); + + if (!connected()) + { + return 0; + } + } else { + Serial.println("No Socket available"); + return 0; + } + return 1; +} + +int WiFiClient::connectSSL(IPAddress ip, uint16_t port) +{ + if (_sock != NO_SOCKET_AVAIL) + { + stop(); + } + + _sock = ServerDrv::getSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startClient(uint32_t(ip), port, _sock, TLS_MODE); + + unsigned long start = millis(); + + // wait 4 second for the connection to close + while (!connected() && millis() - start < 10000) + delay(1); + + if (!connected()) + { + return 0; + } + } else { + Serial.println("No Socket available"); + return 0; + } + return 1; +} + +int WiFiClient::connectSSL(const char *host, uint16_t port) +{ + if (_sock != NO_SOCKET_AVAIL) + { + stop(); + } + + _sock = ServerDrv::getSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startClient(host, strlen(host), uint32_t(0), port, _sock, TLS_MODE); + + unsigned long start = millis(); + + // wait 4 second for the connection to close + while (!connected() && millis() - start < 10000) + delay(1); + + if (!connected()) + { + return 0; + } + } else { + Serial.println("No Socket available"); + return 0; + } + return 1; +} + +int WiFiClient::connectBearSSL(IPAddress ip, uint16_t port) +{ + if (_sock != NO_SOCKET_AVAIL) + { + stop(); + } + + _sock = ServerDrv::getSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startClient(uint32_t(ip), port, _sock, TLS_BEARSSL_MODE); + + unsigned long start = millis(); + + // wait 4 second for the connection to close + while (!connected() && millis() - start < 10000) + delay(1); + + if (!connected()) + { + return 0; + } + } else { + Serial.println("No Socket available"); + return 0; + } + return 1; +} + +int WiFiClient::connectBearSSL(const char *host, uint16_t port) +{ + if (_sock != NO_SOCKET_AVAIL) + { + stop(); + } + + _sock = ServerDrv::getSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startClient(host, strlen(host), uint32_t(0), port, _sock, TLS_BEARSSL_MODE); + + unsigned long start = millis(); + + // wait 4 second for the connection to close + while (!connected() && millis() - start < 10000) + delay(1); + + if (!connected()) + { + return 0; + } + } else { + Serial.println("No Socket available"); + return 0; + } + return 1; +} + +size_t WiFiClient::write(uint8_t b) { + return write(&b, 1); +} + +size_t WiFiClient::write(const uint8_t *buf, size_t size) { + if (_sock == NO_SOCKET_AVAIL) + { + setWriteError(); + return 0; + } + if (size==0) + { + setWriteError(); + return 0; + } + + size_t written = ServerDrv::sendData(_sock, buf, size); + if (!written && _retrySend) { + written = retry(buf, size, true); + } + if(!written){ + // close socket + ServerDrv::stopClient(_sock); + setWriteError(); + return 0; + } + + if (!ServerDrv::checkDataSent(_sock)) + { + setWriteError(); + return 0; + } + + return written; +} + +size_t WiFiClient::retry(const uint8_t *buf, size_t size, bool write) { + size_t rec_bytes = 0; + + if (write) { + + //RETRY WRITE + for (int i=0; i<5; i++) { + rec_bytes = ServerDrv::sendData(_sock, buf, size); + if (rec_bytes) { + break; + } + } + return rec_bytes; + + } else { + //RETRY READ + // To be implemented, if needed + } + +} + +int WiFiClient::available() { + if (_sock != 255) + { + return WiFiSocketBuffer.available(_sock); + } + + return 0; +} + +int WiFiClient::read() { + if (!available()) + { + return -1; + } + + uint8_t b; + + WiFiSocketBuffer.read(_sock, &b, sizeof(b)); + + return b; +} + + +int WiFiClient::read(uint8_t* buf, size_t size) { + return WiFiSocketBuffer.read(_sock, buf, size); +} + +int WiFiClient::peek() { + return WiFiSocketBuffer.peek(_sock); +} + +void WiFiClient::setRetry(bool retry) { + _retrySend = retry; +} + +void WiFiClient::flush() { + // TODO: a real check to ensure transmission has been completed +} + +void WiFiClient::stop() { + + if (_sock == 255) + return; + + ServerDrv::stopClient(_sock); + + int count = 0; + // wait maximum 5 secs for the connection to close + while (status() != CLOSED && ++count < 50) + delay(100); + + WiFiSocketBuffer.close(_sock); + _sock = 255; +} + +uint8_t WiFiClient::connected() { + + if (_sock == 255) { + return 0; + } else if (available()) { + return 1; + } else { + uint8_t s = status(); + + uint8_t result = !(s == LISTEN || s == CLOSED || s == FIN_WAIT_1 || + s == FIN_WAIT_2 || s == TIME_WAIT || + s == SYN_SENT || s== SYN_RCVD || + (s == CLOSE_WAIT)); + + if (result == 0) { + WiFiSocketBuffer.close(_sock); + _sock = 255; + } + + return result; + } +} + +uint8_t WiFiClient::status() { + if (_sock == 255) { + return CLOSED; + } else { + return ServerDrv::getClientState(_sock); + } +} + +WiFiClient::operator bool() { + return _sock != 255; +} + +IPAddress WiFiClient::remoteIP() +{ + uint8_t _remoteIp[4] = {0}; + uint8_t _remotePort[2] = {0}; + + WiFiDrv::getRemoteData(_sock, _remoteIp, _remotePort); + IPAddress ip(_remoteIp); + return ip; +} + +uint16_t WiFiClient::remotePort() +{ + uint8_t _remoteIp[4] = {0}; + uint8_t _remotePort[2] = {0}; + + WiFiDrv::getRemoteData(_sock, _remoteIp, _remotePort); + uint16_t port = (_remotePort[0]<<8)+_remotePort[1]; + return port; +} diff --git a/arduino/libraries/WiFiNINA/src/WiFiClient.h b/arduino/libraries/WiFiNINA/src/WiFiClient.h new file mode 100644 index 0000000..a6f43e2 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/WiFiClient.h @@ -0,0 +1,69 @@ +/* + WiFiClient.cpp - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef wificlient_h +#define wificlient_h +#include "Arduino.h" +#include "Print.h" +#include "Client.h" +#include "IPAddress.h" + +class WiFiClient : public Client { + +public: + WiFiClient(); + WiFiClient(uint8_t sock); + + uint8_t status(); + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char *host, uint16_t port); + virtual int connectSSL(IPAddress ip, uint16_t port); + virtual int connectSSL(const char *host, uint16_t port); + virtual int connectBearSSL(IPAddress ip, uint16_t port); + virtual int connectBearSSL(const char *host, uint16_t port); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + virtual size_t retry(const uint8_t *buf, size_t size, bool write); + virtual int available(); + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual void setRetry(bool retry); + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + virtual operator bool(); + + virtual IPAddress remoteIP(); + virtual uint16_t remotePort(); + + friend class WiFiServer; + friend class WiFiDrv; + + using Print::write; + +private: + static uint16_t _srcport; + uint8_t _sock; //not used + uint16_t _socket; + bool _retrySend; +}; + +#endif diff --git a/arduino/libraries/WiFiNINA/src/WiFiNINA.h b/arduino/libraries/WiFiNINA/src/WiFiNINA.h new file mode 100644 index 0000000..c6c7754 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/WiFiNINA.h @@ -0,0 +1,25 @@ +/* + This file is part of the WiFiNINA library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WiFiNINA_h +#define WiFiNINA_h + +#include "WiFi.h" + +#endif diff --git a/arduino/libraries/WiFiNINA/src/WiFiSSLClient.cpp b/arduino/libraries/WiFiNINA/src/WiFiSSLClient.cpp new file mode 100644 index 0000000..f051144 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/WiFiSSLClient.cpp @@ -0,0 +1,60 @@ +/* + This file is part of the WiFiNINA library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "WiFiSSLClient.h" + +WiFiSSLClient::WiFiSSLClient() : + WiFiClient() +{ +} + +WiFiSSLClient::WiFiSSLClient(uint8_t sock) : + WiFiClient(sock) +{ +} + +int WiFiSSLClient::connect(IPAddress ip, uint16_t port) +{ + return WiFiClient::connectSSL(ip, port); +} + +int WiFiSSLClient::connect(const char* host, uint16_t port) +{ + return WiFiClient::connectSSL(host, port); +} + +WiFiBearSSLClient::WiFiBearSSLClient() : + WiFiClient() +{ +} + +WiFiBearSSLClient::WiFiBearSSLClient(uint8_t sock) : + WiFiClient(sock) +{ +} + +int WiFiBearSSLClient::connect(IPAddress ip, uint16_t port) +{ + return WiFiClient::connectBearSSL(ip, port); +} + +int WiFiBearSSLClient::connect(const char* host, uint16_t port) +{ + return WiFiClient::connectBearSSL(host, port); +} diff --git a/arduino/libraries/WiFiNINA/src/WiFiSSLClient.h b/arduino/libraries/WiFiNINA/src/WiFiSSLClient.h new file mode 100644 index 0000000..41c3a6a --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/WiFiSSLClient.h @@ -0,0 +1,45 @@ +/* + This file is part of the WiFiNINA library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIFISSLCLIENT_H +#define WIFISSLCLIENT_H + +#include "WiFiClient.h" + +class WiFiSSLClient : public WiFiClient { + +public: + WiFiSSLClient(); + WiFiSSLClient(uint8_t sock); + + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char* host, uint16_t port); +}; + +class WiFiBearSSLClient : public WiFiClient { + +public: + WiFiBearSSLClient(); + WiFiBearSSLClient(uint8_t sock); + + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char* host, uint16_t port); +}; + +#endif /* WIFISSLCLIENT_H */ diff --git a/arduino/libraries/WiFiNINA/src/WiFiServer.cpp b/arduino/libraries/WiFiNINA/src/WiFiServer.cpp new file mode 100644 index 0000000..729958b --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/WiFiServer.cpp @@ -0,0 +1,119 @@ +/* + WiFiServer.cpp - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "utility/server_drv.h" + +extern "C" { + #include "utility/debug.h" +} + +#include "WiFi.h" +#include "WiFiClient.h" +#include "WiFiServer.h" + +WiFiServer::WiFiServer(uint16_t port) : + _sock(NO_SOCKET_AVAIL), + _lastSock(NO_SOCKET_AVAIL) +{ + _port = port; +} + +void WiFiServer::begin() +{ + _sock = ServerDrv::getSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startServer(_port, _sock); + } +} + +WiFiClient WiFiServer::available(byte* status) +{ + int sock = NO_SOCKET_AVAIL; + + if (_sock != NO_SOCKET_AVAIL) { + // check previous received client socket + if (_lastSock != NO_SOCKET_AVAIL) { + WiFiClient client(_lastSock); + + if (client.connected() && client.available()) { + sock = _lastSock; + } + } + + if (sock == NO_SOCKET_AVAIL) { + // check for new client socket + sock = ServerDrv::availServer(_sock); + } + } + + if (sock != NO_SOCKET_AVAIL) { + WiFiClient client(sock); + + if (status != NULL) { + *status = client.status(); + } + + _lastSock = sock; + + return client; + } + + return WiFiClient(255); +} + +uint8_t WiFiServer::status() { + if (_sock == NO_SOCKET_AVAIL) { + return CLOSED; + } else { + return ServerDrv::getServerState(_sock); + } +} + + +size_t WiFiServer::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t WiFiServer::write(const uint8_t *buffer, size_t size) +{ + if (size==0) + { + setWriteError(); + return 0; + } + + size_t written = ServerDrv::sendData(_sock, buffer, size); + if (!written) + { + setWriteError(); + return 0; + } + + if (!ServerDrv::checkDataSent(_sock)) + { + setWriteError(); + return 0; + } + + return written; +} diff --git a/arduino/libraries/WiFiNINA/src/WiFiServer.h b/arduino/libraries/WiFiNINA/src/WiFiServer.h new file mode 100644 index 0000000..d60f558 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/WiFiServer.h @@ -0,0 +1,49 @@ +/* + WiFiServer.h - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef wifiserver_h +#define wifiserver_h + +extern "C" { + #include "utility/wl_definitions.h" +} + +#include "Server.h" + +class WiFiClient; + +class WiFiServer : public Server { +private: + uint8_t _sock; + uint8_t _lastSock; + uint16_t _port; + void* pcb; +public: + WiFiServer(uint16_t); + WiFiClient available(uint8_t* status = NULL); + void begin(); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + uint8_t status(); + + using Print::write; +}; + +#endif diff --git a/arduino/libraries/WiFiNINA/src/WiFiStorage.cpp b/arduino/libraries/WiFiNINA/src/WiFiStorage.cpp new file mode 100644 index 0000000..21b50c9 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/WiFiStorage.cpp @@ -0,0 +1,30 @@ +/* + WiFiStorage.cpp - Library for Arduino boards based on NINA WiFi module. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "WiFiStorage.h" + +WiFiStorageFile WiFiStorageClass::open(const char *filename) { + WiFiStorageFile file(filename); + file.size(); + return file; +} + +WiFiStorageFile WiFiStorageClass::open(String filename) { + return open(filename.c_str()); +} \ No newline at end of file diff --git a/arduino/libraries/WiFiNINA/src/WiFiStorage.h b/arduino/libraries/WiFiNINA/src/WiFiStorage.h new file mode 100644 index 0000000..30a6276 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/WiFiStorage.h @@ -0,0 +1,151 @@ +/* + WiFiStorage.h - Library for Arduino boards based on NINA WiFi module. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef wifistorage_h +#define wifistorage_h + +#include "utility/wifi_drv.h" + +class WiFiStorageFile; + +class WiFiStorageClass +{ +public: + static bool begin(); + + static WiFiStorageFile open(const char *filename); + static WiFiStorageFile open(String filename); + + static bool exists(const char *filename) { + uint32_t len; + return (WiFiDrv::existsFile(filename, strlen(filename), &len) > 0); + } + static bool exists(const char *filename, uint32_t* len) { + return (WiFiDrv::existsFile(filename, strlen(filename), len) > 0); + } + static bool remove(const char *filename) { + WiFiDrv::deleteFile(filename, strlen(filename)); + return true; + } + static bool rename(const char * old_file_name, const char * new_file_name) { + return (WiFiDrv::renameFile(old_file_name, strlen(old_file_name), new_file_name, strlen(new_file_name)) == 0); + } + static bool read(const char *filename, uint32_t offset, uint8_t* buffer, uint32_t buffer_len) { + WiFiDrv::readFile(filename, strlen(filename), offset, buffer, buffer_len); + return true; + } + static bool write(const char *filename, uint32_t offset, uint8_t* buffer, uint32_t buffer_len) { + WiFiDrv::writeFile(filename, strlen(filename), offset, buffer, buffer_len); + return true; + } + static bool download(const char* url, const char *filename) { + WiFiDrv::downloadFile(url, strlen(url), filename, strlen(filename)); + return true; + } + static bool downloadOTA(const char * url, uint8_t * res_ota_download = NULL) { + /* The buffer within the nina firmware allows a maximum + * url size of 128 bytes. It's better to prevent the + * transmission of over-sized URL as soon as possible. + */ + if (strlen(url) > 128) + return false; + + uint8_t const res = WiFiDrv::downloadOTA(url, strlen(url)); + if (res_ota_download) + *res_ota_download = res; + bool const success = (res == 0); + return success; + } + + + static bool remove(String filename) { + return remove(filename.c_str()); + } + static bool rename(String old_file_name, String new_file_name) { + return rename(old_file_name.c_str(), new_file_name.c_str()); + } + static bool read(String filename, uint32_t offset, uint8_t* buffer, uint32_t buffer_len) { + return read(filename.c_str(), offset, buffer, buffer_len); + } + static bool write(String filename, uint32_t offset, uint8_t* buffer, uint32_t buffer_len) { + return write(filename.c_str(), offset, buffer, buffer_len); + } + static bool download(String url, String filename) { + return download(url.c_str(), filename.c_str()); + } + static bool download(String url, uint8_t * res_ota_download = NULL) { + return downloadOTA(url.c_str(), res_ota_download); + } +}; + +extern WiFiStorageClass WiFiStorage; + + +class WiFiStorageFile +{ +public: + constexpr WiFiStorageFile(const char* _filename) : filename(_filename) { } + + operator bool() { + return WiFiStorage.exists(filename, &length); + } + uint32_t read(void *buf, uint32_t rdlen) { + if (offset + rdlen > length) { + if (offset >= length) return 0; + rdlen = length - offset; + } + WiFiStorage.read(filename, offset, (uint8_t*)buf, rdlen); + offset += rdlen; + return rdlen; + } + uint32_t write(const void *buf, uint32_t wrlen) { + WiFiStorage.write(filename, offset, (uint8_t*)buf, wrlen); + offset += wrlen; + return wrlen; + } + void seek(uint32_t n) { + offset = n; + } + uint32_t position() { + return offset; + } + uint32_t size() { + WiFiStorage.exists(filename, &length); + return length; + } + uint32_t available() { + WiFiStorage.exists(filename, &length); + return length - offset; + } + void erase() { + offset = 0; + WiFiStorage.remove(filename); + } + void flush(); + void close() { + offset = 0; + } +protected: + friend class WiFiStorageClass; + uint32_t offset = 0; + uint32_t length = 0; + const char* filename; +}; + +#endif \ No newline at end of file diff --git a/arduino/libraries/WiFiNINA/src/WiFiUdp.cpp b/arduino/libraries/WiFiNINA/src/WiFiUdp.cpp new file mode 100644 index 0000000..12f27fa --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/WiFiUdp.cpp @@ -0,0 +1,217 @@ +/* + WiFiUdp.cpp - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +extern "C" { + #include "utility/debug.h" + #include "utility/wifi_spi.h" +} + +#include "utility/server_drv.h" +#include "utility/wifi_drv.h" +#include "utility/WiFiSocketBuffer.h" + +#include "WiFi.h" +#include "WiFiUdp.h" +#include "WiFiClient.h" +#include "WiFiServer.h" + + +/* Constructor */ +WiFiUDP::WiFiUDP() : _sock(NO_SOCKET_AVAIL), _parsed(0) {} + +/* Start WiFiUDP socket, listening at local port PORT */ +uint8_t WiFiUDP::begin(uint16_t port) { + if (_sock != NO_SOCKET_AVAIL) + { + stop(); + } + + uint8_t sock = ServerDrv::getSocket(); + if (sock != NO_SOCKET_AVAIL) + { + ServerDrv::startServer(port, sock, UDP_MODE); + _sock = sock; + _port = port; + _parsed = 0; + return 1; + } + return 0; +} + +uint8_t WiFiUDP::beginMulticast(IPAddress ip, uint16_t port) { + if (_sock != NO_SOCKET_AVAIL) + { + stop(); + } + + uint8_t sock = ServerDrv::getSocket(); + if (sock != NO_SOCKET_AVAIL) + { + ServerDrv::startServer(ip, port, sock, UDP_MULTICAST_MODE); + _sock = sock; + _port = port; + _parsed = 0; + return 1; + } + return 0; +} + +/* return number of bytes available in the current packet, + will return zero if parsePacket hasn't been called yet */ +int WiFiUDP::available() { + return _parsed; +} + +/* Release any resources being used by this WiFiUDP instance */ +void WiFiUDP::stop() +{ + if (_sock == NO_SOCKET_AVAIL) + return; + + ServerDrv::stopClient(_sock); + + WiFiSocketBuffer.close(_sock); + _sock = NO_SOCKET_AVAIL; +} + +int WiFiUDP::beginPacket(const char *host, uint16_t port) +{ + // Look up the host first + int ret = 0; + IPAddress remote_addr; + if (WiFi.hostByName(host, remote_addr)) + { + return beginPacket(remote_addr, port); + } + return ret; +} + +int WiFiUDP::beginPacket(IPAddress ip, uint16_t port) +{ + if (_sock == NO_SOCKET_AVAIL) + _sock = ServerDrv::getSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startClient(uint32_t(ip), port, _sock, UDP_MODE); + return 1; + } + return 0; +} + +int WiFiUDP::endPacket() +{ + return ServerDrv::sendUdpData(_sock); +} + +size_t WiFiUDP::write(uint8_t byte) +{ + return write(&byte, 1); +} + +size_t WiFiUDP::write(const uint8_t *buffer, size_t size) +{ + ServerDrv::insertDataBuf(_sock, buffer, size); + return size; +} + +int WiFiUDP::parsePacket() +{ + while (_parsed--) + { + // discard previously parsed packet data + uint8_t b; + + WiFiSocketBuffer.read(_sock, &b, sizeof(b)); + } + + _parsed = ServerDrv::availData(_sock); + + return _parsed; +} + +int WiFiUDP::read() +{ + if (_parsed < 1) + { + return -1; + } + + uint8_t b; + + WiFiSocketBuffer.read(_sock, &b, sizeof(b)); + _parsed--; + + return b; +} + +int WiFiUDP::read(unsigned char* buffer, size_t len) +{ + if (_parsed < 1) + { + return 0; + } + + int result = WiFiSocketBuffer.read(_sock, buffer, len); + + if (result > 0) + { + _parsed -= result; + } + + return result; +} + +int WiFiUDP::peek() +{ + if (_parsed < 1) + { + return -1; + } + + return WiFiSocketBuffer.peek(_sock); +} + +void WiFiUDP::flush() +{ + // TODO: a real check to ensure transmission has been completed +} + +IPAddress WiFiUDP::remoteIP() +{ + uint8_t _remoteIp[4] = {0}; + uint8_t _remotePort[2] = {0}; + + WiFiDrv::getRemoteData(_sock, _remoteIp, _remotePort); + IPAddress ip(_remoteIp); + return ip; +} + +uint16_t WiFiUDP::remotePort() +{ + uint8_t _remoteIp[4] = {0}; + uint8_t _remotePort[2] = {0}; + + WiFiDrv::getRemoteData(_sock, _remoteIp, _remotePort); + uint16_t port = (_remotePort[0]<<8)+_remotePort[1]; + return port; +} + diff --git a/arduino/libraries/WiFiNINA/src/WiFiUdp.h b/arduino/libraries/WiFiNINA/src/WiFiUdp.h new file mode 100644 index 0000000..96c019e --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/WiFiUdp.h @@ -0,0 +1,83 @@ +/* + WiFiUdp.h - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef wifiudp_h +#define wifiudp_h + +#include + +#define UDP_TX_PACKET_MAX_SIZE 24 + +class WiFiUDP : public UDP { +private: + uint8_t _sock; // socket ID for Wiz5100 + uint16_t _port; // local port to listen on + int _parsed; + +public: + WiFiUDP(); // Constructor + virtual uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual uint8_t beginMulticast(IPAddress, uint16_t); // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 if there are no sockets available to use + virtual void stop(); // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port); + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port); + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket(); + // Write a single byte into the packet + virtual size_t write(uint8_t); + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size); + + using Print::write; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket(); + // Number of bytes remaining in the current packet + virtual int available(); + // Read a single byte from the current packet + virtual int read(); + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len); + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); }; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek(); + virtual void flush(); // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP(); + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort(); + + friend class WiFiDrv; +}; + +#endif diff --git a/arduino/libraries/WiFiNINA/src/utility/WiFiSocketBuffer.cpp b/arduino/libraries/WiFiNINA/src/utility/WiFiSocketBuffer.cpp new file mode 100644 index 0000000..2a73069 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/utility/WiFiSocketBuffer.cpp @@ -0,0 +1,104 @@ +/* + This file is part of the WiFiNINA library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +#include "utility/server_drv.h" + +#include "WiFiSocketBuffer.h" + +#define WIFI_SOCKET_NUM_BUFFERS (sizeof(_buffers) / sizeof(_buffers[0])) + +#ifdef __AVR__ +#define WIFI_SOCKET_BUFFER_SIZE 64 +#else +#define WIFI_SOCKET_BUFFER_SIZE 1500 +#endif + +WiFiSocketBufferClass::WiFiSocketBufferClass() +{ + memset(&_buffers, 0x00, sizeof(_buffers)); +} + +WiFiSocketBufferClass::~WiFiSocketBufferClass() +{ + for (unsigned int i = 0; i < WIFI_SOCKET_NUM_BUFFERS; i++) { + close(i); + } +} + +void WiFiSocketBufferClass::close(int socket) +{ + if (_buffers[socket].data) { + free(_buffers[socket].data); + _buffers[socket].data = _buffers[socket].head = NULL; + _buffers[socket].length = 0; + } +} + +int WiFiSocketBufferClass::available(int socket) +{ + if (_buffers[socket].length == 0) { + if (_buffers[socket].data == NULL) { + _buffers[socket].data = _buffers[socket].head = (uint8_t*)malloc(WIFI_SOCKET_BUFFER_SIZE); + _buffers[socket].length = 0; + } + + // sizeof(size_t) is architecture dependent + // but we need a 16 bit data type here + uint16_t size = WIFI_SOCKET_BUFFER_SIZE; + if (ServerDrv::getDataBuf(socket, _buffers[socket].data, &size)) { + _buffers[socket].head = _buffers[socket].data; + _buffers[socket].length = size; + } + } + + return _buffers[socket].length; +} + +int WiFiSocketBufferClass::peek(int socket) +{ + if (!available(socket)) { + return -1; + } + + return *_buffers[socket].head; +} + +int WiFiSocketBufferClass::read(int socket, uint8_t* data, size_t length) +{ + int avail = available(socket); + + if (!avail) { + return 0; + } + + if (avail < (int)length) { + length = avail; + } + + memcpy(data, _buffers[socket].head, length); + _buffers[socket].head += length; + _buffers[socket].length -= length; + + return length; +} + +WiFiSocketBufferClass WiFiSocketBuffer; diff --git a/arduino/libraries/WiFiNINA/src/utility/WiFiSocketBuffer.h b/arduino/libraries/WiFiNINA/src/utility/WiFiSocketBuffer.h new file mode 100644 index 0000000..88572b7 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/utility/WiFiSocketBuffer.h @@ -0,0 +1,52 @@ +/* + This file is part of the WiFiNINA library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WiFiSocketBuffer_h +#define WiFiSocketBuffer_h + +#include +#include + +extern "C" { + #include "utility/wl_definitions.h" +} + +class WiFiSocketBufferClass { + +public: + WiFiSocketBufferClass(); + ~WiFiSocketBufferClass(); + + void close(int socket); + + int available(int socket); + int peek(int socket); + int read(int socket, uint8_t* data, size_t length); + +private: + struct { + uint8_t* data; + uint8_t* head; + int length; + } _buffers[WIFI_MAX_SOCK_NUM]; +}; + +extern WiFiSocketBufferClass WiFiSocketBuffer; + +#endif diff --git a/arduino/libraries/WiFiNINA/src/utility/debug.h b/arduino/libraries/WiFiNINA/src/utility/debug.h new file mode 100644 index 0000000..5569e45 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/utility/debug.h @@ -0,0 +1,95 @@ +/* + debug.h - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +//*********************************************/ +// +// File: debug.h +// +// Author: dlf (Metodo2 srl) +// +//********************************************/ + + +#ifndef Debug_H +#define Debug_H + +#include +#include + +#define PRINT_FILE_LINE() do { \ + Serial.print("[");Serial.print(__FILE__); \ + Serial.print("::");Serial.print(__LINE__);Serial.print("]");\ +}while (0); + +#ifdef _DEBUG_ + +#define INFO(format, args...) do { \ + char buf[250]; \ + sprintf(buf, format, args); \ + Serial.println(buf); \ +} while(0); + +#define INFO1(x) do { PRINT_FILE_LINE() Serial.print("-I-");\ + Serial.println(x); \ +}while (0); + + +#define INFO2(x,y) do { PRINT_FILE_LINE() Serial.print("-I-");\ + Serial.print(x,16);Serial.print(",");Serial.println(y,16); \ +}while (0); + + +#else +#define INFO1(x) do {} while(0); +#define INFO2(x,y) do {} while(0); +#define INFO(format, args...) do {} while(0); +#endif + +#if 0 +#define WARN(args) do { PRINT_FILE_LINE() \ + Serial.print("-W-"); Serial.println(args); \ +}while (0); +#else +#define WARN(args) do {} while (0); +#endif + +#if _DEBUG_SPI_ +#define DBG_PIN2 5 +#define DBG_PIN 4 + +#define START() digitalWrite(DBG_PIN2, HIGH); +#define END() digitalWrite(DBG_PIN2, LOW); +#define SET_TRIGGER() digitalWrite(DBG_PIN, HIGH); +#define RST_TRIGGER() digitalWrite(DBG_PIN, LOW); + +#define INIT_TRIGGER() pinMode(DBG_PIN, OUTPUT); \ + pinMode(DBG_PIN2, OUTPUT); \ + RST_TRIGGER() +#define TOGGLE_TRIGGER() SET_TRIGGER() \ + delayMicroseconds(2); \ + RST_TRIGGER() +#else +#define START() +#define END() +#define SET_TRIGGER() +#define RST_TRIGGER() +#define INIT_TRIGGER() +#define TOGGLE_TRIGGER() +#endif + +#endif diff --git a/arduino/libraries/WiFiNINA/src/utility/server_drv.cpp b/arduino/libraries/WiFiNINA/src/utility/server_drv.cpp new file mode 100644 index 0000000..4fc35b4 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/utility/server_drv.cpp @@ -0,0 +1,520 @@ +/* + server_drv.cpp - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//#define _DEBUG_ + +#include "utility/server_drv.h" + +#include "Arduino.h" +#include "utility/spi_drv.h" + +extern "C" { +#include "utility/wl_types.h" +#include "utility/debug.h" +} + + +// Start server TCP on port specified +void ServerDrv::startServer(uint16_t port, uint8_t sock, uint8_t protMode) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(START_SERVER_TCP_CMD, PARAM_NUMS_3); + SpiDrv::sendParam(port); + SpiDrv::sendParam(&sock, 1); + SpiDrv::sendParam(&protMode, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(START_SERVER_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); +} + +void ServerDrv::startServer(uint32_t ipAddress, uint16_t port, uint8_t sock, uint8_t protMode) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(START_SERVER_TCP_CMD, PARAM_NUMS_4); + SpiDrv::sendParam((uint8_t*)&ipAddress, sizeof(ipAddress)); + SpiDrv::sendParam(port); + SpiDrv::sendParam(&sock, 1); + SpiDrv::sendParam(&protMode, 1, LAST_PARAM); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(START_SERVER_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); +} + +// Start server TCP on port specified +void ServerDrv::startClient(uint32_t ipAddress, uint16_t port, uint8_t sock, uint8_t protMode) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(START_CLIENT_TCP_CMD, PARAM_NUMS_4); + SpiDrv::sendParam((uint8_t*)&ipAddress, sizeof(ipAddress)); + SpiDrv::sendParam(port); + SpiDrv::sendParam(&sock, 1); + SpiDrv::sendParam(&protMode, 1, LAST_PARAM); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(START_CLIENT_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); +} + +void ServerDrv::startClient(const char* host, uint8_t host_len, uint32_t ipAddress, uint16_t port, uint8_t sock, uint8_t protMode) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(START_CLIENT_TCP_CMD, PARAM_NUMS_5); + SpiDrv::sendParam((uint8_t*)host, host_len); + SpiDrv::sendParam((uint8_t*)&ipAddress, sizeof(ipAddress)); + SpiDrv::sendParam(port); + SpiDrv::sendParam(&sock, 1); + SpiDrv::sendParam(&protMode, 1, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 17 + host_len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(/* feed_watchdog = */ (protMode == TLS_BEARSSL_MODE)); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(START_CLIENT_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); +} + +// Start server TCP on port specified +void ServerDrv::stopClient(uint8_t sock) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(STOP_CLIENT_TCP_CMD, PARAM_NUMS_1); + SpiDrv::sendParam(&sock, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(STOP_CLIENT_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); +} + + +uint8_t ServerDrv::getServerState(uint8_t sock) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(GET_STATE_TCP_CMD, PARAM_NUMS_1); + SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(GET_STATE_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +uint8_t ServerDrv::getClientState(uint8_t sock) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(GET_CLIENT_STATE_TCP_CMD, PARAM_NUMS_1); + SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(GET_CLIENT_STATE_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +uint16_t ServerDrv::availData(uint8_t sock) +{ + if (!SpiDrv::available()) { + return 0; + } + + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(AVAIL_DATA_TCP_CMD, PARAM_NUMS_1); + SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + uint16_t len = 0; + + SpiDrv::waitResponseCmd(AVAIL_DATA_TCP_CMD, PARAM_NUMS_1, (uint8_t*)&len, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return len; +} + +uint8_t ServerDrv::availServer(uint8_t sock) +{ + if (!SpiDrv::available()) { + return 255; + } + + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(AVAIL_DATA_TCP_CMD, PARAM_NUMS_1); + SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + uint16_t socket = 0; + + SpiDrv::waitResponseCmd(AVAIL_DATA_TCP_CMD, PARAM_NUMS_1, (uint8_t*)&socket, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return socket; +} + +bool ServerDrv::getData(uint8_t sock, uint8_t *data, uint8_t peek) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(GET_DATA_TCP_CMD, PARAM_NUMS_2); + SpiDrv::sendParam(&sock, sizeof(sock)); + SpiDrv::sendParam(peek, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseData8(GET_DATA_TCP_CMD, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + if (_dataLen!=0) + { + *data = _data; + return true; + } + return false; +} + +bool ServerDrv::getDataBuf(uint8_t sock, uint8_t *_data, uint16_t *_dataLen) +{ + if (!SpiDrv::available()) + { + *_dataLen = 0; + return false; + } + + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(GET_DATABUF_TCP_CMD, PARAM_NUMS_2); + SpiDrv::sendBuffer(&sock, sizeof(sock)); + SpiDrv::sendBuffer((uint8_t *)_dataLen, sizeof(*_dataLen), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + if (!SpiDrv::waitResponseData16(GET_DATABUF_TCP_CMD, _data, _dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + if (*_dataLen!=0) + { + return true; + } + return false; +} + +bool ServerDrv::insertDataBuf(uint8_t sock, const uint8_t *data, uint16_t _len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(INSERT_DATABUF_CMD, PARAM_NUMS_2); + SpiDrv::sendBuffer(&sock, sizeof(sock)); + SpiDrv::sendBuffer((uint8_t *)data, _len, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 9 + _len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseData8(INSERT_DATABUF_CMD, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + if (_dataLen!=0) + { + return (_data == 1); + } + return false; +} + +bool ServerDrv::sendUdpData(uint8_t sock) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SEND_DATA_UDP_CMD, PARAM_NUMS_1); + SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseData8(SEND_DATA_UDP_CMD, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + if (_dataLen!=0) + { + return (_data == 1); + } + return false; +} + + +uint16_t ServerDrv::sendData(uint8_t sock, const uint8_t *data, uint16_t len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SEND_DATA_TCP_CMD, PARAM_NUMS_2); + SpiDrv::sendBuffer(&sock, sizeof(sock)); + SpiDrv::sendBuffer((uint8_t *)data, len, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 9 + len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint16_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseData8(SEND_DATA_TCP_CMD, (uint8_t*)&_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + + return _data; +} + + +uint8_t ServerDrv::checkDataSent(uint8_t sock) +{ + const uint16_t TIMEOUT_DATA_SENT = 25; + uint16_t timeout = 0; + uint8_t _data = 0; + uint8_t _dataLen = 0; + + do { + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(DATA_SENT_TCP_CMD, PARAM_NUMS_1); + SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + if (!SpiDrv::waitResponseCmd(DATA_SENT_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse isDataSent"); + } + SpiDrv::spiSlaveDeselect(); + + if (_data) timeout = 0; + else{ + ++timeout; + delay(100); + } + + }while((_data==0)&&(timeout +#include "utility/wifi_spi.h" + +typedef enum eProtMode {TCP_MODE, UDP_MODE, TLS_MODE, UDP_MULTICAST_MODE, TLS_BEARSSL_MODE}tProtMode; + +class ServerDrv +{ +public: + + // Start server TCP on port specified + static void startServer(uint16_t port, uint8_t sock, uint8_t protMode=TCP_MODE); + + static void startServer(uint32_t ipAddress, uint16_t port, uint8_t sock, uint8_t protMode=TCP_MODE); + + static void startClient(uint32_t ipAddress, uint16_t port, uint8_t sock, uint8_t protMode=TCP_MODE); + + static void startClient(const char* host, uint8_t host_len, uint32_t ipAddress, uint16_t port, uint8_t sock, uint8_t protMode=TCP_MODE); + + static void stopClient(uint8_t sock); + + static uint8_t getServerState(uint8_t sock); + + static uint8_t getClientState(uint8_t sock); + + static bool getData(uint8_t sock, uint8_t *data, uint8_t peek = 0); + + static bool getDataBuf(uint8_t sock, uint8_t *data, uint16_t *len); + + static bool insertDataBuf(uint8_t sock, const uint8_t *_data, uint16_t _dataLen); + + static uint16_t sendData(uint8_t sock, const uint8_t *data, uint16_t len); + + static bool sendUdpData(uint8_t sock); + + static uint16_t availData(uint8_t sock); + + static uint8_t availServer(uint8_t sock); + + static uint8_t checkDataSent(uint8_t sock); + + static uint8_t getSocket(); +}; + +extern ServerDrv serverDrv; + +#endif diff --git a/arduino/libraries/WiFiNINA/src/utility/spi_drv.cpp b/arduino/libraries/WiFiNINA/src/utility/spi_drv.cpp new file mode 100644 index 0000000..744bd85 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/utility/spi_drv.cpp @@ -0,0 +1,584 @@ +/* + spi_drv.cpp - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "Arduino.h" +#include +#include "utility/spi_drv.h" +#include "pins_arduino.h" + +#ifdef ARDUINO_SAMD_MKRVIDOR4000 +// STRIX: the STRIX FPGA image passes the NINA module's pins through to SAMD21 pins, so the +// module is driven directly (SPI on D8-D10) instead of through Arduino's FPGA peripherals. +#define NINA_GPIO0 6 +#define SPIWIFI_SS 5 +#define SPIWIFI_ACK 4 +#define SPIWIFI_RESET 7 +#endif + +//#define _DEBUG_ +extern "C" { +#include "utility/debug.h" +} + +static uint8_t SLAVESELECT = 10; // ss +static uint8_t SLAVEREADY = 7; // handshake pin +static uint8_t SLAVERESET = 5; // reset pin + +static bool inverted_reset = false; + +#define DELAY_TRANSFER() + +#ifndef SPIWIFI +#define SPIWIFI SPI +#endif + +bool SpiDrv::initialized = false; + +__attribute__((weak)) void wifi_nina_feed_watchdog() +{ + /* This function can be overwritten by a "strong" implementation + * in a higher level application, such as the ArduinoIoTCloud + * firmware stack. + */ +} + +void SpiDrv::begin() +{ +#ifdef SPIWIFI_SS + SLAVESELECT = SPIWIFI_SS; +#endif + +#ifdef SPIWIFI_ACK + SLAVEREADY = SPIWIFI_ACK; +#endif + +#ifdef SPIWIFI_RESET + SLAVERESET = (uint8_t)SPIWIFI_RESET; +#endif + +#ifdef ARDUINO_SAMD_MKRVIDOR4000 + inverted_reset = false; +#else + if (SLAVERESET > PINS_COUNT) { + inverted_reset = true; + SLAVERESET = ~SLAVERESET; + } +#endif + + SPIWIFI.begin(); + pinMode(SLAVESELECT, OUTPUT); + pinMode(SLAVEREADY, INPUT); + pinMode(SLAVERESET, OUTPUT); + pinMode(NINA_GPIO0, OUTPUT); + + digitalWrite(NINA_GPIO0, HIGH); + digitalWrite(SLAVESELECT, HIGH); + digitalWrite(SLAVERESET, inverted_reset ? HIGH : LOW); + delay(10); + digitalWrite(SLAVERESET, inverted_reset ? LOW : HIGH); + delay(750); + + digitalWrite(NINA_GPIO0, LOW); + pinMode(NINA_GPIO0, INPUT); + +#ifdef _DEBUG_ + INIT_TRIGGER() +#endif + + initialized = true; +} + +void SpiDrv::end() { + digitalWrite(SLAVERESET, inverted_reset ? HIGH : LOW); + + pinMode(SLAVESELECT, INPUT); + + SPIWIFI.end(); + + initialized = false; +} + +void SpiDrv::spiSlaveSelect() +{ + SPIWIFI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0)); + digitalWrite(SLAVESELECT,LOW); + + // wait for up to 5 ms for the NINA to indicate it is not ready for transfer + // the timeout is only needed for the case when the shield or module is not present + for (unsigned long start = millis(); (digitalRead(SLAVEREADY) != HIGH) && (millis() - start) < 5;); +} + + +void SpiDrv::spiSlaveDeselect() +{ + digitalWrite(SLAVESELECT,HIGH); + SPIWIFI.endTransaction(); +} + + +char SpiDrv::spiTransfer(volatile char data) +{ + char result = SPIWIFI.transfer(data); + DELAY_TRANSFER(); + + return result; // return the received byte +} + +int SpiDrv::waitSpiChar(unsigned char waitChar) +{ + int timeout = TIMEOUT_CHAR; + unsigned char _readChar = 0; + do{ + _readChar = readChar(); //get data byte + if (_readChar == ERR_CMD) + { + WARN("Err cmd received\n"); + return -1; + } + }while((timeout-- > 0) && (_readChar != waitChar)); + return (_readChar == waitChar); +} + +int SpiDrv::readAndCheckChar(char checkChar, char* readChar) +{ + getParam((uint8_t*)readChar); + + return (*readChar == checkChar); +} + +char SpiDrv::readChar() +{ + uint8_t readChar = 0; + getParam(&readChar); + return readChar; +} + +#define WAIT_START_CMD(x) waitSpiChar(START_CMD) + +#define IF_CHECK_START_CMD(x) \ + if (!WAIT_START_CMD(_data)) \ + { \ + TOGGLE_TRIGGER() \ + WARN("Error waiting START_CMD"); \ + return 0; \ + }else \ + +#define CHECK_DATA(check, x) \ + if (!readAndCheckChar(check, &x)) \ + { \ + TOGGLE_TRIGGER() \ + WARN("Reply error"); \ + INFO2(check, (uint8_t)x); \ + return 0; \ + }else \ + +#define waitSlaveReady() (digitalRead(SLAVEREADY) == LOW) +#define waitSlaveSign() (digitalRead(SLAVEREADY) == HIGH) +#define waitSlaveSignalH() while(digitalRead(SLAVEREADY) != HIGH){} +#define waitSlaveSignalL() while(digitalRead(SLAVEREADY) != LOW){} + +void SpiDrv::waitForSlaveSign() +{ + while (!waitSlaveSign()); +} + +void SpiDrv::waitForSlaveReady(bool const feed_watchdog) +{ + unsigned long const start = millis(); + while (!waitSlaveReady()) + { + if (feed_watchdog) { + if ((millis() - start) < 10000) { + wifi_nina_feed_watchdog(); + } + } + } +} + +void SpiDrv::getParam(uint8_t* param) +{ + // Get Params data + *param = spiTransfer(DUMMY_DATA); + DELAY_TRANSFER(); +} + +int SpiDrv::waitResponseCmd(uint8_t cmd, uint8_t numParam, uint8_t* param, uint8_t* param_len) +{ + char _data = 0; + int ii = 0; + + IF_CHECK_START_CMD(_data) + { + CHECK_DATA(cmd | REPLY_FLAG, _data){}; + + CHECK_DATA(numParam, _data) + { + readParamLen8(param_len); + for (ii=0; ii<(*param_len); ++ii) + { + // Get Params data + //param[ii] = spiTransfer(DUMMY_DATA); + getParam(¶m[ii]); + } + } + + readAndCheckChar(END_CMD, &_data); + } + + return 1; +} +/* +int SpiDrv::waitResponse(uint8_t cmd, uint8_t numParam, uint8_t* param, uint16_t* param_len) +{ + char _data = 0; + int i =0, ii = 0; + + IF_CHECK_START_CMD(_data) + { + CHECK_DATA(cmd | REPLY_FLAG, _data){}; + + CHECK_DATA(numParam, _data); + { + readParamLen16(param_len); + for (ii=0; ii<(*param_len); ++ii) + { + // Get Params data + param[ii] = spiTransfer(DUMMY_DATA); + } + } + + readAndCheckChar(END_CMD, &_data); + } + + return 1; +} +*/ + +int SpiDrv::waitResponseData16(uint8_t cmd, uint8_t* param, uint16_t* param_len) +{ + char _data = 0; + uint16_t ii = 0; + + IF_CHECK_START_CMD(_data) + { + CHECK_DATA(cmd | REPLY_FLAG, _data){}; + + uint8_t numParam = readChar(); + if (numParam != 0) + { + readParamLen16(param_len); + for (ii=0; ii<(*param_len); ++ii) + { + // Get Params data + param[ii] = spiTransfer(DUMMY_DATA); + } + } + + readAndCheckChar(END_CMD, &_data); + } + + return 1; +} + +int SpiDrv::waitResponseData8(uint8_t cmd, uint8_t* param, uint8_t* param_len) +{ + char _data = 0; + int ii = 0; + + IF_CHECK_START_CMD(_data) + { + CHECK_DATA(cmd | REPLY_FLAG, _data){}; + + uint8_t numParam = readChar(); + if (numParam != 0) + { + readParamLen8(param_len); + for (ii=0; ii<(*param_len); ++ii) + { + // Get Params data + param[ii] = spiTransfer(DUMMY_DATA); + } + } + + readAndCheckChar(END_CMD, &_data); + } + + return 1; +} + +int SpiDrv::waitResponseParams(uint8_t cmd, uint8_t numParam, tParam* params) +{ + char _data = 0; + int i =0, ii = 0; + + + IF_CHECK_START_CMD(_data) + { + CHECK_DATA(cmd | REPLY_FLAG, _data){}; + + uint8_t _numParam = readChar(); + if (_numParam != 0) + { + for (i=0; i<_numParam; ++i) + { + params[i].paramLen = readParamLen8(); + for (ii=0; ii maxNumParams) + { + numParam = maxNumParams; + } + *numParamRead = numParam; + if (numParam != 0) + { + for (i=0; i maxNumParams) + { + numParam = maxNumParams; + } + *numParamRead = numParam; + if (numParam != 0) + { + for (i=0; i>8)); + spiTransfer((uint8_t)(param_len & 0xff)); +} + +uint8_t SpiDrv::readParamLen8(uint8_t* param_len) +{ + uint8_t _param_len = spiTransfer(DUMMY_DATA); + if (param_len != NULL) + { + *param_len = _param_len; + } + return _param_len; +} + +uint16_t SpiDrv::readParamLen16(uint16_t* param_len) +{ + uint16_t _param_len = spiTransfer(DUMMY_DATA)<<8 | (spiTransfer(DUMMY_DATA)& 0xff); + if (param_len != NULL) + { + *param_len = _param_len; + } + return _param_len; +} + + +void SpiDrv::sendBuffer(uint8_t* param, uint16_t param_len, uint8_t lastParam) +{ + uint16_t i = 0; + + // Send Spi paramLen + sendParamLen16(param_len); + + // Send Spi param data + for (i=0; i>8)); + spiTransfer((uint8_t)(param & 0xff)); + + // if lastParam==1 Send Spi END CMD + if (lastParam == 1) + spiTransfer(END_CMD); +} + +/* Cmd Struct Message */ +/* _________________________________________________________________________________ */ +/*| START CMD | C/R | CMD |[TOT LEN]| N.PARAM | PARAM LEN | PARAM | .. | END CMD | */ +/*|___________|______|______|_________|_________|___________|________|____|_________| */ +/*| 8 bit | 1bit | 7bit | 8bit | 8bit | 8bit | nbytes | .. | 8bit | */ +/*|___________|______|______|_________|_________|___________|________|____|_________| */ + +void SpiDrv::sendCmd(uint8_t cmd, uint8_t numParam) +{ + // Send Spi START CMD + spiTransfer(START_CMD); + + // Send Spi C + cmd + spiTransfer(cmd & ~(REPLY_FLAG)); + + // Send Spi totLen + //spiTransfer(totLen); + + // Send Spi numParam + spiTransfer(numParam); + + // If numParam == 0 send END CMD + if (numParam == 0) + spiTransfer(END_CMD); + +} + +int SpiDrv::available() +{ + return (digitalRead(NINA_GPIO0) != LOW); +} + +SpiDrv spiDrv; diff --git a/arduino/libraries/WiFiNINA/src/utility/spi_drv.h b/arduino/libraries/WiFiNINA/src/utility/spi_drv.h new file mode 100644 index 0000000..d8d1186 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/utility/spi_drv.h @@ -0,0 +1,109 @@ +/* + spi_drv.h - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef SPI_Drv_h +#define SPI_Drv_h + +#include +#include "utility/wifi_spi.h" + +#define SPI_START_CMD_DELAY 10 + +#define NO_LAST_PARAM 0 +#define LAST_PARAM 1 + +#define DUMMY_DATA 0xFF + +#define WAIT_FOR_SLAVE_SELECT() \ + if (!SpiDrv::initialized) { \ + SpiDrv::begin(); \ + } \ + SpiDrv::waitForSlaveReady(); \ + SpiDrv::spiSlaveSelect(); + +class SpiDrv +{ +private: + //static bool waitSlaveReady(); + static void waitForSlaveSign(); + static void getParam(uint8_t* param); +public: + static bool initialized; + + static void begin(); + + static void end(); + + static void spiDriverInit(); + + static void spiSlaveSelect(); + + static void spiSlaveDeselect(); + + static char spiTransfer(volatile char data); + + static void waitForSlaveReady(bool const feed_watchdog = false); + + //static int waitSpiChar(char waitChar, char* readChar); + + static int waitSpiChar(unsigned char waitChar); + + static int readAndCheckChar(char checkChar, char* readChar); + + static char readChar(); + + static int waitResponseParams(uint8_t cmd, uint8_t numParam, tParam* params); + + static int waitResponseCmd(uint8_t cmd, uint8_t numParam, uint8_t* param, uint8_t* param_len); + + static int waitResponseData8(uint8_t cmd, uint8_t* param, uint8_t* param_len); + + static int waitResponseData16(uint8_t cmd, uint8_t* param, uint16_t* param_len); + /* + static int waitResponse(uint8_t cmd, tParam* params, uint8_t* numParamRead, uint8_t maxNumParams); + + static int waitResponse(uint8_t cmd, uint8_t numParam, uint8_t* param, uint16_t* param_len); +*/ + static int waitResponse(uint8_t cmd, uint8_t* numParamRead, uint8_t** params, uint8_t maxNumParams); + + static void sendParam(uint8_t* param, uint8_t param_len, uint8_t lastParam = NO_LAST_PARAM); + + static void sendParamNoLen(uint8_t* param, size_t param_len, uint8_t lastParam = NO_LAST_PARAM); + + static void sendParamLen8(uint8_t param_len); + + static void sendParamLen16(uint16_t param_len); + + static uint8_t readParamLen8(uint8_t* param_len = NULL); + + static uint16_t readParamLen16(uint16_t* param_len = NULL); + + static void sendBuffer(uint8_t* param, uint16_t param_len, uint8_t lastParam = NO_LAST_PARAM); + + static void sendParam(uint16_t param, uint8_t lastParam = NO_LAST_PARAM); + + static void sendCmd(uint8_t cmd, uint8_t numParam); + + static int available(); +}; + +extern SpiDrv spiDrv; + +#endif diff --git a/arduino/libraries/WiFiNINA/src/utility/wifi_drv.cpp b/arduino/libraries/WiFiNINA/src/utility/wifi_drv.cpp new file mode 100644 index 0000000..24beece --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/utility/wifi_drv.cpp @@ -0,0 +1,1262 @@ +/* + wifi_drv.cpp - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +#include "Arduino.h" +#include "utility/spi_drv.h" +#include "utility/wifi_drv.h" + +#define _DEBUG_ + +extern "C" { +#include "utility/wifi_spi.h" +#include "utility/wl_types.h" +#include "utility/debug.h" +} + +// Array of data to cache the information related to the networks discovered +char WiFiDrv::_networkSsid[][WL_SSID_MAX_LENGTH] = {{"1"},{"2"},{"3"},{"4"},{"5"}}; + +// Cached values of retrieved data +char WiFiDrv::_ssid[] = {0}; +uint8_t WiFiDrv::_bssid[] = {0}; +uint8_t WiFiDrv::_mac[] = {0}; +uint8_t WiFiDrv::_localIp[] = {0}; +uint8_t WiFiDrv::_subnetMask[] = {0}; +uint8_t WiFiDrv::_gatewayIp[] = {0}; +// Firmware version +char WiFiDrv::fwVersion[] = {0}; + + +// Private Methods + +void WiFiDrv::getNetworkData(uint8_t *ip, uint8_t *mask, uint8_t *gwip) +{ + tParam params[PARAM_NUMS_3] = { {0, (char*)ip}, {0, (char*)mask}, {0, (char*)gwip}}; + + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_IPADDR_CMD, PARAM_NUMS_1); + + uint8_t _dummy = DUMMY_DATA; + SpiDrv::sendParam(&_dummy, sizeof(_dummy), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + SpiDrv::waitResponseParams(GET_IPADDR_CMD, PARAM_NUMS_3, params); + + SpiDrv::spiSlaveDeselect(); +} + +void WiFiDrv::getRemoteData(uint8_t sock, uint8_t *ip, uint8_t *port) +{ + tParam params[PARAM_NUMS_2] = { {0, (char*)ip}, {0, (char*)port} }; + + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_REMOTE_DATA_CMD, PARAM_NUMS_1); + SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + SpiDrv::waitResponseParams(GET_REMOTE_DATA_CMD, PARAM_NUMS_2, params); + + SpiDrv::spiSlaveDeselect(); +} + + +// Public Methods + + +void WiFiDrv::wifiDriverInit() +{ + SpiDrv::begin(); +} + +void WiFiDrv::wifiDriverDeinit() +{ + SpiDrv::end(); +} + +int8_t WiFiDrv::wifiSetNetwork(const char* ssid, uint8_t ssid_len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_NET_CMD, PARAM_NUMS_1); + SpiDrv::sendParam((uint8_t*)ssid, ssid_len, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 5 + ssid_len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_NET_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + + return(_data == WIFI_SPI_ACK) ? WL_SUCCESS : WL_FAILURE; +} + +int8_t WiFiDrv::wifiSetPassphrase(const char* ssid, uint8_t ssid_len, const char *passphrase, const uint8_t len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_PASSPHRASE_CMD, PARAM_NUMS_2); + SpiDrv::sendParam((uint8_t*)ssid, ssid_len, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)passphrase, len, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 6 + ssid_len + len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_PASSPHRASE_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + + +int8_t WiFiDrv::wifiSetKey(const char* ssid, uint8_t ssid_len, uint8_t key_idx, const void *key, const uint8_t len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_KEY_CMD, PARAM_NUMS_3); + SpiDrv::sendParam((uint8_t*)ssid, ssid_len, NO_LAST_PARAM); + SpiDrv::sendParam(&key_idx, KEY_IDX_LEN, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)key, len, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 8 + ssid_len + len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_KEY_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +void WiFiDrv::config(uint8_t validParams, uint32_t local_ip, uint32_t gateway, uint32_t subnet) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_IP_CONFIG_CMD, PARAM_NUMS_4); + SpiDrv::sendParam((uint8_t*)&validParams, 1, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&local_ip, 4, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&gateway, 4, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&subnet, 4, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_IP_CONFIG_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + +void WiFiDrv::setDNS(uint8_t validParams, uint32_t dns_server1, uint32_t dns_server2) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_DNS_CONFIG_CMD, PARAM_NUMS_3); + SpiDrv::sendParam((uint8_t*)&validParams, 1, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&dns_server1, 4, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&dns_server2, 4, LAST_PARAM); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_DNS_CONFIG_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + +void WiFiDrv::setHostname(const char* hostname) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_HOSTNAME_CMD, PARAM_NUMS_1); + SpiDrv::sendParam((uint8_t*)hostname, strlen(hostname), LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 5 + strlen(hostname); + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_HOSTNAME_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + +int8_t WiFiDrv::disconnect() +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(DISCONNECT_CMD, PARAM_NUMS_1); + + uint8_t _dummy = DUMMY_DATA; + SpiDrv::sendParam(&_dummy, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + int8_t result = SpiDrv::waitResponseCmd(DISCONNECT_CMD, PARAM_NUMS_1, &_data, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return result; +} + +uint8_t WiFiDrv::getReasonCode() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_REASON_CODE_CMD, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 1; + uint8_t _dataLen = 0; + SpiDrv::waitResponseCmd(GET_REASON_CODE_CMD, PARAM_NUMS_1, &_data, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return _data; +} + +uint8_t WiFiDrv::getConnectionStatus() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_CONN_STATUS_CMD, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = -1; + uint8_t _dataLen = 0; + SpiDrv::waitResponseCmd(GET_CONN_STATUS_CMD, PARAM_NUMS_1, &_data, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return _data; +} + +uint8_t* WiFiDrv::getMacAddress() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_MACADDR_CMD, PARAM_NUMS_1); + + uint8_t _dummy = DUMMY_DATA; + SpiDrv::sendParam(&_dummy, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + SpiDrv::waitResponseCmd(GET_MACADDR_CMD, PARAM_NUMS_1, _mac, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return _mac; +} + +void WiFiDrv::getIpAddress(IPAddress& ip) +{ + getNetworkData(_localIp, _subnetMask, _gatewayIp); + ip = _localIp; +} + + void WiFiDrv::getSubnetMask(IPAddress& mask) + { + getNetworkData(_localIp, _subnetMask, _gatewayIp); + mask = _subnetMask; + } + + void WiFiDrv::getGatewayIP(IPAddress& ip) + { + getNetworkData(_localIp, _subnetMask, _gatewayIp); + ip = _gatewayIp; + } + +const char* WiFiDrv::getCurrentSSID() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_CURR_SSID_CMD, PARAM_NUMS_1); + + uint8_t _dummy = DUMMY_DATA; + SpiDrv::sendParam(&_dummy, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + memset(_ssid, 0x00, sizeof(_ssid)); + + // Wait for reply + uint8_t _dataLen = 0; + SpiDrv::waitResponseCmd(GET_CURR_SSID_CMD, PARAM_NUMS_1, (uint8_t*)_ssid, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return _ssid; +} + +uint8_t* WiFiDrv::getCurrentBSSID() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_CURR_BSSID_CMD, PARAM_NUMS_1); + + uint8_t _dummy = DUMMY_DATA; + SpiDrv::sendParam(&_dummy, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + SpiDrv::waitResponseCmd(GET_CURR_BSSID_CMD, PARAM_NUMS_1, _bssid, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return _bssid; +} + +int32_t WiFiDrv::getCurrentRSSI() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_CURR_RSSI_CMD, PARAM_NUMS_1); + + uint8_t _dummy = DUMMY_DATA; + SpiDrv::sendParam(&_dummy, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + int32_t rssi = 0; + SpiDrv::waitResponseCmd(GET_CURR_RSSI_CMD, PARAM_NUMS_1, (uint8_t*)&rssi, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return rssi; +} + +uint8_t WiFiDrv::getCurrentEncryptionType() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_CURR_ENCT_CMD, PARAM_NUMS_1); + + uint8_t _dummy = DUMMY_DATA; + SpiDrv::sendParam(&_dummy, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t dataLen = 0; + uint8_t encType = 0; + SpiDrv::waitResponseCmd(GET_CURR_ENCT_CMD, PARAM_NUMS_1, (uint8_t*)&encType, &dataLen); + + SpiDrv::spiSlaveDeselect(); + + return encType; +} + +int8_t WiFiDrv::startScanNetworks() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(START_SCAN_NETWORKS, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + + if (!SpiDrv::waitResponseCmd(START_SCAN_NETWORKS, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + + SpiDrv::spiSlaveDeselect(); + + return ((int8_t)_data == WL_FAILURE)? _data : (int8_t)WL_SUCCESS; +} + + +uint8_t WiFiDrv::getScanNetworks() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(SCAN_NETWORKS, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t ssidListNum = 0; + SpiDrv::waitResponse(SCAN_NETWORKS, &ssidListNum, (uint8_t**)_networkSsid, WL_NETWORKS_LIST_MAXNUM); + + SpiDrv::spiSlaveDeselect(); + + return ssidListNum; +} + +const char* WiFiDrv::getSSIDNetoworks(uint8_t networkItem) +{ + if (networkItem >= WL_NETWORKS_LIST_MAXNUM) + return (char*)NULL; + + return _networkSsid[networkItem]; +} + +uint8_t WiFiDrv::getEncTypeNetowrks(uint8_t networkItem) +{ + if (networkItem >= WL_NETWORKS_LIST_MAXNUM) + return ENC_TYPE_UNKNOWN; + + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_IDX_ENCT_CMD, PARAM_NUMS_1); + + SpiDrv::sendParam(&networkItem, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t dataLen = 0; + uint8_t encType = 0; + SpiDrv::waitResponseCmd(GET_IDX_ENCT_CMD, PARAM_NUMS_1, (uint8_t*)&encType, &dataLen); + + SpiDrv::spiSlaveDeselect(); + + return encType; +} + +uint8_t* WiFiDrv::getBSSIDNetowrks(uint8_t networkItem, uint8_t* bssid) +{ + if (networkItem >= WL_NETWORKS_LIST_MAXNUM) + return NULL; + + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_IDX_BSSID, PARAM_NUMS_1); + + SpiDrv::sendParam(&networkItem, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t dataLen = 0; + SpiDrv::waitResponseCmd(GET_IDX_BSSID, PARAM_NUMS_1, (uint8_t*)bssid, &dataLen); + + SpiDrv::spiSlaveDeselect(); + + return bssid; +} + +uint8_t WiFiDrv::getChannelNetowrks(uint8_t networkItem) +{ + if (networkItem >= WL_NETWORKS_LIST_MAXNUM) + return 0; + + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_IDX_CHANNEL_CMD, PARAM_NUMS_1); + + SpiDrv::sendParam(&networkItem, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t dataLen = 0; + uint8_t channel = 0; + SpiDrv::waitResponseCmd(GET_IDX_CHANNEL_CMD, PARAM_NUMS_1, (uint8_t*)&channel, &dataLen); + + SpiDrv::spiSlaveDeselect(); + + return channel; +} + +int32_t WiFiDrv::getRSSINetoworks(uint8_t networkItem) +{ + if (networkItem >= WL_NETWORKS_LIST_MAXNUM) + return 0; + int32_t networkRssi = 0; + + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_IDX_RSSI_CMD, PARAM_NUMS_1); + + SpiDrv::sendParam(&networkItem, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t dataLen = 0; + SpiDrv::waitResponseCmd(GET_IDX_RSSI_CMD, PARAM_NUMS_1, (uint8_t*)&networkRssi, &dataLen); + + SpiDrv::spiSlaveDeselect(); + + return networkRssi; +} + +uint8_t WiFiDrv::reqHostByName(const char* aHostname) +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(REQ_HOST_BY_NAME_CMD, PARAM_NUMS_1); + SpiDrv::sendParam((uint8_t*)aHostname, strlen(aHostname), LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 5 + strlen(aHostname); + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + uint8_t result = SpiDrv::waitResponseCmd(REQ_HOST_BY_NAME_CMD, PARAM_NUMS_1, &_data, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + if (result) { + result = (_data == 1); + } + + return result; +} + +int WiFiDrv::getHostByName(IPAddress& aResult) +{ + uint8_t _ipAddr[WL_IPV4_LENGTH]; + IPAddress dummy(0xFF,0xFF,0xFF,0xFF); + int result = 0; + + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(GET_HOST_BY_NAME_CMD, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(GET_HOST_BY_NAME_CMD, PARAM_NUMS_1, _ipAddr, &_dataLen)) + { + WARN("error waitResponse"); + }else{ + aResult = _ipAddr; + result = (aResult != dummy); + } + SpiDrv::spiSlaveDeselect(); + return result; +} + +int WiFiDrv::getHostByName(const char* aHostname, IPAddress& aResult) +{ + if (reqHostByName(aHostname)) + { + return getHostByName(aResult); + }else{ + return 0; + } +} + +const char* WiFiDrv::getFwVersion() +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(GET_FW_VERSION_CMD, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(GET_FW_VERSION_CMD, PARAM_NUMS_1, (uint8_t*)fwVersion, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + return fwVersion; +} + +uint32_t WiFiDrv::getTime() +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(GET_TIME_CMD, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + uint32_t _data = 0; + if (!SpiDrv::waitResponseCmd(GET_TIME_CMD, PARAM_NUMS_1, (uint8_t*)&_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +void WiFiDrv::setPowerMode(uint8_t mode) +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(SET_POWER_MODE_CMD, PARAM_NUMS_1); + + SpiDrv::sendParam(&mode, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t dataLen = 0; + uint8_t data = 0; + SpiDrv::waitResponseCmd(SET_POWER_MODE_CMD, PARAM_NUMS_1, &data, &dataLen); + + SpiDrv::spiSlaveDeselect(); +} + +int8_t WiFiDrv::wifiSetApNetwork(const char* ssid, uint8_t ssid_len, uint8_t channel) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_AP_NET_CMD, PARAM_NUMS_2); + SpiDrv::sendParam((uint8_t*)ssid, ssid_len); + SpiDrv::sendParam(&channel, 1, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 3 + ssid_len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_AP_NET_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + + return(_data == WIFI_SPI_ACK) ? WL_SUCCESS : WL_FAILURE; +} + +int8_t WiFiDrv::wifiSetApPassphrase(const char* ssid, uint8_t ssid_len, const char *passphrase, const uint8_t len, uint8_t channel) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_AP_PASSPHRASE_CMD, PARAM_NUMS_3); + SpiDrv::sendParam((uint8_t*)ssid, ssid_len, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)passphrase, len, NO_LAST_PARAM); + SpiDrv::sendParam(&channel, 1, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 4 + ssid_len + len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_AP_PASSPHRASE_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +int8_t WiFiDrv::wifiSetEnterprise(uint8_t eapType, const char* ssid, uint8_t ssid_len, const char *username, const uint8_t username_len, const char *password, const uint8_t password_len, const char *identity, const uint8_t identity_len, const char* ca_cert, uint16_t ca_cert_len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_ENT_CMD, PARAM_NUMS_6); + SpiDrv::sendBuffer(&eapType, sizeof(eapType)); + SpiDrv::sendBuffer((uint8_t*)ssid, ssid_len); + SpiDrv::sendBuffer((uint8_t*)username, username_len); + SpiDrv::sendBuffer((uint8_t*)password, password_len); + SpiDrv::sendBuffer((uint8_t*)identity, identity_len); + SpiDrv::sendBuffer((uint8_t*)ca_cert, ca_cert_len, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 15 + sizeof(eapType) + ssid_len + username_len + password_len + identity_len + ca_cert_len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_ENT_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +int16_t WiFiDrv::ping(uint32_t ipAddress, uint8_t ttl) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(PING_CMD, PARAM_NUMS_2); + SpiDrv::sendParam((uint8_t*)&ipAddress, sizeof(ipAddress), NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&ttl, sizeof(ttl), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint16_t _data; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(PING_CMD, PARAM_NUMS_1, (uint8_t*)&_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_PING_ERROR; + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +void WiFiDrv::debug(uint8_t on) +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(SET_DEBUG_CMD, PARAM_NUMS_1); + + SpiDrv::sendParam(&on, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t dataLen = 0; + uint8_t data = 0; + SpiDrv::waitResponseCmd(SET_DEBUG_CMD, PARAM_NUMS_1, &data, &dataLen); + + SpiDrv::spiSlaveDeselect(); +} + +float WiFiDrv::getTemperature() +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(GET_TEMPERATURE_CMD, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + float _data = 0; + if (!SpiDrv::waitResponseCmd(GET_TEMPERATURE_CMD, PARAM_NUMS_1, (uint8_t*)&_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +void WiFiDrv::pinMode(uint8_t pin, uint8_t mode) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_PIN_MODE, PARAM_NUMS_2); + SpiDrv::sendParam((uint8_t*)&pin, 1, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&mode, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_PIN_MODE, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + +void WiFiDrv::digitalWrite(uint8_t pin, uint8_t value) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_DIGITAL_WRITE, PARAM_NUMS_2); + SpiDrv::sendParam((uint8_t*)&pin, 1, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&value, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_DIGITAL_WRITE, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + +void WiFiDrv::analogWrite(uint8_t pin, uint8_t value) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_ANALOG_WRITE, PARAM_NUMS_2); + SpiDrv::sendParam((uint8_t*)&pin, 1, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&value, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_ANALOG_WRITE, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + +int8_t WiFiDrv::downloadFile(const char* url, uint8_t url_len, const char *filename, uint8_t filename_len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(DOWNLOAD_FILE, PARAM_NUMS_2); + SpiDrv::sendParam((uint8_t*)url, url_len, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)filename, filename_len, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 6 + url_len + filename_len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(DOWNLOAD_FILE, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +int8_t WiFiDrv::downloadOTA(const char* url, uint8_t url_len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(DOWNLOAD_OTA, PARAM_NUMS_1); + SpiDrv::sendParam((uint8_t*)url, url_len, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 5 + url_len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(DOWNLOAD_OTA, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +int8_t WiFiDrv::renameFile(const char * old_file_name, uint8_t const old_file_name_len, const char * new_file_name, uint8_t const new_file_name_len) +{ + WAIT_FOR_SLAVE_SELECT(); + /* Send Command */ + SpiDrv::sendCmd(RENAME_FILE, PARAM_NUMS_2); + SpiDrv::sendParam((uint8_t*)old_file_name, old_file_name_len, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)new_file_name, new_file_name_len, LAST_PARAM); + + /* pad to multiple of 4 */ + int commandSize = 6 + old_file_name_len + new_file_name_len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + /* Wait the reply elaboration */ + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + /* Wait for reply */ + uint8_t data = 0; + uint8_t dataLen = 0; + if (!SpiDrv::waitResponseCmd(RENAME_FILE, PARAM_NUMS_1, &data, &dataLen)) + { + WARN("error waitResponse"); + data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + return data; +} + +int8_t WiFiDrv::fileOperation(uint8_t operation, const char *filename, uint8_t filename_len, uint32_t offset, uint8_t* buffer, uint32_t len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + uint8_t numParams = PARAM_NUMS_3; + if (operation == WRITE_FILE) { + numParams = PARAM_NUMS_4; + } + + SpiDrv::sendCmd(operation, numParams); + SpiDrv::sendParam((uint8_t*)&offset, sizeof(offset), NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&len, sizeof(len), NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)filename, filename_len, (operation == WRITE_FILE) ? NO_LAST_PARAM : LAST_PARAM); + if (operation == WRITE_FILE) { + SpiDrv::sendParamNoLen((uint8_t*)buffer, len, LAST_PARAM); + } + + // pad to multiple of 4 + int commandSize = 4 + numParams + sizeof(offset) + sizeof(len) + filename_len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + SpiDrv::waitResponseCmd(operation, PARAM_NUMS_1, (operation == WRITE_FILE) ? &_data : buffer, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + return _dataLen; +} + +void WiFiDrv::applyOTA() { + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(APPLY_OTA_COMMAND, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + + // don't wait for return; OTA operation should be fire and forget :) +} + + +WiFiDrv wiFiDrv; diff --git a/arduino/libraries/WiFiNINA/src/utility/wifi_drv.h b/arduino/libraries/WiFiNINA/src/utility/wifi_drv.h new file mode 100644 index 0000000..b641301 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/utility/wifi_drv.h @@ -0,0 +1,326 @@ +/* + wifi_drv.h - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WiFi_Drv_h +#define WiFi_Drv_h + +#include +#include "utility/wifi_spi.h" +#include "IPAddress.h" +#include "WiFiUdp.h" +#include "WiFiClient.h" + +// Key index length +#define KEY_IDX_LEN 1 +// 100 msecs of delay to have the connection established +#define WL_DELAY_START_CONNECTION 100 +// firmware version string length +#define WL_FW_VER_LENGTH 6 + +class WiFiDrv +{ +private: + // settings of requested network + static char _networkSsid[WL_NETWORKS_LIST_MAXNUM][WL_SSID_MAX_LENGTH]; + + // firmware version string in the format a.b.c + static char fwVersion[WL_FW_VER_LENGTH]; + + // settings of current selected network + static char _ssid[WL_SSID_MAX_LENGTH]; + static uint8_t _bssid[WL_MAC_ADDR_LENGTH]; + static uint8_t _mac[WL_MAC_ADDR_LENGTH]; + static uint8_t _localIp[WL_IPV4_LENGTH]; + static uint8_t _subnetMask[WL_IPV4_LENGTH]; + static uint8_t _gatewayIp[WL_IPV4_LENGTH]; + + /* + * Get network Data information + */ + static void getNetworkData(uint8_t *ip, uint8_t *mask, uint8_t *gwip); + + static uint8_t reqHostByName(const char* aHostname); + + static int getHostByName(IPAddress& aResult); + + /* + * Get remote Data information on UDP socket + */ + static void getRemoteData(uint8_t sock, uint8_t *ip, uint8_t *port); + +public: + + /* + * Driver initialization + */ + static void wifiDriverInit(); + + static void wifiDriverDeinit(); + + /* + * Set the desired network which the connection manager should try to + * connect to. + * + * The ssid of the desired network should be specified. + * + * param ssid: The ssid of the desired network. + * param ssid_len: Length of ssid string. + * return: WL_SUCCESS or WL_FAILURE + */ + static int8_t wifiSetNetwork(const char* ssid, uint8_t ssid_len); + + /* Start WiFi connection with passphrase + * the most secure supported mode will be automatically selected + * + * param ssid: Pointer to the SSID string. + * param ssid_len: Length of ssid string. + * param passphrase: Passphrase. Valid characters in a passphrase + * must be between ASCII 32-126 (decimal). + * param len: Length of passphrase string. + * return: WL_SUCCESS or WL_FAILURE + */ + static int8_t wifiSetPassphrase(const char* ssid, uint8_t ssid_len, const char *passphrase, const uint8_t len); + + /* Start WiFi connection with WEP encryption. + * Configure a key into the device. The key type (WEP-40, WEP-104) + * is determined by the size of the key (5 bytes for WEP-40, 13 bytes for WEP-104). + * + * param ssid: Pointer to the SSID string. + * param ssid_len: Length of ssid string. + * param key_idx: The key index to set. Valid values are 0-3. + * param key: Key input buffer. + * param len: Length of key string. + * return: WL_SUCCESS or WL_FAILURE + */ + static int8_t wifiSetKey(const char* ssid, uint8_t ssid_len, uint8_t key_idx, const void *key, const uint8_t len); + + static int8_t wifiSetApNetwork(const char* ssid, uint8_t ssid_len); + static int8_t wifiSetApPassphrase(const char* ssid, uint8_t ssid_len, const char *passphrase, const uint8_t len); + + /* Set ip configuration disabling dhcp client + * + * param validParams: set the number of parameters that we want to change + * i.e. validParams = 1 means that we'll change only ip address + * validParams = 3 means that we'll change ip address, gateway and netmask + * param local_ip: Static ip configuration + * param gateway: Static gateway configuration + * param subnet: Static subnet mask configuration + */ + static void config(uint8_t validParams, uint32_t local_ip, uint32_t gateway, uint32_t subnet); + + /* Set DNS ip configuration + * + * param validParams: set the number of parameters that we want to change + * i.e. validParams = 1 means that we'll change only dns_server1 + * validParams = 2 means that we'll change dns_server1 and dns_server2 + * param dns_server1: Static DNS server1 configuration + * param dns_server2: Static DNS server2 configuration + */ + static void setDNS(uint8_t validParams, uint32_t dns_server1, uint32_t dns_server2); + + static void setHostname(const char* hostname); + + /* + * Disconnect from the network + * + * return: WL_SUCCESS or WL_FAILURE + */ + static int8_t disconnect(); + + static uint8_t getReasonCode(); + + /* + * Disconnect from the network + * + * return: one value of wl_status_t enum + */ + static uint8_t getConnectionStatus(); + + /* + * Get the interface MAC address. + * + * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + */ + static uint8_t* getMacAddress(); + + /* + * Get the interface IP address. + * + * return: copy the ip address value in IPAddress object + */ + static void getIpAddress(IPAddress& ip); + + /* + * Get the interface subnet mask address. + * + * return: copy the subnet mask address value in IPAddress object + */ + static void getSubnetMask(IPAddress& mask); + + /* + * Get the gateway ip address. + * + * return: copy the gateway ip address value in IPAddress object + */ + static void getGatewayIP(IPAddress& ip); + + /* + * Return the current SSID associated with the network + * + * return: ssid string + */ + static const char* getCurrentSSID(); + + /* + * Return the current BSSID associated with the network. + * It is the MAC address of the Access Point + * + * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + */ + static uint8_t* getCurrentBSSID(); + + /* + * Return the current RSSI /Received Signal Strength in dBm) + * associated with the network + * + * return: signed value + */ + static int32_t getCurrentRSSI(); + + /* + * Return the Encryption Type associated with the network + * + * return: one value of wl_enc_type enum + */ + static uint8_t getCurrentEncryptionType(); + + /* + * Start scan WiFi networks available + * + * return: Number of discovered networks + */ + static int8_t startScanNetworks(); + + /* + * Get the networks available + * + * return: Number of discovered networks + */ + static uint8_t getScanNetworks(); + + /* + * Return the SSID discovered during the network scan. + * + * param networkItem: specify from which network item want to get the information + * + * return: ssid string of the specified item on the networks scanned list + */ + static const char* getSSIDNetoworks(uint8_t networkItem); + + /* + * Return the RSSI of the networks discovered during the scanNetworks + * + * param networkItem: specify from which network item want to get the information + * + * return: signed value of RSSI of the specified item on the networks scanned list + */ + static int32_t getRSSINetoworks(uint8_t networkItem); + + /* + * Return the encryption type of the networks discovered during the scanNetworks + * + * param networkItem: specify from which network item want to get the information + * + * return: encryption type (enum wl_enc_type) of the specified item on the networks scanned list + */ + static uint8_t getEncTypeNetowrks(uint8_t networkItem); + + static uint8_t* getBSSIDNetowrks(uint8_t networkItem, uint8_t* bssid); + + static uint8_t getChannelNetowrks(uint8_t networkItem); + + /* + * Resolve the given hostname to an IP address. + * param aHostname: Name to be resolved + * param aResult: IPAddress structure to store the returned IP address + * result: 1 if aIPAddrString was successfully converted to an IP address, + * else error code + */ + static int getHostByName(const char* aHostname, IPAddress& aResult); + + /* + * Get the firmware version + * result: version as string with this format a.b.c + */ + static const char* getFwVersion(); + + static uint32_t getTime(); + + static void setPowerMode(uint8_t mode); + + static int8_t wifiSetApNetwork(const char* ssid, uint8_t ssid_len, uint8_t channel); + static int8_t wifiSetApPassphrase(const char* ssid, uint8_t ssid_len, const char *passphrase, const uint8_t len, uint8_t channel); + static int8_t wifiSetEnterprise(uint8_t eapType, + const char* ssid, uint8_t ssid_len, + const char *username, const uint8_t username_len, + const char *password, const uint8_t password_len, + const char *identity, const uint8_t identity_len, + const char* ca_cert, uint16_t ca_cert_len); + + + static int16_t ping(uint32_t ipAddress, uint8_t ttl); + + static void debug(uint8_t on); + static float getTemperature(); + static void pinMode(uint8_t pin, uint8_t mode); + static void digitalWrite(uint8_t pin, uint8_t value); + static void analogWrite(uint8_t pin, uint8_t value); + + static int8_t downloadFile(const char* url, uint8_t url_len, const char *filename, uint8_t filename_len); + static int8_t downloadOTA(const char* url, uint8_t url_len); + static int8_t renameFile(const char * old_file_name, uint8_t const old_file_name_len, const char * new_file_name, uint8_t const new_file_name_len); + + static int8_t fileOperation(uint8_t operation, const char *filename, uint8_t filename_len, uint32_t offset, uint8_t* buffer, uint32_t len); + + static int8_t readFile(const char *filename, uint8_t filename_len, uint32_t offset, uint8_t* buffer, uint32_t buffer_len) { + return fileOperation(READ_FILE, filename, filename_len, offset, buffer, buffer_len); + }; + static int8_t writeFile(const char *filename, uint8_t filename_len, uint32_t offset, uint8_t* buffer, uint32_t buffer_len) { + return fileOperation(WRITE_FILE, filename, filename_len, offset, buffer, buffer_len); + }; + static int8_t deleteFile(const char *filename, uint8_t filename_len) { + return fileOperation(DELETE_FILE, filename, filename_len, 0, NULL, 0); + }; + static int8_t existsFile(const char *filename, uint8_t filename_len, uint32_t* len) { + int32_t length = 0; + fileOperation(EXISTS_FILE, filename, filename_len, 0, (uint8_t*)&length, sizeof(length)); + *len = length; + return length >= 0; + }; + + static void applyOTA(); + + friend class WiFiUDP; + friend class WiFiClient; +}; + +extern WiFiDrv wiFiDrv; + +#endif diff --git a/arduino/libraries/WiFiNINA/src/utility/wifi_spi.h b/arduino/libraries/WiFiNINA/src/utility/wifi_spi.h new file mode 100644 index 0000000..0dc4681 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/utility/wifi_spi.h @@ -0,0 +1,203 @@ +/* + wifi_spi.h - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WiFi_Spi_h +#define WiFi_Spi_h + +#include +#include "utility/wl_definitions.h" + +#define CMD_FLAG 0 +#define REPLY_FLAG 1<<7 +#define DATA_FLAG 0x40 + +#define WIFI_SPI_ACK 1 +#define WIFI_SPI_ERR 0xFF + +#define TIMEOUT_CHAR 1000 + +//#define MAX_SOCK_NUM 4 /**< Maxmium number of socket */ +#define NO_SOCKET_AVAIL 255 + +#define START_CMD 0xE0 +#define END_CMD 0xEE +#define ERR_CMD 0xEF +#define CMD_POS 1 // Position of Command OpCode on SPI stream +#define PARAM_LEN_POS 2 // Position of Param len on SPI stream + + +enum { + SET_NET_CMD = 0x10, + SET_PASSPHRASE_CMD = 0x11, + SET_KEY_CMD = 0x12, +// TEST_CMD = 0x13, + SET_IP_CONFIG_CMD = 0x14, + SET_DNS_CONFIG_CMD = 0x15, + SET_HOSTNAME_CMD = 0x16, + SET_POWER_MODE_CMD = 0x17, + SET_AP_NET_CMD = 0x18, + SET_AP_PASSPHRASE_CMD = 0x19, + SET_DEBUG_CMD = 0x1A, + GET_TEMPERATURE_CMD = 0x1B, + GET_REASON_CODE_CMD = 0x1F, + + GET_CONN_STATUS_CMD = 0x20, + GET_IPADDR_CMD = 0x21, + GET_MACADDR_CMD = 0x22, + GET_CURR_SSID_CMD = 0x23, + GET_CURR_BSSID_CMD = 0x24, + GET_CURR_RSSI_CMD = 0x25, + GET_CURR_ENCT_CMD = 0x26, + SCAN_NETWORKS = 0x27, + START_SERVER_TCP_CMD= 0x28, + GET_STATE_TCP_CMD = 0x29, + DATA_SENT_TCP_CMD = 0x2A, + AVAIL_DATA_TCP_CMD = 0x2B, + GET_DATA_TCP_CMD = 0x2C, + START_CLIENT_TCP_CMD= 0x2D, + STOP_CLIENT_TCP_CMD = 0x2E, + GET_CLIENT_STATE_TCP_CMD= 0x2F, + DISCONNECT_CMD = 0x30, +// GET_IDX_SSID_CMD = 0x31, + GET_IDX_RSSI_CMD = 0x32, + GET_IDX_ENCT_CMD = 0x33, + REQ_HOST_BY_NAME_CMD= 0x34, + GET_HOST_BY_NAME_CMD= 0x35, + START_SCAN_NETWORKS = 0x36, + GET_FW_VERSION_CMD = 0x37, +// GET_TEST_CMD = 0x38, + SEND_DATA_UDP_CMD = 0x39, + GET_REMOTE_DATA_CMD = 0x3A, + GET_TIME_CMD = 0x3B, + GET_IDX_BSSID = 0x3C, + GET_IDX_CHANNEL_CMD = 0x3D, + PING_CMD = 0x3E, + GET_SOCKET_CMD = 0x3F, + + // All command with DATA_FLAG 0x40 send a 16bit Len + SET_ENT_CMD = 0x40, + + SEND_DATA_TCP_CMD = 0x44, + GET_DATABUF_TCP_CMD = 0x45, + INSERT_DATABUF_CMD = 0x46, + + // regular format commands + SET_PIN_MODE = 0x50, + SET_DIGITAL_WRITE = 0x51, + SET_ANALOG_WRITE = 0x52, + + // regular format commands + WRITE_FILE = 0x60, + READ_FILE = 0x61, + DELETE_FILE = 0x62, + EXISTS_FILE = 0x63, + DOWNLOAD_FILE = 0x64, + APPLY_OTA_COMMAND = 0x65, + RENAME_FILE = 0x66, + DOWNLOAD_OTA = 0x67, +}; + + +enum wl_tcp_state { + CLOSED = 0, + LISTEN = 1, + SYN_SENT = 2, + SYN_RCVD = 3, + ESTABLISHED = 4, + FIN_WAIT_1 = 5, + FIN_WAIT_2 = 6, + CLOSE_WAIT = 7, + CLOSING = 8, + LAST_ACK = 9, + TIME_WAIT = 10 +}; + + +enum numParams{ + PARAM_NUMS_0, + PARAM_NUMS_1, + PARAM_NUMS_2, + PARAM_NUMS_3, + PARAM_NUMS_4, + PARAM_NUMS_5, + PARAM_NUMS_6, + MAX_PARAM_NUMS +}; + +#define MAX_PARAMS MAX_PARAM_NUMS-1 +#define PARAM_LEN_SIZE 1 + +typedef struct __attribute__((__packed__)) +{ + uint8_t paramLen; + char* param; +}tParam; + +typedef struct __attribute__((__packed__)) +{ + uint16_t dataLen; + char* data; +}tDataParam; + + +typedef struct __attribute__((__packed__)) +{ + unsigned char cmd; + unsigned char tcmd; + unsigned char nParam; + tParam params[MAX_PARAMS]; +}tSpiMsg; + +typedef struct __attribute__((__packed__)) +{ + unsigned char cmd; + unsigned char tcmd; + unsigned char nParam; + tDataParam params[MAX_PARAMS]; +}tSpiMsgData; + + +typedef struct __attribute__((__packed__)) +{ + unsigned char cmd; + unsigned char tcmd; + //unsigned char totLen; + unsigned char nParam; +}tSpiHdr; + +typedef struct __attribute__((__packed__)) +{ + uint8_t paramLen; + uint32_t param; +}tLongParam; + +typedef struct __attribute__((__packed__)) +{ + uint8_t paramLen; + uint16_t param; +}tIntParam; + +typedef struct __attribute__((__packed__)) +{ + uint8_t paramLen; + uint8_t param; +}tByteParam; + +#endif diff --git a/arduino/libraries/WiFiNINA/src/utility/wl_definitions.h b/arduino/libraries/WiFiNINA/src/utility/wl_definitions.h new file mode 100644 index 0000000..dc14045 --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/utility/wl_definitions.h @@ -0,0 +1,77 @@ +/* + wl_definitions.h - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/* + * wl_definitions.h + * + * Created on: Mar 6, 2011 + * Author: dlafauci + */ + +#ifndef WL_DEFINITIONS_H_ +#define WL_DEFINITIONS_H_ + +// Maximum size of a SSID +#define WL_SSID_MAX_LENGTH 32 +// Length of passphrase. Valid lengths are 8-63. +#define WL_WPA_KEY_MAX_LENGTH 63 +// Length of key in bytes. Valid values are 5 and 13. +#define WL_WEP_KEY_MAX_LENGTH 13 +// Size of a MAC-address or BSSID +#define WL_MAC_ADDR_LENGTH 6 +// Size of a MAC-address or BSSID +#define WL_IPV4_LENGTH 4 +// Maximum size of a SSID list +#define WL_NETWORKS_LIST_MAXNUM 10 +// Maxmium number of socket +#define WIFI_MAX_SOCK_NUM 10 +// Socket not available constant +#define SOCK_NOT_AVAIL 255 +// Default state value for WiFi state field +#define NA_STATE -1 + +typedef enum { + WL_NO_SHIELD = 255, + WL_NO_MODULE = WL_NO_SHIELD, + WL_IDLE_STATUS = 0, + WL_NO_SSID_AVAIL, + WL_SCAN_COMPLETED, + WL_CONNECTED, + WL_CONNECT_FAILED, + WL_CONNECTION_LOST, + WL_DISCONNECTED, + WL_AP_LISTENING, + WL_AP_CONNECTED, + WL_AP_FAILED +} wl_status_t; + +/* Encryption modes */ +enum wl_enc_type { /* Values map to 802.11 encryption suites... */ + ENC_TYPE_WEP = 5, + ENC_TYPE_TKIP = 2, + ENC_TYPE_CCMP = 4, + /* ... except these two, 7 and 8 are reserved in 802.11-2007 */ + ENC_TYPE_NONE = 7, + ENC_TYPE_AUTO = 8, + + ENC_TYPE_UNKNOWN = 255 +}; + + +#endif /* WL_DEFINITIONS_H_ */ diff --git a/arduino/libraries/WiFiNINA/src/utility/wl_types.h b/arduino/libraries/WiFiNINA/src/utility/wl_types.h new file mode 100644 index 0000000..ff0187e --- /dev/null +++ b/arduino/libraries/WiFiNINA/src/utility/wl_types.h @@ -0,0 +1,57 @@ +/* + wl_types.h - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/* + * wl_types.h + * + * Created on: Jul 30, 2010 + * Author: dlafauci + */ + + +#ifndef _WL_TYPES_H_ +#define _WL_TYPES_H_ + +#include + +typedef enum { + WL_FAILURE = -1, + WL_SUCCESS = 1, +} wl_error_code_t; + +/* Authentication modes */ +enum wl_auth_mode { + AUTH_MODE_INVALID, + AUTH_MODE_AUTO, + AUTH_MODE_OPEN_SYSTEM, + AUTH_MODE_SHARED_KEY, + AUTH_MODE_WPA, + AUTH_MODE_WPA2, + AUTH_MODE_WPA_PSK, + AUTH_MODE_WPA2_PSK +}; + +typedef enum { + WL_PING_DEST_UNREACHABLE = -1, + WL_PING_TIMEOUT = -2, + WL_PING_UNKNOWN_HOST = -3, + WL_PING_ERROR = -4 +} wl_ping_result_t; + +#endif //_WL_TYPES_H_ diff --git a/arduino/strix/API.md b/arduino/strix/API.md index b390e47..039c7f6 100644 --- a/arduino/strix/API.md +++ b/arduino/strix/API.md @@ -1,4 +1,8 @@ -# STRIX USB API +# STRIX API + +The firmware serves the same commands over USB serial and over HTTP on its own WiFi access point. + +## USB The firmware speaks a line protocol over the board's USB serial port (115200 baud setting, ignored by native USB). Send one command per line. Every reply is a single JSON line, except `entropy`. Errors look like `{"error":"..."}`, and settings changes confirm with `{"ok":true}`. @@ -6,7 +10,10 @@ The firmware speaks a line protocol over the board's USB serial port (115200 bau | Command | Reply | |---|---| -| `id` | Device, firmware and FPGA version, generator and ring counts | +| `id` | Device, firmware and FPGA version, generator and ring counts, and the reset cause of the last boot (`reset_cause`: SAMD21 PM->RCAUSE; 1 power-on, 4 brown-out, 16 reset pin, 64 software) | +| `wifi` | WiFi status: module probed, access point running, module firmware, SSID, IP | +| `wifi probe` | Releases the WiFi module from reset and queries it, without starting the radio | +| `wifi start` | Starts the access point and the HTTP server | | `entropy [hex\|bin]` | `n` (1–65536) entropy bytes from the stream source. `hex` (default): one line of hex. `bin`: a line `BIN `, then `n` raw bytes. Refused if the stream source is not healthy. If the source stops delivering for 2 s, hex ends with an error line and binary ends early. | | `health` | Per generator: healthy, active, swept, test failures and event counts, dead rings. Stream FIFO level and dropped bytes. | | `health clear` | Clears latched test failures and event counters | @@ -37,11 +44,27 @@ The firmware speaks a line protocol over the board's USB serial port (115200 bau Changing an `amp_*` setting restarts the amplifier. +## WiFi + +Without a USB host (wall charger or battery), the device starts WiFi by itself: an access point named `Strix` (WPA2, password `owl12345678`) at `192.168.4.1`, with an HTTP server on port 80. With a computer attached, WiFi stays off until `wifi start`. On weak USB power the radio's current bursts plus the ring oscillators can reset the board. + +Until WiFi is started, the FPGA holds the WiFi module in reset. + +| URL | USB equivalent | +|---|---| +| `/entropy?bytes=[&format=hex\|bin]` | `entropy [hex\|bin]`. `bin` is sent as `application/octet-stream`, without the `BIN` line. | +| `/?length=` | `entropy hex` (compatible with the earlier STRIX sketch) | +| `/id`, `/health`, `/stats`, `/amp`, `/wifi` | same command | +| `/config` | `get` | +| `/set?key=&value=` | `set ` | + +Replies have status 200 (errors are JSON `{"error":...}`), or 404 for unknown paths, and allow cross-origin requests. `watch` is USB-only. + ## Example ``` > id -{"device":"STRIX","firmware":"0.1.0","fpga_ready":true,"fpga_version":7,"generators":4,"rings_per_generator":90} +{"device":"STRIX","firmware":"0.2.0","fpga_ready":true,"fpga_version":8,"generators":4,"rings_per_generator":90,"reset_cause":1} > entropy 8 3F09A2C47E11D05B > set amp_stages 8,8,4 diff --git a/arduino/strix/strix.ino b/arduino/strix/strix.ino index 0f88af7..c63e1c8 100644 --- a/arduino/strix/strix.ino +++ b/arduino/strix/strix.ino @@ -1,24 +1,41 @@ // STRIX firmware for the Arduino MKR Vidor 4000: boots the STRIX FPGA image and serves -// entropy, health, live statistics and bias amplifier trials over USB serial. +// entropy, health, live statistics and bias amplifier trials over USB serial and over HTTP on +// its own WiFi access point. // -// Protocol: one command per line; replies are single JSON lines, except `entropy`, which -// replies with hex text or a "BIN " header followed by n raw bytes. See API.md. +// USB protocol: one command per line; replies are single JSON lines, except `entropy`, which +// replies with hex text or a "BIN " header followed by n raw bytes. HTTP serves the same +// commands as URLs. See API.md. #include +#include using namespace strix; -const char FIRMWARE_VERSION[] = "0.1.0"; +const char FIRMWARE_VERSION[] = "0.2.0"; const unsigned long POLL_MS = 10; const unsigned long ENTROPY_TIMEOUT_MS = 2000; +const unsigned long USB_HOST_WAIT_MS = 1500; const size_t MAX_ENTROPY_BYTES = 65536; const size_t CHUNK_BYTES = 256; const uint8_t MAX_ROLLING = 50; const char *CHANNEL_NAMES[STATS_CHANNELS] = {"g0", "g1", "g2", "g3", "combined"}; const char *PATH_NAMES[2] = {"bias", "autocorr"}; +const char WIFI_SSID[] = "Strix"; +const char WIFI_PASSWORD[] = "owl12345678"; // WPA2, at least 8 characters + +// Replies go to *out: USB serial, or the HTTP response while one is being served. +Print *out = &Serial; +// USB binary entropy is announced with a "BIN " line; HTTP sends the bytes alone. +bool binaryHeader = true; + +WiFiServer httpServer(80); +bool wifiProbed = false; // the NINA module has been reset and queried +bool wifiReady = false; // access point and HTTP server running StrixFPGA fpga; bool fpgaReady = false; +uint8_t resetCause = 0; // PM->RCAUSE at boot: 0x01 power-on, 0x02 BOD12, 0x04 BOD33, + // 0x10 external pin, 0x20 watchdog, 0x40 software // Statistics windows, built from the FPGA's per-trial snapshots @@ -81,52 +98,52 @@ void printU64(uint64_t value) { digits[--i] = '0' + value % 10; value /= 10; } while (value); - Serial.print(&digits[i]); + out->print(&digits[i]); } void printI64(int64_t value) { if (value < 0) { - Serial.print('-'); + out->print('-'); printU64((uint64_t)(-value)); } else { printU64((uint64_t)value); } } -void printBool(bool value) { Serial.print(value ? "true" : "false"); } +void printBool(bool value) { out->print(value ? "true" : "false"); } // Bias z = (2 ones - n) / sqrt(n); lag-1 autocorrelation z = (2 agreements - n) / sqrt(n). void printZ(double numerator, double bits) { if (bits <= 0) { - Serial.print("null"); + out->print("null"); } else { - Serial.print(numerator / sqrt(bits), 3); + out->print(numerator / sqrt(bits), 3); } } void printWindow(uint64_t bits, uint64_t ones, uint64_t agreements, bool withWalk) { - Serial.print("{\"bits\":"); + out->print("{\"bits\":"); printU64(bits); - Serial.print(",\"ones\":"); + out->print(",\"ones\":"); printU64(ones); - Serial.print(",\"z\":"); + out->print(",\"z\":"); printZ(2.0 * (double)ones - (double)bits, (double)bits); - Serial.print(",\"autocorr_z\":"); + out->print(",\"autocorr_z\":"); printZ(2.0 * (double)agreements - (double)bits, (double)bits); if (withWalk) { - Serial.print(",\"walk\":"); + out->print(",\"walk\":"); printI64(2 * (int64_t)ones - (int64_t)bits); } - Serial.print('}'); + out->print('}'); } void printError(const char *message) { - Serial.print("{\"error\":\""); - Serial.print(message); - Serial.println("\"}"); + out->print("{\"error\":\""); + out->print(message); + out->println("\"}"); } -void printOk() { Serial.println("{\"ok\":true}"); } +void printOk() { out->println("{\"ok\":true}"); } // FPGA polling @@ -159,6 +176,7 @@ void restartAmplifier() { void printStats(); void printAmp(); +void printWifi(); void pollStats() { uint8_t raw[STATS_SNAPSHOT_BYTES]; @@ -222,50 +240,52 @@ void pollAmp() { // Commands void printId() { - Serial.print("{\"device\":\"STRIX\",\"firmware\":\""); - Serial.print(FIRMWARE_VERSION); - Serial.print("\",\"fpga_ready\":"); + out->print("{\"device\":\"STRIX\",\"firmware\":\""); + out->print(FIRMWARE_VERSION); + out->print("\",\"fpga_ready\":"); printBool(fpgaReady); - Serial.print(",\"fpga_version\":"); - Serial.print(fpga.version()); - Serial.print(",\"generators\":"); - Serial.print(fpgaReady ? fpga.read(REG_GENERATORS) : 0); - Serial.print(",\"rings_per_generator\":"); - Serial.print(fpgaReady ? fpga.read(REG_RINGS) : 0); - Serial.println('}'); + out->print(",\"fpga_version\":"); + out->print(fpga.version()); + out->print(",\"generators\":"); + out->print(fpgaReady ? fpga.read(REG_GENERATORS) : 0); + out->print(",\"rings_per_generator\":"); + out->print(fpgaReady ? fpga.read(REG_RINGS) : 0); + out->print(",\"reset_cause\":"); + out->print(resetCause); + out->println('}'); } void printHealth() { uint8_t healthy = fpga.read(REG_HEALTHY); - Serial.print("{\"healthy\":"); - Serial.print(healthy); - Serial.print(",\"generators\":["); + out->print("{\"healthy\":"); + out->print(healthy); + out->print(",\"generators\":["); for (uint8_t g = 0; g < GENERATORS; g++) { uint8_t flags = fpga.read(REG_GEN_HEALTH + 4 * g); - if (g) Serial.print(','); - Serial.print("{\"healthy\":"); + if (g) out->print(','); + out->print("{\"healthy\":"); printBool(flags & FLAG_HEALTHY); - Serial.print(",\"active\":"); + out->print(",\"active\":"); printBool(flags & FLAG_ACTIVE); - Serial.print(",\"swept\":"); + out->print(",\"swept\":"); printBool(flags & FLAG_SWEPT); - Serial.print(",\"rct_failed\":"); + out->print(",\"rct_failed\":"); printBool(flags & FLAG_RCT_FAILED); - Serial.print(",\"apt_failed\":"); + out->print(",\"apt_failed\":"); printBool(flags & FLAG_APT_FAILED); - Serial.print(",\"rct_events\":"); - Serial.print(fpga.read(REG_GEN_HEALTH + 4 * g + 1)); - Serial.print(",\"apt_events\":"); - Serial.print(fpga.read(REG_GEN_HEALTH + 4 * g + 2)); - Serial.print(",\"dead_rings\":"); - Serial.print(fpga.read(REG_GEN_HEALTH + 4 * g + 3)); - Serial.print('}'); + out->print(",\"rct_events\":"); + out->print(fpga.read(REG_GEN_HEALTH + 4 * g + 1)); + out->print(",\"apt_events\":"); + out->print(fpga.read(REG_GEN_HEALTH + 4 * g + 2)); + out->print(",\"dead_rings\":"); + out->print(fpga.read(REG_GEN_HEALTH + 4 * g + 3)); + out->print('}'); } - Serial.print("],\"stream\":{\"level\":"); - Serial.print((uint16_t)fpga.read(REG_LEVEL_HIGH) << 8 | fpga.read(REG_LEVEL_LOW)); - Serial.print(",\"dropped\":"); - Serial.print((uint16_t)fpga.read(REG_DROP_HIGH) << 8 | fpga.read(REG_DROP_LOW)); - Serial.println("}}"); + out->print("],\"stream\":{\"level\":"); + out->print((uint16_t)fpga.read(REG_LEVEL_HIGH) << 8 | fpga.read(REG_LEVEL_LOW)); + out->print(",\"dropped\":"); + out->print((uint16_t)fpga.read(REG_DROP_HIGH) << 8 | fpga.read(REG_DROP_LOW)); + out->println("}}"); } void printStats() { @@ -274,21 +294,21 @@ void printStats() { return; } uint8_t window = rolling < historyCount ? rolling : historyCount; - Serial.print("{\"trial\":"); - Serial.print(latestStats.sequence); - Serial.print(",\"trial_ms\":"); - Serial.print(latestStats.trialMs); - Serial.print(",\"von_neumann\":"); + out->print("{\"trial\":"); + out->print(latestStats.sequence); + out->print(",\"trial_ms\":"); + out->print(latestStats.trialMs); + out->print(",\"von_neumann\":"); printBool(latestStats.vonNeumann); - Serial.print(",\"healthy\":"); - Serial.print(latestStats.healthy); - Serial.print(",\"trials\":"); - Serial.print(trialsCounted); - Serial.print(",\"missed\":"); - Serial.print(missedTrials); - Serial.print(",\"rolling_trials\":"); - Serial.print(window); - Serial.print(",\"channels\":["); + out->print(",\"healthy\":"); + out->print(latestStats.healthy); + out->print(",\"trials\":"); + out->print(trialsCounted); + out->print(",\"missed\":"); + out->print(missedTrials); + out->print(",\"rolling_trials\":"); + out->print(window); + out->print(",\"channels\":["); for (uint8_t c = 0; c < STATS_CHANNELS; c++) { uint64_t bits = 0, ones = 0, agreements = 0; for (uint8_t i = 0; i < window; i++) { @@ -298,18 +318,18 @@ void printStats() { agreements += counts.agreements; } const Counts &trial = latestStats.channels[c]; - if (c) Serial.print(','); - Serial.print("{\"name\":\""); - Serial.print(CHANNEL_NAMES[c]); - Serial.print("\",\"trial\":"); + if (c) out->print(','); + out->print("{\"name\":\""); + out->print(CHANNEL_NAMES[c]); + out->print("\",\"trial\":"); printWindow(trial.bits, trial.ones, trial.agreements, false); - Serial.print(",\"rolling\":"); + out->print(",\"rolling\":"); printWindow(bits, ones, agreements, false); - Serial.print(",\"total\":"); + out->print(",\"total\":"); printWindow(totals[c].bits, totals[c].ones, totals[c].agreements, true); - Serial.print('}'); + out->print('}'); } - Serial.println("]}"); + out->println("]}"); } void printAmp() { @@ -317,43 +337,43 @@ void printAmp() { printError("no trial completed yet"); return; } - Serial.print("{\"trial\":"); - Serial.print(latestAmp.sequence); - Serial.print(",\"sources\":"); - Serial.print(latestAmp.sources); - Serial.print(",\"von_neumann\":"); + out->print("{\"trial\":"); + out->print(latestAmp.sequence); + out->print(",\"sources\":"); + out->print(latestAmp.sources); + out->print(",\"von_neumann\":"); printBool(latestAmp.vonNeumann); - Serial.print(",\"subtrials\":"); - Serial.print(latestAmp.subtrials); - Serial.print(",\"sub_ms\":"); - Serial.print(latestAmp.subMs); - Serial.print(",\"overflow\":"); + out->print(",\"subtrials\":"); + out->print(latestAmp.subtrials); + out->print(",\"sub_ms\":"); + out->print(latestAmp.subMs); + out->print(",\"overflow\":"); printBool(latestAmp.overflow); - Serial.print(",\"paths\":["); + out->print(",\"paths\":["); for (uint8_t p = 0; p < 2; p++) { const AmpPath &path = latestAmp.paths[p]; - if (p) Serial.print(','); - Serial.print("{\"name\":\""); - Serial.print(PATH_NAMES[p]); - Serial.print("\",\"bits\":"); - Serial.print(path.bits); - Serial.print(",\"ones\":"); - Serial.print(path.ones); - Serial.print(",\"z\":"); + if (p) out->print(','); + out->print("{\"name\":\""); + out->print(PATH_NAMES[p]); + out->print("\",\"bits\":"); + out->print(path.bits); + out->print(",\"ones\":"); + out->print(path.ones); + out->print(",\"z\":"); printZ(2.0 * path.ones - (double)path.bits, (double)path.bits); - Serial.print(",\"votes\":\""); + out->print(",\"votes\":\""); for (uint8_t i = 0; i < latestAmp.subtrials; i++) { - Serial.print(path.voted >> i & 1 ? (path.votes >> i & 1 ? '1' : '0') : '.'); + out->print(path.voted >> i & 1 ? (path.votes >> i & 1 ? '1' : '0') : '.'); } - Serial.print("\",\"result\":"); + out->print("\",\"result\":"); if (path.valid) { - Serial.print(path.result ? 1 : 0); + out->print(path.result ? 1 : 0); } else { - Serial.print("null"); + out->print("null"); } - Serial.print('}'); + out->print('}'); } - Serial.println("]}"); + out->println("]}"); } // Streams `count` entropy bytes as hex or binary. Stops early (binary: short output, hex: an @@ -367,9 +387,9 @@ void sendEntropy(size_t count, bool binary) { printError("stream source is not healthy"); return; } - if (binary) { - Serial.print("BIN "); - Serial.println(count); + if (binary && binaryHeader) { + out->print("BIN "); + out->println(count); } static uint8_t chunk[CHUNK_BYTES]; size_t sent = 0; @@ -379,7 +399,7 @@ void sendEntropy(size_t count, bool binary) { if (level == 0) { if (millis() - lastData > ENTROPY_TIMEOUT_MS) { if (!binary) { - Serial.println(); + out->println(); printError("entropy timeout"); } return; @@ -391,51 +411,51 @@ void sendEntropy(size_t count, bool binary) { if (length > CHUNK_BYTES) length = CHUNK_BYTES; fpga.readBurst(REG_STREAM, chunk, length); if (binary) { - Serial.write(chunk, length); + out->write(chunk, length); } else { for (size_t i = 0; i < length; i++) { - if (chunk[i] < 0x10) Serial.print('0'); - Serial.print(chunk[i], HEX); + if (chunk[i] < 0x10) out->print('0'); + out->print(chunk[i], HEX); } } sent += length; lastData = millis(); } - if (!binary) Serial.println(); + if (!binary) out->println(); } void printConfig() { - Serial.print("{\"temporal\":"); - Serial.print(fpga.read(REG_TEMPORAL)); - Serial.print(",\"generators\":"); - Serial.print(fpga.read(REG_GEN_ENABLE)); - Serial.print(",\"trial_ms\":"); - Serial.print((uint16_t)fpga.read(REG_TRIAL_HIGH) << 8 | fpga.read(REG_TRIAL_LOW)); - Serial.print(",\"stats_vn\":"); - Serial.print(fpga.read(REG_STATS_CTRL) & STATS_VON_NEUMANN); - Serial.print(",\"rolling\":"); - Serial.print(rolling); + out->print("{\"temporal\":"); + out->print(fpga.read(REG_TEMPORAL)); + out->print(",\"generators\":"); + out->print(fpga.read(REG_GEN_ENABLE)); + out->print(",\"trial_ms\":"); + out->print((uint16_t)fpga.read(REG_TRIAL_HIGH) << 8 | fpga.read(REG_TRIAL_LOW)); + out->print(",\"stats_vn\":"); + out->print(fpga.read(REG_STATS_CTRL) & STATS_VON_NEUMANN); + out->print(",\"rolling\":"); + out->print(rolling); uint8_t stream = fpga.read(REG_STREAM_CTRL); - Serial.print(",\"stream_source\":"); - Serial.print(stream & 0x07); - Serial.print(",\"stream_vn\":"); - Serial.print(stream & STREAM_VON_NEUMANN ? 1 : 0); - Serial.print(",\"amp_sources\":"); - Serial.print(fpga.read(REG_AMP_SOURCES)); - Serial.print(",\"amp_method\":\""); - Serial.print(fpga.read(REG_AMP_STAGE) & 1 ? "vote" : "walk"); - Serial.print("\",\"amp_stages\":\""); + out->print(",\"stream_source\":"); + out->print(stream & 0x07); + out->print(",\"stream_vn\":"); + out->print(stream & STREAM_VON_NEUMANN ? 1 : 0); + out->print(",\"amp_sources\":"); + out->print(fpga.read(REG_AMP_SOURCES)); + out->print(",\"amp_method\":\""); + out->print(fpga.read(REG_AMP_STAGE) & 1 ? "vote" : "walk"); + out->print("\",\"amp_stages\":\""); for (uint8_t s = 0; s < 3; s++) { - if (s) Serial.print(','); - Serial.print((uint16_t)fpga.read(REG_AMP_STAGE + 3 * s + 1) << 8 | fpga.read(REG_AMP_STAGE + 3 * s + 2)); + if (s) out->print(','); + out->print((uint16_t)fpga.read(REG_AMP_STAGE + 3 * s + 1) << 8 | fpga.read(REG_AMP_STAGE + 3 * s + 2)); } - Serial.print("\",\"amp_sub_ms\":"); - Serial.print(fpga.read(REG_AMP_SUB_MS)); - Serial.print(",\"amp_subtrials\":"); - Serial.print(fpga.read(REG_AMP_SUBS)); - Serial.print(",\"amp_vn\":"); - Serial.print(fpga.read(REG_AMP_CTRL) & AMP_VON_NEUMANN); - Serial.println('}'); + out->print("\",\"amp_sub_ms\":"); + out->print(fpga.read(REG_AMP_SUB_MS)); + out->print(",\"amp_subtrials\":"); + out->print(fpga.read(REG_AMP_SUBS)); + out->print(",\"amp_vn\":"); + out->print(fpga.read(REG_AMP_CTRL) & AMP_VON_NEUMANN); + out->println('}'); } bool inRange(long value, long low, long high) { return value >= low && value <= high; } @@ -524,6 +544,11 @@ void handleCommand(String line) { } else { sendEntropy(count, rest == "bin"); } + } else if (command == "wifi") { + // The NINA module is reached through the FPGA's pin pass-through, so the FPGA must run. + if (first == "probe") probeWifi(); + if (first == "start") startWifi(); + printWifi(); } else if (command == "health") { if (first == "clear") { fpga.write(REG_HEALTH_CTRL, HEALTH_CLEAR); @@ -552,6 +577,156 @@ void handleCommand(String line) { } } +// WiFi + +void printWifi() { + out->print("{\"probed\":"); + printBool(wifiProbed); + out->print(",\"access_point\":"); + printBool(wifiReady); + if (wifiProbed) { + out->print(",\"module\":"); + printBool(WiFi.status() != WL_NO_MODULE); + out->print(",\"firmware\":\""); + out->print(WiFi.firmwareVersion()); + out->print('"'); + } + if (wifiReady) { + out->print(",\"ssid\":\""); + out->print(WIFI_SSID); + out->print("\",\"ip\":\""); + out->print(WiFi.localIP()); + out->print("\",\"status\":"); + out->print(WiFi.status()); + } + out->println('}'); +} + +// Collects a response and sends it to the client in chunks: every write to the NINA module +// is an SPI transaction, so byte-sized writes would be very slow. +class BufferedClient : public Print { + public: + explicit BufferedClient(WiFiClient &client) : client_(client) {} + + size_t write(uint8_t value) override { + buffer_[length_++] = value; + if (length_ == sizeof(buffer_)) flush(); + return 1; + } + + void flush() override { + if (length_) client_.write(buffer_, length_); + length_ = 0; + } + + private: + WiFiClient &client_; + uint8_t buffer_[512]; + size_t length_ = 0; +}; + +String decodeUrl(const String &text) { + String result; + for (unsigned i = 0; i < text.length(); i++) { + char c = text[i]; + if (c == '+') { + result += ' '; + } else if (c == '%' && i + 2 < text.length()) { + result += (char)strtol(text.substring(i + 1, i + 3).c_str(), nullptr, 16); + i += 2; + } else { + result += c; + } + } + return result; +} + +String queryParam(const String &query, const char *name) { + String key = String(name) + "="; + int start = 0; + while (start < (int)query.length()) { + int end = query.indexOf('&', start); + if (end < 0) end = query.length(); + if (query.substring(start, start + key.length()) == key) { + return decodeUrl(query.substring(start + key.length(), end)); + } + start = end + 1; + } + return ""; +} + +// Maps a request path to a USB command line; sets the content type. Empty if not found. +String httpCommand(const String &path, const String &query, const char *&type) { + type = "application/json"; + if (path == "/" && queryParam(query, "length").length()) { + type = "text/plain"; // compatibility with the earlier STRIX sketch: GET /?length= + return "entropy " + queryParam(query, "length") + " hex"; + } + if (path == "/entropy") { + String format = queryParam(query, "format"); + type = format == "bin" ? "application/octet-stream" : "text/plain"; + return "entropy " + queryParam(query, "bytes") + " " + (format == "bin" ? "bin" : "hex"); + } + if (path == "/id" || path == "/health" || path == "/stats" || path == "/amp" || path == "/wifi") { + return path.substring(1); + } + if (path == "/config") return "get"; + if (path == "/set") return "set " + queryParam(query, "key") + " " + queryParam(query, "value"); + return ""; +} + +void serveHttp() { + WiFiClient client = httpServer.available(); + if (!client) return; + client.setTimeout(1000); + String request = client.readStringUntil('\n'); // e.g. "GET /stats HTTP/1.1" + while (client.connected()) { + String header = client.readStringUntil('\n'); + if (header.length() <= 1) break; // blank line ends the headers + } + + int methodEnd = request.indexOf(' '); + int targetEnd = request.indexOf(' ', methodEnd + 1); + String target = request.substring(methodEnd + 1, targetEnd < 0 ? request.length() : targetEnd); + int question = target.indexOf('?'); + String path = question < 0 ? target : target.substring(0, question); + String query = question < 0 ? "" : target.substring(question + 1); + + const char *type; + String command = httpCommand(path, query, type); + BufferedClient response(client); + response.print(command.length() ? "HTTP/1.1 200 OK\r\n" : "HTTP/1.1 404 Not Found\r\n"); + response.print("Content-Type: "); + response.print(type); + response.print("\r\nAccess-Control-Allow-Origin: *\r\nConnection: close\r\n\r\n"); + + out = &response; + binaryHeader = false; + if (command.length()) { + handleCommand(command); + } else { + printError("not found"); + } + out = &Serial; + binaryHeader = true; + response.flush(); + client.stop(); +} + +// Resets the NINA module and checks that it answers, without starting the radio. +void probeWifi() { + fpga.write(REG_NINA_CTRL, 1); // the FPGA holds the module in reset until now + WiFi.status(); + wifiProbed = true; +} + +void startWifi() { + probeWifi(); + if (WiFi.status() == WL_NO_MODULE) return; + wifiReady = WiFi.beginAP(WIFI_SSID, WIFI_PASSWORD) == WL_AP_LISTENING; + if (wifiReady) httpServer.begin(); +} + // Main char lineBuffer[128]; @@ -572,15 +747,31 @@ void readSerial() { } } +// True if a USB host has configured the device within a short wait after boot. +bool usbHostPresent() { + unsigned long start = millis(); + while (millis() - start < USB_HOST_WAIT_MS) { + if (USBDevice.configured()) return true; + delay(10); + } + return false; +} + void setup() { + resetCause = PM->RCAUSE.reg; Serial.begin(115200); // no wait for a host: the device also runs on battery pinMode(LED_BUILTIN, OUTPUT); fpgaReady = fpga.begin(); if (fpgaReady) restartStats(); + // Stationary mode: without a USB host (wall charger or battery) WiFi starts by itself. With a + // computer attached it stays off, since radio bursts plus the ring oscillators can brown out + // the board on weak USB power; `wifi start` still starts it. + if (fpgaReady && !usbHostPresent()) startWifi(); } void loop() { readSerial(); + if (wifiReady) serveHttp(); static unsigned long lastPoll = 0; if (fpgaReady && millis() - lastPoll >= POLL_MS) { lastPoll = millis(); diff --git a/devbox.json b/devbox.json index b7dc124..1d66ffa 100644 --- a/devbox.json +++ b/devbox.json @@ -17,8 +17,7 @@ "scripts": { "setup": [ "arduino-cli core update-index", - "arduino-cli core install arduino:samd", - "arduino-cli lib install WiFiNINA@1.8.5" + "arduino-cli core install arduino:samd" ], "build": [ "arduino-cli compile --fqbn arduino:samd:mkrvidor4000 --libraries arduino/libraries arduino/strix"