diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml index 808258ed..5541359d 100644 --- a/.github/workflows/compile-examples.yml +++ b/.github/workflows/compile-examples.yml @@ -38,6 +38,7 @@ jobs: - name: Blues Wireless Notecard SKETCH_PATHS: | - examples/ConnectionHandlerDemo + - examples/CheckInternetAvailabilityDemo ARDUINOCORE_MBED_STAGING_PATH: extras/ArduinoCore-mbed ARDUINOCORE_API_STAGING_PATH: extras/ArduinoCore-API SKETCHES_REPORTS_PATH: sketches-reports diff --git a/examples/CheckInternetAvailabilityDemo/CheckInternetAvailabilityDemo.ino b/examples/CheckInternetAvailabilityDemo/CheckInternetAvailabilityDemo.ino new file mode 100644 index 00000000..ca530ddf --- /dev/null +++ b/examples/CheckInternetAvailabilityDemo/CheckInternetAvailabilityDemo.ino @@ -0,0 +1,152 @@ +/* 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_WIFI_SSID) and password (SECRET_WIFI_PASS) in the + * arduino_secrets.h file (or Secrets tab in Create Web Editor). + * + * 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 + * + * GSMConnectionHandler conMan(SECRET_PIN, SECRET_APN, SECRET_GSM_USER, SECRET_GSM_PASS); + * + * If using a MKR NB1500 you'll need a NBConnectionHandler object as follows + * + * NBConnectionHandler conMan(SECRET_PIN); + * + * If using a Portenta + Ethernet shield you'll need a EthernetConnectionHandler object as follows: + * + * DHCP mode + * EthernetConnectionHandler conMan; + * + * Manual configuration + * EthernetConnectionHandler conMan(SECRET_IP, SECRET_DNS, SECRET_GATEWAY, SECRET_NETMASK); + * + * Manual configuration will fallback on DHCP mode if SECRET_IP is invalid or equal to INADDR_NONE. + * + * This sketch enables the ConnectionHandler to check for internet availability (only for IP based connectivity) + * before reporting the Connected state. By default the check is disabled. + * + */ + +#include + +#include "arduino_secrets.h" + +#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_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) +NBConnectionHandler conMan(SECRET_PIN); +#elif defined(BOARD_HAS_LORA) +LoRaConnectionHandler conMan(SECRET_APP_EUI, SECRET_APP_KEY); +#elif defined(BOARD_HAS_CATM1_NBIOT) +CatM1ConnectionHandler conMan(SECRET_PIN, SECRET_APN, SECRET_GSM_USER, SECRET_GSM_PASS); +#elif defined(BOARD_HAS_CELLULAR) +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); + 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 + /* Enable the connection handler to check for internet availability. + * By default is disabled. + */ + conMan.enableCheckInternetAvailability(true); + /* 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 + * 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 onNetworkConnect() { + Serial.println(">>>> CONNECTED to network"); +} + +void onNetworkDisconnect() { + Serial.println(">>>> DISCONNECTED from network"); +} + +void onNetworkError() { + Serial.println(">>>> ERROR"); +} diff --git a/examples/CheckInternetAvailabilityDemo/arduino_secrets.h b/examples/CheckInternetAvailabilityDemo/arduino_secrets.h new file mode 100644 index 00000000..f9906f69 --- /dev/null +++ b/examples/CheckInternetAvailabilityDemo/arduino_secrets.h @@ -0,0 +1,19 @@ +// Required for WiFiConnectionHandler +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"; + +// Required for LoRaConnectionHandler +const char SECRET_APP_EUI[] = "APP_EUI"; +const char SECRET_APP_KEY[] = "APP_KEY"; + +// Required for EthernetConnectionHandler (without DHCP mode) +const char SECRET_IP[] = "IP ADDRESS"; +const char SECRET_DNS[] = "DNS ADDRESS"; +const char SECRET_GATEWAY[] = "GATEWAY ADDRESS"; +const char SECRET_NETMASK[] = "NETWORK MASK"; diff --git a/examples/GenericConnectionHandlerDemo/GenericConnectionHandlerDemo.ino b/examples/GenericConnectionHandlerDemo/GenericConnectionHandlerDemo.ino new file mode 100644 index 00000000..2ce18f7e --- /dev/null +++ b/examples/GenericConnectionHandlerDemo/GenericConnectionHandlerDemo.ino @@ -0,0 +1,139 @@ +/* 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_WIFI_SSID) and password (SECRET_WIFI_PASS) in the + * arduino_secrets.h file (or Secrets tab in Create Web Editor). + * + * 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 + * + * GSMConnectionHandler conMan(SECRET_PIN, SECRET_APN, SECRET_GSM_USER, SECRET_GSM_PASS); + * + * If using a MKR NB1500 you'll need a NBConnectionHandler object as follows + * + * NBConnectionHandler conMan(SECRET_PIN); + * + * If using a Portenta + Ethernet shield you'll need a EthernetConnectionHandler object as follows: + * + * DHCP mode + * EthernetConnectionHandler conMan; + * + * Manual configuration + * EthernetConnectionHandler conMan(SECRET_IP, SECRET_DNS, SECRET_GATEWAY, SECRET_NETMASK); + * + * Manual configuration will fallback on DHCP mode if SECRET_IP is invalid or equal to INADDR_NONE. + * + */ + +#include + +#include "arduino_secrets.h" + +#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 + +GenericConnectionHandler conMan; + + +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); ) { } + +#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 + + models::NetworkSetting setting = models::settingsDefault(NetworkAdapter::WIFI); + + strcpy(setting.wifi.ssid, SECRET_WIFI_SSID); + strcpy(setting.wifi.pwd, SECRET_WIFI_PASS); + + /* 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); + + conMan.updateSetting(setting); + 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 + * 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 onNetworkConnect() { + Serial.println(">>>> CONNECTED to network"); +} + +void onNetworkDisconnect() { + Serial.println(">>>> DISCONNECTED from network"); +} + +void onNetworkError() { + Serial.println(">>>> ERROR"); +} diff --git a/examples/GenericConnectionHandlerDemo/arduino_secrets.h b/examples/GenericConnectionHandlerDemo/arduino_secrets.h new file mode 100644 index 00000000..cecefa42 --- /dev/null +++ b/examples/GenericConnectionHandlerDemo/arduino_secrets.h @@ -0,0 +1,19 @@ +// Required for WiFiConnectionHandler +const char SECRET_WIFI_SSID[] = "SSID"; +const char SECRET_WIFI_PASS[] = "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"; + +// Required for LoRaConnectionHandler +const char SECRET_APP_EUI[] = "APP_EUI"; +const char SECRET_APP_KEY[] = "APP_KEY"; + +// Required for EthernetConnectionHandler (without DHCP mode) +const char SECRET_IP[] = "IP ADDRESS"; +const char SECRET_DNS[] = "DNS ADDRESS"; +const char SECRET_GATEWAY[] = "GATEWAY ADDRESS"; +const char SECRET_NETMASK[] = "NETWORK MASK"; diff --git a/library.properties b/library.properties index 4539afee..3592a568 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Arduino_ConnectionHandler -version=1.0.2 +version=1.1.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], Notecard) diff --git a/src/CatM1ConnectionHandler.cpp b/src/CatM1ConnectionHandler.cpp index 0263a397..2a63dea0 100644 --- a/src/CatM1ConnectionHandler.cpp +++ b/src/CatM1ConnectionHandler.cpp @@ -28,16 +28,21 @@ CTOR/DTOR ******************************************************************************/ -CatM1ConnectionHandler::CatM1ConnectionHandler(const char * pin, const char * apn, const char * login, const char * pass, RadioAccessTechnologyType rat, uint32_t band, bool const keep_alive) +CatM1ConnectionHandler::CatM1ConnectionHandler() +: ConnectionHandler(true, NetworkAdapter::CATM1) { } + +CatM1ConnectionHandler::CatM1ConnectionHandler( + const char * pin, const char * apn, const char * login, const char * pass, + RadioAccessTechnologyType rat, uint32_t band, bool const keep_alive) : ConnectionHandler{keep_alive, NetworkAdapter::CATM1} -, _pin(pin) -, _apn(apn) -, _login(login) -, _pass(pass) -, _rat(rat) -, _band(band) { - + _settings.type = NetworkAdapter::CATM1; + strncpy(_settings.catm1.pin, pin, sizeof(_settings.catm1.pin)-1); + strncpy(_settings.catm1.apn, apn, sizeof(_settings.catm1.apn)-1); + strncpy(_settings.catm1.login, login, sizeof(_settings.catm1.login)-1); + strncpy(_settings.catm1.pass, pass, sizeof(_settings.catm1.pass)-1); + _settings.catm1.rat = static_cast(rat); + _settings.catm1.band = band; } /****************************************************************************** @@ -59,18 +64,45 @@ NetworkConnectionState CatM1ConnectionHandler::update_handleInit() pinMode(ON_MKR2, OUTPUT); digitalWrite(ON_MKR2, HIGH); #endif + + if(!GSM.begin( + _settings.catm1.pin, + _settings.catm1.apn, + _settings.catm1.login, + _settings.catm1.pass, + static_cast(_settings.catm1.rat) , + _settings.catm1.band)) + { + Debug.print(DBG_ERROR, F("The board was not able to register to the network...")); + return NetworkConnectionState::ERROR; + } return NetworkConnectionState::CONNECTING; } NetworkConnectionState CatM1ConnectionHandler::update_handleConnecting() { - if(!GSM.begin(_pin, _apn, _login, _pass, _rat, _band)) + if (!GSM.isConnected()) { - Debug.print(DBG_ERROR, F("The board was not able to register to the network...")); - return NetworkConnectionState::ERROR; + return NetworkConnectionState::INIT; + } + + if(!_check_internet_availability){ + return NetworkConnectionState::CONNECTED; + } + + int ping_result = GSM.ping("time.arduino.cc"); + Debug.print(DBG_INFO, F("GSM.ping(): %d"), ping_result); + if (ping_result < 0) + { + Debug.print(DBG_ERROR, F("Internet check failed")); + Debug.print(DBG_INFO, F("Retrying in \"%d\" milliseconds"), CHECK_INTERVAL_TABLE[static_cast(NetworkConnectionState::CONNECTING)]); + return NetworkConnectionState::CONNECTING; + } + else + { + Debug.print(DBG_INFO, F("Connected to Internet")); + return NetworkConnectionState::CONNECTED; } - Debug.print(DBG_INFO, F("Connected to Network")); - return NetworkConnectionState::CONNECTED; } NetworkConnectionState CatM1ConnectionHandler::update_handleConnected() diff --git a/src/CatM1ConnectionHandler.h b/src/CatM1ConnectionHandler.h index 33ac9fea..67f317b7 100644 --- a/src/CatM1ConnectionHandler.h +++ b/src/CatM1ConnectionHandler.h @@ -40,6 +40,7 @@ class CatM1ConnectionHandler : public ConnectionHandler { public: + CatM1ConnectionHandler(); CatM1ConnectionHandler(const char * pin, const char * apn, const char * login, const char * pass, RadioAccessTechnologyType rat = CATM1, uint32_t band = BAND_3 | BAND_20 | BAND_19, bool const keep_alive = true); @@ -59,14 +60,6 @@ class CatM1ConnectionHandler : public ConnectionHandler private: - const char * _pin; - const char * _apn; - const char * _login; - const char * _pass; - - RadioAccessTechnologyType _rat; - uint32_t _band; - GSMUDP _gsm_udp; GSMClient _gsm_client; }; diff --git a/src/CellularConnectionHandler.cpp b/src/CellularConnectionHandler.cpp index 2e4499a0..c6a90774 100644 --- a/src/CellularConnectionHandler.cpp +++ b/src/CellularConnectionHandler.cpp @@ -21,14 +21,17 @@ /****************************************************************************** CTOR/DTOR ******************************************************************************/ +CellularConnectionHandler::CellularConnectionHandler() +: ConnectionHandler(true, NetworkAdapter::CELL) {} CellularConnectionHandler::CellularConnectionHandler(const char * pin, const char * apn, const char * login, const char * pass, bool const keep_alive) : ConnectionHandler{keep_alive, NetworkAdapter::CELL} -, _pin(pin) -, _apn(apn) -, _login(login) -, _pass(pass) { + _settings.type = NetworkAdapter::CELL; + strncpy(_settings.cell.pin, pin, sizeof(_settings.cell.pin)-1); + strncpy(_settings.cell.apn, apn, sizeof(_settings.cell.apn)-1); + strncpy(_settings.cell.login, login, sizeof(_settings.cell.login)-1); + strncpy(_settings.cell.pass, pass, sizeof(_settings.cell.pass)-1); } @@ -55,20 +58,35 @@ NetworkConnectionState CellularConnectionHandler::update_handleInit() { _cellular.begin(); _cellular.setDebugStream(Serial); - if (String(_pin).length() > 0 && !_cellular.unlockSIM(_pin)) { + if (strlen(_settings.cell.pin) > 0 && !_cellular.unlockSIM(_settings.cell.pin)) { Debug.print(DBG_ERROR, F("SIM not present or wrong PIN")); return NetworkConnectionState::ERROR; } + + if (!_cellular.connect(String(_settings.cell.apn), String(_settings.cell.login), String(_settings.cell.pass))) { + Debug.print(DBG_ERROR, F("The board was not able to register to the network...")); + return NetworkConnectionState::ERROR; + } + Debug.print(DBG_INFO, F("Connected to Network")); return NetworkConnectionState::CONNECTING; } NetworkConnectionState CellularConnectionHandler::update_handleConnecting() { - if (!_cellular.connect(_apn, _login, _pass)) { - Debug.print(DBG_ERROR, F("The board was not able to register to the network...")); - return NetworkConnectionState::ERROR; + if (!_cellular.isConnectedToInternet()) { + return NetworkConnectionState::INIT; } - Debug.print(DBG_INFO, F("Connected to Network")); + + if (!_check_internet_availability) { + return NetworkConnectionState::CONNECTED; + } + + if(getTime() == 0){ + Debug.print(DBG_ERROR, F("Internet check failed")); + Debug.print(DBG_INFO, F("Retrying in \"%d\" milliseconds"), CHECK_INTERVAL_TABLE[static_cast(NetworkConnectionState::CONNECTING)]); + return NetworkConnectionState::CONNECTING; + } + return NetworkConnectionState::CONNECTED; } diff --git a/src/CellularConnectionHandler.h b/src/CellularConnectionHandler.h index 2addd29b..fcc02c66 100644 --- a/src/CellularConnectionHandler.h +++ b/src/CellularConnectionHandler.h @@ -33,7 +33,7 @@ class CellularConnectionHandler : public ConnectionHandler { public: - + CellularConnectionHandler(); CellularConnectionHandler(const char * pin, const char * apn, const char * login, const char * pass, bool const keep_alive = true); @@ -53,11 +53,6 @@ class CellularConnectionHandler : public ConnectionHandler private: - const char * _pin; - const char * _apn; - const char * _login; - const char * _pass; - ArduinoCellular _cellular; TinyGsmClient _gsm_client = _cellular.getNetworkClient(); }; diff --git a/src/ConnectionHandlerDefinitions.h b/src/ConnectionHandlerDefinitions.h index 4f295592..4cefc5de 100644 --- a/src/ConnectionHandlerDefinitions.h +++ b/src/ConnectionHandlerDefinitions.h @@ -174,6 +174,7 @@ enum class NetworkConnectionEvent { }; enum class NetworkAdapter { + NONE, WIFI, ETHERNET, NB, @@ -190,12 +191,12 @@ enum class NetworkAdapter { static unsigned int const CHECK_INTERVAL_TABLE[] = { - /* INIT */ 100, #if defined(BOARD_HAS_NOTECARD) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) - /* CONNECTING */ 4000, + /* INIT */ 4000, #else - /* CONNECTING */ 500, + /* INIT */ 500, #endif + /* CONNECTING */ 500, /* CONNECTED */ 10000, /* DISCONNECTING */ 100, /* DISCONNECTED */ 1000, diff --git a/src/ConnectionHandlerInterface.cpp b/src/ConnectionHandlerInterface.cpp index 2fdc10e1..237b465d 100644 --- a/src/ConnectionHandlerInterface.cpp +++ b/src/ConnectionHandlerInterface.cpp @@ -29,6 +29,7 @@ ConnectionHandler::ConnectionHandler(bool const keep_alive, NetworkAdapter inter : _keep_alive{keep_alive} , _interface{interface} , _lastConnectionTickTime{millis()} +, _check_internet_availability{false} , _current_net_connection_state{NetworkConnectionState::INIT} { @@ -46,42 +47,22 @@ NetworkConnectionState ConnectionHandler::check() if((now - _lastConnectionTickTime) > connectionTickTimeInterval) { _lastConnectionTickTime = now; - NetworkConnectionState next_net_connection_state = _current_net_connection_state; - /* While the state machine is implemented here, the concrete implementation of the - * states is done in the derived connection handlers. - */ - switch (_current_net_connection_state) - { - case NetworkConnectionState::INIT: next_net_connection_state = update_handleInit (); break; - case NetworkConnectionState::CONNECTING: next_net_connection_state = update_handleConnecting (); break; - case NetworkConnectionState::CONNECTED: next_net_connection_state = update_handleConnected (); break; - case NetworkConnectionState::DISCONNECTING: next_net_connection_state = update_handleDisconnecting(); break; - case NetworkConnectionState::DISCONNECTED: next_net_connection_state = update_handleDisconnected (); break; - case NetworkConnectionState::ERROR: break; - case NetworkConnectionState::CLOSED: break; - } + NetworkConnectionState old_net_connection_state = _current_net_connection_state; + NetworkConnectionState next_net_connection_state = updateConnectionState(); /* Here we are determining whether a state transition from one state to the next has * occurred - and if it has, we call eventually registered callbacks. */ - if(next_net_connection_state != _current_net_connection_state) - { - /* Check the next state to determine the kind of state conversion which has occurred (and call the appropriate callback) */ - if(next_net_connection_state == NetworkConnectionState::CONNECTED) - { - if(_on_connect_event_callback) _on_connect_event_callback(); - } - if(next_net_connection_state == NetworkConnectionState::DISCONNECTED) - { - if(_on_disconnect_event_callback) _on_disconnect_event_callback(); - } - if(next_net_connection_state == NetworkConnectionState::ERROR) - { - if(_on_error_event_callback) _on_error_event_callback(); - } - - /* Assign new state to the member variable holding the state */ + + if(old_net_connection_state != next_net_connection_state) { + updateCallback(next_net_connection_state); + + /* It may happen that the local _current_net_connection_state + * is not updated by the updateConnectionState() call. This is the case for GenericConnection handler + * where the call of updateConnectionState() is replaced by the inner ConnectionHandler call + * that updates its state, but not the outer one. For this reason it is required to perform this call twice + */ _current_net_connection_state = next_net_connection_state; } } @@ -89,6 +70,46 @@ NetworkConnectionState ConnectionHandler::check() return _current_net_connection_state; } +NetworkConnectionState ConnectionHandler::updateConnectionState() { + NetworkConnectionState next_net_connection_state = _current_net_connection_state; + + /* While the state machine is implemented here, the concrete implementation of the + * states is done in the derived connection handlers. + */ + switch (_current_net_connection_state) + { + case NetworkConnectionState::INIT: next_net_connection_state = update_handleInit (); break; + case NetworkConnectionState::CONNECTING: next_net_connection_state = update_handleConnecting (); break; + case NetworkConnectionState::CONNECTED: next_net_connection_state = update_handleConnected (); break; + case NetworkConnectionState::DISCONNECTING: next_net_connection_state = update_handleDisconnecting(); break; + case NetworkConnectionState::DISCONNECTED: next_net_connection_state = update_handleDisconnected (); break; + case NetworkConnectionState::ERROR: break; + case NetworkConnectionState::CLOSED: break; + } + + /* Assign new state to the member variable holding the state */ + _current_net_connection_state = next_net_connection_state; + + return next_net_connection_state; +} + +void ConnectionHandler::updateCallback(NetworkConnectionState next_net_connection_state) { + + /* Check the next state to determine the kind of state conversion which has occurred (and call the appropriate callback) */ + if(next_net_connection_state == NetworkConnectionState::CONNECTED) + { + if(_on_connect_event_callback) _on_connect_event_callback(); + } + if(next_net_connection_state == NetworkConnectionState::DISCONNECTED) + { + if(_on_disconnect_event_callback) _on_disconnect_event_callback(); + } + if(next_net_connection_state == NetworkConnectionState::ERROR) + { + if(_on_error_event_callback) _on_error_event_callback(); + } +} + void ConnectionHandler::connect() { if (_current_net_connection_state != NetworkConnectionState::INIT && _current_net_connection_state != NetworkConnectionState::CONNECTING) diff --git a/src/ConnectionHandlerInterface.h b/src/ConnectionHandlerInterface.h index 228827e7..6af40d47 100644 --- a/src/ConnectionHandlerInterface.h +++ b/src/ConnectionHandlerInterface.h @@ -29,6 +29,7 @@ #include #include #include "ConnectionHandlerDefinitions.h" +#include "connectionHandlerModels/settings.h" /****************************************************************************** TYPEDEFS @@ -40,13 +41,17 @@ typedef void (*OnNetworkEventCallback)(); CLASS DECLARATION ******************************************************************************/ +// forward declaration FIXME +class GenericConnectionHandler; + class ConnectionHandler { public: - ConnectionHandler(bool const keep_alive, NetworkAdapter interface); + ConnectionHandler(bool const keep_alive=true, NetworkAdapter interface=NetworkAdapter::NONE); + virtual ~ConnectionHandler() {} - NetworkConnectionState check(); + virtual NetworkConnectionState check(); #if not defined(BOARD_HAS_LORA) virtual unsigned long getTime() = 0; @@ -69,17 +74,42 @@ class ConnectionHandler { return _interface; } - void connect(); - void disconnect(); + virtual void connect(); + virtual void disconnect(); + void enableCheckInternetAvailability(bool enable) { + _check_internet_availability = enable; + } - void addCallback(NetworkConnectionEvent const event, OnNetworkEventCallback callback); + virtual 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)); + /** + * Update the interface settings. This can be performed only when the interface is + * in INIT state. otherwise nothing is performed. The type of the interface should match + * the type of the settings provided + * + * @return true if the update is successful, false otherwise + */ + virtual bool updateSetting(const models::NetworkSetting& s) { + if(_current_net_connection_state == NetworkConnectionState::INIT && s.type == _interface) { + memcpy(&_settings, &s, sizeof(s)); + return true; + } + + return false; + } + + virtual void setKeepAlive(bool keep_alive=true) { this->_keep_alive = keep_alive; } + protected: + virtual NetworkConnectionState updateConnectionState(); + virtual void updateCallback(NetworkConnectionState next_net_connection_state); + bool _keep_alive; + bool _check_internet_availability; NetworkAdapter _interface; virtual NetworkConnectionState update_handleInit () = 0; @@ -88,6 +118,8 @@ class ConnectionHandler { virtual NetworkConnectionState update_handleDisconnecting() = 0; virtual NetworkConnectionState update_handleDisconnected () = 0; + models::NetworkSetting _settings; + private: unsigned long _lastConnectionTickTime; @@ -95,5 +127,7 @@ class ConnectionHandler { OnNetworkEventCallback _on_connect_event_callback = NULL, _on_disconnect_event_callback = NULL, _on_error_event_callback = NULL; + + friend GenericConnectionHandler; }; diff --git a/src/EthernetConnectionHandler.cpp b/src/EthernetConnectionHandler.cpp index 14f7aee4..6e730381 100644 --- a/src/EthernetConnectionHandler.cpp +++ b/src/EthernetConnectionHandler.cpp @@ -25,51 +25,41 @@ CTOR/DTOR ******************************************************************************/ -EthernetConnectionHandler::EthernetConnectionHandler(unsigned long const timeout, unsigned long const responseTimeout, bool const keep_alive) -: ConnectionHandler{keep_alive, NetworkAdapter::ETHERNET} -,_ip{INADDR_NONE} -,_dns{INADDR_NONE} -,_gateway{INADDR_NONE} -,_netmask{INADDR_NONE} -,_timeout{timeout} -,_response_timeout{responseTimeout} -{ - +static inline void fromIPAddress(const IPAddress src, models::ip_addr& dst) { + if(src.type() == IPv4) { + dst.dword[IPADDRESS_V4_DWORD_INDEX] = (uint32_t)src; + } else if(src.type() == IPv6) { + for(uint8_t i=0; i static ip configuration + if (ip != INADDR_NONE) { + if (Ethernet.begin(nullptr, ip, + IPAddress(_settings.eth.dns.type, _settings.eth.dns.bytes), + IPAddress(_settings.eth.gateway.type, _settings.eth.gateway.bytes), + IPAddress(_settings.eth.netmask.type, _settings.eth.netmask.bytes), + _settings.eth.timeout, + _settings.eth.response_timeout) == 0) { -NetworkConnectionState EthernetConnectionHandler::update_handleConnecting() -{ - if (_ip != INADDR_NONE) { - if (Ethernet.begin(nullptr, _ip, _dns, _gateway, _netmask, _timeout, _response_timeout) == 0) { Debug.print(DBG_ERROR, F("Failed to configure Ethernet, check cable connection")); - Debug.print(DBG_VERBOSE, "timeout: %d, response timeout: %d", _timeout, _response_timeout); - return NetworkConnectionState::CONNECTING; + Debug.print(DBG_VERBOSE, "timeout: %d, response timeout: %d", + _settings.eth.timeout, _settings.eth.response_timeout); + return NetworkConnectionState::INIT; } + // An ip address is not provided -> dhcp configuration } else { - if (Ethernet.begin(nullptr, _timeout, _response_timeout) == 0) { + if (Ethernet.begin(nullptr, _settings.eth.timeout, _settings.eth.response_timeout) == 0) { Debug.print(DBG_ERROR, F("Waiting Ethernet configuration from DHCP server, check cable connection")); - Debug.print(DBG_VERBOSE, "timeout: %d, response timeout: %d", _timeout, _response_timeout); - return NetworkConnectionState::CONNECTING; + Debug.print(DBG_VERBOSE, "timeout: %d, response timeout: %d", + _settings.eth.timeout, _settings.eth.response_timeout); + + return NetworkConnectionState::INIT; } } - return NetworkConnectionState::CONNECTED; + return NetworkConnectionState::CONNECTING; +} + +NetworkConnectionState EthernetConnectionHandler::update_handleConnecting() +{ + if (Ethernet.linkStatus() == LinkOFF) { + return NetworkConnectionState::INIT; + } + + if (!_check_internet_availability) { + return NetworkConnectionState::CONNECTED; + } + + int ping_result = Ethernet.ping("time.arduino.cc"); + Debug.print(DBG_INFO, F("Ethernet.ping(): %d"), ping_result); + if (ping_result < 0) + { + Debug.print(DBG_ERROR, F("Internet check failed")); + Debug.print(DBG_INFO, F("Retrying in \"%d\" milliseconds"), CHECK_INTERVAL_TABLE[static_cast(NetworkConnectionState::CONNECTING)]); + return NetworkConnectionState::CONNECTING; + } + else + { + Debug.print(DBG_INFO, F("Connected to Internet")); + return NetworkConnectionState::CONNECTED; + } + } NetworkConnectionState EthernetConnectionHandler::update_handleConnected() diff --git a/src/EthernetConnectionHandler.h b/src/EthernetConnectionHandler.h index 35a02cd9..738b6a8c 100644 --- a/src/EthernetConnectionHandler.h +++ b/src/EthernetConnectionHandler.h @@ -44,16 +44,24 @@ class EthernetConnectionHandler : public ConnectionHandler { public: - EthernetConnectionHandler(unsigned long const timeout = 15000, unsigned long const responseTimeout = 4000, bool const keep_alive = true); - EthernetConnectionHandler(const IPAddress ip, const IPAddress dns, const IPAddress gateway, const IPAddress netmask, unsigned long const timeout = 15000, unsigned long const responseTimeout = 4000, bool const keep_alive = true); - EthernetConnectionHandler(const char * ip, const char * dns, const char * gateway, const char * netmask, unsigned long const timeout = 15000, unsigned long const responseTimeout = 4000, bool const keep_alive = true); - + EthernetConnectionHandler( + unsigned long const timeout = 15000, + unsigned long const responseTimeout = 4000, + bool const keep_alive = true); + + EthernetConnectionHandler( + const IPAddress ip, + const IPAddress dns, + const IPAddress gateway, + const IPAddress netmask, + unsigned long const timeout = 15000, + unsigned long const responseTimeout = 4000, + bool const keep_alive = true); virtual unsigned long getTime() override { return 0; } virtual Client & getClient() override{ return _eth_client; } virtual UDP & getUDP() override { return _eth_udp; } - protected: virtual NetworkConnectionState update_handleInit () override; @@ -64,14 +72,6 @@ class EthernetConnectionHandler : public ConnectionHandler private: - IPAddress _ip; - IPAddress _dns; - IPAddress _gateway; - IPAddress _netmask; - - unsigned long _timeout; - unsigned long _response_timeout; - EthernetUDP _eth_udp; EthernetClient _eth_client; diff --git a/src/GSMConnectionHandler.cpp b/src/GSMConnectionHandler.cpp index 34bf1792..64b04d0e 100644 --- a/src/GSMConnectionHandler.cpp +++ b/src/GSMConnectionHandler.cpp @@ -46,15 +46,19 @@ __attribute__((weak)) void mkr_gsm_feed_watchdog() /****************************************************************************** CTOR/DTOR ******************************************************************************/ +GSMConnectionHandler::GSMConnectionHandler() +: ConnectionHandler(true, NetworkAdapter::GSM) {} GSMConnectionHandler::GSMConnectionHandler(const char * pin, const char * apn, const char * login, const char * pass, bool const keep_alive) : ConnectionHandler{keep_alive, NetworkAdapter::GSM} -, _pin(pin) -, _apn(apn) -, _login(login) -, _pass(pass) { - + _settings.type = NetworkAdapter::GSM; + // To keep the backward compatibility, the user can call enableCheckInternetAvailability(false) for disabling the check + _check_internet_availability = true; + strncpy(_settings.gsm.pin, pin, sizeof(_settings.gsm.pin)-1); + strncpy(_settings.gsm.apn, apn, sizeof(_settings.gsm.apn)-1); + strncpy(_settings.gsm.login, login, sizeof(_settings.gsm.login)-1); + strncpy(_settings.gsm.pass, pass, sizeof(_settings.gsm.pass)-1); } /****************************************************************************** @@ -74,7 +78,7 @@ NetworkConnectionState GSMConnectionHandler::update_handleInit() { mkr_gsm_feed_watchdog(); - if (_gsm.begin(_pin) != GSM_READY) + if (_gsm.begin(_settings.gsm.pin) != GSM_READY) { Debug.print(DBG_ERROR, F("SIM not present or wrong PIN")); return NetworkConnectionState::ERROR; @@ -88,7 +92,8 @@ NetworkConnectionState GSMConnectionHandler::update_handleInit() mkr_gsm_feed_watchdog(); - GSM3_NetworkStatus_t const network_status = _gprs.attachGPRS(_apn, _login, _pass, true); + GSM3_NetworkStatus_t const network_status = _gprs.attachGPRS( + _settings.gsm.apn, _settings.gsm.login, _settings.gsm.pass, true); Debug.print(DBG_DEBUG, F("GPRS.attachGPRS(): %d"), network_status); if (network_status == GSM3_NetworkStatus_t::ERROR) { @@ -102,6 +107,10 @@ NetworkConnectionState GSMConnectionHandler::update_handleInit() NetworkConnectionState GSMConnectionHandler::update_handleConnecting() { + if(!_check_internet_availability){ + return NetworkConnectionState::CONNECTED; + } + Debug.print(DBG_INFO, F("Sending PING to outer space...")); int const ping_result = _gprs.ping("time.arduino.cc"); Debug.print(DBG_INFO, F("GPRS.ping(): %d"), ping_result); diff --git a/src/GSMConnectionHandler.h b/src/GSMConnectionHandler.h index 1f3db49a..891fb989 100644 --- a/src/GSMConnectionHandler.h +++ b/src/GSMConnectionHandler.h @@ -39,7 +39,7 @@ class GSMConnectionHandler : public ConnectionHandler { public: - + GSMConnectionHandler(); GSMConnectionHandler(const char * pin, const char * apn, const char * login, const char * pass, bool const keep_alive = true); @@ -59,11 +59,6 @@ class GSMConnectionHandler : public ConnectionHandler private: - const char * _pin; - const char * _apn; - const char * _login; - const char * _pass; - GSM _gsm; GPRS _gprs; GSMUDP _gsm_udp; diff --git a/src/GenericConnectionHandler.cpp b/src/GenericConnectionHandler.cpp new file mode 100644 index 00000000..ce6c198c --- /dev/null +++ b/src/GenericConnectionHandler.cpp @@ -0,0 +1,152 @@ +/* + This file is part of the Arduino_ConnectionHandler library. + + Copyright (c) 2024 Arduino SA + + 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 "GenericConnectionHandler.h" +#include "Arduino_ConnectionHandler.h" + +static inline ConnectionHandler* instantiate_handler(NetworkAdapter adapter); + +bool GenericConnectionHandler::updateSetting(const models::NetworkSetting& s) { + if(_ch != nullptr && _ch->_current_net_connection_state != NetworkConnectionState::INIT) { + // If the internal connection handler is already being used and not in INIT phase we cannot update the settings + return false; + } else if(_ch != nullptr && _ch->_current_net_connection_state == NetworkConnectionState::INIT && _interface != s.type) { + // If the internal connection handler is already being used and in INIT phase and the interface type is being changed + // -> we need to deallocate the previously allocated handler + + // if interface type is not being changed -> we just need to call updateSettings + delete _ch; + _ch = nullptr; + } + + if(_ch == nullptr) { + _ch = instantiate_handler(s.type); + } + + if(_ch != nullptr) { + _interface = s.type; + _ch->setKeepAlive(_keep_alive); + _ch->enableCheckInternetAvailability(_check_internet_availability); + return _ch->updateSetting(s); + } else { + _interface = NetworkAdapter::NONE; + + return false; + } +} + +NetworkConnectionState GenericConnectionHandler::updateConnectionState() { + return _ch != nullptr ? _ch->updateConnectionState() : NetworkConnectionState::INIT; +} + +NetworkConnectionState GenericConnectionHandler::update_handleInit() { + return _ch != nullptr ? _ch->update_handleInit() : NetworkConnectionState::INIT; +} + +NetworkConnectionState GenericConnectionHandler::update_handleConnecting() { + return _ch != nullptr ? _ch->update_handleConnecting() : NetworkConnectionState::INIT; +} + +NetworkConnectionState GenericConnectionHandler::update_handleConnected() { + return _ch != nullptr ? _ch->update_handleConnected() : NetworkConnectionState::INIT; +} + +NetworkConnectionState GenericConnectionHandler::update_handleDisconnecting() { + return _ch != nullptr ? _ch->update_handleDisconnecting() : NetworkConnectionState::INIT; +} + +NetworkConnectionState GenericConnectionHandler::update_handleDisconnected() { + return _ch != nullptr ? _ch->update_handleDisconnected() : NetworkConnectionState::INIT; +} + +#if not (defined(BOARD_HAS_LORA) or defined(BOARD_HAS_NOTECARD)) +unsigned long GenericConnectionHandler::getTime() { + return _ch != nullptr ? _ch->getTime() : 0; +} + +Client & GenericConnectionHandler::getClient() { + return _ch->getClient(); // NOTE _ch may be nullptr +} + +UDP & GenericConnectionHandler::getUDP() { + return _ch->getUDP(); // NOTE _ch may be nullptr +} + +#endif // not (defined(BOARD_HAS_LORA) or defined(BOARD_HAS_NOTECARD)) + +void GenericConnectionHandler::connect() { + if(_ch!=nullptr) { + _ch->connect(); + } + ConnectionHandler::connect(); +} + +void GenericConnectionHandler::disconnect() { + if(_ch!=nullptr) { + _ch->disconnect(); + } + ConnectionHandler::disconnect(); +} + +void GenericConnectionHandler::setKeepAlive(bool keep_alive) { + _keep_alive = keep_alive; + + if(_ch!=nullptr) { + _ch->setKeepAlive(keep_alive); + } +} + +static inline ConnectionHandler* instantiate_handler(NetworkAdapter adapter) { + switch(adapter) { + #if defined(BOARD_HAS_WIFI) + case NetworkAdapter::WIFI: + return new WiFiConnectionHandler(); + break; + #endif + + #if defined(BOARD_HAS_ETHERNET) + case NetworkAdapter::ETHERNET: + return new EthernetConnectionHandler(); + break; + #endif + + #if defined(BOARD_HAS_NB) + case NetworkAdapter::NB: + return new NBConnectionHandler(); + break; + #endif + + #if defined(BOARD_HAS_GSM) + case NetworkAdapter::GSM: + return new GSMConnectionHandler(); + break; + #endif + + #if defined(BOARD_HAS_CATM1_NBIOT) + case NetworkAdapter::CATM1: + return new CatM1ConnectionHandler(); + break; + #endif + + #if defined(BOARD_HAS_CELLULAR) + case NetworkAdapter::CELL: + return new CellularConnectionHandler(); + break; + #endif + + default: + Debug.print(DBG_ERROR, "Network adapter not supported by this platform: %d", adapter); + return nullptr; + } +} diff --git a/src/GenericConnectionHandler.h b/src/GenericConnectionHandler.h new file mode 100644 index 00000000..e1b315e4 --- /dev/null +++ b/src/GenericConnectionHandler.h @@ -0,0 +1,73 @@ +/* + This file is part of the Arduino_ConnectionHandler library. + + Copyright (c) 2024 Arduino SA + + 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_GENERIC_CONNECTION_HANDLER_H_ +#define ARDUINO_GENERIC_CONNECTION_HANDLER_H_ + +/****************************************************************************** + INCLUDE + ******************************************************************************/ + +#include "ConnectionHandlerInterface.h" + +/****************************************************************************** + CLASS DECLARATION + ******************************************************************************/ + +/** GenericConnectionHandler class + * This class aims to wrap a connectionHandler and provide a generic way to + * instantiate a specific connectionHandler type + */ +class GenericConnectionHandler : public ConnectionHandler +{ + public: + + GenericConnectionHandler(bool const keep_alive=true): ConnectionHandler(keep_alive), _ch(nullptr) {} + + #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 + unsigned long getTime() override; + + /* + * NOTE: The following functions have a huge risk of returning a reference to a non existing memory location + * It is important to make sure that the internal connection handler is already allocated before calling them + * When updateSettings is called and the internal connectionHandler is reallocated the references to TCP and UDP + * handles should be deleted. + */ + Client & getClient() override; + UDP & getUDP() override; + #endif + + bool updateSetting(const models::NetworkSetting& s) override; + + void connect() override; + void disconnect() override; + + void setKeepAlive(bool keep_alive=true) override; + + protected: + + NetworkConnectionState updateConnectionState() override; + + NetworkConnectionState update_handleInit () override; + NetworkConnectionState update_handleConnecting () override; + NetworkConnectionState update_handleConnected () override; + NetworkConnectionState update_handleDisconnecting() override; + NetworkConnectionState update_handleDisconnected () override; + + private: + + ConnectionHandler* _ch; +}; + +#endif /* ARDUINO_GENERIC_CONNECTION_HANDLER_H_ */ diff --git a/src/LoRaConnectionHandler.cpp b/src/LoRaConnectionHandler.cpp index 1f454a51..bc753fd2 100644 --- a/src/LoRaConnectionHandler.cpp +++ b/src/LoRaConnectionHandler.cpp @@ -46,13 +46,13 @@ typedef enum ******************************************************************************/ LoRaConnectionHandler::LoRaConnectionHandler(char const * appeui, char const * appkey, _lora_band const band, char const * channelMask, _lora_class const device_class) : ConnectionHandler{false, NetworkAdapter::LORA} -, _appeui(appeui) -, _appkey(appkey) -, _band(band) -, _channelMask(channelMask) -, _device_class(device_class) { - + _settings.type = NetworkAdapter::LORA; + strncpy(_settings.lora.appeui, appeui, sizeof(_settings.lora.appeui)-1); + strncpy(_settings.lora.appkey, appkey, sizeof(_settings.lora.appkey)-1); + _settings.lora.band = band; + strncpy(_settings.lora.channelMask, channelMask, sizeof(_settings.lora.channelMask)-1); + _settings.lora.deviceClass = device_class; } /****************************************************************************** @@ -103,18 +103,18 @@ bool LoRaConnectionHandler::available() NetworkConnectionState LoRaConnectionHandler::update_handleInit() { - if (!_modem.begin(_band)) + if (!_modem.begin((_lora_band)_settings.lora.band)) { Debug.print(DBG_ERROR, F("Something went wrong; are you indoor? Move near a window, then reset and retry.")); return NetworkConnectionState::ERROR; } // Set channelmask based on configuration - if (_channelMask) { - _modem.sendMask(_channelMask); + if (_settings.lora.channelMask) { + _modem.sendMask(_settings.lora.channelMask); } //A delay is required between _modem.begin(band) and _modem.joinOTAA(appeui, appkey) in order to let the chip to be correctly initialized before the connection attempt delay(100); - _modem.configureClass(_device_class); + _modem.configureClass((_lora_class)_settings.lora.deviceClass); delay(100); Debug.print(DBG_INFO, F("Connecting to the network")); return NetworkConnectionState::CONNECTING; @@ -122,7 +122,7 @@ NetworkConnectionState LoRaConnectionHandler::update_handleInit() NetworkConnectionState LoRaConnectionHandler::update_handleConnecting() { - bool const network_status = _modem.joinOTAA(_appeui, _appkey); + bool const network_status = _modem.joinOTAA(_settings.lora.appeui, _settings.lora.appkey); if (network_status != true) { Debug.print(DBG_ERROR, F("Connection to the network failed")); diff --git a/src/LoRaConnectionHandler.h b/src/LoRaConnectionHandler.h index 3ddcca24..cecf8302 100644 --- a/src/LoRaConnectionHandler.h +++ b/src/LoRaConnectionHandler.h @@ -73,11 +73,6 @@ class LoRaConnectionHandler : public ConnectionHandler private: - char const * _appeui; - char const * _appkey; - _lora_band _band; - char const * _channelMask; - _lora_class _device_class; LoRaModem _modem; }; diff --git a/src/NBConnectionHandler.cpp b/src/NBConnectionHandler.cpp index eb72f3e7..02d62ba2 100644 --- a/src/NBConnectionHandler.cpp +++ b/src/NBConnectionHandler.cpp @@ -45,6 +45,10 @@ __attribute__((weak)) void mkr_nb_feed_watchdog() /****************************************************************************** CTOR/DTOR ******************************************************************************/ + +NBConnectionHandler::NBConnectionHandler() +: ConnectionHandler(true, NetworkAdapter::NB) {} + NBConnectionHandler::NBConnectionHandler(char const * pin, bool const keep_alive) : NBConnectionHandler(pin, "", keep_alive) { @@ -59,12 +63,12 @@ NBConnectionHandler::NBConnectionHandler(char const * pin, char const * apn, boo NBConnectionHandler::NBConnectionHandler(char const * pin, char const * apn, char const * login, char const * pass, bool const keep_alive) : ConnectionHandler{keep_alive, NetworkAdapter::NB} -, _pin(pin) -, _apn(apn) -, _login(login) -, _pass(pass) { - + _settings.type = NetworkAdapter::NB; + strncpy(_settings.nb.pin, pin, sizeof(_settings.nb.pin)-1); + strncpy(_settings.nb.apn, apn, sizeof(_settings.nb.apn)-1); + strncpy(_settings.nb.login, login, sizeof(_settings.nb.login)-1); + strncpy(_settings.nb.pass, pass, sizeof(_settings.nb.pass)-1); } /****************************************************************************** @@ -84,7 +88,10 @@ NetworkConnectionState NBConnectionHandler::update_handleInit() { mkr_nb_feed_watchdog(); - if (_nb.begin(_pin, _apn, _login, _pass) == NB_READY) + if (_nb.begin(_settings.nb.pin, + _settings.nb.apn, + _settings.nb.login, + _settings.nb.pass) == NB_READY) { Debug.print(DBG_INFO, F("SIM card ok")); _nb.setTimeout(NB_TIMEOUT); diff --git a/src/NBConnectionHandler.h b/src/NBConnectionHandler.h index fd2afb6c..6641bb69 100644 --- a/src/NBConnectionHandler.h +++ b/src/NBConnectionHandler.h @@ -39,7 +39,7 @@ class NBConnectionHandler : public ConnectionHandler { public: - + NBConnectionHandler(); NBConnectionHandler(char const * pin, bool const keep_alive = true); NBConnectionHandler(char const * pin, char const * apn, bool const keep_alive = true); NBConnectionHandler(char const * pin, char const * apn, char const * login, char const * pass, bool const keep_alive = true); @@ -63,11 +63,6 @@ class NBConnectionHandler : public ConnectionHandler void changeConnectionState(NetworkConnectionState _newState); - char const * _pin; - char const * _apn; - char const * _login; - char const * _pass; - NB _nb; GPRS _nb_gprs; NBUDP _nb_udp; diff --git a/src/WiFiConnectionHandler.cpp b/src/WiFiConnectionHandler.cpp index 0cd2e126..37d3ff66 100644 --- a/src/WiFiConnectionHandler.cpp +++ b/src/WiFiConnectionHandler.cpp @@ -35,12 +35,16 @@ static int const ESP_WIFI_CONNECTION_TIMEOUT = 3000; CTOR/DTOR ******************************************************************************/ +WiFiConnectionHandler::WiFiConnectionHandler() +: ConnectionHandler(true, NetworkAdapter::WIFI) { +} + WiFiConnectionHandler::WiFiConnectionHandler(char const * ssid, char const * pass, bool const keep_alive) : ConnectionHandler{keep_alive, NetworkAdapter::WIFI} -, _ssid{ssid} -, _pass{pass} { - + _settings.type = NetworkAdapter::WIFI; + strncpy(_settings.wifi.ssid, ssid, sizeof(_settings.wifi.ssid)-1); + strncpy(_settings.wifi.pwd, pass, sizeof(_settings.wifi.pwd)-1); } /****************************************************************************** @@ -92,14 +96,10 @@ NetworkConnectionState WiFiConnectionHandler::update_handleInit() #else WiFi.mode(WIFI_STA); #endif /* #if !defined(ARDUINO_ARCH_ESP8266) && !defined(ARDUINO_ARCH_ESP32) */ - return NetworkConnectionState::CONNECTING; -} -NetworkConnectionState WiFiConnectionHandler::update_handleConnecting() -{ if (WiFi.status() != WL_CONNECTED) { - WiFi.begin(_ssid, _pass); + WiFi.begin(_settings.wifi.ssid, _settings.wifi.pwd); #if defined(ARDUINO_ARCH_ESP8266) /* Wait connection otherwise board won't connect */ unsigned long start = millis(); @@ -113,21 +113,46 @@ NetworkConnectionState WiFiConnectionHandler::update_handleConnecting() if (WiFi.status() != NETWORK_CONNECTED) { #if !defined(__AVR__) - Debug.print(DBG_ERROR, F("Connection to \"%s\" failed"), _ssid); - Debug.print(DBG_INFO, F("Retrying in \"%d\" milliseconds"), CHECK_INTERVAL_TABLE[static_cast(NetworkConnectionState::CONNECTING)]); + Debug.print(DBG_ERROR, F("Connection to \"%s\" failed"), _settings.wifi.ssid); + Debug.print(DBG_INFO, F("Retrying in \"%d\" milliseconds"), CHECK_INTERVAL_TABLE[static_cast(NetworkConnectionState::INIT)]); #endif - return NetworkConnectionState::CONNECTING; + return NetworkConnectionState::INIT; } else { #if !defined(__AVR__) - Debug.print(DBG_INFO, F("Connected to \"%s\""), _ssid); + Debug.print(DBG_INFO, F("Connected to \"%s\""), _settings.wifi.ssid); #endif #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) configTime(0, 0, "time.arduino.cc", "pool.ntp.org", "time.nist.gov"); #endif + return NetworkConnectionState::CONNECTING; + } +} + +NetworkConnectionState WiFiConnectionHandler::update_handleConnecting() +{ + if (WiFi.status() != WL_CONNECTED){ + return NetworkConnectionState::INIT; + } + + if(!_check_internet_availability){ return NetworkConnectionState::CONNECTED; } + + #if !defined(ARDUINO_ARCH_ESP8266) && !defined(ARDUINO_ARCH_ESP32) + int ping_result = WiFi.ping("time.arduino.cc"); + Debug.print(DBG_INFO, F("WiFi.ping(): %d"), ping_result); + if (ping_result < 0) + { + Debug.print(DBG_ERROR, F("Internet check failed")); + Debug.print(DBG_INFO, F("Retrying in \"%d\" milliseconds"), CHECK_INTERVAL_TABLE[static_cast(NetworkConnectionState::CONNECTING)]); + return NetworkConnectionState::CONNECTING; + } + #endif + Debug.print(DBG_INFO, F("Connected to Internet")); + return NetworkConnectionState::CONNECTED; + } NetworkConnectionState WiFiConnectionHandler::update_handleConnected() @@ -136,7 +161,7 @@ NetworkConnectionState WiFiConnectionHandler::update_handleConnected() { #if !defined(__AVR__) Debug.print(DBG_VERBOSE, F("WiFi.status(): %d"), WiFi.status()); - Debug.print(DBG_ERROR, F("Connection to \"%s\" lost."), _ssid); + Debug.print(DBG_ERROR, F("Connection to \"%s\" lost."), _settings.wifi.ssid); #endif if (_keep_alive) { diff --git a/src/WiFiConnectionHandler.h b/src/WiFiConnectionHandler.h index 2ee674a5..1d360b70 100644 --- a/src/WiFiConnectionHandler.h +++ b/src/WiFiConnectionHandler.h @@ -62,7 +62,7 @@ class WiFiConnectionHandler : public ConnectionHandler { public: - + WiFiConnectionHandler(); WiFiConnectionHandler(char const * ssid, char const * pass, bool const keep_alive = true); @@ -80,10 +80,6 @@ class WiFiConnectionHandler : public ConnectionHandler virtual NetworkConnectionState update_handleDisconnected () override; private: - - char const * _ssid; - char const * _pass; - WiFiUDP _wifi_udp; WiFiClient _wifi_client; }; diff --git a/src/connectionHandlerModels/settings.h b/src/connectionHandlerModels/settings.h new file mode 100644 index 00000000..40319d66 --- /dev/null +++ b/src/connectionHandlerModels/settings.h @@ -0,0 +1,130 @@ +/* + This file is part of the Arduino_ConnectionHandler library. + + Copyright (c) 2024 Arduino SA + + 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/. +*/ + +#pragma once + +#include "ConnectionHandlerDefinitions.h" +#include +#include + +namespace models { + constexpr size_t WifiSsidLength = 33; // Max length of wifi ssid is 32 + \0 + constexpr size_t WifiPwdLength = 64; // Max length of wifi password is 63 + \0 + + constexpr size_t CellularPinLength = 9; + constexpr size_t CellularApnLength = 101; // Max length of apn is 100 + \0 + constexpr size_t CellularLoginLength = 65; + constexpr size_t CellularPassLength = 65; + + constexpr size_t LoraAppeuiLength = 17; // appeui is 8 octets * 2 (hex format) + \0 + constexpr size_t LoraAppkeyLength = 33; // appeui is 16 octets * 2 (hex format) + \0 + constexpr size_t LoraChannelMaskLength = 13; + + #if defined(BOARD_HAS_WIFI) + struct WiFiSetting { + char ssid[WifiSsidLength]; + char pwd[WifiPwdLength]; + }; + #endif //defined(BOARD_HAS_WIFI) + + #if defined(BOARD_HAS_ETHERNET) + // this struct represents an ip address in its simplest form. + // FIXME this should be available from ArduinoCore-api IPAddress + struct ip_addr { + IPType type; + union { + uint8_t bytes[16]; + uint32_t dword[4]; + }; + }; + + struct EthernetSetting { + ip_addr ip; + ip_addr dns; + ip_addr gateway; + ip_addr netmask; + unsigned long timeout; + unsigned long response_timeout; + }; + #endif // BOARD_HAS_ETHERNET + + #if defined(BOARD_HAS_NB) || defined(BOARD_HAS_GSM) ||defined(BOARD_HAS_CELLULAR) + struct CellularSetting { + char pin[CellularPinLength]; + char apn[CellularApnLength]; + char login[CellularLoginLength]; + char pass[CellularPassLength]; + }; + #endif // defined(BOARD_HAS_NB) || defined(BOARD_HAS_GSM) || defined(BOARD_HAS_CATM1_NBIOT) || defined(BOARD_HAS_CELLULAR) + + #if defined(BOARD_HAS_GSM) + typedef CellularSetting GSMSetting; + #endif //defined(BOARD_HAS_GSM) + + #if defined(BOARD_HAS_NB) + typedef CellularSetting NBSetting; + #endif //defined(BOARD_HAS_NB) + + #if defined(BOARD_HAS_CATM1_NBIOT) + struct CATM1Setting { + char pin[CellularPinLength]; + char apn[CellularApnLength]; + char login[CellularLoginLength]; + char pass[CellularPassLength]; + uint32_t band; + uint8_t rat; + }; + #endif //defined(BOARD_HAS_CATM1_NBIOT) + +#if defined(BOARD_HAS_LORA) + struct LoraSetting { + char appeui[LoraAppeuiLength]; + char appkey[LoraAppkeyLength]; + uint8_t band; + char channelMask[LoraChannelMaskLength]; + uint8_t deviceClass; + }; +#endif + + struct NetworkSetting { + NetworkAdapter type; + union { + #if defined(BOARD_HAS_WIFI) + WiFiSetting wifi; + #endif + + #if defined(BOARD_HAS_ETHERNET) + EthernetSetting eth; + #endif + + #if defined(BOARD_HAS_NB) + NBSetting nb; + #endif + + #if defined(BOARD_HAS_GSM) + GSMSetting gsm; + #endif + + #if defined(BOARD_HAS_CATM1_NBIOT) + CATM1Setting catm1; + #endif + + #if defined(BOARD_HAS_CELLULAR) + CellularSetting cell; + #endif + + #if defined(BOARD_HAS_LORA) + LoraSetting lora; + #endif + }; + }; +} + +#include "settings_default.h" diff --git a/src/connectionHandlerModels/settings_default.h b/src/connectionHandlerModels/settings_default.h new file mode 100644 index 00000000..dc9a4efd --- /dev/null +++ b/src/connectionHandlerModels/settings_default.h @@ -0,0 +1,72 @@ +/* + This file is part of the Arduino_ConnectionHandler library. + + Copyright (c) 2024 Arduino SA + + 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/. +*/ + +#pragma once +#include "settings.h" + +namespace models { + + /* + * if the cpp version is older than cpp14 then a constexpr function cannot include + * other than a simple return statement, thsu we can define it only as inline + */ + #if __cplusplus > 201103L + constexpr NetworkSetting settingsDefault(NetworkAdapter type) { + #else + inline NetworkSetting settingsDefault(NetworkAdapter type) { + #endif + + NetworkSetting res = {type}; + + switch(type) { + #if defined(BOARD_HAS_ETHERNET) + case NetworkAdapter::ETHERNET: + res.eth.timeout = 15000; + res.eth.response_timeout = 4000; + break; + #endif //defined(BOARD_HAS_ETHERNET) + + #if defined(BOARD_HAS_CATM1_NBIOT) + case NetworkAdapter::CATM1: + res.catm1.rat = 7; // CATM1 + res.catm1.band = 0x04 | 0x80000 | 0x40000; // BAND_3 | BAND_20 | BAND_19 + break; + #endif //defined(BOARD_HAS_CATM1_NBIOT) + + #if defined(BOARD_HAS_LORA) + case NetworkAdapter::LORA: + res.lora.band = 5; // _lora_band::EU868 + res.lora.channelMask[0] = '\0'; + res.lora.deviceClass = 'A'; // _lora_class::CLASS_A + break; + #endif //defined(BOARD_HAS_LORA) + + #if defined(BOARD_HAS_WIFI) + case NetworkAdapter::WIFI: // nothing todo, default optional values are fine with 0 + #endif //defined(BOARD_HAS_WIFI) + + #if defined(BOARD_HAS_NB) + case NetworkAdapter::NB: // nothing todo, default optional values are fine with 0 + #endif //defined(BOARD_HAS_NB) + + #if defined(BOARD_HAS_GSM) + case NetworkAdapter::GSM: // nothing todo, default optional values are fine with 0 + #endif //defined(BOARD_HAS_GSM) + + #if defined(BOARD_HAS_CELLULAR) + case NetworkAdapter::CELL: // nothing todo, default optional values are fine with 0 + #endif //defined(BOARD_HAS_CELLULAR) + default: + (void) 0; + } + + return res; + } +} 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