From 5db15c08504b9a229bb47bc5cba034616af9f745 Mon Sep 17 00:00:00 2001 From: Andrea Gilardoni Date: Tue, 3 Jun 2025 14:22:53 +0200 Subject: [PATCH 01/20] Addressing Issue #552 While using platformio build system some new structures are not included in the final binary, for this reason it is required for concrete encoder and decoder for cbor commands to be referenced in files that are referenced by the sketch entrypoint --- src/ArduinoIoTCloudTCP.cpp | 3 ++- src/cbor/IoTCloudMessageDecoder.cpp | 10 ++++++++++ src/cbor/IoTCloudMessageDecoder.h | 8 ++++++++ src/cbor/IoTCloudMessageEncoder.cpp | 11 +++++++++++ src/cbor/IoTCloudMessageEncoder.h | 7 +++++++ 5 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 9de9d301a..31e972882 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -72,7 +72,8 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP() , _get_ota_confirmation{nullptr} #endif /* OTA_ENABLED */ { - + cbor::encoder::iotcloud::commandEncoders(); + cbor::decoder::iotcloud::commandDecoders(); } /****************************************************************************** diff --git a/src/cbor/IoTCloudMessageDecoder.cpp b/src/cbor/IoTCloudMessageDecoder.cpp index 8a17ba1f3..8deb9e3e5 100644 --- a/src/cbor/IoTCloudMessageDecoder.cpp +++ b/src/cbor/IoTCloudMessageDecoder.cpp @@ -176,3 +176,13 @@ static ThingUpdateCommandDecoder thingUpdateCommandDecoder; static ThingDetachCommandDecoder thingDetachCommandDecoder; static LastValuesUpdateCommandDecoder lastValuesUpdateCommandDecoder; static TimezoneCommandDownDecoder timezoneCommandDownDecoder; + +namespace cbor { namespace decoder { namespace iotcloud { + void commandDecoders() { + (void) otaUpdateCommandDecoder; + (void) thingUpdateCommandDecoder; + (void) thingDetachCommandDecoder; + (void) lastValuesUpdateCommandDecoder; + (void) timezoneCommandDownDecoder; + } +}}} diff --git a/src/cbor/IoTCloudMessageDecoder.h b/src/cbor/IoTCloudMessageDecoder.h index 4b444f5c8..f072a2c3a 100644 --- a/src/cbor/IoTCloudMessageDecoder.h +++ b/src/cbor/IoTCloudMessageDecoder.h @@ -63,4 +63,12 @@ class TimezoneCommandDownDecoder: public CBORMessageDecoderInterface { MessageDecoder::Status decode(CborValue* iter, Message *msg) override; }; +namespace cbor { namespace decoder { namespace iotcloud { + /** + * Some link time optimization may exclude these classes to be instantiated + * thus it may be required to reference them from outside of this file + */ + void commandDecoders(); +}}} + #endif /* ARDUINO_CBOR_MESSAGE_DECODER_H_ */ diff --git a/src/cbor/IoTCloudMessageEncoder.cpp b/src/cbor/IoTCloudMessageEncoder.cpp index ed4c6d823..71363cf5e 100644 --- a/src/cbor/IoTCloudMessageEncoder.cpp +++ b/src/cbor/IoTCloudMessageEncoder.cpp @@ -159,3 +159,14 @@ static LastValuesBeginCommandEncoder lastValuesBeginCommandEncoder; static DeviceBeginCommandEncoder deviceBeginCommandEncoder; static OtaProgressCommandUpEncoder otaProgressCommandUpEncoder; static TimezoneCommandUpEncoder timezoneCommandUpEncoder; + +namespace cbor { namespace encoder { namespace iotcloud { + void commandEncoders() { + (void) otaBeginCommandEncoder; + (void) thingBeginCommandEncoder; + (void) lastValuesBeginCommandEncoder; + (void) deviceBeginCommandEncoder; + (void) otaProgressCommandUpEncoder; + (void) timezoneCommandUpEncoder; + } +}}} diff --git a/src/cbor/IoTCloudMessageEncoder.h b/src/cbor/IoTCloudMessageEncoder.h index 99922bc59..9b5ca441d 100644 --- a/src/cbor/IoTCloudMessageEncoder.h +++ b/src/cbor/IoTCloudMessageEncoder.h @@ -71,5 +71,12 @@ class TimezoneCommandUpEncoder: public CBORMessageEncoderInterface { MessageEncoder::Status encode(CborEncoder* encoder, Message *msg) override; }; +namespace cbor { namespace encoder { namespace iotcloud { + /** + * Some link time optimization may exclude these classes to be instantiated + * thus it may be required to reference them from outside of this file + */ + void commandEncoders(); +}}} #endif /* ARDUINO_CBOR_MESSAGE_ENCODER_H_ */ From 824f9c4f8f5e15458ef0397f8c08bc6a8b2b2708 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 6 Jun 2025 10:07:46 +0200 Subject: [PATCH 02/20] Device: fix missing initializer warnign --- src/ArduinoIoTCloudDevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ArduinoIoTCloudDevice.cpp b/src/ArduinoIoTCloudDevice.cpp index 58f00d202..17ce9626b 100644 --- a/src/ArduinoIoTCloudDevice.cpp +++ b/src/ArduinoIoTCloudDevice.cpp @@ -110,7 +110,7 @@ ArduinoCloudDevice::State ArduinoCloudDevice::handleSendCapabilities() { deliver(reinterpret_cast(&deviceBegin)); /* Subscribe to device topic to request */ - ThingBeginCmd thingBegin = { ThingBeginCmdId }; + ThingBeginCmd thingBegin = { ThingBeginCmdId, {} }; deliver(reinterpret_cast(&thingBegin)); /* No device configuration received. Wait: 4s -> 8s -> 16s -> 32s -> 32s ...*/ From 08f8b58c463193bb3237f2b4e505f3fb3f99a611 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 6 Jun 2025 10:08:23 +0200 Subject: [PATCH 03/20] CloudTelevision: suppress aliasing warning --- src/property/types/automation/CloudTelevision.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/property/types/automation/CloudTelevision.h b/src/property/types/automation/CloudTelevision.h index 75967dd4f..f1d203d3b 100644 --- a/src/property/types/automation/CloudTelevision.h +++ b/src/property/types/automation/CloudTelevision.h @@ -226,8 +226,14 @@ class CloudTelevision : public Property { setAttribute(_cloud_value.swi, "swi"); setAttribute(_cloud_value.vol, "vol"); setAttribute(_cloud_value.mut, "mut"); +/* PlaybackCommands and InputValue are enum of type int so we can safely disable + * strict aliasing warnings here. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" setAttribute((int&)_cloud_value.pbc, "pbc"); setAttribute((int&)_cloud_value.inp, "inp"); +#pragma GCC diagnostic pop setAttribute(_cloud_value.cha, "cha"); } }; From 79eb0ca186c8b1148ef25b7cbf1ad432aa840c4d Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 6 Jun 2025 10:09:46 +0200 Subject: [PATCH 04/20] UNOR4 OTA: suppress unused variable warning --- src/ota/implementation/OTAUnoR4.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ota/implementation/OTAUnoR4.cpp b/src/ota/implementation/OTAUnoR4.cpp index 5ba12afa9..68a06d775 100644 --- a/src/ota/implementation/OTAUnoR4.cpp +++ b/src/ota/implementation/OTAUnoR4.cpp @@ -32,6 +32,7 @@ UNOR4OTACloudProcess::UNOR4OTACloudProcess(MessageStream *ms) } OTACloudProcessInterface::State UNOR4OTACloudProcess::resume(Message* msg) { + (void)msg; return OtaBegin; } From 59e326fece5fa34b6fa0012db2a2199449904e75 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 6 Jun 2025 10:10:35 +0200 Subject: [PATCH 05/20] UNOR4 OTA: remove unused variable --- src/ota/implementation/OTAUnoR4.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ota/implementation/OTAUnoR4.cpp b/src/ota/implementation/OTAUnoR4.cpp index 68a06d775..e630f9d13 100644 --- a/src/ota/implementation/OTAUnoR4.cpp +++ b/src/ota/implementation/OTAUnoR4.cpp @@ -58,8 +58,6 @@ OTACloudProcessInterface::State UNOR4OTACloudProcess::startOTA() { } OTACloudProcessInterface::State UNOR4OTACloudProcess::fetch() { - int ota_err = OTAUpdate::OTA_ERROR_NONE; - String fv = WiFi.firmwareVersion(); if(fv >= "0.5.0") { auto progress = ota.downloadProgress(); From 87766d8cdc531f834ea3793b436ce59919276f2e Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 6 Jun 2025 10:14:10 +0200 Subject: [PATCH 06/20] UNOR4 OTA: add missing return value --- src/ota/implementation/OTAUnoR4.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ota/implementation/OTAUnoR4.cpp b/src/ota/implementation/OTAUnoR4.cpp index e630f9d13..9569960fd 100644 --- a/src/ota/implementation/OTAUnoR4.cpp +++ b/src/ota/implementation/OTAUnoR4.cpp @@ -105,6 +105,8 @@ OTACloudProcessInterface::State UNOR4OTACloudProcess::flashOTA() { } OTACloudProcessInterface::State UNOR4OTACloudProcess::reboot() { + /* This is never called; the microcontroller reboots in flashOTA state */ + return Resume; } void UNOR4OTACloudProcess::reset() { From 7623846b43984f608305aa28516daf8e70c18446 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 6 Jun 2025 10:16:00 +0200 Subject: [PATCH 07/20] UNOR4 OTA: add missing return value --- src/ota/implementation/OTAUnoR4.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ota/implementation/OTAUnoR4.cpp b/src/ota/implementation/OTAUnoR4.cpp index 9569960fd..3fd014d9a 100644 --- a/src/ota/implementation/OTAUnoR4.cpp +++ b/src/ota/implementation/OTAUnoR4.cpp @@ -98,10 +98,13 @@ OTACloudProcessInterface::State UNOR4OTACloudProcess::flashOTA() { } /* Flash new firmware */ - if ((ota_err = ota.update(UPDATE_FILE_NAME)) != OTAUpdate::OTA_ERROR_NONE) { // This reboots the MCU + if ((ota_err = ota.update(UPDATE_FILE_NAME)) != OTAUpdate::OTA_ERROR_NONE) { DEBUG_VERBOSE("OTAUpdate::update() failed with %d", ota_err); return convertUnor4ErrorToState(ota_err); } + + /* This is never called because ota.uptade reboots the microcontroller */ + return Resume; } OTACloudProcessInterface::State UNOR4OTACloudProcess::reboot() { From 86bbcc114fde0aaa1405b8fac7eeaf89ec1d99d9 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 6 Jun 2025 10:20:44 +0200 Subject: [PATCH 08/20] OTAInterface: add missing initializers --- src/ota/interface/OTAInterface.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ota/interface/OTAInterface.cpp b/src/ota/interface/OTAInterface.cpp index e72d062d4..13644cabb 100644 --- a/src/ota/interface/OTAInterface.cpp +++ b/src/ota/interface/OTAInterface.cpp @@ -106,6 +106,7 @@ OTACloudProcessInterface::State OTACloudProcessInterface::otaBegin() { struct OtaBeginUp msg = { OtaBeginUpId, + {} }; SHA256 sha256_calc; @@ -199,6 +200,7 @@ void OTACloudProcessInterface::reportStatus(int32_t state_data) { struct OtaProgressCmdUp msg = { OtaProgressCmdUpId, + {} }; memcpy(msg.params.id, context->id, ID_SIZE); From aad8c4b1435e24f265c2e25f8d267faa07fc95ad Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 6 Jun 2025 10:21:26 +0200 Subject: [PATCH 09/20] OTAInterfaceDefault: remove unused static function declaration --- src/ota/interface/OTAInterfaceDefault.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ota/interface/OTAInterfaceDefault.cpp b/src/ota/interface/OTAInterfaceDefault.cpp index fbea43e68..97389d430 100644 --- a/src/ota/interface/OTAInterfaceDefault.cpp +++ b/src/ota/interface/OTAInterfaceDefault.cpp @@ -14,8 +14,6 @@ #include "OTAInterfaceDefault.h" #include "../OTA.h" -static uint32_t crc_update(uint32_t crc, const void * data, size_t data_len); - OTADefaultCloudProcessInterface::OTADefaultCloudProcessInterface(MessageStream *ms, Client* client) : OTACloudProcessInterface(ms) , client(client) From fd2e4eee8bb71fce741b97b2cf53e197e9da6761 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 6 Jun 2025 10:35:16 +0200 Subject: [PATCH 10/20] UNOR4 OTA: fix signed comparison warning --- src/ota/implementation/OTAUnoR4.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ota/implementation/OTAUnoR4.cpp b/src/ota/implementation/OTAUnoR4.cpp index 3fd014d9a..afe37b4a7 100644 --- a/src/ota/implementation/OTAUnoR4.cpp +++ b/src/ota/implementation/OTAUnoR4.cpp @@ -59,19 +59,24 @@ OTACloudProcessInterface::State UNOR4OTACloudProcess::startOTA() { OTACloudProcessInterface::State UNOR4OTACloudProcess::fetch() { String fv = WiFi.firmwareVersion(); - if(fv >= "0.5.0") { + /* Firmware supports non blocking OTA */ + if (fv >= "0.5.0") { auto progress = ota.downloadProgress(); + if (progress < 0) { + return OtaDownloadFail; + } - if((millis() - context->lastReportTime) > 5000) { // Report the download progress each X millisecond + if ((millis() - context->lastReportTime) > 5000) { // Report the download progress each X millisecond DEBUG_VERBOSE("OTA Download Progress %d/%d", progress, context->downloadSize); reportStatus(progress); context->lastReportTime = millis(); } - if(progress < context->downloadSize) { + /* It is safe to cast progress here because we are sure that is positive */ + if ((size_t)progress < context->downloadSize) { return Fetch; - } else if(progress > context->downloadSize || progress < 0) { + } else if ((size_t)progress > context->downloadSize) { return OtaDownloadFail; } else { return FlashOTA; @@ -84,7 +89,6 @@ OTACloudProcessInterface::State UNOR4OTACloudProcess::fetch() { } DEBUG_VERBOSE("OTAUpdate::download() %d bytes downloaded", ota_download); - return FlashOTA; } } From 654b7052476263c8a944cebad7a253c0ef38cee5 Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 9 Jun 2025 11:02:25 +0200 Subject: [PATCH 11/20] TimeService: RTC automatically fallback on software implementation --- src/AIoTC_Config.h | 6 + src/utility/time/RTCMillis.cpp | 4 +- src/utility/time/RTCMillis.h | 4 +- src/utility/time/TimeService.cpp | 308 ++++++++----------------------- 4 files changed, 91 insertions(+), 231 deletions(-) diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index a25b81080..9127676c3 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -142,6 +142,12 @@ #define BOARD_HAS_SECURE_ELEMENT #endif +#if (defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_MBED) ||\ + defined(ARDUINO_ARCH_RENESAS) || defined(ARDUINO_ARCH_ESP32)) &&\ + !defined(ARDUINO_ARCH_ZEPHYR) + #define BOARD_HAS_HW_RTC +#endif + #endif // HAS_NOTECARD #if defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_NICLA_VISION) || defined(ARDUINO_OPTA) || defined(ARDUINO_GIGA) diff --git a/src/utility/time/RTCMillis.cpp b/src/utility/time/RTCMillis.cpp index 7ceb27436..0dc970e8d 100644 --- a/src/utility/time/RTCMillis.cpp +++ b/src/utility/time/RTCMillis.cpp @@ -21,7 +21,7 @@ #include "AIoTC_Config.h" -#if defined(HAS_NOTECARD) || defined(ARDUINO_ARCH_ESP8266) || defined (ARDUINO_RASPBERRY_PI_PICO_W) +#if !defined(BOARD_HAS_HW_RTC) #include #include "RTCMillis.h" @@ -61,4 +61,4 @@ unsigned long RTCMillis::get() return _last_rtc_update_value; } -#endif /* HAS_NOTECARD || ARDUINO_ARCH_ESP8266 || ARDUINO_RASPBERRY_PI_PICO_W */ +#endif /* BOARD_HAS_HW_RTC */ diff --git a/src/utility/time/RTCMillis.h b/src/utility/time/RTCMillis.h index 03d352941..543988071 100644 --- a/src/utility/time/RTCMillis.h +++ b/src/utility/time/RTCMillis.h @@ -18,7 +18,7 @@ #ifndef ARDUINO_IOT_CLOUD_RTC_MILLIS_H_ #define ARDUINO_IOT_CLOUD_RTC_MILLIS_H_ -#if defined(HAS_NOTECARD) || defined(ARDUINO_ARCH_ESP8266) || defined (ARDUINO_RASPBERRY_PI_PICO_W) +#if !defined(BOARD_HAS_HW_RTC) /************************************************************************************** * INCLUDE @@ -45,6 +45,6 @@ class RTCMillis }; -#endif /* HAS_NOTECARD || ARDUINO_ARCH_ESP8266 || ARDUINO_RASPBERRY_PI_PICO_W */ +#endif /* BOARD_HAS_HW_RTC */ #endif /* ARDUINO_IOT_CLOUD_RTC_MILLIS_H_ */ diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index fb7272fc4..577d4b86a 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -19,7 +19,6 @@ * INCLUDE **************************************************************************************/ - #include #include "AIoTC_Config.h" @@ -27,23 +26,29 @@ #include "NTPUtils.h" #include "TimeService.h" -#if defined(HAS_NOTECARD) || defined(ARDUINO_ARCH_ESP8266) || defined (ARDUINO_RASPBERRY_PI_PICO_W) +#if defined(BOARD_HAS_HW_RTC) + #if defined(ARDUINO_ARCH_SAMD) + #include + #endif + #if defined(ARDUINO_ARCH_MBED) + #include + #endif + #if defined(ARDUINO_ARCH_RENESAS) + #include + #endif +#else #include "RTCMillis.h" -#elif defined(ARDUINO_ARCH_SAMD) - #include -#elif defined(ARDUINO_ARCH_MBED) - #include -#elif defined(ARDUINO_ARCH_RENESAS) - #include "RTC.h" #endif /************************************************************************************** * GLOBAL VARIABLES **************************************************************************************/ -#if defined(HAS_NOTECARD) || defined(ARDUINO_ARCH_ESP8266) || defined (ARDUINO_RASPBERRY_PI_PICO_W) +#if !defined(BOARD_HAS_HW_RTC) RTCMillis rtc; -#elif defined(ARDUINO_ARCH_SAMD) +#endif + +#if defined(BOARD_HAS_HW_RTC) && defined(ARDUINO_ARCH_SAMD) RTCZero rtc; #endif @@ -53,50 +58,72 @@ RTCZero rtc; time_t cvt_time(char const * time); -#if defined(HAS_NOTECARD) -void notecard_initRTC(); -void notecard_setRTC(unsigned long time); -unsigned long notecard_getRTC(); -#else - -#ifdef ARDUINO_ARCH_SAMD -void samd_initRTC(); -void samd_setRTC(unsigned long time); -unsigned long samd_getRTC(); -#endif - -#ifdef ARDUINO_ARCH_MBED -void mbed_initRTC(); -void mbed_setRTC(unsigned long time); -unsigned long mbed_getRTC(); -#endif - -#ifdef ARDUINO_ARCH_ESP32 -void esp32_initRTC(); -void esp32_setRTC(unsigned long time); -unsigned long esp32_getRTC(); -#endif - -#ifdef ARDUINO_ARCH_ESP8266 -void esp8266_initRTC(); -void esp8266_setRTC(unsigned long time); -unsigned long esp8266_getRTC(); -#endif - -#ifdef ARDUINO_ARCH_RENESAS -void renesas_initRTC(); -void renesas_setRTC(unsigned long time); -unsigned long renesas_getRTC(); -#endif +/************************************************************************************** + * RTC PRIVATE FUNCTION DEFINITION + **************************************************************************************/ -#ifdef ARDUINO_RASPBERRY_PI_PICO_W -void pico_w_initRTC(); -void pico_w_setRTC(unsigned long time); -unsigned long pico_w_getRTC(); +#if defined(BOARD_HAS_HW_RTC) + #if defined(ARDUINO_ARCH_SAMD) +static inline void _initRTC() { + rtc.begin(); +} +static inline void _setRTC(unsigned long time) { + rtc.setEpoch(time); +} +static inline unsigned long _getRTC() { + return rtc.getEpoch(); +} + #endif + #if defined(ARDUINO_ARCH_MBED) +static inline void _initRTC() { + /* Nothing to do */ +} +static inline void _setRTC(unsigned long time) { + set_time(time); +} +static inline unsigned long _getRTC() { + return time(NULL); +} + #endif + #if defined(ARDUINO_ARCH_RENESAS) +static inline void _initRTC() { + RTC.begin(); +} +static inline void _setRTC(unsigned long time) { + RTCTime t(time); + RTC.setTime(t); +} +static inline unsigned long _getRTC() { + RTCTime t; + RTC.getTime(t); + return t.getUnixTime(); +} + #endif + #if defined(ARDUINO_ARCH_ESP32) +static inline void _initRTC() { + //configTime(0, 0, "time.arduino.cc", "pool.ntp.org", "time.nist.gov"); +} +static inline void _setRTC(unsigned long time) { + const timeval epoch = {(time_t)time, 0}; + settimeofday(&epoch, 0); +} +static inline unsigned long _getRTC() { + return time(NULL); +} + #endif +#else /* !BOARD_HAS_HW_RTC */ + #pragma message "No hardware RTC implementation found, using soft RTC" +static inline void _initRTC() { + rtc.begin(); +} +static inline void _setRTC(unsigned long time) { + rtc.set(time); +} +static inline unsigned long _getRTC() { + return rtc.get(); +} #endif -#endif /* HAS_NOTECARD */ - /************************************************************************************** * DEFINES **************************************************************************************/ @@ -349,65 +376,17 @@ bool TimeServiceClass::isTimeZoneOffsetValid(long const offset) void TimeServiceClass::initRTC() { -#if defined (HAS_NOTECARD) - notecard_initRTC(); -#elif defined (ARDUINO_ARCH_SAMD) - samd_initRTC(); -#elif defined (ARDUINO_ARCH_MBED) - mbed_initRTC(); -#elif defined (ARDUINO_ARCH_ESP32) - esp32_initRTC(); -#elif defined (ARDUINO_ARCH_ESP8266) - esp8266_initRTC(); -#elif defined (ARDUINO_ARCH_RENESAS) - renesas_initRTC(); -#elif defined (ARDUINO_RASPBERRY_PI_PICO_W) - pico_w_initRTC(); -#else - #error "RTC not available for this architecture" -#endif + _initRTC(); } void TimeServiceClass::setRTC(unsigned long time) { -#if defined (HAS_NOTECARD) - notecard_setRTC(time); -#elif defined (ARDUINO_ARCH_SAMD) - samd_setRTC(time); -#elif defined (ARDUINO_ARCH_MBED) - mbed_setRTC(time); -#elif defined (ARDUINO_ARCH_ESP32) - esp32_setRTC(time); -#elif defined (ARDUINO_ARCH_ESP8266) - esp8266_setRTC(time); -#elif defined (ARDUINO_ARCH_RENESAS) - renesas_setRTC(time); -#elif defined (ARDUINO_RASPBERRY_PI_PICO_W) - pico_w_setRTC(time); -#else - #error "RTC not available for this architecture" -#endif + _setRTC(time); } unsigned long TimeServiceClass::getRTC() { -#if defined (HAS_NOTECARD) - return notecard_getRTC(); -#elif defined (ARDUINO_ARCH_SAMD) - return samd_getRTC(); -#elif defined (ARDUINO_ARCH_MBED) - return mbed_getRTC(); -#elif defined (ARDUINO_ARCH_ESP32) - return esp32_getRTC(); -#elif defined (ARDUINO_ARCH_ESP8266) - return esp8266_getRTC(); -#elif defined (ARDUINO_ARCH_RENESAS) - return renesas_getRTC(); -#elif defined (ARDUINO_RASPBERRY_PI_PICO_W) - return pico_w_getRTC(); -#else - #error "RTC not available for this architecture" -#endif + return _getRTC(); } /************************************************************************************** @@ -450,131 +429,6 @@ time_t cvt_time(char const * time) return build_time; } -#ifdef HAS_NOTECARD -void notecard_initRTC() -{ - rtc.begin(); -} - -void notecard_setRTC(unsigned long time) -{ - rtc.set(time); -} - -unsigned long notecard_getRTC() -{ - return rtc.get(); -} -#else - -#ifdef ARDUINO_ARCH_SAMD -void samd_initRTC() -{ - rtc.begin(); -} - -void samd_setRTC(unsigned long time) -{ - rtc.setEpoch(time); -} - -unsigned long samd_getRTC() -{ - return rtc.getEpoch(); -} -#endif - -#ifdef ARDUINO_ARCH_MBED -void mbed_initRTC() -{ - /* Nothing to do */ -} - -void mbed_setRTC(unsigned long time) -{ - set_time(time); -} - -unsigned long mbed_getRTC() -{ - return time(NULL); -} -#endif - -#ifdef ARDUINO_ARCH_ESP32 -void esp32_initRTC() -{ - //configTime(0, 0, "time.arduino.cc", "pool.ntp.org", "time.nist.gov"); -} - -void esp32_setRTC(unsigned long time) -{ - const timeval epoch = {(time_t)time, 0}; - settimeofday(&epoch, 0); -} - -unsigned long esp32_getRTC() -{ - return time(NULL); -} -#endif - -#ifdef ARDUINO_ARCH_ESP8266 -void esp8266_initRTC() -{ - rtc.begin(); -} - -void esp8266_setRTC(unsigned long time) -{ - rtc.set(time); -} - -unsigned long esp8266_getRTC() -{ - return rtc.get(); -} -#endif - -#ifdef ARDUINO_ARCH_RENESAS -void renesas_initRTC() -{ - RTC.begin(); -} - -void renesas_setRTC(unsigned long time) -{ - RTCTime t(time); - RTC.setTime(t); -} - -unsigned long renesas_getRTC() -{ - RTCTime t; - RTC.getTime(t); - return t.getUnixTime(); -} -#endif - -#ifdef ARDUINO_RASPBERRY_PI_PICO_W -void pico_w_initRTC() -{ - rtc.begin(); -} - -void pico_w_setRTC(unsigned long time) -{ - rtc.set(time); -} - -unsigned long pico_w_getRTC() -{ - return rtc.get(); -} -#endif - -#endif /* HAS_NOTECARD */ - /****************************************************************************** * EXTERN DEFINITION ******************************************************************************/ From 79a2e5a5803867afcb0467ef045030ce1493fe9b Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 9 Jun 2025 14:40:49 +0200 Subject: [PATCH 12/20] TimeService: re-licensing --- src/utility/time/TimeService.cpp | 17 +++++------------ src/utility/time/TimeService.h | 17 +++++------------ 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index 577d4b86a..fa822d068 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -1,18 +1,11 @@ /* - This file is part of ArduinoIoTCloud. + This file is part of the ArduinoIoTCloud library. - Copyright 2020 ARDUINO SA (http://www.arduino.cc/) + Copyright (c) 2020 Arduino SA - This software is released under the GNU General Public License version 3, - which covers the main part of arduino-cli. - The terms of this license can be found at: - https://www.gnu.org/licenses/gpl-3.0.en.html - - You can be released from the requirements of the above licenses by purchasing - a commercial license. Buying such a license is mandatory if you want to modify or - otherwise use the software for commercial activities involving the Arduino - software without disclosing the source code of your own applications. To purchase - a commercial license, send an email to license@arduino.cc. + 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/. */ /************************************************************************************** diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index 71656d948..1f58bd781 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -1,18 +1,11 @@ /* - This file is part of ArduinoIoTCloud. + This file is part of the ArduinoIoTCloud library. - Copyright 2020 ARDUINO SA (http://www.arduino.cc/) + Copyright (c) 2020 Arduino SA - This software is released under the GNU General Public License version 3, - which covers the main part of arduino-cli. - The terms of this license can be found at: - https://www.gnu.org/licenses/gpl-3.0.en.html - - You can be released from the requirements of the above licenses by purchasing - a commercial license. Buying such a license is mandatory if you want to modify or - otherwise use the software for commercial activities involving the Arduino - software without disclosing the source code of your own applications. To purchase - a commercial license, send an email to license@arduino.cc. + 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_IOT_CLOUD_TIME_SERVICE_H_ From 239cd744bbd555037ad4036924b78da6fd164790 Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 9 Jun 2025 14:51:24 +0200 Subject: [PATCH 13/20] TimeService: cosmetic changes --- src/utility/time/TimeService.cpp | 40 ++++++++++++++++---------------- src/utility/time/TimeService.h | 8 +++---- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index fa822d068..9d88551df 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -8,9 +8,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -/************************************************************************************** +/****************************************************************************** * INCLUDE - **************************************************************************************/ + ******************************************************************************/ #include @@ -33,9 +33,9 @@ #include "RTCMillis.h" #endif -/************************************************************************************** +/****************************************************************************** * GLOBAL VARIABLES - **************************************************************************************/ + ******************************************************************************/ #if !defined(BOARD_HAS_HW_RTC) RTCMillis rtc; @@ -45,15 +45,15 @@ RTCMillis rtc; RTCZero rtc; #endif -/************************************************************************************** +/****************************************************************************** * INTERNAL FUNCTION DECLARATION - **************************************************************************************/ + ******************************************************************************/ time_t cvt_time(char const * time); -/************************************************************************************** +/****************************************************************************** * RTC PRIVATE FUNCTION DEFINITION - **************************************************************************************/ + ******************************************************************************/ #if defined(BOARD_HAS_HW_RTC) #if defined(ARDUINO_ARCH_SAMD) @@ -117,23 +117,23 @@ static inline unsigned long _getRTC() { } #endif -/************************************************************************************** +/****************************************************************************** * DEFINES - **************************************************************************************/ + ******************************************************************************/ #define EPOCH_AT_COMPILE_TIME cvt_time(__DATE__) -/************************************************************************************** +/****************************************************************************** * CONSTANTS - **************************************************************************************/ + ******************************************************************************/ /* Default NTP synch is scheduled each 24 hours from startup */ static time_t const TIMESERVICE_NTP_SYNC_TIMEOUT_ms = DAYS * 1000; static time_t const EPOCH = 0; -/************************************************************************************** +/****************************************************************************** * CTOR/DTOR - **************************************************************************************/ + ******************************************************************************/ TimeServiceClass::TimeServiceClass() : _con_hdl(nullptr) @@ -148,9 +148,9 @@ TimeServiceClass::TimeServiceClass() } -/************************************************************************************** +/****************************************************************************** * PUBLIC MEMBER FUNCTIONS - **************************************************************************************/ + ******************************************************************************/ void TimeServiceClass::begin(ConnectionHandler * con_hdl) { @@ -306,9 +306,9 @@ unsigned long TimeServiceClass::getTimeFromString(const String& input) return mktime(&t); } -/************************************************************************************** +/****************************************************************************** * PRIVATE MEMBER FUNCTIONS - **************************************************************************************/ + ******************************************************************************/ #if defined(HAS_NOTECARD) || defined(HAS_TCP) bool TimeServiceClass::connected() @@ -382,9 +382,9 @@ unsigned long TimeServiceClass::getRTC() return _getRTC(); } -/************************************************************************************** +/****************************************************************************** * INTERNAL FUNCTION DEFINITION - **************************************************************************************/ + ******************************************************************************/ time_t cvt_time(char const * time) { diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index 1f58bd781..d4a455cef 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -11,9 +11,9 @@ #ifndef ARDUINO_IOT_CLOUD_TIME_SERVICE_H_ #define ARDUINO_IOT_CLOUD_TIME_SERVICE_H_ -/************************************************************************************** +/****************************************************************************** * INCLUDE - **************************************************************************************/ + ******************************************************************************/ #include #include @@ -24,9 +24,9 @@ typedef unsigned long(*syncTimeFunctionPtr)(void); -/************************************************************************************** +/****************************************************************************** * CLASS DECLARATION - **************************************************************************************/ + ******************************************************************************/ class TimeServiceClass { From 5b167154e787d265617a3e4819b6c67539c6c6c9 Mon Sep 17 00:00:00 2001 From: Mattia Pennasilico Date: Tue, 10 Jun 2025 10:59:55 +0200 Subject: [PATCH 14/20] Fix SPDX typo in file header --- src/ArduinoIoTCloudDevice.h | 2 +- src/ArduinoIoTCloudThing.cpp | 2 +- src/ArduinoIoTCloudThing.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ArduinoIoTCloudDevice.h b/src/ArduinoIoTCloudDevice.h index 5bfe052fa..0fda9be53 100644 --- a/src/ArduinoIoTCloudDevice.h +++ b/src/ArduinoIoTCloudDevice.h @@ -1,5 +1,5 @@ /* - This file is part of the Arduino_SecureElement library. + This file is part of the ArduinoIoTCloud library. Copyright (c) 2024 Arduino SA diff --git a/src/ArduinoIoTCloudThing.cpp b/src/ArduinoIoTCloudThing.cpp index a6bb74190..20ddc382d 100644 --- a/src/ArduinoIoTCloudThing.cpp +++ b/src/ArduinoIoTCloudThing.cpp @@ -1,5 +1,5 @@ /* - This file is part of the Arduino_SecureElement library. + This file is part of the ArduinoIoTCloud library. Copyright (c) 2024 Arduino SA diff --git a/src/ArduinoIoTCloudThing.h b/src/ArduinoIoTCloudThing.h index d6a9b8dac..3e379be61 100644 --- a/src/ArduinoIoTCloudThing.h +++ b/src/ArduinoIoTCloudThing.h @@ -1,5 +1,5 @@ /* - This file is part of the Arduino_SecureElement library. + This file is part of the ArduinoIoTCloud library. Copyright (c) 2024 Arduino SA From 2cd7da745342e59aff8cd8d9fcbcda9f7272f57d Mon Sep 17 00:00:00 2001 From: fabik111 Date: Tue, 27 May 2025 18:12:42 +0200 Subject: [PATCH 15/20] add cbor encoding for sending network configuration in cloud --- extras/test/CMakeLists.txt | 24 +- extras/test/include/Arduino.h | 1 + extras/test/include/IPAddress.h | 13 + extras/test/src/test_command_encode.cpp | 331 ++++++++++++++++++++++++ src/cbor/CBOR.h | 23 +- src/cbor/IoTCloudMessageEncoder.cpp | 189 ++++++++++++++ src/cbor/IoTCloudMessageEncoder.h | 33 +++ src/message/Commands.h | 7 + 8 files changed, 609 insertions(+), 12 deletions(-) create mode 100644 extras/test/include/IPAddress.h diff --git a/extras/test/CMakeLists.txt b/extras/test/CMakeLists.txt index dfe322324..f9c13c8c0 100644 --- a/extras/test/CMakeLists.txt +++ b/extras/test/CMakeLists.txt @@ -20,9 +20,17 @@ FetchContent_Declare( GIT_TAG main ) +FetchContent_Declare( + connectionhandler + GIT_REPOSITORY https://github.com/arduino-libraries/Arduino_ConnectionHandler.git + GIT_TAG master +) + FetchContent_MakeAvailable(Catch2) FetchContent_MakeAvailable(cloudutils) + +FetchContent_MakeAvailable(connectionhandler) ########################################################################## include_directories(include) @@ -55,6 +63,18 @@ target_include_directories( ${cloudutils_SOURCE_DIR}/src/interfaces ) +add_library(connectionhandler INTERFACE) + +target_include_directories( + connectionhandler INTERFACE + ${connectionhandler_SOURCE_DIR}/src/ +) + +target_include_directories( + connectionhandler INTERFACE + ${connectionhandler_SOURCE_DIR}/src/connectionHandlerModels +) + ########################################################################## set(CMAKE_CXX_STANDARD 11) @@ -126,12 +146,13 @@ set(TEST_TARGET_SRCS ########################################################################## +add_compile_definitions(BOARD_HAS_LORA BOARD_HAS_CATM1_NBIOT BOARD_HAS_WIFI BOARD_HAS_ETHERNET BOARD_HAS_CELLULAR BOARD_HAS_NB BOARD_HAS_GSM) add_compile_definitions(HOST HAS_TCP) add_compile_options(-Wall -Wextra -Wpedantic -Werror) add_compile_options(-Wno-cast-function-type) set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "--coverage") -set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "--coverage -Wno-deprecated-copy") +set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "--coverage -Wno-deprecated-copy -Wno-missing-field-initializers") ########################################################################## @@ -140,6 +161,7 @@ add_executable( ${TEST_TARGET_SRCS} ) +target_link_libraries( ${TEST_TARGET} connectionhandler) target_link_libraries( ${TEST_TARGET} cloudutils) target_link_libraries( ${TEST_TARGET} Catch2WithMain ) diff --git a/extras/test/include/Arduino.h b/extras/test/include/Arduino.h index 9e743f96f..dbdcc7380 100644 --- a/extras/test/include/Arduino.h +++ b/extras/test/include/Arduino.h @@ -10,6 +10,7 @@ ******************************************************************************/ #include +#include /****************************************************************************** DEFINES diff --git a/extras/test/include/IPAddress.h b/extras/test/include/IPAddress.h new file mode 100644 index 000000000..241796caa --- /dev/null +++ b/extras/test/include/IPAddress.h @@ -0,0 +1,13 @@ +/* + Copyright (c) 2019 Arduino. All rights reserved. +*/ + +#ifndef TEST_IPADDRESS_H_ +#define TEST_IPADDRESS_H_ + +enum IPType { + IPv4, + IPv6 +}; + +#endif diff --git a/extras/test/src/test_command_encode.cpp b/extras/test/src/test_command_encode.cpp index 3b7ae4425..af9975532 100644 --- a/extras/test/src/test_command_encode.cpp +++ b/extras/test/src/test_command_encode.cpp @@ -14,6 +14,9 @@ #include #include #include +#include +//#include + /****************************************************************************** TEST CODE @@ -648,4 +651,332 @@ SCENARIO("Test the encoding of command messages") { REQUIRE(err == MessageEncoder::Status::Error); } } + + WHEN("Encode the DeviceNetConfigCmdUp message with WiFi") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::WIFI; + String ssid = "SSID"; + strcpy(command.params.wifi.ssid, ssid.c_str()); + uint8_t buffer[512]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + uint8_t expected_result[] = { + 0xda, 0x00, 0x01, 0x11, 0x00, 0x82, 0x01, 0x64, 0x53, 0x53, 0x49, 0x44 + }; + + // Test the encoding is + // DA 00011100 # tag(73728) + // 82 # array(2) + // 01 # unsigned(1) + // 64 # text(4) + // 53534944 # "SSID" + THEN("The encoding is successful") { + REQUIRE(err == MessageEncoder::Status::Complete); + REQUIRE(bytes_encoded == sizeof(expected_result)); + REQUIRE(memcmp(buffer, expected_result, sizeof(expected_result)) == 0); + } + } + + WHEN("Encode the DeviceNetConfigCmdUp message with LoraWan") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::LORA; + + String app_eui = "APPEUI"; + strcpy(command.params.lora.appeui, app_eui.c_str()); + String app_key = "APPKEY"; + strcpy(command.params.lora.appkey, app_key.c_str()); + uint8_t buffer[512]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + uint8_t expected_result[] = { + 0xda, 0x00, 0x01, 0x11, 0x00, 0x82, + 0x02, 0x66, 0x41, 0x50, 0x50, 0x45, 0x55, 0x49 + }; + + // Test the encoding is + // DA 00011100 # tag(73728) + // 82 # array(2) + // 02 # unsigned(2) + // 66 # text(6) + // 415050455549 # "APPEUI" + THEN("The encoding is successful") { + REQUIRE(err == MessageEncoder::Status::Complete); + REQUIRE(bytes_encoded == sizeof(expected_result)); + REQUIRE(memcmp(buffer, expected_result, sizeof(expected_result)) == 0); + } + } + + WHEN("Encode the DeviceNetConfigCmdUp message with GSM") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::GSM; + String apn = "apn.arduino.cc"; + strcpy(command.params.gsm.apn, apn.c_str()); + String user = "username"; + strcpy(command.params.gsm.login, user.c_str()); + String password = "PASSWORD"; + strcpy(command.params.gsm.pass, password.c_str()); + uint8_t buffer[512]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + uint8_t expected_result[] = { + 0xda, 0x00, 0x01, 0x11, 0x00, 0x83, + 0x03, 0x6e, 0x61, 0x70, 0x6e, 0x2e, 0x61, 0x72, + 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x63, + 0x68, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, + 0x65 + }; + + // Test the encoding is + // DA 00011100 # tag(73728) + // 83 # array(3) + // 03 # unsigned(3) + // 6E # text(14) + // 61706E2E61726475696E6F2E6363 # "apn.arduino.cc" + // 68 # text(8) + // 757365726E616D65 # "username" + + THEN("The encoding is successful") { + REQUIRE(err == MessageEncoder::Status::Complete); + REQUIRE(bytes_encoded == sizeof(expected_result)); + REQUIRE(memcmp(buffer, expected_result, sizeof(expected_result)) == 0); + } + } + + WHEN("Encode the DeviceNetConfigCmdUp message with NB-IoT") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::NB; + String apn = "apn.arduino.cc"; + strcpy(command.params.nb.apn, apn.c_str()); + String user = "username"; + strcpy(command.params.nb.login, user.c_str()); + String password = "PASSWORD"; + strcpy(command.params.nb.pass, password.c_str()); + uint8_t buffer[512]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + uint8_t expected_result[] = { + 0xda, 0x00, 0x01, 0x11, 0x00, 0x83, + 0x04, 0x6e, 0x61, 0x70, 0x6e, 0x2e, 0x61, 0x72, + 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x63, + 0x68, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, + 0x65 + }; + + // Test the encoding is + // DA 00011100 # tag(73728) + // 83 # array(3) + // 04 # unsigned(4) + // 6E # text(14) + // 61706E2E61726475696E6F2E6363 # "apn.arduino.cc" + // 68 # text(8) + // 757365726E616D65 # "username" + + THEN("The encoding is successful") { + REQUIRE(err == MessageEncoder::Status::Complete); + REQUIRE(bytes_encoded == sizeof(expected_result)); + REQUIRE(memcmp(buffer, expected_result, sizeof(expected_result)) == 0); + } + } + + WHEN("Encode the DeviceNetConfigCmdUp message with CAT-M1") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::CATM1; + String apn = "apn.arduino.cc"; + strcpy(command.params.catm1.apn, apn.c_str()); + String user = "username"; + strcpy(command.params.catm1.login, user.c_str()); + String password = "PASSWORD"; + strcpy(command.params.catm1.pass, password.c_str()); + uint8_t buffer[512]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + uint8_t expected_result[] = { + 0xda, 0x00, 0x01, 0x11, 0x00, 0x83, + 0x05, 0x6e, 0x61, 0x70, 0x6e, 0x2e, 0x61, 0x72, + 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x63, + 0x68, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, + 0x65 + }; + + // Test the encoding is + // DA 00011100 # tag(73728) + // 83 # array(3) + // 05 # unsigned(5) + // 6E # text(14) + // 61706E2E61726475696E6F2E6363 # "apn.arduino.cc" + // 68 # text(8) + // 757365726E616D65 # "username" + + THEN("The encoding is successful") { + REQUIRE(err == MessageEncoder::Status::Complete); + REQUIRE(bytes_encoded == sizeof(expected_result)); + REQUIRE(memcmp(buffer, expected_result, sizeof(expected_result)) == 0); + } + } + + WHEN("Encode the DeviceNetConfigCmdUp message with Ethernet") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::ETHERNET; + uint8_t ip [4] = {192, 168, 0, 2}; + command.params.eth.ip.type = IPType::IPv4; + memcpy(command.params.eth.ip.bytes, ip, sizeof(ip)); + uint8_t dns[4] = {8, 8, 8, 8}; + command.params.eth.dns.type = IPType::IPv4; + memcpy(command.params.eth.dns.bytes, dns, sizeof(dns)); + uint8_t gateway [4] = {192, 168, 1, 1}; + command.params.eth.gateway.type = IPType::IPv4; + memcpy(command.params.eth.gateway.bytes, gateway, sizeof(gateway)); + uint8_t netmask [4] = {255, 255, 255, 0}; + command.params.eth.netmask.type = IPType::IPv4; + memcpy(command.params.eth.netmask.bytes, netmask, sizeof(netmask)); + uint8_t buffer[512]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + uint8_t expected_result[] = { + 0xda, 0x00, 0x01, 0x11, 0x00, 0x85, + 0x06, 0x44, 0xc0, 0xa8, 0x00, 0x02, + 0x44, 0x08, 0x08, 0x08, 0x08, + 0x44, 0xc0, 0xa8, 0x01, 0x01, + 0x44, 0xff, 0xff, 0xff, 0x00 + }; + + // Test the encoding is + // DA 00011100 # tag(73728) + // 85 # array(5) + // 06 # unsigned(6) + // 44 # bytes(4) + // C0A80002 # "\xC0\xA8\u0000\u0002" + // 44 # bytes(4) + // 08080808 # "\b\b\b\b" + // 44 # bytes(4) + // C0A80101 # "\xC0\xA8\u0001\u0001" + // 44 # bytes(4) + // FFFFFF00 # "\xFF\xFF\xFF\u0000" + + THEN("The encoding is successful") { + REQUIRE(err == MessageEncoder::Status::Complete); + REQUIRE(bytes_encoded == sizeof(expected_result)); + REQUIRE(memcmp(buffer, expected_result, sizeof(expected_result)) == 0); + } + } + + WHEN("Encode the DeviceNetConfigCmdUp message with Ethernet DHCP") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::ETHERNET; + + memset(command.params.eth.ip.bytes, 0, sizeof(command.params.eth.ip.bytes)); + memset(command.params.eth.dns.bytes, 0, sizeof(command.params.eth.dns.bytes)); + memset(command.params.eth.gateway.bytes, 0, sizeof(command.params.eth.gateway.bytes)); + memset(command.params.eth.netmask.bytes, 0, sizeof(command.params.eth.netmask.bytes)); + uint8_t buffer[512]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + uint8_t expected_result[] = { + 0xda, 0x00, 0x01, 0x11, 0x00, 0x85, + 0x06, 0x40, 0x40, 0x40, 0x40, + }; + + // Test the encoding is + // DA 00011100 # tag(73737) + // 85 # array(5) + // 06 # unsigned(6) + // 40 # bytes(0) + // # "" + // 40 # bytes(0) + // # "" + // 40 # bytes(0) + // # "" + // 40 # bytes(0) + // # "" + + THEN("The encoding is successful") { + REQUIRE(err == MessageEncoder::Status::Complete); + REQUIRE(bytes_encoded == sizeof(expected_result)); + REQUIRE(memcmp(buffer, expected_result, sizeof(expected_result)) == 0); + } + } + + WHEN("Encode the DeviceNetConfigCmdUp message with Cellular") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::CELL; + String apn = "apn.arduino.cc"; + strcpy(command.params.cell.apn, apn.c_str()); + String user = "username"; + strcpy(command.params.cell.login, user.c_str()); + String password = "PASSWORD"; + strcpy(command.params.cell.pass, password.c_str()); + uint8_t buffer[512]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + uint8_t expected_result[] = { + 0xda, 0x00, 0x01, 0x11, 0x00, 0x83, + 0x07, 0x6e, 0x61, 0x70, 0x6e, 0x2e, 0x61, 0x72, + 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x63, + 0x68, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, + 0x65 + }; + + // Test the encoding is + // DA 00011100 # tag(73728) + // 83 # array(3) + // 07 # unsigned(7) + // 6E # text(14) + // 61706E2E61726475696E6F2E6363 # "apn.arduino.cc" + // 68 # text(8) + // 757365726E616D65 # "username" + + THEN("The encoding is successful") { + REQUIRE(err == MessageEncoder::Status::Complete); + REQUIRE(bytes_encoded == sizeof(expected_result)); + REQUIRE(memcmp(buffer, expected_result, sizeof(expected_result)) == 0); + } + } } diff --git a/src/cbor/CBOR.h b/src/cbor/CBOR.h index a5e6bfdcc..5200f9d60 100644 --- a/src/cbor/CBOR.h +++ b/src/cbor/CBOR.h @@ -22,17 +22,18 @@ enum CBORCommandTag: CBORTag { // Commands UP - CBOROtaBeginUp = 0x010000, - CBORThingBeginCmd = 0x010300, - CBORLastValuesBeginCmd = 0x010500, - CBORDeviceBeginCmd = 0x010700, - CBOROtaProgressCmdUp = 0x010200, - CBORTimezoneCommandUp = 0x010800, + CBOROtaBeginUp = 0x010000, + CBORThingBeginCmd = 0x010300, + CBORLastValuesBeginCmd = 0x010500, + CBORDeviceBeginCmd = 0x010700, + CBOROtaProgressCmdUp = 0x010200, + CBORTimezoneCommandUp = 0x010800, + CBORDeviceNetConfigCmdUp = 0x011100, // Commands DOWN - CBOROtaUpdateCmdDown = 0x010100, - CBORThingUpdateCmd = 0x010400, - CBORThingDetachCmd = 0x011000, - CBORLastValuesUpdate = 0x010600, - CBORTimezoneCommandDown = 0x010900, + CBOROtaUpdateCmdDown = 0x010100, + CBORThingUpdateCmd = 0x010400, + CBORThingDetachCmd = 0x011000, + CBORLastValuesUpdate = 0x010600, + CBORTimezoneCommandDown = 0x010900, }; diff --git a/src/cbor/IoTCloudMessageEncoder.cpp b/src/cbor/IoTCloudMessageEncoder.cpp index 71363cf5e..154053224 100644 --- a/src/cbor/IoTCloudMessageEncoder.cpp +++ b/src/cbor/IoTCloudMessageEncoder.cpp @@ -153,12 +153,199 @@ MessageEncoder::Status TimezoneCommandUpEncoder::encode(CborEncoder* encoder, Me return MessageEncoder::Status::Complete; } +MessageEncoder::Status DeviceNetConfigCmdUpEncoder::encode(CborEncoder* encoder, Message *msg) { + DeviceNetConfigCmdUp * netConfig = (DeviceNetConfigCmdUp*) msg; + CborEncoder array_encoder; + + uint8_t typeID, paramsNum; + getEncodingParams(netConfig->params.type, &typeID, ¶msNum); + + if(cbor_encoder_create_array(encoder, &array_encoder, 1 + paramsNum) != CborNoError) { + return MessageEncoder::Status::Error; + } + + if(cbor_encode_uint(&array_encoder, typeID) != CborNoError) { + return MessageEncoder::Status::Error; + } + + MessageEncoder::Status encodeStatus = MessageEncoder::Status::Complete; + + switch (netConfig->params.type) + { + #if defined(BOARD_HAS_WIFI) + case NetworkAdapter::WIFI: + encodeStatus = encodeWiFiNetwork(&array_encoder, &netConfig->params.wifi); + break; + #endif // defined(BOARD_HAS_WIFI) + + #if defined(BOARD_HAS_LORA) + case NetworkAdapter::LORA: + encodeStatus = encodeLoRaNetwork(&array_encoder, &netConfig->params.lora); + break; + #endif // defined(BOARD_HAS_LORA) + + #if defined(BOARD_HAS_GSM) + case NetworkAdapter::GSM: + encodeStatus = encodeCellularNetwork(&array_encoder, &netConfig->params.gsm); + break; + #endif // defined(BOARD_HAS_GSM) + + #if defined(BOARD_HAS_NB) + case NetworkAdapter::NB: + encodeStatus = encodeCellularNetwork(&array_encoder, &netConfig->params.nb); + break; + #endif // defined(BOARD_HAS_NB) + + #if defined(BOARD_HAS_CATM1_NBIOT) + case NetworkAdapter::CATM1: + encodeStatus = encodeCatM1Network(&array_encoder, &netConfig->params.catm1); + break; + #endif // defined(BOARD_HAS_CATM1_NBIOT) + + #if defined(BOARD_HAS_ETHERNET) + case NetworkAdapter::ETHERNET: + encodeStatus = encodeEthernetNetwork(&array_encoder, &netConfig->params.eth); + break; + #endif // defined(BOARD_HAS_ETHERNET) + + #if defined(BOARD_HAS_CELLULAR) + case NetworkAdapter::CELL: + encodeStatus = encodeCellularNetwork(&array_encoder, &netConfig->params.cell); + break; + #endif // defined(BOARD_HAS_CELLULAR) + + default: + // Nothing to encode + break; + } + + if(encodeStatus != MessageEncoder::Status::Complete) { + return MessageEncoder::Status::Error; + } + + if(cbor_encoder_close_container(encoder, &array_encoder) != CborNoError) { + return MessageEncoder::Status::Error; + } + + return MessageEncoder::Status::Complete; +} + +void DeviceNetConfigCmdUpEncoder::getEncodingParams(NetworkAdapter type, uint8_t *typeID, uint8_t *paramsNum) { + switch (type) + { + case NetworkAdapter::WIFI: *typeID = 1; *paramsNum = 1; break; + case NetworkAdapter::LORA: *typeID = 2; *paramsNum = 1; break; + case NetworkAdapter::GSM: *typeID = 3; *paramsNum = 2; break; + case NetworkAdapter::NB: *typeID = 4; *paramsNum = 2; break; + case NetworkAdapter::CATM1: *typeID = 5; *paramsNum = 2; break; + case NetworkAdapter::ETHERNET: *typeID = 6; *paramsNum = 4; break; + case NetworkAdapter::CELL: *typeID = 7; *paramsNum = 2; break; + case NetworkAdapter::NOTECARD: *typeID = 8; *paramsNum = 0; break; + default: *typeID = 0; *paramsNum = 0; break; + } +} + +#if defined(BOARD_HAS_WIFI) +MessageEncoder::Status DeviceNetConfigCmdUpEncoder::encodeWiFiNetwork(CborEncoder *encoder, models::WiFiSetting *config) { + + if(cbor_encode_text_stringz(encoder, config->ssid) != CborNoError) { + return MessageEncoder::Status::Error; + } + + return MessageEncoder::Status::Complete; +} +#endif // defined(BOARD_HAS_WIFI) + +#if defined(BOARD_HAS_CATM1_NBIOT) +MessageEncoder::Status DeviceNetConfigCmdUpEncoder::encodeCatM1Network(CborEncoder *encoder, models::CATM1Setting *config) +{ + if(cbor_encode_text_stringz(encoder, config->apn) != CborNoError) { + return MessageEncoder::Status::Error; + } + + if(cbor_encode_text_stringz(encoder, config->login) != CborNoError) { + return MessageEncoder::Status::Error; + } + + return MessageEncoder::Status::Complete; +} +#endif // defined(BOARD_HAS_CATM1_NBIOT) + +#if defined(BOARD_HAS_ETHERNET) +MessageEncoder::Status DeviceNetConfigCmdUpEncoder::encodeEthernetNetwork(CborEncoder *encoder, models::EthernetSetting *config) { + + if(encodeIP(encoder, &config->ip) != MessageEncoder::Status::Complete) { + return MessageEncoder::Status::Error; + } + + if(encodeIP(encoder, &config->dns) != MessageEncoder::Status::Complete) { + return MessageEncoder::Status::Error; + } + + if(encodeIP(encoder, &config->gateway) != MessageEncoder::Status::Complete) { + return MessageEncoder::Status::Error; + } + + if(encodeIP(encoder, &config->netmask) != MessageEncoder::Status::Complete) { + return MessageEncoder::Status::Error; + } + + return MessageEncoder::Status::Complete; +} + +MessageEncoder::Status DeviceNetConfigCmdUpEncoder::encodeIP(CborEncoder *encoder, const models::ip_addr *ip) +{ + uint8_t ip_len = 0; + uint8_t emptyIP[16]; + memset(emptyIP, 0, sizeof(emptyIP)); + // Check if the IP is empty, DHCP case + if(memcmp(ip->bytes, emptyIP, sizeof(emptyIP)) == 0) { + ip_len = 0; + } else if(ip->type == IPType::IPv4) { + ip_len = 4; + } else if(ip->type == IPType::IPv6) { + ip_len = 16; + } + + if(cbor_encode_byte_string(encoder, ip->bytes, ip_len) != CborNoError) { + return MessageEncoder::Status::Error; + } + + return MessageEncoder::Status::Complete; +} +#endif // defined(BOARD_HAS_ETHERNET) + +#if defined(BOARD_HAS_NB) || defined(BOARD_HAS_GSM) || defined(BOARD_HAS_CELLULAR) +MessageEncoder::Status DeviceNetConfigCmdUpEncoder::encodeCellularNetwork(CborEncoder *encoder, models::CellularSetting *config) { + if(cbor_encode_text_stringz(encoder, config->apn) != CborNoError) { + return MessageEncoder::Status::Error; + } + + if(cbor_encode_text_stringz(encoder, config->login) != CborNoError) { + return MessageEncoder::Status::Error; + } + + return MessageEncoder::Status::Complete; +} +#endif // defined(BOARD_HAS_NB) || defined(BOARD_HAS_GSM) ||defined(BOARD_HAS_CELLULAR) + +#if defined(BOARD_HAS_LORA) +MessageEncoder::Status DeviceNetConfigCmdUpEncoder::encodeLoRaNetwork(CborEncoder *encoder, models::LoraSetting *config) { + if(cbor_encode_text_stringz(encoder, config->appeui) != CborNoError) { + return MessageEncoder::Status::Error; + } + + return MessageEncoder::Status::Complete; +} +#endif // defined(BOARD_HAS_LORA) + static OtaBeginCommandEncoder otaBeginCommandEncoder; static ThingBeginCommandEncoder thingBeginCommandEncoder; static LastValuesBeginCommandEncoder lastValuesBeginCommandEncoder; static DeviceBeginCommandEncoder deviceBeginCommandEncoder; static OtaProgressCommandUpEncoder otaProgressCommandUpEncoder; static TimezoneCommandUpEncoder timezoneCommandUpEncoder; +static DeviceNetConfigCmdUpEncoder deviceNetConfigCmdUpEncoder; namespace cbor { namespace encoder { namespace iotcloud { void commandEncoders() { @@ -168,5 +355,7 @@ namespace cbor { namespace encoder { namespace iotcloud { (void) deviceBeginCommandEncoder; (void) otaProgressCommandUpEncoder; (void) timezoneCommandUpEncoder; + (void) deviceNetConfigCmdUpEncoder; } }}} + diff --git a/src/cbor/IoTCloudMessageEncoder.h b/src/cbor/IoTCloudMessageEncoder.h index 9b5ca441d..e71f4defc 100644 --- a/src/cbor/IoTCloudMessageEncoder.h +++ b/src/cbor/IoTCloudMessageEncoder.h @@ -15,6 +15,7 @@ * INCLUDE ******************************************************************************/ +#include #include "./CBOR.h" #include #include "message/Commands.h" @@ -71,6 +72,38 @@ class TimezoneCommandUpEncoder: public CBORMessageEncoderInterface { MessageEncoder::Status encode(CborEncoder* encoder, Message *msg) override; }; +class DeviceNetConfigCmdUpEncoder: public CBORMessageEncoderInterface { +public: + DeviceNetConfigCmdUpEncoder() + : CBORMessageEncoderInterface(CBORDeviceNetConfigCmdUp, DeviceNetConfigCmdUpId) {} +protected: + MessageEncoder::Status encode(CborEncoder* encoder, Message *msg) override; +private: + void getEncodingParams(NetworkAdapter type, uint8_t *typeID, uint8_t *paramsNum); + +#if defined(BOARD_HAS_WIFI) + MessageEncoder::Status encodeWiFiNetwork(CborEncoder* encoder, models::WiFiSetting *config); +#endif + +#if defined(BOARD_HAS_CATM1_NBIOT) + MessageEncoder::Status encodeCatM1Network(CborEncoder* encoder, models::CATM1Setting *config); +#endif + +#if defined(BOARD_HAS_ETHERNET) + MessageEncoder::Status encodeEthernetNetwork(CborEncoder* encoder, models::EthernetSetting *config); + MessageEncoder::Status encodeIP(CborEncoder* encoder, const models::ip_addr *ip); +#endif + +#if defined(BOARD_HAS_NB) || defined(BOARD_HAS_GSM) || defined(BOARD_HAS_CELLULAR) + MessageEncoder::Status encodeCellularNetwork(CborEncoder* encoder, models::CellularSetting *config); +#endif + +#if defined(BOARD_HAS_LORA) + MessageEncoder::Status encodeLoRaNetwork(CborEncoder* encoder, models::LoraSetting *config); +#endif + +}; + namespace cbor { namespace encoder { namespace iotcloud { /** * Some link time optimization may exclude these classes to be instantiated diff --git a/src/message/Commands.h b/src/message/Commands.h index 7e044b7a7..2195e4395 100644 --- a/src/message/Commands.h +++ b/src/message/Commands.h @@ -17,6 +17,7 @@ #include #include #include +#include /****************************************************************************** * DEFINE @@ -42,6 +43,7 @@ enum CommandId: MessageId { DeviceRegisteredCmdId, DeviceAttachedCmdId, DeviceDetachedCmdId, + DeviceNetConfigCmdUpId, /* Thing commands */ LastValuesBeginCmdId, @@ -145,6 +147,11 @@ struct TimezoneCommandDown { } params; }; +struct DeviceNetConfigCmdUp { + Command c; + models::NetworkSetting params; +}; + union CommandDown { Command c; struct OtaUpdateCmdDown otaUpdateCmdDown; From 73149298e2d63eab049f2e30823ca117c285001a Mon Sep 17 00:00:00 2001 From: fabik111 Date: Fri, 30 May 2025 17:45:32 +0200 Subject: [PATCH 16/20] send network data to cloud --- src/ArduinoIoTCloudDevice.cpp | 8 ++++++++ src/ArduinoIoTCloudDevice.h | 9 +++++++++ src/ArduinoIoTCloudNotecard.cpp | 3 +++ src/ArduinoIoTCloudTCP.cpp | 4 ++++ 4 files changed, 24 insertions(+) diff --git a/src/ArduinoIoTCloudDevice.cpp b/src/ArduinoIoTCloudDevice.cpp index 58f00d202..76474e12d 100644 --- a/src/ArduinoIoTCloudDevice.cpp +++ b/src/ArduinoIoTCloudDevice.cpp @@ -28,6 +28,7 @@ _state{State::Init}, _attachAttempt(0, 0), _propertyContainer(), _propertyContainerIndex(0), +_getNetConfigCallback(nullptr), _attached(false), _registered(false) { } @@ -109,6 +110,13 @@ ArduinoCloudDevice::State ArduinoCloudDevice::handleSendCapabilities() { DeviceBeginCmd deviceBegin = { DeviceBeginCmdId, AIOT_CONFIG_LIB_VERSION }; deliver(reinterpret_cast(&deviceBegin)); + /* Send Network Configuration */ + if(_getNetConfigCallback){ + DeviceNetConfigCmdUp deviceNetConfig = { DeviceNetConfigCmdUpId }; + _getNetConfigCallback(deviceNetConfig.params ); + deliver(reinterpret_cast(&deviceNetConfig)); + } + /* Subscribe to device topic to request */ ThingBeginCmd thingBegin = { ThingBeginCmdId }; deliver(reinterpret_cast(&thingBegin)); diff --git a/src/ArduinoIoTCloudDevice.h b/src/ArduinoIoTCloudDevice.h index 0fda9be53..ae4386403 100644 --- a/src/ArduinoIoTCloudDevice.h +++ b/src/ArduinoIoTCloudDevice.h @@ -18,6 +18,8 @@ #include #include "interfaces/CloudProcess.h" #include "property/PropertyContainer.h" +#include +#include /****************************************************************************** * CLASS DECLARATION @@ -26,6 +28,8 @@ class ArduinoCloudDevice : public CloudProcess { public: + typedef std::function GetNetworkSettingCbk; + ArduinoCloudDevice(MessageStream* stream); virtual void update() override; virtual void handleMessage(Message* m) override; @@ -43,6 +47,10 @@ class ArduinoCloudDevice : public CloudProcess { return _attached; }; + void setGetNetworkSettingCbk(GetNetworkSettingCbk cbk) { + _getNetConfigCallback = cbk; + } + private: @@ -57,6 +65,7 @@ class ArduinoCloudDevice : public CloudProcess { CommandId _command; TimedAttempt _attachAttempt; PropertyContainer _propertyContainer; + GetNetworkSettingCbk _getNetConfigCallback; unsigned int _propertyContainerIndex; bool _attached; bool _registered; diff --git a/src/ArduinoIoTCloudNotecard.cpp b/src/ArduinoIoTCloudNotecard.cpp index fac028e61..90f00ceb5 100644 --- a/src/ArduinoIoTCloudNotecard.cpp +++ b/src/ArduinoIoTCloudNotecard.cpp @@ -105,6 +105,9 @@ int ArduinoIoTCloudNotecard::begin(ConnectionHandler &connection_, int interrupt // Configure the Device and Thing property containers _thing.begin(); _device.begin(); + _device.setGetNetworkSettingCbk([connection = this->_connection](models::NetworkSetting &setting) { + connection->getSetting(setting); + }); return 1; // (true -> success) } diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 31e972882..96907800e 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -168,6 +168,10 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, _thing.begin(); _device.begin(); + _device.setGetNetworkSettingCbk([connection = this->_connection](models::NetworkSetting &setting) { + connection->getSetting(setting); + }); + #if OTA_ENABLED && !defined(OFFLOADED_DOWNLOAD) _ota.setClient(&_otaClient); #endif // OTA_ENABLED && !defined(OFFLOADED_DOWNLOAD) From f242759195f402d928ab2a04417bad488e259a1a Mon Sep 17 00:00:00 2001 From: fabik111 Date: Tue, 3 Jun 2025 11:57:39 +0200 Subject: [PATCH 17/20] add test cases --- extras/test/src/test_command_encode.cpp | 416 +++++++++++++++++++++++- 1 file changed, 413 insertions(+), 3 deletions(-) diff --git a/extras/test/src/test_command_encode.cpp b/extras/test/src/test_command_encode.cpp index af9975532..8cad13d1e 100644 --- a/extras/test/src/test_command_encode.cpp +++ b/extras/test/src/test_command_encode.cpp @@ -683,6 +683,27 @@ SCENARIO("Test the encoding of command messages") { } } + + WHEN("Encode the DeviceNetConfigCmdUp message with Wifi and buffer without enough space") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::WIFI; + String longSsid = "longSSID"; + strcpy(command.params.wifi.ssid, longSsid.c_str()); + + uint8_t buffer[7]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + THEN("The encoding fails") { + REQUIRE(err == MessageEncoder::Status::Error); + } + } + WHEN("Encode the DeviceNetConfigCmdUp message with LoraWan") { DeviceNetConfigCmdUp command; @@ -718,6 +739,28 @@ SCENARIO("Test the encoding of command messages") { } } + WHEN("Encode the DeviceNetConfigCmdUp message with LoRa buffer without enough space") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::LORA; + + String app_eui = "APPEUI"; + strcpy(command.params.lora.appeui, app_eui.c_str()); + String app_key = "APPKEY"; + strcpy(command.params.lora.appkey, app_key.c_str()); + uint8_t buffer[7]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + THEN("The encoding fails") { + REQUIRE(err == MessageEncoder::Status::Error); + } + } + WHEN("Encode the DeviceNetConfigCmdUp message with GSM") { DeviceNetConfigCmdUp command; @@ -760,18 +803,41 @@ SCENARIO("Test the encoding of command messages") { } } - WHEN("Encode the DeviceNetConfigCmdUp message with NB-IoT") + WHEN("Encode the DeviceNetConfigCmdUp message with GSM buffer without enough space for login") { DeviceNetConfigCmdUp command; command.c.id = CommandId::DeviceNetConfigCmdUpId; - command.params.type = NetworkAdapter::NB; + command.params.type = NetworkAdapter::GSM; String apn = "apn.arduino.cc"; strcpy(command.params.nb.apn, apn.c_str()); String user = "username"; strcpy(command.params.nb.login, user.c_str()); String password = "PASSWORD"; strcpy(command.params.nb.pass, password.c_str()); + uint8_t buffer[25]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + THEN("The encoding fails") { + REQUIRE(err == MessageEncoder::Status::Error); + } + } + + WHEN("Encode the DeviceNetConfigCmdUp message with NB-IoT") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::NB; + String apn = "apn.arduino.cc"; + strcpy(command.params.gsm.apn, apn.c_str()); + String user = "username"; + strcpy(command.params.gsm.login, user.c_str()); + String password = "PASSWORD"; + strcpy(command.params.gsm.pass, password.c_str()); uint8_t buffer[512]; size_t bytes_encoded = sizeof(buffer); @@ -789,7 +855,7 @@ SCENARIO("Test the encoding of command messages") { // Test the encoding is // DA 00011100 # tag(73728) // 83 # array(3) - // 04 # unsigned(4) + // 03 # unsigned(3) // 6E # text(14) // 61706E2E61726475696E6F2E6363 # "apn.arduino.cc" // 68 # text(8) @@ -802,6 +868,29 @@ SCENARIO("Test the encoding of command messages") { } } + WHEN("Encode the DeviceNetConfigCmdUp message with NB-IoT buffer without enough space") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::NB; + String apn = "apn.arduino.cc"; + strcpy(command.params.nb.apn, apn.c_str()); + String user = "username"; + strcpy(command.params.nb.login, user.c_str()); + String password = "PASSWORD"; + strcpy(command.params.nb.pass, password.c_str()); + uint8_t buffer[12]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + THEN("The encoding fails") { + REQUIRE(err == MessageEncoder::Status::Error); + } + } + WHEN("Encode the DeviceNetConfigCmdUp message with CAT-M1") { DeviceNetConfigCmdUp command; @@ -844,6 +933,52 @@ SCENARIO("Test the encoding of command messages") { } } + WHEN("Encode the DeviceNetConfigCmdUp message with CAT-M1 buffer without enough space") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::CATM1; + String apn = "apn.arduino.cc"; + strcpy(command.params.nb.apn, apn.c_str()); + String user = "username"; + strcpy(command.params.nb.login, user.c_str()); + String password = "PASSWORD"; + strcpy(command.params.nb.pass, password.c_str()); + uint8_t buffer[12]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + THEN("The encoding fails") { + REQUIRE(err == MessageEncoder::Status::Error); + } + } + + WHEN("Encode the DeviceNetConfigCmdUp message with CAT-M1 buffer without enough space for login") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::CATM1; + String apn = "apn.arduino.cc"; + strcpy(command.params.nb.apn, apn.c_str()); + String user = "username"; + strcpy(command.params.nb.login, user.c_str()); + String password = "PASSWORD"; + strcpy(command.params.nb.pass, password.c_str()); + uint8_t buffer[25]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + THEN("The encoding fails") { + REQUIRE(err == MessageEncoder::Status::Error); + } + } + WHEN("Encode the DeviceNetConfigCmdUp message with Ethernet") { DeviceNetConfigCmdUp command; @@ -896,6 +1031,65 @@ SCENARIO("Test the encoding of command messages") { } } + WHEN("Encode the DeviceNetConfigCmdUp message with Ethernet IPv6") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::ETHERNET; + uint8_t ip[] = {0x1a, 0x4f, 0xa7, 0xa9, 0x92, 0x8f, 0x7b, 0x1c, 0xec, 0x3b, 0x1e, 0xcd, 0x88, 0x58, 0x0d, 0x1e}; + command.params.eth.ip.type = IPType::IPv6; + memcpy(command.params.eth.ip.bytes, ip, sizeof(ip)); + uint8_t dns[] = {0x21, 0xf6, 0x3b, 0x22, 0x99, 0x6f, 0x5b, 0x72, 0x25, 0xd9, 0xe0, 0x24, 0xf0, 0x36, 0xb5, 0xd2}; + command.params.eth.dns.type = IPType::IPv6; + memcpy(command.params.eth.dns.bytes, dns, sizeof(dns)); + uint8_t gateway[] = {0x2e, 0xc2, 0x27, 0xf1, 0xf1, 0x9a, 0x0c, 0x11, 0x47, 0x1b, 0x84, 0xaf, 0x96, 0x10, 0xb0, 0x17}; + command.params.eth.gateway.type = IPType::IPv6; + memcpy(command.params.eth.gateway.bytes, gateway, sizeof(gateway)); + uint8_t netmask[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + command.params.eth.netmask.type = IPType::IPv6; + memcpy(command.params.eth.netmask.bytes, netmask, sizeof(netmask)); + + + uint8_t buffer[512]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + uint8_t expected_result[] = { + 0xda, 0x00, 0x01, 0x11, 0x00, 0x85, + 0x06,0x50, 0x1A, 0x4F, 0xA7, 0xA9, 0x92, 0x8F, 0x7B, 0x1C, + 0xEC, 0x3B, 0x1E, 0xCD, 0x88, 0x58, 0x0D, 0x1E, + 0x50, 0x21, 0xF6, 0x3B, 0x22, 0x99, 0x6F, + 0x5B, 0x72, 0x25, 0xD9, 0xE0, 0x24, 0xF0, 0x36, + 0xB5, 0xD2, 0x50, 0x2E, 0xC2, 0x27, 0xF1, + 0xF1, 0x9A, 0x0C, 0x11, 0x47, 0x1B, 0x84, 0xAF, + 0x96, 0x10, 0xB0, 0x17, 0x50, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + // Test the encoding is + // DA 00011100 # tag(73728) + // 85 # array(5) + // 06 # unsigned(6) + // 50 # bytes(16) + // 1A4FA7A9928F7B1CEC3B1ECD88580D1E # "\u001AO\xA7\xA9\x92\x8F{\u001C\xEC;\u001E͈X\r\u001E" + // 50 # bytes(16) + // 21F63B22996F5B7225D9E024F036B5D2 # "!\xF6;\"\x99o[r%\xD9\xE0$\xF06\xB5\xD2" + // 50 # bytes(16) + // 2EC227F1F19A0C11471B84AF9610B017 # ".\xC2'\xF1\xF1\x9A\f\u0011G\e\x84\xAF\x96\u0010\xB0\u0017" + // 50 # bytes(16) + // FFFFFFFFFFFFFFFF0000000000000000 # "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + + THEN("The encoding is successful") { + REQUIRE(err == MessageEncoder::Status::Complete); + REQUIRE(bytes_encoded == sizeof(expected_result)); + REQUIRE(memcmp(buffer, expected_result, sizeof(expected_result)) == 0); + } + } + WHEN("Encode the DeviceNetConfigCmdUp message with Ethernet DHCP") { DeviceNetConfigCmdUp command; @@ -938,6 +1132,126 @@ SCENARIO("Test the encoding of command messages") { } } + WHEN("Encode the DeviceNetConfigCmdUp message with Ethernet IPv6 not enough space") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::ETHERNET; + uint8_t ip[] = {0x1a, 0x4f, 0xa7, 0xa9, 0x92, 0x8f, 0x7b, 0x1c, 0xec, 0x3b, 0x1e, 0xcd, 0x88, 0x58, 0x0d, 0x1e}; + command.params.eth.ip.type = IPType::IPv6; + memcpy(command.params.eth.ip.bytes, ip, sizeof(ip)); + uint8_t dns[] = {0x21, 0xf6, 0x3b, 0x22, 0x99, 0x6f, 0x5b, 0x72, 0x25, 0xd9, 0xe0, 0x24, 0xf0, 0x36, 0xb5, 0xd2}; + command.params.eth.dns.type = IPType::IPv6; + memcpy(command.params.eth.dns.bytes, dns, sizeof(dns)); + uint8_t gateway[] = {0x2e, 0xc2, 0x27, 0xf1, 0xf1, 0x9a, 0x0c, 0x11, 0x47, 0x1b, 0x84, 0xaf, 0x96, 0x10, 0xb0, 0x17}; + command.params.eth.gateway.type = IPType::IPv6; + memcpy(command.params.eth.gateway.bytes, gateway, sizeof(gateway)); + uint8_t netmask[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + command.params.eth.netmask.type = IPType::IPv6; + memcpy(command.params.eth.netmask.bytes, netmask, sizeof(netmask)); + + + uint8_t buffer[35]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + THEN("The encoding fails") { + REQUIRE(err == MessageEncoder::Status::Error); + } + } + + WHEN("Encode the DeviceNetConfigCmdUp message with Ethernet IPv4 not enough space") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::ETHERNET; + uint8_t ip [4] = {192, 168, 0, 2}; + command.params.eth.ip.type = IPType::IPv4; + memcpy(command.params.eth.ip.bytes, ip, sizeof(ip)); + uint8_t dns[4] = {8, 8, 8, 8}; + command.params.eth.dns.type = IPType::IPv4; + memcpy(command.params.eth.dns.bytes, dns, sizeof(dns)); + uint8_t gateway [4] = {192, 168, 1, 1}; + command.params.eth.gateway.type = IPType::IPv4; + memcpy(command.params.eth.gateway.bytes, gateway, sizeof(gateway)); + uint8_t netmask [4] = {255, 255, 255, 0}; + command.params.eth.netmask.type = IPType::IPv4; + memcpy(command.params.eth.netmask.bytes, netmask, sizeof(netmask)); + uint8_t buffer[20]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + THEN("The encoding fails") { + REQUIRE(err == MessageEncoder::Status::Error); + } + } + + WHEN("Encode the DeviceNetConfigCmdUp message with Ethernet IPv4 not enough space for netmask") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::ETHERNET; + uint8_t ip [4] = {192, 168, 0, 2}; + command.params.eth.ip.type = IPType::IPv4; + memcpy(command.params.eth.ip.bytes, ip, sizeof(ip)); + uint8_t dns[4] = {8, 8, 8, 8}; + command.params.eth.dns.type = IPType::IPv4; + memcpy(command.params.eth.dns.bytes, dns, sizeof(dns)); + uint8_t gateway [4] = {192, 168, 1, 1}; + command.params.eth.gateway.type = IPType::IPv4; + memcpy(command.params.eth.gateway.bytes, gateway, sizeof(gateway)); + uint8_t netmask [4] = {255, 255, 255, 0}; + command.params.eth.netmask.type = IPType::IPv4; + memcpy(command.params.eth.netmask.bytes, netmask, sizeof(netmask)); + uint8_t buffer[25]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + THEN("The encoding fails") { + REQUIRE(err == MessageEncoder::Status::Error); + } + } + + WHEN("Encode the DeviceNetConfigCmdUp message with Ethernet IPv6 not enough space for any") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::ETHERNET; + uint8_t ip[] = {0x1a, 0x4f, 0xa7, 0xa9, 0x92, 0x8f, 0x7b, 0x1c, 0xec, 0x3b, 0x1e, 0xcd, 0x88, 0x58, 0x0d, 0x1e}; + command.params.eth.ip.type = IPType::IPv6; + memcpy(command.params.eth.ip.bytes, ip, sizeof(ip)); + uint8_t dns[] = {0x21, 0xf6, 0x3b, 0x22, 0x99, 0x6f, 0x5b, 0x72, 0x25, 0xd9, 0xe0, 0x24, 0xf0, 0x36, 0xb5, 0xd2}; + command.params.eth.dns.type = IPType::IPv6; + memcpy(command.params.eth.dns.bytes, dns, sizeof(dns)); + uint8_t gateway[] = {0x2e, 0xc2, 0x27, 0xf1, 0xf1, 0x9a, 0x0c, 0x11, 0x47, 0x1b, 0x84, 0xaf, 0x96, 0x10, 0xb0, 0x17}; + command.params.eth.gateway.type = IPType::IPv6; + memcpy(command.params.eth.gateway.bytes, gateway, sizeof(gateway)); + uint8_t netmask[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + command.params.eth.netmask.type = IPType::IPv6; + memcpy(command.params.eth.netmask.bytes, netmask, sizeof(netmask)); + + + uint8_t buffer[12]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + THEN("The encoding fails") { + REQUIRE(err == MessageEncoder::Status::Error); + } + } + WHEN("Encode the DeviceNetConfigCmdUp message with Cellular") { DeviceNetConfigCmdUp command; @@ -979,4 +1293,100 @@ SCENARIO("Test the encoding of command messages") { REQUIRE(memcmp(buffer, expected_result, sizeof(expected_result)) == 0); } } + + WHEN("Encode the DeviceNetConfigCmdUp message with Notecard") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::NOTECARD; + + uint8_t buffer[512]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + uint8_t expected_result[] = { + 0xda, 0x00, 0x01, 0x11, 0x00, 0x81, + 0x08 + }; + + // Test the encoding is + // DA 00011100 # tag(73728) + // 81 # array(1) + // 08 # unsigned(8) + + THEN("The encoding is successful") { + REQUIRE(err == MessageEncoder::Status::Complete); + REQUIRE(bytes_encoded == sizeof(expected_result)); + REQUIRE(memcmp(buffer, expected_result, sizeof(expected_result)) == 0); + } + } + + WHEN("Encode the DeviceNetConfigCmdUp message with None") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::NONE; + + uint8_t buffer[512]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + uint8_t expected_result[] = { + 0xda, 0x00, 0x01, 0x11, 0x00, 0x81, 0x00 + }; + + // Test the encoding is + // DA 00011100 # tag(73728) + // 80 # array(1) + + THEN("The encoding is successful") { + REQUIRE(err == MessageEncoder::Status::Complete); + REQUIRE(bytes_encoded == sizeof(expected_result)); + REQUIRE(memcmp(buffer, expected_result, sizeof(expected_result)) == 0); + } + } + + WHEN("Encode the DeviceNetConfigCmdUp message buffer without enough space") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::ETHERNET; + + + uint8_t buffer[6]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + THEN("The encoding fails") { + REQUIRE(err == MessageEncoder::Status::Error); + } + } + + WHEN("Encode the DeviceNetConfigCmdUp message buffer without enough space for array") + { + DeviceNetConfigCmdUp command; + command.c.id = CommandId::DeviceNetConfigCmdUpId; + + command.params.type = NetworkAdapter::ETHERNET; + + + uint8_t buffer[5]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + MessageEncoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + THEN("The encoding fails") { + REQUIRE(err == MessageEncoder::Status::Error); + } + } } From 99a82f79942276e3544df6c6daa7aeb050cb505a Mon Sep 17 00:00:00 2001 From: fabik111 Date: Tue, 3 Jun 2025 18:16:05 +0200 Subject: [PATCH 18/20] send wifi fw version to cloud --- src/ArduinoIoTCloudDevice.cpp | 5 +++++ src/message/Commands.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/ArduinoIoTCloudDevice.cpp b/src/ArduinoIoTCloudDevice.cpp index 76474e12d..e693923bc 100644 --- a/src/ArduinoIoTCloudDevice.cpp +++ b/src/ArduinoIoTCloudDevice.cpp @@ -117,6 +117,11 @@ ArduinoCloudDevice::State ArduinoCloudDevice::handleSendCapabilities() { deliver(reinterpret_cast(&deviceNetConfig)); } +#if defined(BOARD_HAS_WIFI) && not defined(BOARD_ESP) + String WiFiFWVersion = WiFi.firmwareVersion(); + VersionMessage versionMessage = { WiFiFWVersionMessageId, WiFiFWVersion.c_str() }; + deliver(reinterpret_cast(&versionMessage)); +#endif /* Subscribe to device topic to request */ ThingBeginCmd thingBegin = { ThingBeginCmdId }; deliver(reinterpret_cast(&thingBegin)); diff --git a/src/message/Commands.h b/src/message/Commands.h index 2195e4395..60840231a 100644 --- a/src/message/Commands.h +++ b/src/message/Commands.h @@ -17,6 +17,7 @@ #include #include #include +#include #include /****************************************************************************** From 2322475d3a8d495c8e43577a2ad0d422096d8de4 Mon Sep 17 00:00:00 2001 From: fabik111 Date: Tue, 15 Jul 2025 16:15:22 +0200 Subject: [PATCH 19/20] add updatePhy state for re-initialization of the FSM after an update of network credentials --- src/ArduinoIoTCloudTCP.cpp | 16 +++++++++++++++- src/ArduinoIoTCloudTCP.h | 2 ++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 96907800e..9fa9de583 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -216,6 +216,7 @@ void ArduinoIoTCloudTCP::update() switch (_state) { case State::ConfigPhy: next_state = handle_ConfigPhy(); break; + case State::UpdatePhy: next_state = handle_UpdatePhy(); break; case State::Init: next_state = handle_Init(); break; case State::ConnectPhy: next_state = handle_ConnectPhy(); break; case State::SyncTime: next_state = handle_SyncTime(); break; @@ -240,7 +241,7 @@ void ArduinoIoTCloudTCP::update() */ #if NETWORK_CONFIGURATOR_ENABLED if(_configurator != nullptr && _state > State::Init && _configurator->update() == NetworkConfiguratorStates::UPDATING_CONFIG){ - _state = State::ConfigPhy; + _state = State::UpdatePhy; } #endif @@ -316,6 +317,19 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConfigPhy() #endif } +ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_UpdatePhy() +{ +#if NETWORK_CONFIGURATOR_ENABLED + if(_configurator->update() == NetworkConfiguratorStates::CONFIGURED) { + _configurator->disconnectAgent(); + return State::Disconnect; + } + return State::UpdatePhy; +#else + return State::Init; +#endif +} + ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Init() { /* Setup broker TLS client */ diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index d59c6de97..fd2ffab7f 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -122,6 +122,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass enum class State { ConfigPhy, + UpdatePhy, Init, ConnectPhy, SyncTime, @@ -178,6 +179,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass inline String getTopic_datain () { return ( getThingId().length() == 0) ? String("") : String("/a/t/" + getThingId() + "/e/i"); } State handle_ConfigPhy(); + State handle_UpdatePhy(); State handle_Init(); State handle_ConnectPhy(); State handle_SyncTime(); From b81778f158a356ce85da278238bb877f2d2653eb Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 21 Jul 2025 10:24:04 +0200 Subject: [PATCH 20/20] Release v2.7.0 --- library.properties | 2 +- src/AIoTC_Config.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 7ab62ce5c..b6ea055d6 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ArduinoIoTCloud -version=2.6.1 +version=2.7.0 author=Arduino maintainer=Arduino sentence=This library allows connecting to the Arduino IoT Cloud service. diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index 9127676c3..b0fba96a3 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -191,6 +191,6 @@ #define AIOT_CONFIG_LASTVALUES_SYNC_MAX_RETRY_CNT (10UL) #endif -#define AIOT_CONFIG_LIB_VERSION "2.6.1" +#define AIOT_CONFIG_LIB_VERSION "2.7.0" #endif /* ARDUINO_AIOTC_CONFIG_H_ */