diff --git a/examples/GenericConnectionHandlerDemo/GenericConnectionHandlerDemo.ino b/examples/GenericConnectionHandlerDemo/GenericConnectionHandlerDemo.ino new file mode 100644 index 0000000..2ce18f7 --- /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 0000000..cecefa4 --- /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/src/CatM1ConnectionHandler.cpp b/src/CatM1ConnectionHandler.cpp index 0263a39..2a63dea 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 33ac9fe..67f317b 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 2e4499a..c6a9077 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 2addd29..fcc02c6 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 4f29559..4cefc5d 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 2fdc10e..237b465 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 228827e..ff57bf8 100644 --- a/src/ConnectionHandlerInterface.h +++ b/src/ConnectionHandlerInterface.h @@ -29,6 +29,7 @@ #include #include #include "ConnectionHandlerDefinitions.h" +#include "settings/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 14f7aee..543f073 100644 --- a/src/EthernetConnectionHandler.cpp +++ b/src/EthernetConnectionHandler.cpp @@ -20,56 +20,47 @@ #ifdef BOARD_HAS_ETHERNET /* Only compile if the board has ethernet */ #include "EthernetConnectionHandler.h" +#include /****************************************************************************** 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 35a02cd..738b6a8 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 34bf179..64b04d0 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 1f3db49..891fb98 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 0000000..ce6c198 --- /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 0000000..e1b315e --- /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 1f454a5..bc753fd 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 3ddcca2..cecf830 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 eb72f3e..02d62ba 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 fd2afb6..6641bb6 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 0cd2e12..218e1cc 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_ERROR, F("Connection to \"%s\" failed"), _settings.wifi.ssid); Debug.print(DBG_INFO, F("Retrying in \"%d\" milliseconds"), CHECK_INTERVAL_TABLE[static_cast(NetworkConnectionState::CONNECTING)]); #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 2ee674a..1d360b7 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/settings/settings.h b/src/settings/settings.h new file mode 100644 index 0000000..40319d6 --- /dev/null +++ b/src/settings/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/settings/settings_default.h b/src/settings/settings_default.h new file mode 100644 index 0000000..fb3d52b --- /dev/null +++ b/src/settings/settings_default.h @@ -0,0 +1,74 @@ +/* + 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_WIFI) + case NetworkAdapter::WIFI: // nothing todo, default optional values are fine with 0 + break; + #endif //defined(BOARD_HAS_WIFI) + + #if defined(BOARD_HAS_NB) + case NetworkAdapter::NB: // nothing todo, default optional values are fine with 0 + break; + #endif //defined(BOARD_HAS_NB) + + #if defined(BOARD_HAS_GSM) + case NetworkAdapter::GSM: // nothing todo, default optional values are fine with 0 + break; + #endif //defined(BOARD_HAS_GSM) + + #if defined(BOARD_HAS_CELLULAR) + case NetworkAdapter::CELL: // nothing todo, default optional values are fine with 0 + break; + #endif //defined(BOARD_HAS_CELLULAR) + + #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) + } + + return res; + } +}