diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml index 878d5669..808258ed 100644 --- a/.github/workflows/compile-examples.yml +++ b/.github/workflows/compile-examples.yml @@ -35,6 +35,9 @@ jobs: - name: MKRNB - name: MKRWAN - name: Arduino_Cellular + - name: Blues Wireless Notecard + SKETCH_PATHS: | + - examples/ConnectionHandlerDemo ARDUINOCORE_MBED_STAGING_PATH: extras/ArduinoCore-mbed ARDUINOCORE_API_STAGING_PATH: extras/ArduinoCore-API SKETCHES_REPORTS_PATH: sketches-reports @@ -98,6 +101,9 @@ jobs: - fqbn: arduino:mbed_edge:edge_control platform-name: arduino:mbed_edge artifact-name-suffix: arduino-mbed_edge-edge_control + - fqbn: "rp2040:rp2040:rpipicow" + platform-name: rp2040:rp2040 + artifact-name-suffix: rp2040-rp2040-rpipicow # Make board type-specific customizations to the matrix jobs include: @@ -106,6 +112,8 @@ jobs: platforms: | # Install Arduino SAMD Boards via Boards Manager - name: arduino:samd + sketch-paths: | + - examples/ConnectionHandlerDemo-Notecard - board: platform-name: arduino:mbed platforms: | @@ -114,21 +122,53 @@ jobs: # Overwrite the Arduino mbed-Enabled Boards release version with version from the tip of the default branch (located in local path because of the need to first install ArduinoCore-API) - source-path: extras/ArduinoCore-mbed name: arduino:mbed + sketch-paths: | + - examples/ConnectionHandlerDemo-Notecard + - board: + platform-name: arduino:mbed_portenta + sketch-paths: | + - examples/ConnectionHandlerDemo-Notecard + - board: + platform-name: arduino:mbed_nano + sketch-paths: | + - examples/ConnectionHandlerDemo-Notecard + - board: + platform-name: arduino:mbed_nicla + sketch-paths: | + - examples/ConnectionHandlerDemo-Notecard + - board: + platform-name: arduino:mbed_opta + sketch-paths: | + - examples/ConnectionHandlerDemo-Notecard + - board: + platform-name: arduino:mbed_giga + sketch-paths: | + - examples/ConnectionHandlerDemo-Notecard + - board: + platform-name: arduino:mbed_edge + sketch-paths: | + - examples/ConnectionHandlerDemo-Notecard - board: platform-name: arduino:renesas_portenta platforms: | # Install Arduino Renesas portenta Boards via Boards Manager - name: arduino:renesas_portenta + sketch-paths: | + - examples/ConnectionHandlerDemo-Notecard - board: platform-name: arduino:renesas_uno platforms: | # Install Arduino Renesas uno Boards via Boards Manager - name: arduino:renesas_uno + sketch-paths: | + - examples/ConnectionHandlerDemo-Notecard - board: platform-name: arduino:esp32 platforms: | # Install Arduino ESP32 Boards via Boards Manager - name: arduino:esp32 + sketch-paths: | + - examples/ConnectionHandlerDemo-Notecard - board: platform-name: esp8266:esp8266 platforms: | @@ -142,6 +182,16 @@ jobs: # Install ESP32 platform via Boards Manager - name: esp32:esp32 source-url: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json + sketch-paths: | + - examples/ConnectionHandlerDemo-Notecard + - board: + platform-name: rp2040:rp2040 + platforms: | + # Install rp2040 platform via Boards Manager + - name: rp2040:rp2040 + source-url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json + sketch-paths: | + - examples/ConnectionHandlerDemo-Notecard steps: - uses: actions/checkout@v4 @@ -180,6 +230,9 @@ jobs: platforms: ${{ matrix.platforms }} fqbn: ${{ matrix.board.fqbn }} libraries: ${{ env.LIBRARIES }} + sketch-paths: | + ${{ env.SKETCH_PATHS }} + ${{ matrix.sketch-paths }} enable-deltas-report: 'true' sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }} diff --git a/README.md b/README.md index c2759ac3..139db7f9 100644 --- a/README.md +++ b/README.md @@ -6,21 +6,25 @@ Arduino Library for network connections management [![Spell Check status](https://github.com/arduino-libraries/Arduino_ConnectionHandler/actions/workflows/spell-check.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_ConnectionHandler/actions/workflows/spell-check.yml) Library for handling and managing network connections by providing keep-alive functionality and automatic reconnection in case of connection-loss. It supports the following boards: + * **WiFi**: [`MKR 1000`](https://store.arduino.cc/arduino-mkr1000-wifi), [`MKR WiFi 1010`](https://store.arduino.cc/arduino-mkr-wifi-1010), [`Nano 33 IoT`](https://store.arduino.cc/arduino-nano-33-iot), [`Portenta H7`](https://store.arduino.cc/products/portenta-h7), [`Nano RP2040 Connect`](https://store.arduino.cc/products/arduino-nano-rp2040-connect), [`Nicla Vision`](https://store.arduino.cc/products/nicla-vision), [`OPTA WiFi`](https://store.arduino.cc/products/opta-wifi), [`GIGA R1 WiFi`](https://store.arduino.cc/products/giga-r1-wifi), [`Portenta C33`](https://store.arduino.cc/products/portenta-c33), [`UNO R4 WiFi`](https://store.arduino.cc/products/uno-r4-wifi), [`Nano ESP32`](https://store.arduino.cc/products/nano-esp32), [`ESP8266`](https://github.com/esp8266/Arduino/releases/tag/2.5.0), [`ESP32`](https://github.com/espressif/arduino-esp32) * **GSM**: [`MKR GSM 1400`](https://store.arduino.cc/arduino-mkr-gsm-1400-1415) * **5G**: [`MKR NB 1500`](https://store.arduino.cc/arduino-mkr-nb-1500-1413) * **LoRa**: [`MKR WAN 1300/1310`](https://store.arduino.cc/mkr-wan-1310) * **Ethernet**: [`Portenta H7`](https://store.arduino.cc/products/portenta-h7) + [`Vision Shield Ethernet`](https://store.arduino.cc/products/arduino-portenta-vision-shield-ethernet), [`Max Carrier`](https://store.arduino.cc/products/portenta-max-carrier), [`Breakout`](https://store.arduino.cc/products/arduino-portenta-breakout), [`Portenta Machine Control`](https://store.arduino.cc/products/arduino-portenta-machine-control), [`OPTA WiFi`](https://store.arduino.cc/products/opta-wifi), [`OPTA RS485`](https://store.arduino.cc/products/opta-rs485), [`OPTA Lite`](https://store.arduino.cc/products/opta-lite), [`Portenta C33`](https://store.arduino.cc/products/portenta-c33) + [`Vision Shield Ethernet`](https://store.arduino.cc/products/arduino-portenta-vision-shield-ethernet) +* **Notecard**: [Provides Cellular/LoRa/Satellite/Wi-Fi to any modern board/architecture](examples/ConnectionHandlerDemo-Notecard/README.md) ### How-to-use ```C++ #include /* ... */ -#if defined(BOARD_HAS_ETHERNET) +#if defined(BOARD_HAS_NOTECARD) +NotecardConnectionHandler conMan("com.domain.you:product"); +#elif defined(BOARD_HAS_ETHERNET) EthernetConnectionHandler conMan; #elif defined(BOARD_HAS_WIFI) -WiFiConnectionHandler conMan("SECRET_SSID", "SECRET_PASS"); +WiFiConnectionHandler conMan("SECRET_WIFI_SSID", "SECRET_WIFI_PASS"); #elif defined(BOARD_HAS_GSM) GSMConnectionHandler conMan("SECRET_PIN", "SECRET_APN", "SECRET_GSM_LOGIN", "SECRET_GSM_PASS"); #elif defined(BOARD_HAS_NB) diff --git a/examples/ConnectionHandlerDemo-Notecard/ConnectionHandlerDemo-Notecard.ino b/examples/ConnectionHandlerDemo-Notecard/ConnectionHandlerDemo-Notecard.ino new file mode 100644 index 00000000..e4183618 --- /dev/null +++ b/examples/ConnectionHandlerDemo-Notecard/ConnectionHandlerDemo-Notecard.ino @@ -0,0 +1,144 @@ +/* SECRET_ fields are in `arduino_secrets.h` (included below) + * + * If using a Host + Notecard connected over I2C you'll need a + * NotecardConnectionHandler object as follows: + * + * NotecardConnectionHandler conMan(NOTECARD_PRODUCT_UID); + * + * If using a Host + Notecard connected over Serial you'll need a + * NotecardConnectionHandler object as follows: + * + * NotecardConnectionHandler conMan(NOTECARD_PRODUCT_UID, UART_INTERFACE); + */ + +#include // MUST include this first to enable Notecard support +#include + +#include "arduino_secrets.h" + +/* Uncomment the following line to use this example in a manner that is more + * compatible with LoRa. + */ +// #define USE_NOTE_LORA + +#ifndef USE_NOTE_LORA +#define CONN_TOGGLE_MS 60000 +#else +#define CONN_TOGGLE_MS 300000 +#endif + +/* The Notecard can provide connectivity to almost any board via ESLOV (I2C) + * or UART. An empty string (or the default value provided below) will not + * override the Notecard's existing configuration. + * Learn more at: https://dev.blues.io */ +#define NOTECARD_PRODUCT_UID "com.domain.you:product" + +/* Uncomment the following line to use the Notecard over UART */ +// #define UART_INTERFACE Serial1 + +#ifndef UART_INTERFACE +NotecardConnectionHandler conMan(NOTECARD_PRODUCT_UID); +#else +NotecardConnectionHandler conMan(NOTECARD_PRODUCT_UID, UART_INTERFACE); +#endif + +bool attemptConnect = false; +uint32_t lastConnToggleMs = 0; + +void setup() { + /* Initialize serial debug port and wait up to 5 seconds for port to open */ + Serial.begin(9600); + for(unsigned long const serialBeginTime = millis(); !Serial && (millis() - serialBeginTime <= 5000); ) { } + + /* Set the debug message level: + * - DBG_ERROR: Only show error messages + * - DBG_WARNING: Show warning and error messages + * - DBG_INFO: Show info, warning, and error messages + * - DBG_DEBUG: Show debug, info, warning, and error messages + * - DBG_VERBOSE: Show all messages + */ + setDebugMessageLevel(DBG_INFO); + + /* Add callbacks to the ConnectionHandler object to get notified of network + * connection events. */ + conMan.addCallback(NetworkConnectionEvent::CONNECTED, onNetworkConnect); + conMan.addCallback(NetworkConnectionEvent::DISCONNECTED, onNetworkDisconnect); + conMan.addCallback(NetworkConnectionEvent::ERROR, onNetworkError); + + /* First call to `check()` initializes the connection to the Notecard. While + * not strictly necessary, it cleans up the logging from this application. + */ + conMan.check(); + +#ifndef USE_NOTE_LORA + /* Set the Wi-Fi credentials for the Notecard */ + String ssid = SECRET_WIFI_SSID; + if (ssid.length() > 0 && ssid != "NETWORK NAME") { + conMan.setWiFiCredentials(SECRET_WIFI_SSID, SECRET_WIFI_PASS); + } +#else + conMan.setNotehubPollingInterval(720); // poll twice per day +#endif + + /* Confirm Interface */ + Serial.print("Network Adapter Interface: "); + if (NetworkAdapter::NOTECARD == conMan.getInterface()) { + Serial.print("Notecard "); + Serial.print(conMan.getNotecardUid()); +#ifndef UART_INTERFACE + Serial.println(" (via I2C)"); +#else + Serial.println(" (via UART)"); +#endif + } else { + Serial.println("ERROR: Unexpected Interface"); + while(1); + } + + /* Display the Arduino IoT Cloud Device ID */ + displayCachedDeviceId(); +} + +void loop() { + /* Toggle the connection every `CONN_TOGGLE_MS` milliseconds */ + if ((millis() - lastConnToggleMs) > CONN_TOGGLE_MS) { + Serial.println("Toggling connection..."); + if (attemptConnect) { + displayCachedDeviceId(); + conMan.connect(); + } else { + // Flush any queued Notecard requests before disconnecting + conMan.initiateNotehubSync(NotecardConnectionHandler::SyncType::Outbound); + conMan.disconnect(); + } + attemptConnect = !attemptConnect; + lastConnToggleMs = millis(); + } + + /* The following code keeps on running connection workflows on our + * ConnectionHandler object, hence allowing reconnection in case of failure + * and notification of connect/disconnect event if enabled (see + * addConnectCallback/addDisconnectCallback) NOTE: any use of delay() within + * the loop or methods called from it will delay the execution of .update(), + * which might not guarantee the correct functioning of the ConnectionHandler + * object. + */ + conMan.check(); +} + +void displayCachedDeviceId() { + Serial.print("Cached Arduino IoT Cloud Device ID: "); + Serial.println(conMan.getDeviceId()); +} + +void onNetworkConnect() { + Serial.println(">>>> CONNECTED to network"); +} + +void onNetworkDisconnect() { + Serial.println(">>>> DISCONNECTED from network"); +} + +void onNetworkError() { + Serial.println(">>>> ERROR"); +} diff --git a/examples/ConnectionHandlerDemo-Notecard/README.md b/examples/ConnectionHandlerDemo-Notecard/README.md new file mode 100644 index 00000000..7f90a7cf --- /dev/null +++ b/examples/ConnectionHandlerDemo-Notecard/README.md @@ -0,0 +1,71 @@ +Notecard Connectivity +===================== + +The Notecard is a wireless, secure abstraction for device connectivity, that can +be used to enable _ANY*_ device with I2C, or UART, to connect to the Arduino IoT +Cloud via cellular, LoRa, satellite or Wi-Fi! + +As a result, your existing device architecture can now have first class support +in the Arduino IoT Cloud, by using a Notecard as a secure communication channel. + +> \*_While any device with I2C/UART may use the Notecard, the Arduino IoT Cloud +> library is not supported by the AVR toolchain. Therefore, devices based on the +> AVR architecture cannot access the Arduino IoT Cloud via the Notecard._ +> +> _However, any device (including AVR), may use the Notecard library to send data +> to Notehub, then that data may be routed to any endpoint of your choosing. See the +> [Notecard Routing Guide](https://dev.blues.io/guides-and-tutorials/routing-data-to-cloud) +> for more information..._ + +Wireless Connectivity Options +----------------------------- + +- [Cellular](https://shop.blues.com/collections/notecard/products/notecard-cellular) +- [Cellular + Wi-Fi](https://shop.blues.com/collections/notecard/products/notecard-cell-wifi) +- [Wi-Fi](https://shop.blues.com/collections/notecard/products/wifi-notecard) +- [LoRa](https://shop.blues.com/collections/notecard/products/notecard-lora) +- [Satellite](https://shop.blues.com/products/starnote) + +How it Works +------------ + +**Architecture Diagram:** + +``` +-------- ------------ ----------- ----------- +| | | | | | | | +| Host | | | Secure | | | Arduino | +| MCU |------| Notecard | ( ( Wireless ) ) | Notehub |------| IoT | +| | | | Protocol | | | Cloud | +|______| |__________| |_________| |_________| +``` + +Getting Started +--------------- + +### Setup a Notehub Account + +Using the Notecard only requires a couple of easy steps: + +1. [Purchase a Notecard](https://shop.blues.com/collections/notecard) (and +[Notecarrier](https://shop.blues.com/collections/notecarrier)) that fits the +needs of your device. + > _**NOTE:** We recommend starting with our [Dev Kit](https://shop.blues.com/products/blues-global-starter-kit) + > if you are unsure._ +1. [Setup a Notehub account](https://dev.blues.io/quickstart/notecard-quickstart/notecard-and-notecarrier-f/#set-up-notehub). + > _**NOTE:** Notehub accounts are free (no credit card required)._ +1. [Create a project on your Notehub account](https://dev.blues.io/quickstart/notecard-quickstart/notecard-and-notecarrier-f/#create-a-notehub-project). +1. In `ConnectionHandlerDemo-Notecard`, replace "com.domain.you:product" (from +`NOTECARD_PRODUCT_UID`) with the ProductUID of your new Notehub project. + +### Power-up the Device + +1. [Connect the Notecard to your Host MCU](https://dev.blues.io/quickstart/notecard-quickstart/notecard-and-notecarrier-f/#connect-your-notecard-and-notecarrier) +1. Flash the `ConnectionHanderDemo-Notecard` example sketch to your device. You +should see the device reporting itself as online in your [Notehub Project](https://notehub.io). + +### More Information + +For more information about the Notecard and Notehub in general, please see our +[Quickstart Guide](https://dev.blues.io/quickstart/) for a general overview of +how the Notecard and Notehub are designed to work. diff --git a/examples/ConnectionHandlerDemo-Notecard/arduino_secrets.h b/examples/ConnectionHandlerDemo-Notecard/arduino_secrets.h new file mode 100644 index 00000000..bd2a9d58 --- /dev/null +++ b/examples/ConnectionHandlerDemo-Notecard/arduino_secrets.h @@ -0,0 +1,5 @@ +/* If provided, the Wi-Fi Credentials will be passed along to the Notecard. If + * the Notecard supports Wi-Fi, it will attempt to connect to the network using + * these credentials, if not, the Notecard will safely ignore these values. */ +const char SECRET_WIFI_SSID[] = "NETWORK NAME"; +const char SECRET_WIFI_PASS[] = "NETWORK PASSWORD"; diff --git a/examples/ConnectionHandlerDemo/ConnectionHandlerDemo.ino b/examples/ConnectionHandlerDemo/ConnectionHandlerDemo.ino index 13ad117c..46a0c9d4 100644 --- a/examples/ConnectionHandlerDemo/ConnectionHandlerDemo.ino +++ b/examples/ConnectionHandlerDemo/ConnectionHandlerDemo.ino @@ -1,10 +1,11 @@ -/* SECRET_ fields are in arduino_secrets.h included above - * if using a WiFi board (Arduino MKR1000, MKR WiFi 1010, Nano 33 IoT, UNO +/* SECRET_ fields are in `arduino_secrets.h` (included below) + * + * If using a WiFi board (Arduino MKR1000, MKR WiFi 1010, Nano 33 IoT, UNO * WiFi Rev 2 or ESP8266/32), create a WiFiConnectionHandler object by adding - * Network Name (SECRET_SSID) and password (SECRET_PASS) in the arduino_secrets.h - * file (or Secrets tab in Create Web Editor). + * Network Name (SECRET_WIFI_SSID) and password (SECRET_WIFI_PASS) in the + * arduino_secrets.h file (or Secrets tab in Create Web Editor). * - * WiFiConnectionHandler conMan(SECRET_SSID, SECRET_PASS); + * WiFiConnectionHandler conMan(SECRET_WIFI_SSID, SECRET_WIFI_PASS); * * If using a MKR GSM 1400 or other GSM boards supporting the same API you'll * need a GSMConnectionHandler object as follows @@ -27,14 +28,21 @@ * */ +#include + #include "arduino_secrets.h" -#include +#define CONN_TOGGLE_MS 60000 + +#if !(defined(BOARD_HAS_WIFI) || defined(BOARD_HAS_GSM) || defined(BOARD_HAS_LORA) || \ + defined(BOARD_HAS_NB) || defined(BOARD_HAS_ETHERNET) || defined(BOARD_HAS_CATM1_NBIOT)) + #error "Please check Arduino Connection Handler supported boards list: https://github.com/arduino-libraries/Arduino_ConnectionHandler/blob/master/README.md" +#endif #if defined(BOARD_HAS_ETHERNET) EthernetConnectionHandler conMan(SECRET_IP, SECRET_DNS, SECRET_GATEWAY, SECRET_NETMASK); #elif defined(BOARD_HAS_WIFI) -WiFiConnectionHandler conMan(SECRET_SSID, SECRET_PASS); +WiFiConnectionHandler conMan(SECRET_WIFI_SSID, SECRET_WIFI_PASS); #elif defined(BOARD_HAS_GSM) GSMConnectionHandler conMan(SECRET_PIN, SECRET_APN, SECRET_GSM_USER, SECRET_GSM_PASS); #elif defined(BOARD_HAS_NB) @@ -47,19 +55,73 @@ CatM1ConnectionHandler conMan(SECRET_PIN, SECRET_APN, SECRET_GSM_USER, SECRET_GS CellularConnectionHandler conMan(SECRET_PIN, SECRET_APN, SECRET_GSM_USER, SECRET_GSM_PASS); #endif +bool attemptConnect = false; +uint32_t lastConnToggleMs = 0; + void setup() { + /* Initialize serial debug port and wait up to 5 seconds for port to open */ Serial.begin(9600); - /* Give a few seconds for the Serial connection to be available */ - delay(4000); + for(unsigned long const serialBeginTime = millis(); !Serial && (millis() - serialBeginTime <= 5000); ) { } + #ifndef __AVR__ + /* Set the debug message level: + * - DBG_ERROR: Only show error messages + * - DBG_WARNING: Show warning and error messages + * - DBG_INFO: Show info, warning, and error messages + * - DBG_DEBUG: Show debug, info, warning, and error messages + * - DBG_VERBOSE: Show all messages + */ setDebugMessageLevel(DBG_INFO); #endif + + /* Add callbacks to the ConnectionHandler object to get notified of network + * connection events. */ conMan.addCallback(NetworkConnectionEvent::CONNECTED, onNetworkConnect); conMan.addCallback(NetworkConnectionEvent::DISCONNECTED, onNetworkDisconnect); conMan.addCallback(NetworkConnectionEvent::ERROR, onNetworkError); + + Serial.print("Network Adapter Interface: "); + switch (conMan.getInterface()) { + case NetworkAdapter::WIFI: + Serial.println("Wi-Fi"); + break; + case NetworkAdapter::ETHERNET: + Serial.println("Ethernet"); + break; + case NetworkAdapter::NB: + Serial.println("Narrowband"); + break; + case NetworkAdapter::GSM: + Serial.println("GSM"); + break; + case NetworkAdapter::LORA: + Serial.println("LoRa"); + break; + case NetworkAdapter::CATM1: + Serial.println("Category M1"); + break; + case NetworkAdapter::CELL: + Serial.println("Cellular"); + break; + default: + Serial.println("Unknown"); + break; + } } void loop() { + /* Toggle the connection every `CONN_TOGGLE_MS` milliseconds */ + if ((millis() - lastConnToggleMs) > CONN_TOGGLE_MS) { + Serial.println("Toggling connection..."); + if (attemptConnect) { + conMan.connect(); + } else { + conMan.disconnect(); + } + attemptConnect = !attemptConnect; + lastConnToggleMs = millis(); + } + /* The following code keeps on running connection workflows on our * ConnectionHandler object, hence allowing reconnection in case of failure * and notification of connect/disconnect event if enabled (see @@ -68,7 +130,6 @@ void loop() { * which might not guarantee the correct functioning of the ConnectionHandler * object. */ - conMan.check(); } diff --git a/examples/ConnectionHandlerDemo/arduino_secrets.h b/examples/ConnectionHandlerDemo/arduino_secrets.h index 4d9fb7c8..f9906f69 100644 --- a/examples/ConnectionHandlerDemo/arduino_secrets.h +++ b/examples/ConnectionHandlerDemo/arduino_secrets.h @@ -1,12 +1,12 @@ // Required for WiFiConnectionHandler -const char SECRET_SSID[] = "NETWORK NAME"; -const char SECRET_PASS[] = "NETWORK PASSWORD"; +const char SECRET_WIFI_SSID[] = "NETWORK NAME"; +const char SECRET_WIFI_PASS[] = "NETWORK PASSWORD"; // Required for GSMConnectionHandler -const char SECRET_APN[] = "MOBILE PROVIDER APN ADDRESS"; -const char SECRET_PIN[] = "0000"; // Required for NBConnectionHandler -const char SECRET_GSM_USER[] = "GSM USERNAME"; -const char SECRET_GSM_PASS[] = "GSM PASSWORD"; +const char SECRET_APN[] = "MOBILE PROVIDER APN ADDRESS"; +const char SECRET_PIN[] = "0000"; // Required for NBConnectionHandler +const char SECRET_GSM_USER[] = "GSM USERNAME"; +const char SECRET_GSM_PASS[] = "GSM PASSWORD"; // Required for LoRaConnectionHandler const char SECRET_APP_EUI[] = "APP_EUI"; diff --git a/keywords.txt b/keywords.txt index ef5227f0..68e2be2d 100644 --- a/keywords.txt +++ b/keywords.txt @@ -11,13 +11,17 @@ GSMConnectionHandler KEYWORD1 NBConnectionHandler KEYWORD1 LoRaConnectionHandler KEYWORD1 EthernetConnectionHandler KEYWORD1 -CatM1ConnectionHandler KEYWORD1 +CatM1ConnectionHandler KEYWORD1 +NotecardConnectionHandler KEYWORD1 #################################################### # Methods and Functions (KEYWORD2) #################################################### ConnectionHandler KEYWORD2 +available KEYWORD2 +read KEYWORD2 +write KEYWORD2 check KEYWORD2 connect KEYWORD2 disconnect KEYWORD2 @@ -26,6 +30,10 @@ getTime KEYWORD2 getClient KEYWORD2 getUDP KEYWORD2 +# NotecardConnectionHandler.h +initiateNotehubSync KEYWORD2 +setWiFiCredentials KEYWORD2 + #################################################### # Constants (LITERAL1) #################################################### diff --git a/library.properties b/library.properties index 16239e46..c202d604 100644 --- a/library.properties +++ b/library.properties @@ -1,10 +1,10 @@ name=Arduino_ConnectionHandler -version=0.9.0 +version=1.0.0 author=Ubi de Feo, Cristian Maglie, Andrea Catozzi, Alexander Entinger et al. maintainer=Arduino -sentence=Arduino Library for network connection management (WiFi, GSM, NB, [Ethernet]) +sentence=Arduino Library for network connection management (WiFi, GSM, NB, [Ethernet], Notecard) paragraph=Originally part of ArduinoIoTCloud category=Communication url=https://github.com/arduino-libraries/Arduino_ConnectionHandler -architectures=samd,esp32,esp8266,mbed,megaavr,mbed_nano,mbed_portenta,mbed_nicla,mbed_opta,mbed_giga,renesas_portenta,renesas_uno,mbed_edge -depends=Arduino_DebugUtils, WiFi101, WiFiNINA, MKRGSM, MKRNB, MKRWAN +architectures=samd,esp32,esp8266,mbed,megaavr,mbed_nano,mbed_portenta,mbed_nicla,mbed_opta,mbed_giga,renesas_portenta,renesas_uno,mbed_edge,stm32 +depends=Arduino_DebugUtils, WiFi101, WiFiNINA, MKRGSM, MKRNB, MKRWAN, Blues Wireless Notecard (>=1.6.3) diff --git a/src/Arduino_ConnectionHandler.h b/src/Arduino_ConnectionHandler.h index b4f8e315..48327268 100644 --- a/src/Arduino_ConnectionHandler.h +++ b/src/Arduino_ConnectionHandler.h @@ -27,288 +27,40 @@ #endif #include +#include "ConnectionHandlerDefinitions.h" -#ifdef ARDUINO_SAMD_MKR1000 - #include - #include - - #define BOARD_HAS_WIFI - #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD - #define NETWORK_IDLE_STATUS WL_IDLE_STATUS - #define NETWORK_CONNECTED WL_CONNECTED - #define WIFI_FIRMWARE_VERSION_REQUIRED WIFI_FIRMWARE_REQUIRED -#endif - -#if defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT) || \ - defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined (ARDUINO_NANO_RP2040_CONNECT) - #include - #include - - #define BOARD_HAS_WIFI - #define NETWORK_HARDWARE_ERROR WL_NO_MODULE - #define NETWORK_IDLE_STATUS WL_IDLE_STATUS - #define NETWORK_CONNECTED WL_CONNECTED - #define WIFI_FIRMWARE_VERSION_REQUIRED WIFI_FIRMWARE_LATEST_VERSION -#endif - -#if defined(ARDUINO_PORTENTA_H7_M7) - #include - #include - #include - #include - #include - #include - - #define BOARD_HAS_WIFI - #define BOARD_HAS_ETHERNET - #define BOARD_HAS_CATM1_NBIOT - #define BOARD_HAS_CELLULAR - #define BOARD_HAS_PORTENTA_CATM1_NBIOT_SHIELD - #define BOARD_HAS_PORTENTA_VISION_SHIELD_ETHERNET - #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD - #define NETWORK_IDLE_STATUS WL_IDLE_STATUS - #define NETWORK_CONNECTED WL_CONNECTED -#endif - -#if defined(ARDUINO_PORTENTA_C33) - #include - #include - #include - #include - #include - - #define BOARD_HAS_WIFI - #define BOARD_HAS_ETHERNET - #define BOARD_HAS_CELLULAR - #define BOARD_HAS_PORTENTA_VISION_SHIELD_ETHERNET - #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD - #define NETWORK_IDLE_STATUS WL_IDLE_STATUS - #define NETWORK_CONNECTED WL_CONNECTED -#endif - -#if defined(ARDUINO_NICLA_VISION) - #include - #include - - #define BOARD_HAS_WIFI - #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD - #define NETWORK_IDLE_STATUS WL_IDLE_STATUS - #define NETWORK_CONNECTED WL_CONNECTED -#endif - -#if defined(ARDUINO_OPTA) - #include - #include - #include - #include - - #define BOARD_HAS_WIFI - #define BOARD_HAS_ETHERNET - #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD - #define NETWORK_IDLE_STATUS WL_IDLE_STATUS - #define NETWORK_CONNECTED WL_CONNECTED -#endif - -#if defined(ARDUINO_GIGA) - #include - #include - - #define BOARD_HAS_WIFI - #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD - #define NETWORK_IDLE_STATUS WL_IDLE_STATUS - #define NETWORK_CONNECTED WL_CONNECTED -#endif - -#ifdef ARDUINO_SAMD_MKRGSM1400 - #include - #define BOARD_HAS_GSM - #define NETWORK_HARDWARE_ERROR GPRS_PING_ERROR - #define NETWORK_IDLE_STATUS GSM3_NetworkStatus_t::IDLE - #define NETWORK_CONNECTED GSM3_NetworkStatus_t::GPRS_READY -#endif - -#ifdef ARDUINO_SAMD_MKRNB1500 - #include - #define BOARD_HAS_NB - #define NETWORK_HARDWARE_ERROR - #define NETWORK_IDLE_STATUS NB_NetworkStatus_t::IDLE - #define NETWORK_CONNECTED NB_NetworkStatus_t::GPRS_READY -#endif - -#if defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310) - #include - #define BOARD_HAS_LORA -#endif - -#if defined(ARDUINO_ARCH_ESP8266) - #include - #include - - #define BOARD_HAS_WIFI - #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD - #define NETWORK_IDLE_STATUS WL_IDLE_STATUS - #define NETWORK_CONNECTED WL_CONNECTED - #define WIFI_FIRMWARE_VERSION_REQUIRED WIFI_FIRMWARE_REQUIRED -#endif - -#if defined(ARDUINO_ARCH_ESP32) - #include - #include - - #define BOARD_HAS_WIFI - #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD - #define NETWORK_IDLE_STATUS WL_IDLE_STATUS - #define NETWORK_CONNECTED WL_CONNECTED - #define WIFI_FIRMWARE_VERSION_REQUIRED WIFI_FIRMWARE_REQUIRED -#endif - -#if defined(ARDUINO_UNOR4_WIFI) - #include +#if defined(BOARD_HAS_NOTECARD) + #include "NotecardConnectionHandler.h" +#else - #define BOARD_HAS_WIFI - #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD - #define NETWORK_IDLE_STATUS WL_IDLE_STATUS - #define NETWORK_CONNECTED WL_CONNECTED - #define WIFI_FIRMWARE_VERSION_REQUIRED WIFI_FIRMWARE_LATEST_VERSION +#if defined(BOARD_HAS_WIFI) + #include "WiFiConnectionHandler.h" #endif -#ifdef ARDUINO_EDGE_CONTROL - #include - #define BOARD_HAS_CATM1_NBIOT - #define BOARD_HAS_PORTENTA_CATM1_NBIOT_SHIELD - #define NETWORK_HARDWARE_ERROR +#if defined(BOARD_HAS_GSM) + #include "GSMConnectionHandler.h" #endif -/****************************************************************************** - TYPEDEFS - ******************************************************************************/ - -enum class NetworkConnectionState : unsigned int { - INIT = 0, - CONNECTING = 1, - CONNECTED = 2, - DISCONNECTING = 3, - DISCONNECTED = 4, - CLOSED = 5, - ERROR = 6 -}; - -enum class NetworkConnectionEvent { - CONNECTED, - DISCONNECTED, - ERROR -}; - -enum class NetworkAdapter { - WIFI, - ETHERNET, - NB, - GSM, - LORA, - CATM1, - CELL -}; - -typedef void (*OnNetworkEventCallback)(); - -/****************************************************************************** - CONSTANTS - ******************************************************************************/ - -static unsigned int const CHECK_INTERVAL_TABLE[] = -{ - /* INIT */ 100, -#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) - /* CONNECTING */ 4000, -#else - /* CONNECTING */ 500, +#if defined(BOARD_HAS_NB) + #include "NBConnectionHandler.h" #endif - /* CONNECTED */ 10000, - /* DISCONNECTING */ 100, - /* DISCONNECTED */ 1000, - /* CLOSED */ 1000, - /* ERROR */ 1000 -}; - -/****************************************************************************** - CLASS DECLARATION - ******************************************************************************/ - -class ConnectionHandler { - public: - ConnectionHandler(bool const keep_alive, NetworkAdapter interface); - - - NetworkConnectionState check(); - - #if !defined(BOARD_HAS_LORA) - virtual unsigned long getTime() = 0; - virtual Client &getClient() = 0; - virtual UDP &getUDP() = 0; - #else - virtual int write(const uint8_t *buf, size_t size) = 0; - virtual int read() = 0; - virtual bool available() = 0; - #endif - - NetworkConnectionState getStatus() __attribute__((deprecated)) { - return _current_net_connection_state; - } - - NetworkAdapter getInterface() { - return _interface; - } - - void connect(); - void disconnect(); - - void addCallback(NetworkConnectionEvent const event, OnNetworkEventCallback callback); - void addConnectCallback(OnNetworkEventCallback callback) __attribute__((deprecated)); - void addDisconnectCallback(OnNetworkEventCallback callback) __attribute__((deprecated)); - void addErrorCallback(OnNetworkEventCallback callback) __attribute__((deprecated)); - - protected: - - bool _keep_alive; - NetworkAdapter _interface; - - virtual NetworkConnectionState update_handleInit () = 0; - virtual NetworkConnectionState update_handleConnecting () = 0; - virtual NetworkConnectionState update_handleConnected () = 0; - virtual NetworkConnectionState update_handleDisconnecting() = 0; - virtual NetworkConnectionState update_handleDisconnected () = 0; - - - private: - - unsigned long _lastConnectionTickTime; - NetworkConnectionState _current_net_connection_state; - OnNetworkEventCallback _on_connect_event_callback = NULL, - _on_disconnect_event_callback = NULL, - _on_error_event_callback = NULL; -}; - -#if defined(BOARD_HAS_WIFI) - #include "Arduino_WiFiConnectionHandler.h" -#elif defined(BOARD_HAS_GSM) - #include "Arduino_GSMConnectionHandler.h" -#elif defined(BOARD_HAS_NB) - #include "Arduino_NBConnectionHandler.h" -#elif defined(BOARD_HAS_LORA) - #include "Arduino_LoRaConnectionHandler.h" +#if defined(BOARD_HAS_LORA) + #include "LoRaConnectionHandler.h" #endif #if defined(BOARD_HAS_ETHERNET) - #include "Arduino_EthernetConnectionHandler.h" + #include "EthernetConnectionHandler.h" #endif #if defined(BOARD_HAS_CATM1_NBIOT) - #include "Arduino_CatM1ConnectionHandler.h" + #include "CatM1ConnectionHandler.h" #endif #if defined(BOARD_HAS_CELLULAR) - #include "Arduino_CellularConnectionHandler.h" + #include "CellularConnectionHandler.h" #endif +#endif // BOARD_HAS_NOTECARD + #endif /* CONNECTION_HANDLER_H_ */ diff --git a/src/Arduino_CatM1ConnectionHandler.cpp b/src/CatM1ConnectionHandler.cpp similarity index 96% rename from src/Arduino_CatM1ConnectionHandler.cpp rename to src/CatM1ConnectionHandler.cpp index 0b99716d..0263a397 100644 --- a/src/Arduino_CatM1ConnectionHandler.cpp +++ b/src/CatM1ConnectionHandler.cpp @@ -19,9 +19,10 @@ INCLUDE ******************************************************************************/ -#include "Arduino_CatM1ConnectionHandler.h" +#include "ConnectionHandlerDefinitions.h" #ifdef BOARD_HAS_CATM1_NBIOT /* Only compile if the board has CatM1 BN-IoT */ +#include "CatM1ConnectionHandler.h" /****************************************************************************** CTOR/DTOR @@ -96,7 +97,7 @@ NetworkConnectionState CatM1ConnectionHandler::update_handleDisconnected() } else { - return NetworkConnectionState::CLOSED; + return NetworkConnectionState::CLOSED; } } diff --git a/src/Arduino_CatM1ConnectionHandler.h b/src/CatM1ConnectionHandler.h similarity index 91% rename from src/Arduino_CatM1ConnectionHandler.h rename to src/CatM1ConnectionHandler.h index de5fd01f..33ac9fea 100644 --- a/src/Arduino_CatM1ConnectionHandler.h +++ b/src/CatM1ConnectionHandler.h @@ -22,10 +22,15 @@ INCLUDE ******************************************************************************/ -#include "Arduino_ConnectionHandler.h" +#include "ConnectionHandlerInterface.h" +#if defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_EDGE_CONTROL) + #include +#endif -#ifdef BOARD_HAS_CATM1_NBIOT /* Only compile if the board has CatM1 BN-IoT */ +#ifndef BOARD_HAS_CATM1_NBIOT + #error "Board doesn't support CATM1_NBIOT" +#endif /****************************************************************************** CLASS DECLARATION @@ -66,6 +71,4 @@ class CatM1ConnectionHandler : public ConnectionHandler GSMClient _gsm_client; }; -#endif /* #ifdef BOARD_HAS_CATM1_NBIOT */ - #endif /* #ifndef ARDUINO_CATM1_CONNECTION_HANDLER_H_ */ diff --git a/src/Arduino_CellularConnectionHandler.cpp b/src/CellularConnectionHandler.cpp similarity index 97% rename from src/Arduino_CellularConnectionHandler.cpp rename to src/CellularConnectionHandler.cpp index 7e543b0e..2e4499a0 100644 --- a/src/Arduino_CellularConnectionHandler.cpp +++ b/src/CellularConnectionHandler.cpp @@ -13,9 +13,10 @@ INCLUDE ******************************************************************************/ -#include "Arduino_CellularConnectionHandler.h" +#include "ConnectionHandlerDefinitions.h" #ifdef BOARD_HAS_CELLULAR /* Only compile if the board has Cellular */ +#include "CellularConnectionHandler.h" /****************************************************************************** CTOR/DTOR diff --git a/src/Arduino_CellularConnectionHandler.h b/src/CellularConnectionHandler.h similarity index 88% rename from src/Arduino_CellularConnectionHandler.h rename to src/CellularConnectionHandler.h index 0c4d5f89..2addd29b 100644 --- a/src/Arduino_CellularConnectionHandler.h +++ b/src/CellularConnectionHandler.h @@ -16,9 +16,15 @@ INCLUDE ******************************************************************************/ -#include "Arduino_ConnectionHandler.h" +#include "ConnectionHandlerInterface.h" -#ifdef BOARD_HAS_CELLULAR /* Only compile if the board has Cellular */ +#if defined(ARDUINO_PORTENTA_C33) || defined(ARDUINO_PORTENTA_H7_M7) +#include +#endif + +#ifndef BOARD_HAS_CELLULAR + #error "Board doesn't support CELLULAR" +#endif /****************************************************************************** CLASS DECLARATION @@ -56,6 +62,4 @@ class CellularConnectionHandler : public ConnectionHandler TinyGsmClient _gsm_client = _cellular.getNetworkClient(); }; -#endif /* #ifdef BOARD_HAS_CELLULAR */ - #endif /* #ifndef ARDUINO_CELLULAR_CONNECTION_HANDLER_H_ */ diff --git a/src/ConnectionHandlerDefinitions.h b/src/ConnectionHandlerDefinitions.h new file mode 100644 index 00000000..4f295592 --- /dev/null +++ b/src/ConnectionHandlerDefinitions.h @@ -0,0 +1,204 @@ +/* + This file is part of ArduinoIoTCloud. + + Copyright 2019 ARDUINO SA (http://www.arduino.cc/) + + This software is released under the GNU General Public License version 3, + which covers the main part of arduino-cli. + The terms of this license can be found at: + https://www.gnu.org/licenses/gpl-3.0.en.html + + You can be released from the requirements of the above licenses by purchasing + a commercial license. Buying such a license is mandatory if you want to modify or + otherwise use the software for commercial activities involving the Arduino + software without disclosing the source code of your own applications. To purchase + a commercial license, send an email to license@arduino.cc. +*/ + +#pragma once + +/****************************************************************************** + INCLUDES + ******************************************************************************/ + +#if defined __has_include + #if __has_include () + #define BOARD_HAS_NOTECARD + #endif +#endif + +#include + +#ifndef BOARD_HAS_NOTECARD + +#ifdef ARDUINO_SAMD_MKR1000 + #define BOARD_HAS_WIFI + #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD + #define NETWORK_IDLE_STATUS WL_IDLE_STATUS + #define NETWORK_CONNECTED WL_CONNECTED + #define WIFI_FIRMWARE_VERSION_REQUIRED WIFI_FIRMWARE_REQUIRED +#endif + +#if defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT) || \ + defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined (ARDUINO_NANO_RP2040_CONNECT) + + #define BOARD_HAS_WIFI + #define NETWORK_HARDWARE_ERROR WL_NO_MODULE + #define NETWORK_IDLE_STATUS WL_IDLE_STATUS + #define NETWORK_CONNECTED WL_CONNECTED + #define WIFI_FIRMWARE_VERSION_REQUIRED WIFI_FIRMWARE_LATEST_VERSION +#endif + +#if defined(ARDUINO_PORTENTA_H7_M7) + #define BOARD_HAS_WIFI + #define BOARD_HAS_ETHERNET + #define BOARD_HAS_CATM1_NBIOT + #define BOARD_HAS_CELLULAR + #define BOARD_HAS_PORTENTA_CATM1_NBIOT_SHIELD + #define BOARD_HAS_PORTENTA_VISION_SHIELD_ETHERNET + #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD + #define NETWORK_IDLE_STATUS WL_IDLE_STATUS + #define NETWORK_CONNECTED WL_CONNECTED +#endif + +#if defined(ARDUINO_PORTENTA_C33) + #define BOARD_HAS_WIFI + #define BOARD_HAS_ETHERNET + #define BOARD_HAS_CELLULAR + #define BOARD_HAS_PORTENTA_VISION_SHIELD_ETHERNET + #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD + #define NETWORK_IDLE_STATUS WL_IDLE_STATUS + #define NETWORK_CONNECTED WL_CONNECTED +#endif + +#if defined(ARDUINO_NICLA_VISION) + #define BOARD_HAS_WIFI + #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD + #define NETWORK_IDLE_STATUS WL_IDLE_STATUS + #define NETWORK_CONNECTED WL_CONNECTED +#endif + +#if defined(ARDUINO_OPTA) + #define BOARD_HAS_WIFI + #define BOARD_HAS_ETHERNET + #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD + #define NETWORK_IDLE_STATUS WL_IDLE_STATUS + #define NETWORK_CONNECTED WL_CONNECTED +#endif + +#if defined(ARDUINO_GIGA) + + #define BOARD_HAS_WIFI + #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD + #define NETWORK_IDLE_STATUS WL_IDLE_STATUS + #define NETWORK_CONNECTED WL_CONNECTED +#endif + +#ifdef ARDUINO_SAMD_MKRGSM1400 + #define BOARD_HAS_GSM + #define NETWORK_HARDWARE_ERROR GPRS_PING_ERROR + #define NETWORK_IDLE_STATUS GSM3_NetworkStatus_t::IDLE + #define NETWORK_CONNECTED GSM3_NetworkStatus_t::GPRS_READY +#endif + +#ifdef ARDUINO_SAMD_MKRNB1500 + #define BOARD_HAS_NB + #define NETWORK_HARDWARE_ERROR + #define NETWORK_IDLE_STATUS NB_NetworkStatus_t::IDLE + #define NETWORK_CONNECTED NB_NetworkStatus_t::GPRS_READY +#endif + +#if defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310) + #define BOARD_HAS_LORA +#endif + +#if defined(ARDUINO_ARCH_ESP8266) + + #define BOARD_HAS_WIFI + #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD + #define NETWORK_IDLE_STATUS WL_IDLE_STATUS + #define NETWORK_CONNECTED WL_CONNECTED + #define WIFI_FIRMWARE_VERSION_REQUIRED WIFI_FIRMWARE_REQUIRED +#endif + +#if defined(ARDUINO_ARCH_ESP32) + #define BOARD_HAS_WIFI + #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD + #define NETWORK_IDLE_STATUS WL_IDLE_STATUS + #define NETWORK_CONNECTED WL_CONNECTED + #define WIFI_FIRMWARE_VERSION_REQUIRED WIFI_FIRMWARE_REQUIRED +#endif + +#if defined(ARDUINO_UNOR4_WIFI) + + #define BOARD_HAS_WIFI + #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD + #define NETWORK_IDLE_STATUS WL_IDLE_STATUS + #define NETWORK_CONNECTED WL_CONNECTED + #define WIFI_FIRMWARE_VERSION_REQUIRED WIFI_FIRMWARE_LATEST_VERSION +#endif + +#ifdef ARDUINO_EDGE_CONTROL + #define BOARD_HAS_CATM1_NBIOT + #define BOARD_HAS_PORTENTA_CATM1_NBIOT_SHIELD + #define NETWORK_HARDWARE_ERROR +#endif + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + #define BOARD_HAS_WIFI + #define NETWORK_HARDWARE_ERROR WL_NO_SHIELD + #define NETWORK_IDLE_STATUS WL_IDLE_STATUS + #define NETWORK_CONNECTED WL_CONNECTED +#endif + +#endif // BOARD_HAS_NOTECARD + +/****************************************************************************** + TYPEDEFS + ******************************************************************************/ + +enum class NetworkConnectionState : unsigned int { + INIT = 0, + CONNECTING = 1, + CONNECTED = 2, + DISCONNECTING = 3, + DISCONNECTED = 4, + CLOSED = 5, + ERROR = 6 +}; + +enum class NetworkConnectionEvent { + CONNECTED, + DISCONNECTED, + ERROR +}; + +enum class NetworkAdapter { + WIFI, + ETHERNET, + NB, + GSM, + LORA, + CATM1, + CELL, + NOTECARD +}; + +/****************************************************************************** + CONSTANTS + ******************************************************************************/ + +static unsigned int const CHECK_INTERVAL_TABLE[] = +{ + /* INIT */ 100, +#if defined(BOARD_HAS_NOTECARD) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) + /* CONNECTING */ 4000, +#else + /* CONNECTING */ 500, +#endif + /* CONNECTED */ 10000, + /* DISCONNECTING */ 100, + /* DISCONNECTED */ 1000, + /* CLOSED */ 1000, + /* ERROR */ 1000 +}; diff --git a/src/Arduino_ConnectionHandler.cpp b/src/ConnectionHandlerInterface.cpp similarity index 99% rename from src/Arduino_ConnectionHandler.cpp rename to src/ConnectionHandlerInterface.cpp index ab83fa08..2fdc10e1 100644 --- a/src/Arduino_ConnectionHandler.cpp +++ b/src/ConnectionHandlerInterface.cpp @@ -19,7 +19,7 @@ INCLUDE ******************************************************************************/ -#include "Arduino_ConnectionHandler.h" +#include "ConnectionHandlerInterface.h" /****************************************************************************** CONSTRUCTOR/DESTRUCTOR diff --git a/src/ConnectionHandlerInterface.h b/src/ConnectionHandlerInterface.h new file mode 100644 index 00000000..228827e7 --- /dev/null +++ b/src/ConnectionHandlerInterface.h @@ -0,0 +1,99 @@ +/* + This file is part of ArduinoIoTCloud. + + Copyright 2019 ARDUINO SA (http://www.arduino.cc/) + + This software is released under the GNU General Public License version 3, + which covers the main part of arduino-cli. + The terms of this license can be found at: + https://www.gnu.org/licenses/gpl-3.0.en.html + + You can be released from the requirements of the above licenses by purchasing + a commercial license. Buying such a license is mandatory if you want to modify or + otherwise use the software for commercial activities involving the Arduino + software without disclosing the source code of your own applications. To purchase + a commercial license, send an email to license@arduino.cc. +*/ + +#pragma once + +/****************************************************************************** + INCLUDES + ******************************************************************************/ + +#if !defined(__AVR__) +# include +#endif + +#include +#include +#include +#include "ConnectionHandlerDefinitions.h" + +/****************************************************************************** + TYPEDEFS + ******************************************************************************/ + +typedef void (*OnNetworkEventCallback)(); + +/****************************************************************************** + CLASS DECLARATION + ******************************************************************************/ + +class ConnectionHandler { + public: + + ConnectionHandler(bool const keep_alive, NetworkAdapter interface); + + + NetworkConnectionState check(); + + #if not defined(BOARD_HAS_LORA) + virtual unsigned long getTime() = 0; + #endif + + #if defined(BOARD_HAS_NOTECARD) || defined(BOARD_HAS_LORA) + virtual bool available() = 0; + virtual int read() = 0; + virtual int write(const uint8_t *buf, size_t size) = 0; + #else + virtual Client &getClient() = 0; + virtual UDP &getUDP() = 0; + #endif + + NetworkConnectionState getStatus() __attribute__((deprecated)) { + return _current_net_connection_state; + } + + NetworkAdapter getInterface() { + return _interface; + } + + void connect(); + void disconnect(); + + void addCallback(NetworkConnectionEvent const event, OnNetworkEventCallback callback); + void addConnectCallback(OnNetworkEventCallback callback) __attribute__((deprecated)); + void addDisconnectCallback(OnNetworkEventCallback callback) __attribute__((deprecated)); + void addErrorCallback(OnNetworkEventCallback callback) __attribute__((deprecated)); + + protected: + + bool _keep_alive; + NetworkAdapter _interface; + + virtual NetworkConnectionState update_handleInit () = 0; + virtual NetworkConnectionState update_handleConnecting () = 0; + virtual NetworkConnectionState update_handleConnected () = 0; + virtual NetworkConnectionState update_handleDisconnecting() = 0; + virtual NetworkConnectionState update_handleDisconnected () = 0; + + private: + + unsigned long _lastConnectionTickTime; + NetworkConnectionState _current_net_connection_state; + OnNetworkEventCallback _on_connect_event_callback = NULL, + _on_disconnect_event_callback = NULL, + _on_error_event_callback = NULL; +}; + diff --git a/src/Arduino_EthernetConnectionHandler.cpp b/src/EthernetConnectionHandler.cpp similarity index 98% rename from src/Arduino_EthernetConnectionHandler.cpp rename to src/EthernetConnectionHandler.cpp index 0fa2e254..14f7aee4 100644 --- a/src/Arduino_EthernetConnectionHandler.cpp +++ b/src/EthernetConnectionHandler.cpp @@ -16,9 +16,10 @@ INCLUDE ******************************************************************************/ -#include "Arduino_EthernetConnectionHandler.h" +#include "ConnectionHandlerDefinitions.h" #ifdef BOARD_HAS_ETHERNET /* Only compile if the board has ethernet */ +#include "EthernetConnectionHandler.h" /****************************************************************************** CTOR/DTOR diff --git a/src/Arduino_EthernetConnectionHandler.h b/src/EthernetConnectionHandler.h similarity index 87% rename from src/Arduino_EthernetConnectionHandler.h rename to src/EthernetConnectionHandler.h index cc22bfee..35a02cd9 100644 --- a/src/Arduino_EthernetConnectionHandler.h +++ b/src/EthernetConnectionHandler.h @@ -19,9 +19,22 @@ INCLUDE ******************************************************************************/ -#include "Arduino_ConnectionHandler.h" - -#ifdef BOARD_HAS_ETHERNET /* Only compile if the board has ethernet */ +#include "ConnectionHandlerInterface.h" + +#if defined(ARDUINO_PORTENTA_H7_M7) + #include + #include +#elif defined(ARDUINO_PORTENTA_C33) + #include + #include +#elif defined(ARDUINO_OPTA) + #include + #include +#endif + +#ifndef BOARD_HAS_ETHERNET + #error "Board doesn't support ETHERNET" +#endif /****************************************************************************** CLASS DECLARATION @@ -64,6 +77,4 @@ class EthernetConnectionHandler : public ConnectionHandler }; -#endif /* #ifdef BOARD_HAS_ETHERNET */ - #endif /* ARDUINO_ETHERNET_CONNECTION_HANDLER_H_ */ diff --git a/src/Arduino_GSMConnectionHandler.cpp b/src/GSMConnectionHandler.cpp similarity index 98% rename from src/Arduino_GSMConnectionHandler.cpp rename to src/GSMConnectionHandler.cpp index e57a7201..34bf1792 100644 --- a/src/Arduino_GSMConnectionHandler.cpp +++ b/src/GSMConnectionHandler.cpp @@ -19,9 +19,10 @@ INCLUDE ******************************************************************************/ -#include "Arduino_GSMConnectionHandler.h" +#include "ConnectionHandlerDefinitions.h" #ifdef BOARD_HAS_GSM /* Only compile if this is a board with GSM */ +#include "GSMConnectionHandler.h" /****************************************************************************** CONSTANTS diff --git a/src/Arduino_GSMConnectionHandler.h b/src/GSMConnectionHandler.h similarity index 92% rename from src/Arduino_GSMConnectionHandler.h rename to src/GSMConnectionHandler.h index 714ed8c5..1f3db49a 100644 --- a/src/Arduino_GSMConnectionHandler.h +++ b/src/GSMConnectionHandler.h @@ -22,10 +22,15 @@ INCLUDE ******************************************************************************/ -#include "Arduino_ConnectionHandler.h" +#include "ConnectionHandlerInterface.h" +#if defined(ARDUINO_SAMD_MKRGSM1400) + #include +#endif -#ifdef BOARD_HAS_GSM /* Only compile if this is a board with GSM */ +#ifndef BOARD_HAS_GSM + #error "Board doesn't support GSM" +#endif /****************************************************************************** CLASS DECLARATION @@ -65,6 +70,4 @@ class GSMConnectionHandler : public ConnectionHandler GSMClient _gsm_client; }; -#endif /* #ifdef BOARD_HAS_GSM */ - #endif /* #ifndef GSM_CONNECTION_MANAGER_H_ */ diff --git a/src/Arduino_LoRaConnectionHandler.cpp b/src/LoRaConnectionHandler.cpp similarity index 98% rename from src/Arduino_LoRaConnectionHandler.cpp rename to src/LoRaConnectionHandler.cpp index cf1deaf0..1f454a51 100644 --- a/src/Arduino_LoRaConnectionHandler.cpp +++ b/src/LoRaConnectionHandler.cpp @@ -19,9 +19,10 @@ INCLUDE ******************************************************************************/ -#include "Arduino_LoRaConnectionHandler.h" +#include "ConnectionHandlerDefinitions.h" #if defined(BOARD_HAS_LORA) /* Only compile if the board has LoRa */ +#include "LoRaConnectionHandler.h" /****************************************************************************** TYPEDEF diff --git a/src/Arduino_LoRaConnectionHandler.h b/src/LoRaConnectionHandler.h similarity index 93% rename from src/Arduino_LoRaConnectionHandler.h rename to src/LoRaConnectionHandler.h index aa769ab5..3ddcca24 100644 --- a/src/Arduino_LoRaConnectionHandler.h +++ b/src/LoRaConnectionHandler.h @@ -22,9 +22,16 @@ INCLUDE ******************************************************************************/ -#include "Arduino_ConnectionHandler.h" +#include "ConnectionHandlerInterface.h" + +#if defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310) + #include +#endif + +#ifndef BOARD_HAS_LORA + #error "Board doesn't support LORA" +#endif -#ifdef BOARD_HAS_LORA /* Only compile if the board has LoRa */ /****************************************************************************** CLASS DECLARATION @@ -74,6 +81,4 @@ class LoRaConnectionHandler : public ConnectionHandler LoRaModem _modem; }; -#endif /* #ifdef BOARD_HAS_LORA */ - #endif /* ARDUINO_LORA_CONNECTION_HANDLER_H_ */ diff --git a/src/Arduino_NBConnectionHandler.cpp b/src/NBConnectionHandler.cpp similarity index 98% rename from src/Arduino_NBConnectionHandler.cpp rename to src/NBConnectionHandler.cpp index 344e104f..eb72f3e7 100644 --- a/src/Arduino_NBConnectionHandler.cpp +++ b/src/NBConnectionHandler.cpp @@ -19,9 +19,10 @@ INCLUDE ******************************************************************************/ -#include "Arduino_NBConnectionHandler.h" +#include "ConnectionHandlerDefinitions.h" #ifdef BOARD_HAS_NB /* Only compile if this is a board with NB */ +#include "NBConnectionHandler.h" /****************************************************************************** CONSTANTS diff --git a/src/Arduino_NBConnectionHandler.h b/src/NBConnectionHandler.h similarity index 93% rename from src/Arduino_NBConnectionHandler.h rename to src/NBConnectionHandler.h index 53d2174e..fd2afb6c 100644 --- a/src/Arduino_NBConnectionHandler.h +++ b/src/NBConnectionHandler.h @@ -22,9 +22,15 @@ INCLUDE ******************************************************************************/ -#include "Arduino_ConnectionHandler.h" +#include "ConnectionHandlerInterface.h" -#ifdef BOARD_HAS_NB /* Only compile if this is a board with NB */ +#ifdef ARDUINO_SAMD_MKRNB1500 + #include +#endif + +#ifndef BOARD_HAS_NB + #error "Board doesn't support NB" +#endif /****************************************************************************** CLASS DECLARATION @@ -68,6 +74,4 @@ class NBConnectionHandler : public ConnectionHandler NBClient _nb_client; }; -#endif /* #ifdef BOARD_HAS_NB */ - #endif /* #ifndef NB_CONNECTION_MANAGER_H_ */ diff --git a/src/NotecardConnectionHandler.cpp b/src/NotecardConnectionHandler.cpp new file mode 100644 index 00000000..5205c4a8 --- /dev/null +++ b/src/NotecardConnectionHandler.cpp @@ -0,0 +1,828 @@ +/* + This file is part of the ArduinoIoTCloud library. + + Copyright 2024 Blues (http://www.blues.com/) + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +/****************************************************************************** + INCLUDE + ******************************************************************************/ + +#include "ConnectionHandlerDefinitions.h" + +#if defined(BOARD_HAS_NOTECARD) // Only compile if the Notecard is present + +#include "NotecardConnectionHandler.h" + +#include +#include +#include + +/****************************************************************************** + DEFINES + ******************************************************************************/ + +#define NO_INBOUND_POLLING -1 + +#define NOTEFILE_BASE_NAME "arduino_iot_cloud" + +// Notecard LoRa requires us to choose an arbitrary port between 1-99 +#define NOTEFILE_DATABASE_LORA_PORT 1 +#define NOTEFILE_INBOUND_LORA_PORT 2 +#define NOTEFILE_OUTBOUND_LORA_PORT 3 + +// Note that we use "s" versions of the Notefile extensions to ensure that +// traffic always happens on a secure transport +#define NOTEFILE_SECURE_DATABASE NOTEFILE_BASE_NAME ".dbs" +#define NOTEFILE_SECURE_INBOUND NOTEFILE_BASE_NAME ".qis" +#define NOTEFILE_SECURE_OUTBOUND NOTEFILE_BASE_NAME ".qos" + +/****************************************************************************** + STLINK DEBUG OUTPUT + ******************************************************************************/ + +// Provide Notehub debug output via STLINK serial port when available +#if defined(ARDUINO_SWAN_R5) || defined(ARDUINO_CYGNET) + #define STLINK_DEBUG + HardwareSerial stlinkSerial(PIN_VCP_RX, PIN_VCP_TX); +#endif + +/****************************************************************************** + TYPEDEF + ******************************************************************************/ + +struct NotecardConnectionStatus +{ + NotecardConnectionStatus(void) : transport_connected(0), connected_to_notehub(0), notecard_error(0), host_error(0), reserved(0) { } + NotecardConnectionStatus(uint_fast8_t x) : transport_connected(x & 0x01), connected_to_notehub(x & 0x02), notecard_error(x & 0x04), host_error(x & 0x08), reserved(x & 0xF0) { } + NotecardConnectionStatus & operator=(uint_fast8_t x) { + transport_connected = (x & 0x01); + connected_to_notehub = (x & 0x02); + notecard_error = (x & 0x04); + host_error = (x & 0x08); + reserved = (x & 0xF0); + return *this; + } + operator uint_fast8_t () const { + return ((reserved << 4) | (host_error << 3) | (notecard_error << 2) | (connected_to_notehub << 1) | (transport_connected)); + } + + bool transport_connected : 1; + bool connected_to_notehub : 1; + bool notecard_error : 1; + bool host_error : 1; + uint_fast8_t reserved : 4; +}; +static_assert(sizeof(NotecardConnectionStatus) == sizeof(uint_fast8_t)); + +/****************************************************************************** + CTOR/DTOR + ******************************************************************************/ + +NotecardConnectionHandler::NotecardConnectionHandler( + const String & project_uid_, + uint32_t i2c_address_, + uint32_t i2c_max_, + TwoWire & wire_, + bool keep_alive_ +) : + ConnectionHandler{keep_alive_, NetworkAdapter::NOTECARD}, + _notecard{}, + _device_id{}, + _notecard_uid{}, + _project_uid(project_uid_), + _serial(nullptr), + _wire(&wire_), + _inbound_buffer(nullptr), + _conn_start_ms(0), + _i2c_address(i2c_address_), + _i2c_max(i2c_max_), + _inbound_buffer_index(0), + _inbound_buffer_size(0), + _inbound_polling_interval_min(NO_INBOUND_POLLING), + _uart_baud(0), + _en_hw_int(false), + _topic_type{TopicType::Invalid} +{ } + +NotecardConnectionHandler::NotecardConnectionHandler( + const String & project_uid_, + HardwareSerial & serial_, + uint32_t baud_, + bool keep_alive_ +) : + ConnectionHandler{keep_alive_, NetworkAdapter::NOTECARD}, + _notecard{}, + _device_id{}, + _notecard_uid{}, + _project_uid(project_uid_), + _serial(&serial_), + _wire(nullptr), + _inbound_buffer(nullptr), + _conn_start_ms(0), + _i2c_address(0), + _i2c_max(0), + _inbound_buffer_index(0), + _inbound_buffer_size(0), + _inbound_polling_interval_min(NO_INBOUND_POLLING), + _uart_baud(baud_), + _en_hw_int(false), + _topic_type{TopicType::Invalid} +{ } + +/****************************************************************************** + PUBLIC MEMBER FUNCTIONS + ******************************************************************************/ + +int NotecardConnectionHandler::initiateNotehubSync (SyncType type_) const +{ + int result; + + Debug.print(DBG_DEBUG, F("NotecardConnectionHandler::%s initiating Notehub sync..."), __FUNCTION__); + if (J *req = _notecard.newRequest("hub.sync")) { + if (type_ == SyncType::Inbound) { + JAddBoolToObject(req, "in", true); + } else if (type_ == SyncType::Outbound) { + JAddBoolToObject(req, "out", true); + } + if (J *rsp = _notecard.requestAndResponse(req)) { + // Check the response for errors + if (NoteResponseError(rsp)) { + const char *err = JGetString(rsp, "err"); + Debug.print(DBG_ERROR, F("%s"), err); + result = NotecardCommunicationError::NOTECARD_ERROR_GENERIC; + } else { + Debug.print(DBG_DEBUG, F("NotecardConnectionHandler::%s successfully initiated Notehub sync."), __FUNCTION__); + result = NotecardCommunicationError::NOTECARD_ERROR_NONE; + } + JDelete(rsp); + } else { + Debug.print(DBG_ERROR, F("Failed to receive response from Notecard.")); + result = NotecardCommunicationError::NOTECARD_ERROR_GENERIC; + } + } else { + Debug.print(DBG_ERROR, "Failed to allocate request: hub.sync"); + result = NotecardCommunicationError::HOST_ERROR_OUT_OF_MEMORY; + } + + return result; +} + +int NotecardConnectionHandler::setWiFiCredentials (const String & ssid_, const String & password_) +{ + int result; + + // Validate the connection state is not in an initialization state + const NetworkConnectionState current_net_connection_state = check(); + if (NetworkConnectionState::INIT == current_net_connection_state) + { + Debug.print(DBG_ERROR, F("Unable to set Wi-Fi credentials. Connection to Notecard uninitialized.")); + result = NotecardCommunicationError::NOTECARD_ERROR_GENERIC; + } else if (J *req = _notecard.newRequest("card.wifi")) { + JAddStringToObject(req, "ssid", ssid_.c_str()); + JAddStringToObject(req, "password", password_.c_str()); + if (J *rsp = _notecard.requestAndResponse(req)) { + // Check the response for errors + if (NoteResponseError(rsp)) { + const char *err = JGetString(rsp, "err"); + Debug.print(DBG_ERROR, F("%s"), err); + Debug.print(DBG_ERROR, F("Failed to set Wi-Fi credentials.")); + result = NotecardCommunicationError::NOTECARD_ERROR_GENERIC; + } else { + Debug.print(DBG_INFO, F("Wi-Fi credentials updated. ssid: \"%s\" password: \"%s\"."), ssid_.c_str(), password_.length() ? "**********" : ""); + result = NotecardCommunicationError::NOTECARD_ERROR_NONE; + } + JDelete(rsp); + } else { + Debug.print(DBG_ERROR, F("Failed to receive response from Notecard.")); + result = NotecardCommunicationError::NOTECARD_ERROR_GENERIC; + } + } else { + Debug.print(DBG_ERROR, F("Failed to allocate request: wifi.set")); + result = NotecardCommunicationError::HOST_ERROR_OUT_OF_MEMORY; + } + + return result; +} + +/****************************************************************************** + PUBLIC INTERFACE MEMBER FUNCTIONS + ******************************************************************************/ + +bool NotecardConnectionHandler::available() +{ + bool buffered_data = (_inbound_buffer_index < _inbound_buffer_size); + bool flush_required = !buffered_data && _inbound_buffer_size; + + // When the buffer is empty, look for a Note in the + // NOTEFILE_SECURE_INBOUND file to reload the buffer. + if (!buffered_data) { + // Reset the buffer + free(_inbound_buffer); + _inbound_buffer = nullptr; + _inbound_buffer_index = 0; + _inbound_buffer_size = 0; + + // Do NOT attempt to buffer the next Note immediately after buffer + // exhaustion (a.k.a. flush required). Returning `false` between Notes, + // will break the read loop, force the CBOR buffer to be parsed, and the + // property containers to be updated. + if (!flush_required) { + // Reload the buffer + J *note = getNote(true); + if (note) { + if (J *body = JGetObject(note, "body")) { + _topic_type = static_cast(JGetInt(body, "topic")); + if (_topic_type == TopicType::Invalid) { + Debug.print(DBG_WARNING, F("Note does not contain a topic")); + } else { + buffered_data = JGetBinaryFromObject(note, "payload", &_inbound_buffer, &_inbound_buffer_size); + if (!buffered_data) { + Debug.print(DBG_WARNING, F("Note does not contain payload data")); + } else { + Debug.print(DBG_DEBUG, F("NotecardConnectionHandler::%s buffered payload with size: %d"), __FUNCTION__, _inbound_buffer_size); + } + } + } else { + _topic_type = TopicType::Invalid; + } + JDelete(note); + } + } + } + + return buffered_data; +} + +unsigned long NotecardConnectionHandler::getTime() +{ + unsigned long result; + + if (J *rsp = _notecard.requestAndResponse(_notecard.newRequest("card.time"))) { + if (NoteResponseError(rsp)) { + const char *err = JGetString(rsp, "err"); + Debug.print(DBG_ERROR, F("%s\n"), err); + result = 0; + } else { + result = JGetInt(rsp, "time"); + } + JDelete(rsp); + } else { + result = 0; + } + + return result; +} + +int NotecardConnectionHandler::read() +{ + int result; + + if (_inbound_buffer_index < _inbound_buffer_size) { + result = _inbound_buffer[_inbound_buffer_index++]; + } else { + result = NotecardCommunicationError::NOTECARD_ERROR_NO_DATA_AVAILABLE; + } + + return result; +} + +int NotecardConnectionHandler::write(const uint8_t * buf_, size_t size_) +{ + int result; + + // Validate the connection state is not uninitialized or in error state + const NetworkConnectionState current_net_connection_state = check(); + if ((NetworkConnectionState::INIT == current_net_connection_state) + || (NetworkConnectionState::ERROR == current_net_connection_state)) + { + Debug.print(DBG_ERROR, F("Unable to write message. Connection to Notecard uninitialized or in error state.")); + result = NotecardCommunicationError::NOTECARD_ERROR_GENERIC; + } else if (J * req = _notecard.newRequest("note.add")) { + JAddStringToObject(req, "file", NOTEFILE_SECURE_OUTBOUND); + if (buf_) { + JAddBinaryToObject(req, "payload", buf_, size_); + } + // Queue the Note when `_keep_alive` is disabled or not connected to Notehub + if (_keep_alive && (NetworkConnectionState::CONNECTED == current_net_connection_state)) { + JAddBoolToObject(req, "live", true); + JAddBoolToObject(req, "sync", true); + } + if (J *body = JAddObjectToObject(req, "body")) { + JAddIntToObject(body, "topic", static_cast(_topic_type)); + J * rsp = _notecard.requestAndResponse(req); + if (NoteResponseError(rsp)) { + const char *err = JGetString(rsp, "err"); + if (NoteErrorContains(err, "{hub-not-connected}")) { + // _current_net_connection_state = NetworkConnectionState::DISCONNECTED; + } + Debug.print(DBG_ERROR, F("%s\n"), err); + result = NotecardCommunicationError::NOTECARD_ERROR_GENERIC; + } else { + result = NotecardCommunicationError::NOTECARD_ERROR_NONE; + Debug.print(DBG_INFO, F("Message sent correctly!")); + } + JDelete(rsp); + } else { + JFree(req); + result = NotecardCommunicationError::HOST_ERROR_OUT_OF_MEMORY; + } + } else { + result = NotecardCommunicationError::HOST_ERROR_OUT_OF_MEMORY; + } + + return result; +} + +/****************************************************************************** + PROTECTED STATE MACHINE FUNCTIONS + ******************************************************************************/ + +NetworkConnectionState NotecardConnectionHandler::update_handleInit() +{ + NetworkConnectionState result = NetworkConnectionState::INIT; + + // Configure Hardware +/////////////////////// + +#if defined(STLINK_DEBUG) + // Output Notecard logs to the STLINK serial port + stlinkSerial.end(); // necessary to handle multiple initializations (e.g. reconnections) + stlinkSerial.begin(115200); + const size_t usb_timeout_ms = 3000; + for (const size_t start_ms = millis(); !stlinkSerial && (millis() - start_ms) < usb_timeout_ms;); + _notecard.setDebugOutputStream(stlinkSerial); +#endif + + // Initialize the Notecard based on the configuration + if (_serial) { + _notecard.begin(*_serial, _uart_baud); + } else { + _notecard.begin(_i2c_address, _i2c_max, *_wire); + } + + // Configure `note-c` + /////////////////////// + + // Set the user agent + NoteSetUserAgent((char *) ("arduino-iot-cloud " NOTECARD_CONNECTION_HANDLER_VERSION)); + + // Configure the ATTN pin to be used as an interrupt to indicate when a Note + // is available to read. `getNote()` will only arm the interrupt if no old + // Notes are available. If `ATTN` remains unarmed, it signals the user + // application that outstanding Notes are queued and need to be processed. + if (J *note = getNote(false)) { + JDelete(note); + } + + // Configure the Notecard + /////////////////////////// + + // Set the project UID + if (NetworkConnectionState::INIT == result) { + if (configureConnection(true)) { + result = NetworkConnectionState::INIT; + } else { + result = NetworkConnectionState::ERROR; + } + } + +#if defined(ARDUINO_OPTA) + // The Opta Extension has an onboard Li-Ion capacitor, that can be utilized + // to monitor the power state of the device and automatically report loss of + // power to Notehub. The following command enables that detection by default + // for the Opta Wirelss Extension. + if (NetworkConnectionState::INIT == result) { + if (J *req = _notecard.newRequest("card.voltage")) { + JAddStringToObject(req, "mode", "lipo"); + JAddBoolToObject(req, "alert", true); + JAddBoolToObject(req, "sync", true); + JAddBoolToObject(req, "usb", true); + if (J *rsp = _notecard.requestAndResponse(req)) { + // Check the response for errors + if (NoteResponseError(rsp)) { + const char *err = JGetString(rsp, "err"); + Debug.print(DBG_ERROR, F("%s"), err); + result = NetworkConnectionState::ERROR; + } else { + result = NetworkConnectionState::INIT; + } + JDelete(rsp); + } else { + Debug.print(DBG_ERROR, F("Failed to receive response from Notecard.")); + result = NetworkConnectionState::ERROR; // Assume the worst + } + } else { + Debug.print(DBG_ERROR, "Failed to allocate request: card.voltage"); + result = NetworkConnectionState::ERROR; // Assume the worst + } + } +#endif + + // Set database template to support LoRa/Satellite Notecard + if (NetworkConnectionState::INIT == result) { + if (J *req = _notecard.newRequest("note.template")) { + JAddStringToObject(req, "file", NOTEFILE_SECURE_DATABASE); + JAddStringToObject(req, "format", "compact"); // Support LoRa/Satellite Notecards + JAddIntToObject(req, "port", NOTEFILE_DATABASE_LORA_PORT); // Support LoRa/Satellite Notecards + if (J *body = JAddObjectToObject(req, "body")) { + JAddStringToObject(body, "text", TSTRINGV); + JAddNumberToObject(body, "value", TFLOAT64); + JAddBoolToObject(body, "flag", TBOOL); + if (J *rsp = _notecard.requestAndResponse(req)) { + // Check the response for errors + if (NoteResponseError(rsp)) { + const char *err = JGetString(rsp, "err"); + Debug.print(DBG_ERROR, F("%s"), err); + result = NetworkConnectionState::ERROR; + } else { + result = NetworkConnectionState::INIT; + } + JDelete(rsp); + } else { + Debug.print(DBG_ERROR, F("Failed to receive response from Notecard.")); + result = NetworkConnectionState::ERROR; // Assume the worst + } + } else { + Debug.print(DBG_ERROR, "Failed to allocate request: note.template:body"); + JFree(req); + result = NetworkConnectionState::ERROR; // Assume the worst + } + } else { + Debug.print(DBG_ERROR, "Failed to allocate request: note.template"); + result = NetworkConnectionState::ERROR; // Assume the worst + } + } + + // Set inbound template to support LoRa/Satellite Notecard + if (NetworkConnectionState::INIT == result) { + if (J *req = _notecard.newRequest("note.template")) { + JAddStringToObject(req, "file", NOTEFILE_SECURE_INBOUND); + JAddStringToObject(req, "format", "compact"); // Support LoRa/Satellite Notecards + JAddIntToObject(req, "port", NOTEFILE_INBOUND_LORA_PORT); // Support LoRa/Satellite Notecards + if (J *body = JAddObjectToObject(req, "body")) { + JAddIntToObject(body, "topic", TUINT8); + if (J *rsp = _notecard.requestAndResponse(req)) { + // Check the response for errors + if (NoteResponseError(rsp)) { + const char *err = JGetString(rsp, "err"); + Debug.print(DBG_ERROR, F("%s"), err); + result = NetworkConnectionState::ERROR; + } else { + result = NetworkConnectionState::INIT; + } + JDelete(rsp); + } else { + Debug.print(DBG_ERROR, F("Failed to receive response from Notecard.")); + result = NetworkConnectionState::ERROR; // Assume the worst + } + } else { + Debug.print(DBG_ERROR, "Failed to allocate request: note.template:body"); + JFree(req); + result = NetworkConnectionState::ERROR; // Assume the worst + } + } else { + Debug.print(DBG_ERROR, "Failed to allocate request: note.template"); + result = NetworkConnectionState::ERROR; // Assume the worst + } + } + + // Set outbound template to remove payload size restrictions + if (NetworkConnectionState::INIT == result) { + if (J *req = _notecard.newRequest("note.template")) { + JAddStringToObject(req, "file", NOTEFILE_SECURE_OUTBOUND); + JAddStringToObject(req, "format", "compact"); // Support LoRa/Satellite Notecards + JAddIntToObject(req, "port", NOTEFILE_OUTBOUND_LORA_PORT); // Support LoRa/Satellite Notecards + if (J *body = JAddObjectToObject(req, "body")) { + JAddIntToObject(body, "topic", TUINT8); + if (J *rsp = _notecard.requestAndResponse(req)) { + // Check the response for errors + if (NoteResponseError(rsp)) { + const char *err = JGetString(rsp, "err"); + Debug.print(DBG_ERROR, F("%s"), err); + result = NetworkConnectionState::ERROR; + } else { + result = NetworkConnectionState::INIT; + } + JDelete(rsp); + } else { + Debug.print(DBG_ERROR, F("Failed to receive response from Notecard.")); + result = NetworkConnectionState::ERROR; // Assume the worst + } + } else { + Debug.print(DBG_ERROR, "Failed to allocate request: note.template:body"); + JFree(req); + result = NetworkConnectionState::ERROR; // Assume the worst + } + } else { + Debug.print(DBG_ERROR, "Failed to allocate request: note.template"); + result = NetworkConnectionState::ERROR; // Assume the worst + } + } + + // Get the device UID + if (NetworkConnectionState::INIT == result) { + if (!updateUidCache()) { + result = NetworkConnectionState::ERROR; + } else { + Debug.print(DBG_INFO, F("Notecard has been initialized.")); + if (_keep_alive) { + _conn_start_ms = ::millis(); + Debug.print(DBG_INFO, F("Starting network connection...")); + result = NetworkConnectionState::CONNECTING; + } else { + Debug.print(DBG_INFO, F("Network is disconnected.")); + result = NetworkConnectionState::DISCONNECTED; + } + } + } + + return result; +} + +NetworkConnectionState NotecardConnectionHandler::update_handleConnecting() +{ + NetworkConnectionState result; + + // Check the connection status + const NotecardConnectionStatus conn_status = connected(); + + // Update the connection state + if (!conn_status.connected_to_notehub) { + if ((::millis() - _conn_start_ms) > NOTEHUB_CONN_TIMEOUT_MS) { + Debug.print(DBG_ERROR, F("Timeout exceeded, connection to the network failed.")); + Debug.print(DBG_INFO, F("Retrying in \"%d\" milliseconds"), CHECK_INTERVAL_TABLE[static_cast(NetworkConnectionState::CONNECTING)]); + result = NetworkConnectionState::INIT; + } else { + // Continue awaiting the connection to Notehub + if (conn_status.transport_connected) { + Debug.print(DBG_INFO, F("Establishing connection to Notehub...")); + } else { + Debug.print(DBG_INFO, F("Connecting to the network...")); + } + result = NetworkConnectionState::CONNECTING; + } + } else { + Debug.print(DBG_INFO, F("Connected to Notehub!")); + result = NetworkConnectionState::CONNECTED; + if (initiateNotehubSync()) { + Debug.print(DBG_ERROR, F("Failed to initiate Notehub sync.")); + } + } + + return result; +} + +NetworkConnectionState NotecardConnectionHandler::update_handleConnected() +{ + NetworkConnectionState result; + + const NotecardConnectionStatus conn_status = connected(); + if (!conn_status.connected_to_notehub) { + if (!conn_status.transport_connected) { + Debug.print(DBG_ERROR, F("Connection to the network lost.")); + } else { + Debug.print(DBG_ERROR, F("Connection to Notehub lost.")); + } + result = NetworkConnectionState::DISCONNECTED; + } else { + result = NetworkConnectionState::CONNECTED; + } + + return result; +} + +NetworkConnectionState NotecardConnectionHandler::update_handleDisconnecting() +{ + NetworkConnectionState result; + + Debug.print(DBG_ERROR, F("Connection to the network lost.")); + result = NetworkConnectionState::DISCONNECTED; + + return result; +} + +NetworkConnectionState NotecardConnectionHandler::update_handleDisconnected() +{ + NetworkConnectionState result; + + if (_keep_alive) + { + Debug.print(DBG_ERROR, F("Attempting reconnection...")); + result = NetworkConnectionState::INIT; + } + else + { + if (configureConnection(false)) { + result = NetworkConnectionState::CLOSED; + Debug.print(DBG_INFO, F("Closing connection...")); + } else { + result = NetworkConnectionState::ERROR; + Debug.print(DBG_INFO, F("Error closing connection...")); + } + } + + return result; +} + +/****************************************************************************** + PRIVATE MEMBER FUNCTIONS + ******************************************************************************/ + +bool NotecardConnectionHandler::armInterrupt (void) const +{ + bool result; + + if (J *req = _notecard.newRequest("card.attn")) { + JAddStringToObject(req, "mode","rearm,files"); + if (J *files = JAddArrayToObject(req, "files")) { + JAddItemToArray(files, JCreateString(NOTEFILE_SECURE_INBOUND)); + if (J *rsp = _notecard.requestAndResponse(req)) { + // Check the response for errors + if (NoteResponseError(rsp)) { + const char *err = JGetString(rsp, "err"); + Debug.print(DBG_ERROR, F("%s\n"), err); + result = false; + } else { + result = true; + } + JDelete(rsp); + } else { + Debug.print(DBG_ERROR, F("Failed to receive response from Notecard.")); + result = false; + } + } else { + Debug.print(DBG_ERROR, "Failed to allocate request: card.attn:files"); + JFree(req); + result = false; + } + } else { + Debug.print(DBG_ERROR, "Failed to allocate request: card.attn"); + result = false; + } + + return result; +} + +bool NotecardConnectionHandler::configureConnection (bool connect_) const +{ + bool result; + + if (J *req = _notecard.newRequest("hub.set")) { + // Only update the product if it is not empty or the default value + if (_project_uid.length() > 0 && _project_uid != "com.domain.you:product") { + JAddStringToObject(req, "product", _project_uid.c_str()); + } + + // Configure the connection mode based on the `connect_` parameter + if (connect_) { + JAddStringToObject(req, "mode", "continuous"); + JAddIntToObject(req, "inbound", _inbound_polling_interval_min); + JAddBoolToObject(req, "sync", true); + } else { + JAddStringToObject(req, "mode", "periodic"); + JAddIntToObject(req, "inbound", NO_INBOUND_POLLING); + JAddIntToObject(req, "outbound", -1); + JAddStringToObject(req, "vinbound", "-"); + JAddStringToObject(req, "voutbound", "-"); + } + + // Send the request to the Notecard + if (J *rsp = _notecard.requestAndResponseWithRetry(req, 30)) { + // Check the response for errors + if (NoteResponseError(rsp)) { + const char *err = JGetString(rsp, "err"); + Debug.print(DBG_ERROR, F("%s"), err); + result = false; + } else { + result = true; + } + JDelete(rsp); + } else { + Debug.print(DBG_ERROR, F("Failed to receive response from Notecard.")); + result = false; // Assume the worst + } + } else { + Debug.print(DBG_ERROR, "Failed to allocate request: hub.set"); + result = false; // Assume the worst + } + + return result; +} + +uint_fast8_t NotecardConnectionHandler::connected (void) const +{ + NotecardConnectionStatus result; + + // Query the connection status from the Notecard + if (J *rsp = _notecard.requestAndResponse(_notecard.newRequest("hub.status"))) { + // Ensure the transaction doesn't return an error + if (NoteResponseError(rsp)) { + const char *err = JGetString(rsp, "err"); + Debug.print(DBG_ERROR, F("%s"),err); + result.notecard_error = true; + } else { + // Parse the transport connection status + result.transport_connected = (strstr(JGetString(rsp,"status"),"{connected}") != nullptr); + + // Parse the status of the connection to Notehub + result.connected_to_notehub = JGetBool(rsp,"connected"); + + // Set the Notecard error status + result.notecard_error = false; + result.host_error = false; + } + + // Free the response + JDelete(rsp); + } else { + Debug.print(DBG_ERROR, F("Failed to acquire Notecard connection status.")); + result.transport_connected = false; + result.connected_to_notehub = false; + result.notecard_error = false; + result.host_error = true; + } + + return result; +} + +J * NotecardConnectionHandler::getNote (bool pop_) const +{ + J * result; + + // Look for a Note in the NOTEFILE_SECURE_INBOUND file + if (J *req = _notecard.newRequest("note.get")) { + JAddStringToObject(req, "file", NOTEFILE_SECURE_INBOUND); + if (pop_) { + JAddBoolToObject(req, "delete", true); + } + if (J *note = _notecard.requestAndResponse(req)) { + // Ensure the transaction doesn't return an error + if (NoteResponseError(note)) { + const char *jErr = JGetString(note, "err"); + if (NoteErrorContains(jErr, "{note-noexist}")) { + // The Notefile is empty, thus no Note is available. + if (_en_hw_int) { + armInterrupt(); + } + } else { + // Any other error indicates that we were unable to + // retrieve a Note, therefore no Note is available. + } + result = nullptr; + JDelete(note); + } else { + // The Note was successfully retrieved, and it now + // becomes the callers responsibility to free it. + result = note; + } + } else { + Debug.print(DBG_ERROR, F("Failed to receive response from Notecard.")); + result = nullptr; + } + } else { + Debug.print(DBG_ERROR, "Failed to allocate request: note.get"); + // Failed to retrieve a Note, therefore no Note is available. + result = nullptr; + } + + return result; +} + +bool NotecardConnectionHandler::updateUidCache (void) +{ + bool result; + + // This operation is safe to perform before a sync has occurred, because the + // Notecard UID is static and the cloud value of Serial Number is strictly + // informational with regard to the host firmware operations. + + // Read the Notecard UID from the Notehub configuration + if (J *rsp = _notecard.requestAndResponse(_notecard.newRequest("hub.get"))) { + // Check the response for errors + if (NoteResponseError(rsp)) { + const char *err = JGetString(rsp, "err"); + Debug.print(DBG_ERROR, F("Failed to read Notecard UID")); + Debug.print(DBG_ERROR, F("Error: %s"), err); + result = false; + } else { + _notecard_uid = JGetString(rsp, "device"); + _device_id = JGetString(rsp, "sn"); + _device_id = (_device_id.length() ? _device_id : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"); + Debug.print(DBG_DEBUG, F("NotecardConnectionHandler::%s updated cache with Notecard UID: <%s> and Arduino Device ID: <%s>"), __FUNCTION__, _notecard_uid.c_str(), _device_id.c_str()); + result = true; + } + JDelete(rsp); + } else { + Debug.print(DBG_ERROR, F("Failed to read Notecard UID")); + result = false; + } + + return result; +} + +#endif /* BOARD_HAS_NOTECARD */ diff --git a/src/NotecardConnectionHandler.h b/src/NotecardConnectionHandler.h new file mode 100644 index 00000000..c758030f --- /dev/null +++ b/src/NotecardConnectionHandler.h @@ -0,0 +1,341 @@ +/* + This file is part of the ArduinoIoTCloud library. + + Copyright 2024 Blues (http://www.blues.com/) + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#ifndef ARDUINO_NOTECARD_CONNECTION_HANDLER_H_ +#define ARDUINO_NOTECARD_CONNECTION_HANDLER_H_ + +/****************************************************************************** + INCLUDE + ******************************************************************************/ + +#include + +#include +#include +#include + +#include "ConnectionHandlerInterface.h" + +/****************************************************************************** + DEFINES + ******************************************************************************/ + +#define NOTECARD_CONNECTION_HANDLER_VERSION_MAJOR 1 +#define NOTECARD_CONNECTION_HANDLER_VERSION_MINOR 0 +#define NOTECARD_CONNECTION_HANDLER_VERSION_PATCH 0 + +#define NOTECARD_CONNECTION_HANDLER_VERSION NOTE_C_STRINGIZE(NOTECARD_CONNECTION_HANDLER_VERSION_MAJOR) "." NOTE_C_STRINGIZE(NOTECARD_CONNECTION_HANDLER_VERSION_MINOR) "." NOTE_C_STRINGIZE(NOTECARD_CONNECTION_HANDLER_VERSION_PATCH) + +/****************************************************************************** + CLASS DECLARATION + ******************************************************************************/ + +/** + * @brief The NotecardConnectionHandler class + * + * The NotecardConnectionHandler class is a concrete implementation of the + * ConnectionHandler interface that provides connectivity to the Arduino IoT + * Cloud using a Notecard. + */ +class NotecardConnectionHandler final : public ConnectionHandler +{ + public: + /** + * @brief The manner in which the Notecard is synchronized with Notehub + * + * The SyncType enum defines the valid types of synchronization operations + * that can be performed by the NotecardConnectionHandler class. + * + * @par + * - Full - synchronize both the inbound and outbound queues. + * - Inbound - synchronize only the inbound queues. + * - Outbound - synchronize only the outbound queues. + */ + enum class SyncType : uint8_t { + Full, + Inbound, + Outbound, + }; + + /** + * @brief The type of topic to be used for R/W operations + * + * The Notecard uses topics to identify the target of a read or write + * operation. The TopicType enum defines the valid types of topics. + * + * @par + * - Command - used to interact with the Arduino IoT Cloud. + * - Thing - used to send application data to the Arduino IoT Cloud. + */ + enum class TopicType : uint8_t { + Invalid = 0, + Command, + Thing, + }; + + /** + * @brief The error codes for communicating with the Notecard + * + * The NotecardCommunicationError enum defines the error codes that can be + * returned by the NotecardConnectionHandler class. + * + * @par + * - NOTECARD_ERROR_NONE - No error occurred. + * - NOTECARD_ERROR_NO_DATA_AVAILABLE - No data is available. + * - NOTECARD_ERROR_GENERIC - A generic error occurred. + * - HOST_ERROR_OUT_OF_MEMORY - The host is out of memory. + */ + typedef enum { + NOTECARD_ERROR_NONE = 0, + NOTECARD_ERROR_NO_DATA_AVAILABLE = -1, + NOTECARD_ERROR_GENERIC = -2, + HOST_ERROR_OUT_OF_MEMORY = -3, + } NotecardCommunicationError; + + /** + * @brief The default timeout for the Notecard to connect to Notehub + */ + static const uint32_t NOTEHUB_CONN_TIMEOUT_MS = 185000; + + /** + * @brief The I2C constructor for the Notecard + * + * @param project_uid[in] The project UID of the related Notehub account + * @param i2c_address[in] The I2C address of the Notecard + * @param i2c_max[in] The maximum I2C transaction size (MTU) + * @param wire[in] The I2C bus to use + * @param keep_alive[in] Keep the connection alive if connection to Notehub drops + */ + NotecardConnectionHandler( + const String & project_uid, + uint32_t i2c_address = NOTE_I2C_ADDR_DEFAULT, + uint32_t i2c_max = NOTE_I2C_MAX_DEFAULT, + TwoWire & wire = Wire, + bool keep_alive = true + ); + + /** + * @brief The UART constructor for the Notecard + * + * @param project_uid[in] The project UID of the related Notehub account + * @param serial[in] The serial port to use + * @param baud[in] The baud rate of the serial port + * @param keep_alive[in] Keep the connection alive if connection to Notehub drops + */ + NotecardConnectionHandler( + const String & project_uid, + HardwareSerial & serial, + uint32_t baud = 9600, + bool keep_alive = true + ); + + /** + * @brief Disable hardware interrupts + * + * When hardware interrupts are disabled, the `NotecardConnectionHandler` + * must be polled for incoming data. This is necessary when the host + * microcontroller is unable to use the ATTN pin of the Notecard. + */ + inline void disableHardwareInterrupts (void) { + _en_hw_int = false; + } + + /** + * @brief Enable hardware interrupts + * + * Hardware interrupts allow the `NotecardConnectionHandler` to leverage the + * ATTN pin of the Notecard. This improves the responsiveness of the + * `NotecardConnectionHandler` by eliminating the need for the host + * microcontroller to poll the Notecard for incoming data. + */ + inline void enableHardwareInterrupts (void) { + _en_hw_int = true; + } + + /** + * @brief Get the Arduino IoT Cloud Device ID + * + * The Arduino IoT Cloud Device ID is set as the serial number of the + * Notecard when the device is provisioned in Notehub. The serial number is + * updated on each sync between the Notecard and Notehub and cached by the + * Notecard. As a result, this value can lag behind the actual value of the + * Arduino IoT Cloud Device ID used by the Notehub. However, this value is + * typically unchanged during the life of the Notecard, so this is rarely, + * if ever, an issue. + * + * @return The Arduino IoT Cloud Device ID + */ + inline const String & getDeviceId (void) { + check(); // Ensure the connection to the Notecard is initialized + return _device_id; + } + + /** + * @brief Get the Notecard object + * + * The Notecard object is used to interact with the Notecard. This object + * provides methods to read and write data to the Notecard, as well as + * methods to configure the Notecard. + * + * @return The Notecard object + */ + inline const Notecard & getNotecard (void) { + return _notecard; + } + + /** + * @brief Get the Notecard Device ID + * + * The Notecard Device ID is the unique identifier of the Notecard. This + * value is set at time of manufacture, and is used to identify the Notecard + * in Notehub. + * + * @return The Notecard Device ID + */ + inline const String & getNotecardUid (void) { + check(); // Ensure the connection to the Notecard is initialized + return _notecard_uid; + } + + /** + * @brief Get the topic type of the most recent R/W operations + * + * @return The current topic type + * + * @see TopicType + */ + TopicType getTopicType (void) const { + return _topic_type; + } + + /** + * @brief Initiate a synchronization operation with Notehub + * + * The Notecard maintains two queues: an inbound queue and an outbound + * queue. The inbound queue is used to receive data from Notehub, while the + * outbound queue is used to send data to Notehub. This method initiates a + * synchronization operation between the Notecard and Notehub. + * + * As the name implies, this method is asynchronous and will only initiate + * the synchronization operation. The actual synchronization operation will + * be performed by the Notecard in the background. + * + * @param type[in] The type of synchronization operation to perform + * @par + * - SyncType::Full - synchronize both the inbound and outbound queues (default) + * - SyncType::Inbound - synchronize only the inbound queues. + * - SyncType::Outbound - synchronize only the outbound queues. + * + * @return 0 if successful, otherwise an error code + * + * @see SyncType + * @see NotecardCommunicationError + */ + int initiateNotehubSync (SyncType type = SyncType::Full) const; + + /** + * @brief Set the inbound polling interval (in minutes) + * + * A cellular Notecard will receive inbound traffic from the Arduino IoT + * Cloud in real-time. As such, the polling interval is used as a fail-safe + * to ensure the Notecard is guaranteed to receive inbound traffic at the + * interval specified by this method. + * + * Alternatively, a LoRa (or Satellite) Notecard does not maintain a + * continuous connection, and therefore must rely on the polling interval to + * establish the maximum acceptable delay before receiving any unsolicited, + * inbound traffic from the Arduino IoT Cloud. The polling interval must + * balance the needs of the application against the regulatory limitations + * of LoRa (or bandwidth limitations and cost of Satellite). + * + * LoRaWAN Fair Use Policy: + * https://www.thethingsnetwork.org/forum/t/fair-use-policy-explained/1300 + * + * @param interval_min[in] The inbound polling interval (in minutes) + * + * @note Set the interval to 0 to disable inbound polling. + */ + inline void setNotehubPollingInterval (int32_t interval_min) { + _inbound_polling_interval_min = (interval_min ? interval_min : -1); + } + + /** + * @brief Set the topic type for R/W operations + * + * @param topic[in] The topic type + * @par + * - TopicType::Command - used to interact with the Arduino IoT Cloud. + * - TopicType::Thing - used to send application data to the Arduino IoT Cloud. + * + * @see TopicType + */ + void setTopicType (TopicType topic) { + _topic_type = topic; + } + + /** + * @brief Set the WiFi credentials to be used by the Notecard + * + * @param ssid[in] The SSID of the WiFi network + * @param pass[in] The password of the WiFi network + * + * @return 0 if successful, otherwise an error code + * + * @note This method is only applicable when using a Wi-Fi capable Notecard, + * and is unnecessary when using a Notecard with cellular connectivity. + * If the Notecard is not Wi-Fi capable, this method will be a no-op. + * + * @see NotecardCommunicationError + */ + int setWiFiCredentials (const String & ssid, const String & pass); + + // ConnectionHandler interface + virtual bool available() override; + virtual unsigned long getTime() override; + virtual int read() override; + virtual int write(const uint8_t *buf, size_t size) override; + + protected: + + virtual NetworkConnectionState update_handleInit () override; + virtual NetworkConnectionState update_handleConnecting () override; + virtual NetworkConnectionState update_handleConnected () override; + virtual NetworkConnectionState update_handleDisconnecting() override; + virtual NetworkConnectionState update_handleDisconnected () override; + + private: + + // Private members + Notecard _notecard; + String _device_id; + String _notecard_uid; + String _project_uid; + HardwareSerial * _serial; + TwoWire * _wire; + uint8_t * _inbound_buffer; + uint32_t _conn_start_ms; + uint32_t _i2c_address; + uint32_t _i2c_max; + uint32_t _inbound_buffer_index; + uint32_t _inbound_buffer_size; + int32_t _inbound_polling_interval_min; + uint32_t _uart_baud; + bool _en_hw_int; + TopicType _topic_type; + + // Private methods + bool armInterrupt (void) const; + bool configureConnection (bool connect) const; + uint_fast8_t connected (void) const; + J * getNote (bool pop = false) const; + bool updateUidCache (void); +}; + +#endif /* ARDUINO_NOTECARD_CONNECTION_HANDLER_H_ */ diff --git a/src/Arduino_WiFiConnectionHandler.cpp b/src/WiFiConnectionHandler.cpp similarity index 98% rename from src/Arduino_WiFiConnectionHandler.cpp rename to src/WiFiConnectionHandler.cpp index 902b53f0..0cd2e126 100644 --- a/src/Arduino_WiFiConnectionHandler.cpp +++ b/src/WiFiConnectionHandler.cpp @@ -19,9 +19,10 @@ INCLUDE ******************************************************************************/ -#include "Arduino_WiFiConnectionHandler.h" +#include "ConnectionHandlerDefinitions.h" #ifdef BOARD_HAS_WIFI /* Only compile if the board has WiFi */ +#include "WiFiConnectionHandler.h" /****************************************************************************** CONSTANTS @@ -143,7 +144,7 @@ NetworkConnectionState WiFiConnectionHandler::update_handleConnected() Debug.print(DBG_INFO, F("Attempting reconnection")); #endif } - + return NetworkConnectionState::DISCONNECTED; } return NetworkConnectionState::CONNECTED; diff --git a/src/Arduino_WiFiConnectionHandler.h b/src/WiFiConnectionHandler.h similarity index 67% rename from src/Arduino_WiFiConnectionHandler.h rename to src/WiFiConnectionHandler.h index bf16fa06..2ee674a5 100644 --- a/src/Arduino_WiFiConnectionHandler.h +++ b/src/WiFiConnectionHandler.h @@ -22,9 +22,38 @@ INCLUDE ******************************************************************************/ -#include "Arduino_ConnectionHandler.h" - -#ifdef BOARD_HAS_WIFI /* Only compile if the board has WiFi */ +#include "ConnectionHandlerInterface.h" + +#ifdef ARDUINO_SAMD_MKR1000 + #include + #include +#elif defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT) || \ + defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined (ARDUINO_NANO_RP2040_CONNECT) + #include + #include +#elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M7) || \ + defined(ARDUINO_NICLA_VISION) || defined(ARDUINO_OPTA) || defined(ARDUINO_GIGA) + #include + #include +#elif defined(ARDUINO_PORTENTA_C33) + #include + #include +#elif defined(ARDUINO_ARCH_ESP8266) + #include + #include +#elif defined(ARDUINO_ARCH_ESP32) + #include + #include +#elif defined(ARDUINO_UNOR4_WIFI) + #include +#elif defined(ARDUINO_RASPBERRY_PI_PICO_W) + #include + #include +#endif + +#ifndef BOARD_HAS_WIFI + #error "Board doesn't support WIFI" +#endif /****************************************************************************** CLASS DECLARATION @@ -59,6 +88,4 @@ class WiFiConnectionHandler : public ConnectionHandler WiFiClient _wifi_client; }; -#endif /* #ifdef BOARD_HAS_WIFI */ - #endif /* ARDUINO_WIFI_CONNECTION_HANDLER_H_ */ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy