/* 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 "ANetworkConfigurator_Config.h" #if NETWORK_CONFIGURATOR_COMPATIBLE #include <Arduino_DebugUtils.h> #include "ConnectionHandlerDefinitions.h" #include "ConfiguratorAgents/MessagesDefinitions.h" #include "Utility/LEDFeedback/LEDFeedback.h" #ifdef BOARD_HAS_WIFI #include "WiFiConnectionHandler.h" #endif #include "Arduino_NetworkConfigurator.h" #define NC_CONNECTION_RETRY_TIMER_ms 120000 #define NC_CONNECTION_TIMEOUT_ms 15000 #define NC_UPDATE_NETWORK_OPTIONS_TIMER_ms 120000 constexpr char *STORAGE_KEY{ "NETWORK_CONFIGS" }; constexpr char *START_BLE_AT_STARTUP_KEY{ "START_BLE" }; /****************************************************************************** * PUBLIC MEMBER FUNCTIONS ******************************************************************************/ NetworkConfiguratorClass::NetworkConfiguratorClass(ConnectionHandler &connectionHandler) : _state{ NetworkConfiguratorStates::END }, _connectionHandler{ &connectionHandler }, _connectionHandlerIstantiated{ false }, _kvstore{ nullptr }, _connectionTimeout{ NC_CONNECTION_TIMEOUT_ms, NC_CONNECTION_TIMEOUT_ms }, _connectionRetryTimer{ NC_CONNECTION_RETRY_TIMER_ms, NC_CONNECTION_RETRY_TIMER_ms }, _optionUpdateTimer{ NC_UPDATE_NETWORK_OPTIONS_TIMER_ms, NC_UPDATE_NETWORK_OPTIONS_TIMER_ms } { _receivedEvent = NetworkConfiguratorEvents::NONE; _optionUpdateTimer.begin(NC_UPDATE_NETWORK_OPTIONS_TIMER_ms); //initialize the timer before calling begin _agentsManager = &AgentsManagerClass::getInstance(); _resetInput = &ResetInput::getInstance(); _ledFeedback = &LEDFeedbackClass::getInstance(); } bool NetworkConfiguratorClass::begin() { if(_state != NetworkConfiguratorStates::END) { return true; } /* * If the board is zero touch capable, starts with zero touch configuration mode * In this state the board will try to connect to the network using a set of * default network settings ex. Ethernet with DHCP * This mode will fail if the provided ConnectionHandler is not GenericConnectionHandler type * falling back to read the network settings from the storage */ #if ZERO_TOUCH_ENABLED _state = NetworkConfiguratorStates::ZERO_TOUCH_CONFIG; #else _state = NetworkConfiguratorStates::READ_STORED_CONFIG; #endif _connectionHandler->enableCheckInternetAvailability(true); memset(&_networkSetting, 0x00, sizeof(models::NetworkSetting)); _ledFeedback->begin(); #ifdef BOARD_HAS_WIFI String fv = WiFi.firmwareVersion(); if (fv < WIFI_FIRMWARE_LATEST_VERSION) { DEBUG_ERROR(F("The current WiFi firmware version is not the latest and it may cause compatibility issues. Please upgrade the WiFi firmware")); } _agentsManager->addRequestHandler(RequestType::SCAN, scanReqHandler); #endif // Register callbacks to agentsManager _agentsManager->addRequestHandler(RequestType::CONNECT, connectReqHandler); _agentsManager->addReturnNetworkSettingsCallback(setNetworkSettingsHandler); _agentsManager->addRequestHandler(RequestType::GET_WIFI_FW_VERSION, getWiFiFWVersionHandler); if (!_agentsManager->begin()) { DEBUG_ERROR("NetworkConfiguratorClass::%s Failed to initialize the AgentsManagerClass", __FUNCTION__); } _connectionTimeout.begin(NC_CONNECTION_TIMEOUT_ms); _connectionRetryTimer.begin(NC_CONNECTION_RETRY_TIMER_ms); _resetInput->begin(); return true; } NetworkConfiguratorStates NetworkConfiguratorClass::update() { NetworkConfiguratorStates nextState = _state; _ledFeedback->update(); switch (_state) { #if ZERO_TOUCH_ENABLED case NetworkConfiguratorStates::ZERO_TOUCH_CONFIG: nextState = handleZeroTouchConfig(); break; #endif case NetworkConfiguratorStates::READ_STORED_CONFIG: nextState = handleReadStorage (); break; case NetworkConfiguratorStates::WAITING_FOR_CONFIG: nextState = handleWaitingForConf (); break; case NetworkConfiguratorStates::CONNECTING: nextState = handleConnecting (); break; case NetworkConfiguratorStates::CONFIGURED: nextState = handleConfigured (); break; case NetworkConfiguratorStates::UPDATING_CONFIG: nextState = handleUpdatingConfig (); break; case NetworkConfiguratorStates::ERROR: nextState = handleErrorState (); break; case NetworkConfiguratorStates::END: break; } if(_state != nextState){ if(nextState == NetworkConfiguratorStates::CONNECTING){ _connectionTimeout.reload(); } _state = nextState; } /* Reconfiguration procedure: * - Arduino Opta: press and hold the user button (BTN_USER) until the led (LED_USER) turns off * - Arduino MKR WiFi 1010: short the pin 7 to GND until the led turns off * - Arduino GIGA R1 WiFi: short the pin 7 to GND until the led turns off * - Arduino Nano RP2040 Connect: short the pin 2 to 3.3V until the led turns off * - Other boards: short the pin 2 to GND until the led turns off */ if(_resetInput->isEventFired()) { startReconfigureProcedure(); } return _state; } bool NetworkConfiguratorClass::resetStoredConfiguration() { memset(&_networkSetting, 0x00, sizeof(models::NetworkSetting)); if(_connectionHandlerIstantiated) { disconnectFromNetwork(); _connectionHandlerIstantiated = false; } if(_state != NetworkConfiguratorStates::END) { _state = NetworkConfiguratorStates::WAITING_FOR_CONFIG; } if(_kvstore == nullptr){ return true; } if(!_kvstore->begin()) { return false; } bool removeRes = true; if(_kvstore->exists(STORAGE_KEY)) { removeRes = _kvstore->remove(STORAGE_KEY); } _kvstore->end(); return removeRes; } bool NetworkConfiguratorClass::end() { if (_state == NetworkConfiguratorStates::END) { return true; } _agentsManager->removeReturnNetworkSettingsCallback(); _agentsManager->removeRequestHandler(RequestType::SCAN); _agentsManager->removeRequestHandler(RequestType::CONNECT); _agentsManager->removeRequestHandler(RequestType::GET_WIFI_FW_VERSION); _state = NetworkConfiguratorStates::END; return _agentsManager->end(); } bool NetworkConfiguratorClass::scanNetworkOptions() { // If board has Wifi scan for networks #ifdef BOARD_HAS_WIFI sendStatus(StatusMessage::SCANNING); //Notify before scan WiFiOption wifiOptObj; if (!scanWiFiNetworks(wifiOptObj)) { sendStatus(StatusMessage::HW_ERROR_CONN_MODULE); return false; } NetworkOptions netOption = { NetworkOptionsClass::WIFI, wifiOptObj }; #else // Send an empty network options message NetworkOptions netOption = { NetworkOptionsClass::NONE }; #endif ProvisioningOutputMessage netOptionMsg = { MessageOutputType::NETWORK_OPTIONS }; netOptionMsg.m.netOptions = &netOption; _agentsManager->sendMsg(netOptionMsg); _optionUpdateTimer.reload(); return true; } void NetworkConfiguratorClass::setStorage(KVStore &kvstore) { _kvstore = &kvstore; } void NetworkConfiguratorClass::setReconfigurePin(int pin) { _resetInput->setPin(pin); } void NetworkConfiguratorClass::addReconfigurePinCallback(ResetInput::ResetInputCallback callback) { _resetInput->setPinChangedCallback(callback); } bool NetworkConfiguratorClass::isAgentEnabled(ConfiguratorAgent::AgentTypes type) { return _agentsManager->isAgentEnabled(type); } void NetworkConfiguratorClass::enableAgent(ConfiguratorAgent::AgentTypes type, bool enable) { _agentsManager->enableAgent(type, enable); } void NetworkConfiguratorClass::disconnectAgent() { _agentsManager->disconnect(); } bool NetworkConfiguratorClass::addAgent(ConfiguratorAgent &agent) { return _agentsManager->addAgent(agent); } /****************************************************************************** * PRIVATE MEMBER FUNCTIONS ******************************************************************************/ NetworkConfiguratorClass::ConnectionResult NetworkConfiguratorClass::connectToNetwork(StatusMessage *err) { ConnectionResult res = ConnectionResult::IN_PROGRESS; NetworkConnectionState connectionRes = NetworkConnectionState::DISCONNECTED; connectionRes = _connectionHandler->check(); if (connectionRes == NetworkConnectionState::CONNECTED) { DEBUG_INFO("NetworkConfigurator: Connected to network"); sendStatus(StatusMessage::CONNECTED); res = ConnectionResult::SUCCESS; } else if (connectionRes != NetworkConnectionState::CONNECTED && _connectionTimeout.isExpired()) //connection attempt failed { String errorMsg = decodeConnectionErrorMessage(connectionRes, err); DEBUG_INFO("NetworkConfigurator: Connection fail: %s", errorMsg.c_str()); _connectionRetryTimer.reload(); res = ConnectionResult::FAILED; } return res; } NetworkConfiguratorClass::ConnectionResult NetworkConfiguratorClass::disconnectFromNetwork() { _connectionHandler->disconnect(); uint32_t startDisconnection = millis(); NetworkConnectionState s; do { s = _connectionHandler->check(); } while (s != NetworkConnectionState::CLOSED && millis() - startDisconnection < 5000); if (s != NetworkConnectionState::CLOSED) { return ConnectionResult::FAILED; } // Reset the connection handler to INIT state _connectionHandler->connect(); return ConnectionResult::SUCCESS; } #ifdef BOARD_HAS_WIFI // insert a new WiFi network in the list of discovered networks bool NetworkConfiguratorClass::insertWiFiAP(WiFiOption &wifiOptObj, char *ssid, int rssi) { if (wifiOptObj.numDiscoveredWiFiNetworks >= MAX_WIFI_NETWORKS) { return false; } // check if the network is already in the list and update the RSSI for (uint8_t i = 0; i < wifiOptObj.numDiscoveredWiFiNetworks; i++) { if (wifiOptObj.discoveredWifiNetworks[i].SSID == nullptr) { break; } if (strcmp(wifiOptObj.discoveredWifiNetworks[i].SSID, ssid) == 0) { if (wifiOptObj.discoveredWifiNetworks[i].RSSI < rssi) { wifiOptObj.discoveredWifiNetworks[i].RSSI = rssi; } return true; } } // add the network to the list wifiOptObj.discoveredWifiNetworks[wifiOptObj.numDiscoveredWiFiNetworks].SSID = ssid; wifiOptObj.discoveredWifiNetworks[wifiOptObj.numDiscoveredWiFiNetworks].SSIDsize = strlen(ssid); wifiOptObj.discoveredWifiNetworks[wifiOptObj.numDiscoveredWiFiNetworks].RSSI = rssi; wifiOptObj.numDiscoveredWiFiNetworks++; return true; } bool NetworkConfiguratorClass::scanWiFiNetworks(WiFiOption &wifiOptObj) { wifiOptObj.numDiscoveredWiFiNetworks = 0; #if defined(ARDUINO_UNOR4_WIFI) WiFi.end(); #endif // check for the WiFi module: if (WiFi.status() == WL_NO_MODULE) { DEBUG_WARNING("NetworkConfiguratorClass::%s Communication with WiFi module failed!", __FUNCTION__); return false; } int numSsid = WiFi.scanNetworks(); if (numSsid == -1) { DEBUG_WARNING("NetworkConfiguratorClass::%s Couldn't get any WiFi connection", __FUNCTION__); return false; } // insert the networks in the list for (int thisNet = 0; thisNet < numSsid && thisNet < MAX_WIFI_NETWORKS; thisNet++) { if (!insertWiFiAP(wifiOptObj, const_cast<char *>(WiFi.SSID(thisNet)), WiFi.RSSI(thisNet))) { break; } } return true; } #endif void NetworkConfiguratorClass::scanReqHandler() { _receivedEvent = NetworkConfiguratorEvents::SCAN_REQ; } void NetworkConfiguratorClass::connectReqHandler() { _receivedEvent = NetworkConfiguratorEvents::CONNECT_REQ; } void NetworkConfiguratorClass::setNetworkSettingsHandler(models::NetworkSetting *netSetting) { memcpy(&_networkSetting, netSetting, sizeof(models::NetworkSetting)); printNetworkSettings(); _receivedEvent = NetworkConfiguratorEvents::NEW_NETWORK_SETTINGS; } void NetworkConfiguratorClass::getWiFiFWVersionHandler() { _receivedEvent = NetworkConfiguratorEvents::GET_WIFI_FW_VERSION; } bool NetworkConfiguratorClass::handleConnectRequest() { if (_networkSetting.type == NetworkAdapter::NONE) { sendStatus(StatusMessage::PARAMS_NOT_FOUND); return false; } if (_kvstore != nullptr) { if (!_kvstore->begin()) { DEBUG_ERROR("NetworkConfiguratorClass::%s error initializing kvstore", __FUNCTION__); sendStatus(StatusMessage::ERROR_STORAGE_BEGIN); _ledFeedback->setMode(LEDFeedbackClass::LEDFeedbackMode::ERROR); return false; } bool storeResult = _kvstore->putBytes(STORAGE_KEY, (uint8_t *)&_networkSetting, sizeof(models::NetworkSetting)); _kvstore->end(); if (!storeResult) { DEBUG_ERROR("NetworkConfiguratorClass::%s error saving network settings", __FUNCTION__); sendStatus(StatusMessage::ERROR); _ledFeedback->setMode(LEDFeedbackClass::LEDFeedbackMode::ERROR); return false; } } if (_connectionHandlerIstantiated) { if(disconnectFromNetwork() == ConnectionResult::FAILED) { sendStatus(StatusMessage::ERROR); _ledFeedback->setMode(LEDFeedbackClass::LEDFeedbackMode::ERROR); return false; } } if (!_connectionHandler->updateSetting(_networkSetting)) { sendStatus(StatusMessage::INVALID_PARAMS); return false; } _connectionHandlerIstantiated = true; _ledFeedback->setMode(LEDFeedbackClass::LEDFeedbackMode::CONNECTING_TO_NETWORK); return true; } String NetworkConfiguratorClass::decodeConnectionErrorMessage(NetworkConnectionState err, StatusMessage *errorCode) { switch (err) { case NetworkConnectionState::ERROR: *errorCode = StatusMessage::HW_ERROR_CONN_MODULE; return "HW error"; case NetworkConnectionState::INIT: //the connection handler doesn't have a state of "Fail to connect", in case of invalid credentials or //missing network configuration the FSM stays on Init state so use this state to detect the fail to connect *errorCode = StatusMessage::FAILED_TO_CONNECT; return "Failed to connect"; case NetworkConnectionState::CLOSED: *errorCode = StatusMessage::HW_CONN_MODULE_STOPPED; return "Peripheral stopped"; case NetworkConnectionState::DISCONNECTED: *errorCode = StatusMessage::DISCONNECTED; return "Disconnected"; case NetworkConnectionState::CONNECTING: //the connection handler doesn't have a state of "Internet not available", in case of it's impossible to reach internet //the FSM stays on Connecting state so use this state to detect if internet is not available *errorCode = StatusMessage::INTERNET_NOT_AVAILABLE; return "Internet not available"; default: *errorCode = StatusMessage::ERROR; return "Generic error"; } } void NetworkConfiguratorClass::handleGetWiFiFWVersion() { String fwVersion = WiFi.firmwareVersion(); ProvisioningOutputMessage fwVersionMsg = { MessageOutputType::WIFI_FW_VERSION }; fwVersionMsg.m.wifiFwVersion = fwVersion.c_str(); _agentsManager->sendMsg(fwVersionMsg); } void NetworkConfiguratorClass::startReconfigureProcedure() { resetStoredConfiguration(); // Set to restart the BLE after reboot if(_kvstore != nullptr){ if (_kvstore->begin()) { if(!_kvstore->putBool(START_BLE_AT_STARTUP_KEY, true)){ DEBUG_ERROR("NetworkConfiguratorClass::%s Error saving BLE enabled at startup", __FUNCTION__); } _kvstore->end(); } } NVIC_SystemReset(); } #if ZERO_TOUCH_ENABLED NetworkConfiguratorStates NetworkConfiguratorClass::handleZeroTouchConfig() { if(_networkSetting.type == NetworkAdapter::NONE) { #ifdef BOARD_HAS_ETHERNET defaultEthernetSettings(); #endif if (!_connectionHandler->updateSetting(_networkSetting)) { return NetworkConfiguratorStates::READ_STORED_CONFIG; } _connectionHandlerIstantiated = true; _connectionTimeout.reload(); } StatusMessage err; ConnectionResult connectionRes = connectToNetwork(&err); if (connectionRes == ConnectionResult::SUCCESS) { return NetworkConfiguratorStates::CONFIGURED; } else if (connectionRes == ConnectionResult::FAILED) { DEBUG_VERBOSE("NetworkConfiguratorClass::%s Connection eth fail", __FUNCTION__); if(disconnectFromNetwork() == ConnectionResult::FAILED) { sendStatus(StatusMessage::ERROR); } _connectionHandlerIstantiated = false; return NetworkConfiguratorStates::READ_STORED_CONFIG; } return NetworkConfiguratorStates::ZERO_TOUCH_CONFIG; } #endif NetworkConfiguratorStates NetworkConfiguratorClass::handleReadStorage() { if(_kvstore == nullptr){ DEBUG_ERROR("NetworkConfiguratorClass::%s KVStore not provided", __FUNCTION__); return NetworkConfiguratorStates::CONFIGURED; } if (!_kvstore->begin()) { DEBUG_ERROR("NetworkConfiguratorClass::%s error initializing kvstore", __FUNCTION__); sendStatus(StatusMessage::ERROR_STORAGE_BEGIN); _ledFeedback->setMode(LEDFeedbackClass::LEDFeedbackMode::ERROR); return NetworkConfiguratorStates::ERROR; } if(_kvstore->exists(START_BLE_AT_STARTUP_KEY)) { if(_kvstore->getBool(START_BLE_AT_STARTUP_KEY)) { _agentsManager->startAgent(ConfiguratorAgent::AgentTypes::BLE); } _kvstore->remove(START_BLE_AT_STARTUP_KEY); } bool credFound = false; if (_kvstore->exists(STORAGE_KEY)) { _kvstore->getBytes(STORAGE_KEY, (uint8_t *)&_networkSetting, sizeof(models::NetworkSetting)); printNetworkSettings(); credFound = true; } _kvstore->end(); if(credFound && _connectionHandler->updateSetting(_networkSetting)) { _connectionHandlerIstantiated = true; return NetworkConfiguratorStates::CONFIGURED; } if (_optionUpdateTimer.getWaitTime() == 0) { scanNetworkOptions(); } return NetworkConfiguratorStates::WAITING_FOR_CONFIG; } NetworkConfiguratorStates NetworkConfiguratorClass::handleWaitingForConf() { NetworkConfiguratorStates nextState = _state; _agentsManager->update(); bool connecting = false; switch (_receivedEvent) { case NetworkConfiguratorEvents::SCAN_REQ: scanNetworkOptions (); break; case NetworkConfiguratorEvents::CONNECT_REQ: connecting = handleConnectRequest (); break; case NetworkConfiguratorEvents::GET_WIFI_FW_VERSION: handleGetWiFiFWVersion(); break; case NetworkConfiguratorEvents::NEW_NETWORK_SETTINGS: break; } _receivedEvent = NetworkConfiguratorEvents::NONE; if((_connectionHandlerIstantiated && _agentsManager->isConfigInProgress() != true && _connectionRetryTimer.isExpired()) || connecting){ sendStatus(StatusMessage::CONNECTING); return NetworkConfiguratorStates::CONNECTING; } //Check if update the network options if (_optionUpdateTimer.isExpired()) { scanNetworkOptions(); } return nextState; } NetworkConfiguratorStates NetworkConfiguratorClass::handleConnecting() { _agentsManager->update(); //To keep alive the connection with the configurator StatusMessage err; ConnectionResult res = connectToNetwork(&err); if (res == ConnectionResult::SUCCESS) { return NetworkConfiguratorStates::CONFIGURED; } else if (res == ConnectionResult::FAILED) { sendStatus(err); return NetworkConfiguratorStates::WAITING_FOR_CONFIG; } //The connection is still in progress return NetworkConfiguratorStates::CONNECTING; } NetworkConfiguratorStates NetworkConfiguratorClass::handleConfigured() { bool configInprogress = _agentsManager->isConfigInProgress(); if (configInprogress) { _ledFeedback->setMode(LEDFeedbackClass::LEDFeedbackMode::PEER_CONNECTED); } _agentsManager->update(); // If the agent manager changes state, it means that user is trying to configure the network, so the network configurator should change state if (_agentsManager->isConfigInProgress() && !configInprogress) { scanNetworkOptions(); return NetworkConfiguratorStates::UPDATING_CONFIG; } return NetworkConfiguratorStates::CONFIGURED; } NetworkConfiguratorStates NetworkConfiguratorClass::handleUpdatingConfig() { if (_agentsManager->isConfigInProgress() == false) { //If peer disconnects without updating the network settings, go to connecting state for check the connection sendStatus(StatusMessage::CONNECTING); return NetworkConfiguratorStates::CONNECTING; } return handleWaitingForConf(); } NetworkConfiguratorStates NetworkConfiguratorClass::handleErrorState() { _agentsManager->update(); return NetworkConfiguratorStates::ERROR; } bool NetworkConfiguratorClass::sendStatus(StatusMessage msg) { ProvisioningOutputMessage statusMsg = { MessageOutputType::STATUS, { msg } }; return _agentsManager->sendMsg(statusMsg); } #if defined(BOARD_HAS_ETHERNET) void PrintIP(models::ip_addr *ip) { int len = 0; if (ip->type == IPType::IPv4) { len = 4; } else { len = 16; } Debug.newlineOff(); for (int i = 0; i < len; i++) { DEBUG_INFO("%d ", ip->bytes[i]); } DEBUG_INFO("\n"); Debug.newlineOn(); } #endif void NetworkConfiguratorClass::printNetworkSettings() { DEBUG_INFO("Network settings received:"); switch (_networkSetting.type) { #if defined(BOARD_HAS_WIFI) case NetworkAdapter::WIFI: DEBUG_INFO("WIFI"); DEBUG_INFO("SSID: %s", _networkSetting.wifi.ssid); #if DEBUG_NETWORK_CREDENTIALS DEBUG_INFO("PSW: %s", _networkSetting.wifi.pwd); #endif break; #endif #if defined(BOARD_HAS_ETHERNET) case NetworkAdapter::ETHERNET: DEBUG_INFO("ETHERNET"); DEBUG_INFO("IP: "); PrintIP(&_networkSetting.eth.ip); DEBUG_INFO(" DNS: "); PrintIP(&_networkSetting.eth.dns); DEBUG_INFO(" Gateway: "); PrintIP(&_networkSetting.eth.gateway); DEBUG_INFO(" Netmask: "); PrintIP(&_networkSetting.eth.netmask); DEBUG_INFO(" Timeout: %d , Response timeout: %d", _networkSetting.eth.timeout, _networkSetting.eth.response_timeout); break; #endif #if defined(BOARD_HAS_NB) case NetworkAdapter::NB: DEBUG_INFO("NB-IoT"); DEBUG_INFO("APN: %s", _networkSetting.nb.apn); DEBUG_INFO("Login: %s", _networkSetting.nb.login); #if DEBUG_NETWORK_CREDENTIALS DEBUG_INFO("PIN: %s", _networkSetting.nb.pin); DEBUG_INFO("Pass: %s", _networkSetting.nb.pass); #endif break; #endif #if defined(BOARD_HAS_GSM) case NetworkAdapter::GSM: DEBUG_INFO("GSM"); DEBUG_INFO("APN: %s", _networkSetting.gsm.apn); DEBUG_INFO("Login: %s", _networkSetting.gsm.login); #if DEBUG_NETWORK_CREDENTIALS DEBUG_INFO("PIN: %s", _networkSetting.gsm.pin); DEBUG_INFO("Pass: %s", _networkSetting.gsm.pass); #endif break; #endif #if defined(BOARD_HAS_CATM1_NBIOT) case NetworkAdapter::CATM1: DEBUG_INFO("CATM1"); DEBUG_INFO("APN: %s", _networkSetting.catm1.apn); DEBUG_INFO("Login: %s", _networkSetting.catm1.login); #if DEBUG_NETWORK_CREDENTIALS DEBUG_INFO("PIN: %s", _networkSetting.catm1.pin); DEBUG_INFO("Pass: %s", _networkSetting.catm1.pass); #endif DEBUG_INFO("Band: %d", _networkSetting.catm1.band); break; #endif #if defined(BOARD_HAS_CELLULAR) case NetworkAdapter::CELL: DEBUG_INFO("CELLULAR"); DEBUG_INFO("APN: %s", _networkSetting.cell.apn); DEBUG_INFO("Login: %s", _networkSetting.cell.login); #if DEBUG_NETWORK_CREDENTIALS DEBUG_INFO("PIN: %s", _networkSetting.cell.pin); DEBUG_INFO("Pass: %s", _networkSetting.cell.pass); #endif break; #endif #if defined(BOARD_HAS_LORA) case NetworkAdapter::LORA: DEBUG_INFO("LORA"); DEBUG_INFO("AppEUI: %s", _networkSetting.lora.appeui); #if DEBUG_NETWORK_CREDENTIALS DEBUG_INFO("AppKey: %s", _networkSetting.lora.appkey); #endif DEBUG_INFO("Band: %d", _networkSetting.lora.band); DEBUG_INFO("Channel mask: %s", _networkSetting.lora.channelMask); DEBUG_INFO("Device class: %c", _networkSetting.lora.deviceClass); #endif default: break; } } #ifdef BOARD_HAS_ETHERNET void NetworkConfiguratorClass::defaultEthernetSettings() { _networkSetting.type = NetworkAdapter::ETHERNET; _networkSetting.eth.timeout = 250; _networkSetting.eth.response_timeout = 500; } #endif #endif // NETWORK_CONFIGURATOR_COMPATIBLE