From d4b225dad22708a60834bee4ec3eb667f829fa76 Mon Sep 17 00:00:00 2001 From: jim Date: Fri, 24 Jan 2025 16:56:29 -0800 Subject: [PATCH 01/80] Add a missing linefeed with a println. --- libraries/WiFiS3/examples/ScanNetworks/ScanNetworks.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/WiFiS3/examples/ScanNetworks/ScanNetworks.ino b/libraries/WiFiS3/examples/ScanNetworks/ScanNetworks.ino index 252676aaf..99ec02d63 100644 --- a/libraries/WiFiS3/examples/ScanNetworks/ScanNetworks.ino +++ b/libraries/WiFiS3/examples/ScanNetworks/ScanNetworks.ino @@ -91,7 +91,7 @@ void printEncryptionType(int thisType) { Serial.println("WPA2"); break; case ENC_TYPE_WPA3: - Serial.print("WPA3"); + Serial.println("WPA3"); break; case ENC_TYPE_NONE: Serial.println("None"); From 76db8986584926ad20160b1f9792e07d1eb8f11d Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 30 Jan 2025 10:29:43 +0100 Subject: [PATCH 02/80] Modem: check wifi firmware softreset response to set initialization done --- libraries/WiFiS3/src/Modem.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/WiFiS3/src/Modem.cpp b/libraries/WiFiS3/src/Modem.cpp index 7aa34391a..bbdb2b073 100644 --- a/libraries/WiFiS3/src/Modem.cpp +++ b/libraries/WiFiS3/src/Modem.cpp @@ -34,10 +34,9 @@ void ModemClass::begin(int badurate){ /* -------------------------------------------------------------------------- */ if(_serial != nullptr && !beginned) { _serial->begin(badurate); - beginned = true; string res = ""; _serial->flush(); - modem.write(string(PROMPT(_SOFTRESETWIFI)),res, "%s" , CMD(_SOFTRESETWIFI)); + beginned = modem.write(string(PROMPT(_SOFTRESETWIFI)),res, "%s" , CMD(_SOFTRESETWIFI)); } } From 836caebfe9a8c24d21f4eb326421c42a30fe8387 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 30 Jan 2025 10:51:44 +0100 Subject: [PATCH 03/80] Modem: reduce wait time begin --- libraries/WiFiS3/src/Modem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/WiFiS3/src/Modem.cpp b/libraries/WiFiS3/src/Modem.cpp index bbdb2b073..597269633 100644 --- a/libraries/WiFiS3/src/Modem.cpp +++ b/libraries/WiFiS3/src/Modem.cpp @@ -36,7 +36,9 @@ void ModemClass::begin(int badurate){ _serial->begin(badurate); string res = ""; _serial->flush(); + modem.timeout(500); beginned = modem.write(string(PROMPT(_SOFTRESETWIFI)),res, "%s" , CMD(_SOFTRESETWIFI)); + modem.timeout(MODEM_TIMEOUT); } } From 3ffc324c5e3cfcee7bbef1117926446805998d1c Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 30 Jan 2025 10:54:13 +0100 Subject: [PATCH 04/80] Modem: add retry if begin fails --- libraries/WiFiS3/src/Modem.cpp | 7 +++++-- libraries/WiFiS3/src/Modem.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/WiFiS3/src/Modem.cpp b/libraries/WiFiS3/src/Modem.cpp index 597269633..d20b1bc7d 100644 --- a/libraries/WiFiS3/src/Modem.cpp +++ b/libraries/WiFiS3/src/Modem.cpp @@ -30,14 +30,17 @@ ModemClass::~ModemClass() { } /* -------------------------------------------------------------------------- */ -void ModemClass::begin(int badurate){ +void ModemClass::begin(int badurate, int retry){ /* -------------------------------------------------------------------------- */ if(_serial != nullptr && !beginned) { _serial->begin(badurate); string res = ""; _serial->flush(); modem.timeout(500); - beginned = modem.write(string(PROMPT(_SOFTRESETWIFI)),res, "%s" , CMD(_SOFTRESETWIFI)); + while(!beginned && retry > 0) { + beginned = modem.write(string(PROMPT(_SOFTRESETWIFI)),res, "%s" , CMD(_SOFTRESETWIFI)); + retry -= 1; + } modem.timeout(MODEM_TIMEOUT); } } diff --git a/libraries/WiFiS3/src/Modem.h b/libraries/WiFiS3/src/Modem.h index 3f785bc9d..d340dd976 100644 --- a/libraries/WiFiS3/src/Modem.h +++ b/libraries/WiFiS3/src/Modem.h @@ -22,7 +22,7 @@ class ModemClass { ModemClass(UART * _serial); ~ModemClass(); - void begin(int badurate = 115200); + void begin(int badurate = 115200, int retry = 3); void end(); bool write(const std::string &cmd, std::string &str, const char * fmt, ...); void write_nowait(const std::string &cmd, std::string &str, const char * fmt, ...); From d7d7fa16df9e0894924e9dd88ecde60fc65772b6 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 6 Feb 2025 16:27:07 +0100 Subject: [PATCH 05/80] Update actions/checkout to v4 --- .github/workflows/compile-examples.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml index 3340e3c46..f6f5b7214 100644 --- a/.github/workflows/compile-examples.yml +++ b/.github/workflows/compile-examples.yml @@ -106,11 +106,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # The source files are in a subfolder of the ArduinoCore-API repository, so it's not possible to clone it directly to the final destination in the core - name: Checkout ArduinoCore-API - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: arduino/ArduinoCore-API path: extras/ArduinoCore-API @@ -125,7 +125,7 @@ jobs: if: steps.checkapi.outputs.IS_API == 'true' - name: Checkout Basic examples - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: arduino/arduino-examples path: examples From 2f9a680a358a15789f46c50312cb2c9fbaa8c1c9 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 6 Feb 2025 16:28:04 +0100 Subject: [PATCH 06/80] Update upload/artifacts to v4 --- .github/workflows/compile-examples.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml index f6f5b7214..7765f8d07 100644 --- a/.github/workflows/compile-examples.yml +++ b/.github/workflows/compile-examples.yml @@ -175,7 +175,7 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} - name: Save memory usage change report as artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: sketches-reports path: sketches-reports From 61299ff27b2217e8bc280e82583559172d2d1ec9 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 6 Feb 2025 16:28:34 +0100 Subject: [PATCH 07/80] Make artifacts name unique --- .github/workflows/compile-examples.yml | 28 +++++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml index 7765f8d07..161a958a8 100644 --- a/.github/workflows/compile-examples.yml +++ b/.github/workflows/compile-examples.yml @@ -38,19 +38,26 @@ jobs: - libraries/RTC/examples/Test_RTC - libraries/SoftwareSerial - libraries/WDT + SKETCHES_REPORTS_PATH: sketches-reports strategy: fail-fast: false matrix: - board: [ - {"fqbn": "arduino:renesas_portenta:portenta_c33"}, - {"fqbn": "arduino:renesas_uno:minima"}, - {"fqbn": "arduino:renesas_uno:unor4wifi"}, - {"fqbn": "arduino-git:renesas:portenta_c33"}, - {"fqbn": "arduino-git:renesas:minima"}, - {"fqbn": "arduino-git:renesas:unor4wifi"}, - ] + board: + - fqbn: arduino:renesas_portenta:portenta_c33 + id: c33 + - fqbn: arduino:renesas_uno:minima + id: minima + - fqbn: arduino:renesas_uno:unor4wifi + id: wifi + - fqbn: arduino-git:renesas:portenta_c33 + id: git_c33 + - fqbn: arduino-git:renesas:minima + id: git_minima + - fqbn: arduino-git:renesas:unor4wifi + id: git_wifi + # make board type-specific customizations to the matrix jobs include: @@ -173,9 +180,10 @@ jobs: enable-deltas-report: 'false' verbose: 'true' github-token: ${{ secrets.GITHUB_TOKEN }} + sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }} - name: Save memory usage change report as artifact uses: actions/upload-artifact@v4 with: - name: sketches-reports - path: sketches-reports + path: ${{ env.SKETCHES_REPORTS_PATH }} + name: ${{ env.SKETCHES_REPORTS_PATH }}-${{ matrix.board.id }} From 08e9d1068c56781495bcc52ce4fb2657eca0bbd9 Mon Sep 17 00:00:00 2001 From: Mattia Pennasilico Date: Fri, 7 Feb 2025 09:17:28 +0100 Subject: [PATCH 08/80] Remove SKETCHES_REPORTS_PATH prefix from actions/upload-artifact name Co-authored-by: Per Tillisch --- .github/workflows/compile-examples.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml index 161a958a8..39e02488f 100644 --- a/.github/workflows/compile-examples.yml +++ b/.github/workflows/compile-examples.yml @@ -186,4 +186,4 @@ jobs: uses: actions/upload-artifact@v4 with: path: ${{ env.SKETCHES_REPORTS_PATH }} - name: ${{ env.SKETCHES_REPORTS_PATH }}-${{ matrix.board.id }} + name: sketches-reports-${{ matrix.board.id }} From f8e01b79fc2d9c5fa8c0a3be8efacc4e949664dc Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 7 Feb 2025 16:19:26 +0100 Subject: [PATCH 09/80] WiFiS3: remove destroy_at_distructor unused flag --- libraries/WiFiS3/src/WiFiClient.cpp | 4 ++-- libraries/WiFiS3/src/WiFiClient.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/WiFiS3/src/WiFiClient.cpp b/libraries/WiFiS3/src/WiFiClient.cpp index 9e6d09261..84bc23b48 100644 --- a/libraries/WiFiS3/src/WiFiClient.cpp +++ b/libraries/WiFiS3/src/WiFiClient.cpp @@ -3,13 +3,13 @@ using namespace std; /* -------------------------------------------------------------------------- */ -WiFiClient::WiFiClient() : _sock(-1), destroy_at_distructor(true), rx_buffer(nullptr) { +WiFiClient::WiFiClient() : _sock(-1), rx_buffer(nullptr) { rx_buffer = std::shared_ptr>(new FifoBuffer()); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -WiFiClient::WiFiClient(int s) : _sock(s), destroy_at_distructor(false), rx_buffer(nullptr) { +WiFiClient::WiFiClient(int s) : _sock(s), rx_buffer(nullptr) { rx_buffer = std::shared_ptr>(new FifoBuffer()); } /* -------------------------------------------------------------------------- */ diff --git a/libraries/WiFiS3/src/WiFiClient.h b/libraries/WiFiS3/src/WiFiClient.h index 63b019c32..e670b594f 100644 --- a/libraries/WiFiS3/src/WiFiClient.h +++ b/libraries/WiFiS3/src/WiFiClient.h @@ -70,7 +70,6 @@ class WiFiClient : public Client { protected: int _sock; - bool destroy_at_distructor; int _connectionTimeout = 0; void getSocket(); static constexpr uint32_t RX_BUFFER_DIM = 1024; From c89f7d7fb10d5dc123727c8ef881970c6a62b013 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 7 Jan 2025 12:09:34 +0100 Subject: [PATCH 10/80] WiFiS3: fix peek() avoiding AT call Fixes https://github.com/arduino/ArduinoCore-renesas/issues/419 --- libraries/WiFiS3/src/WiFiClient.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/libraries/WiFiS3/src/WiFiClient.cpp b/libraries/WiFiS3/src/WiFiClient.cpp index 9e6d09261..e0a37aa9b 100644 --- a/libraries/WiFiS3/src/WiFiClient.cpp +++ b/libraries/WiFiS3/src/WiFiClient.cpp @@ -185,15 +185,11 @@ int WiFiClient::read(uint8_t *buf, size_t size) { /* -------------------------------------------------------------------------- */ int WiFiClient::peek() { /* -------------------------------------------------------------------------- */ - int rv = -1; - if(_sock >= 0) { - string res = ""; - modem.begin(); - if(modem.write(string(PROMPT(_PEEK)),res, "%s%d\r\n" , CMD_WRITE(_PEEK), _sock)) { - rv = atoi(res.c_str()); - } + read_if_needed(1); + if(_sock >= 0 && rx_buffer != nullptr) { + return rx_buffer->peek(); } - return rv; + return -1; } From 47982f8408cc2737a8833e090673062ca5bef013 Mon Sep 17 00:00:00 2001 From: Mattia Pennasilico Date: Wed, 12 Feb 2025 16:51:56 +0100 Subject: [PATCH 11/80] analog: declare aref variable only if used --- cores/arduino/analog.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cores/arduino/analog.cpp b/cores/arduino/analog.cpp index dd1de77f1..37d3d6cc7 100644 --- a/cores/arduino/analog.cpp +++ b/cores/arduino/analog.cpp @@ -558,7 +558,10 @@ void analogReference(uint8_t mode) { R_ADC_Open(&adc1.ctrl, &adc1.cfg); } +#if defined(AVCC_MEASURE_PIN) static float aref = 0; +#endif + float analogReference() { switch (adc.cfg_extend.adc_vref_control) { case ADC_VREF_CONTROL_1_5V_OUTPUT: @@ -817,4 +820,4 @@ void analogWrite(pin_size_t pinNumber, int value) FspTimer* __get_timer_for_channel(int channel) { return pwms.get_from_channel(channel)->get_timer(); -} \ No newline at end of file +} From 1c47231bfd8db63eadc750c5a5852c0d1bd8038a Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 13 Feb 2025 09:58:43 +0100 Subject: [PATCH 12/80] CWiFi: add missing return value to disconnect() --- libraries/WiFi/src/WiFi.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/WiFi/src/WiFi.cpp b/libraries/WiFi/src/WiFi.cpp index 8417aaecd..ba19f311c 100644 --- a/libraries/WiFi/src/WiFi.cpp +++ b/libraries/WiFi/src/WiFi.cpp @@ -156,7 +156,10 @@ void CWifi::setHostname(const char* name) { /* -------------------------------------------------------------------------- */ int CWifi::disconnect() { /* -------------------------------------------------------------------------- */ - CLwipIf::getInstance().disconnectFromAp(); + if(CLwipIf::getInstance().disconnectFromAp() == ESP_CONTROL_OK) { + return 1; + } + return 0; } /* -------------------------------------------------------------------------- */ From 135fffcf55716736cda842132c209437bf336f78 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 19 Feb 2025 14:18:54 +0100 Subject: [PATCH 13/80] Revert "freertos: declare start_freertos_on_header_inclusion only if required" This reverts commit b83fd201289ab7925d9062064f605dcee2372d20. --- libraries/Arduino_FreeRTOS/src/portable/FSP/port.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c b/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c index 3fd8c53c9..598de672d 100644 --- a/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c +++ b/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c @@ -225,7 +225,6 @@ static void prvTaskExitError(void); #endif -#ifdef PROVIDE_FREERTOS_HOOK void loop_thread_func(void* arg) { while (1) { @@ -246,7 +245,6 @@ void start_freertos_on_header_inclusion() { vTaskStartScheduler(); } -#endif /* Arduino specific overrides */ void delay(uint32_t ms) { From 117ce05bedcf63c9d03457ada59a34f806f96b60 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 19 Feb 2025 14:19:02 +0100 Subject: [PATCH 14/80] Revert "Provide FreeRTOS hook only for PortentaC33" This reverts commit acb578e2610d7566f39fd0e8419ff38e460798a2. --- boards.txt | 2 +- cores/arduino/main.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/boards.txt b/boards.txt index b6815e8d9..d89c412aa 100644 --- a/boards.txt +++ b/boards.txt @@ -12,7 +12,7 @@ portenta_c33.build.fpu=-mfpu=fpv5-sp-d16 portenta_c33.build.float-abi=-mfloat-abi=hard portenta_c33.build.board=PORTENTA_C33 -portenta_c33.build.defines=-DF_CPU=200000000 -DPROVIDE_FREERTOS_HOOK +portenta_c33.build.defines=-DF_CPU=200000000 portenta_c33.vid.0=0x2341 portenta_c33.pid.0=0x0068 portenta_c33.vid.1=0x2341 diff --git a/cores/arduino/main.cpp b/cores/arduino/main.cpp index 24dfa3ec8..1d8c1386a 100644 --- a/cores/arduino/main.cpp +++ b/cores/arduino/main.cpp @@ -113,9 +113,7 @@ void arduino_main(void) #endif startAgt(); setup(); -#ifdef PROVIDE_FREERTOS_HOOK start_freertos_on_header_inclusion(); -#endif while (1) { loop(); From 4bd9c6f4ab73574a4f2ab20b0f1224b7f9ee06a0 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 19 Feb 2025 14:19:10 +0100 Subject: [PATCH 15/80] Revert "Move freertos hook between setup() and loop()" This reverts commit 3a3cfe47b5ad977dd1cbf73eb8cad299edd02f37. --- cores/arduino/main.cpp | 2 +- libraries/Arduino_FreeRTOS/src/portable/FSP/port.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cores/arduino/main.cpp b/cores/arduino/main.cpp index 1d8c1386a..8a1e1b2ff 100644 --- a/cores/arduino/main.cpp +++ b/cores/arduino/main.cpp @@ -112,8 +112,8 @@ void arduino_main(void) Serial.begin(115200); #endif startAgt(); - setup(); start_freertos_on_header_inclusion(); + setup(); while (1) { loop(); diff --git a/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c b/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c index 598de672d..036bd6264 100644 --- a/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c +++ b/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c @@ -226,6 +226,7 @@ static void prvTaskExitError(void); #endif void loop_thread_func(void* arg) { + setup(); while (1) { loop(); From 00692e699433b59cbaf01a4ea3435848bca4024d Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 19 Feb 2025 14:19:17 +0100 Subject: [PATCH 16/80] Revert "freertos: start scheduler and loop task on header inclusion" This reverts commit fee8ca9afedb0b768ddee7264c26dd6ec76aefd5. --- cores/arduino/main.cpp | 2 -- .../Arduino_FreeRTOS/src/portable/FSP/port.c | 22 ------------------- 2 files changed, 24 deletions(-) diff --git a/cores/arduino/main.cpp b/cores/arduino/main.cpp index 8a1e1b2ff..85e228081 100644 --- a/cores/arduino/main.cpp +++ b/cores/arduino/main.cpp @@ -64,7 +64,6 @@ void unsecure_registers() { #define str(s) #s extern "C" void Stacktrace_Handler(void); -extern "C" __attribute__((weak)) void start_freertos_on_header_inclusion() {} void arduino_main(void) { @@ -112,7 +111,6 @@ void arduino_main(void) Serial.begin(115200); #endif startAgt(); - start_freertos_on_header_inclusion(); setup(); while (1) { diff --git a/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c b/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c index 036bd6264..c0b5938d0 100644 --- a/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c +++ b/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c @@ -225,28 +225,6 @@ static void prvTaskExitError(void); #endif -void loop_thread_func(void* arg) { - setup(); - while (1) - { - loop(); - } -} - -static TaskHandle_t loop_task; -void start_freertos_on_header_inclusion() { - xTaskCreate( - (TaskFunction_t)loop_thread_func, - "Loop Thread", - 4096 / 4, /* usStackDepth in words */ - NULL, /* pvParameters */ - 4, /* uxPriority */ - &loop_task /* pxCreatedTask */ - ); - - vTaskStartScheduler(); -} - /* Arduino specific overrides */ void delay(uint32_t ms) { if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) { From 71e2fd21fb68c5c0ee7d112ed4e10cbc6f4ebe39 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 19 Feb 2025 14:22:46 +0100 Subject: [PATCH 17/80] FreeRTOS: allow override startup hooks default implementation The default behaviour is do nothing: scheduler has to be started manually by the user. Use AUTOSTART_FREERTOS if you declare tasks in your setup() and use them in loop(). Use EARLY_AUTOSTART_FREERTOS if you need the scheduler to be already running in setup(). Libraries that need to use threads/semaphores during setup() (for example, to implement the usual myObj.begin(); <- this starts a thread while (!myObj) { <- this becomes true when the thread is unlocked delay(); } will need to declare EARLY_START_FREERTOS_HOOK in one of their cpp files --- cores/arduino/main.cpp | 4 +++ .../Arduino_FreeRTOS/src/Arduino_FreeRTOS.h | 21 ++++++++++++++ .../Arduino_FreeRTOS/src/portable/FSP/port.c | 28 +++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/cores/arduino/main.cpp b/cores/arduino/main.cpp index 85e228081..f73ab965b 100644 --- a/cores/arduino/main.cpp +++ b/cores/arduino/main.cpp @@ -64,6 +64,8 @@ void unsecure_registers() { #define str(s) #s extern "C" void Stacktrace_Handler(void); +extern "C" __attribute__((weak)) void start_freertos_on_header_inclusion() {} +extern "C" __attribute__((weak)) void early_start_freertos_on_header_inclusion() {} void arduino_main(void) { @@ -111,7 +113,9 @@ void arduino_main(void) Serial.begin(115200); #endif startAgt(); + early_start_freertos_on_header_inclusion(); setup(); + start_freertos_on_header_inclusion(); while (1) { loop(); diff --git a/libraries/Arduino_FreeRTOS/src/Arduino_FreeRTOS.h b/libraries/Arduino_FreeRTOS/src/Arduino_FreeRTOS.h index 8e58deddd..1edfa529a 100644 --- a/libraries/Arduino_FreeRTOS/src/Arduino_FreeRTOS.h +++ b/libraries/Arduino_FreeRTOS/src/Arduino_FreeRTOS.h @@ -27,6 +27,27 @@ extern "C" { #include "lib/FreeRTOS-Kernel-v10.5.1/semphr.h" #include "lib/FreeRTOS-Kernel-v10.5.1/task.h" #include "lib/FreeRTOS-Kernel-v10.5.1/timers.h" +#include + + +// If you need to automatically start FREERTOS, declare either EARLY_AUTOSTART_FREERTOS or +// AUTOSTART_FREERTOS in your library or sketch code (.ino or .cpp file) +// +// EARLY_AUTOSTART_FREERTOS -> if you need the scheduler to be already running in setup() +// AUTOSTART_FREERTOS -> if you only declare the threads in setup() and use them in loop() + +void _start_freertos_on_header_inclusion_impl(bool early_start); +void early_start_freertos_on_header_inclusion(); +void start_freertos_on_header_inclusion(); +#define EARLY_AUTOSTART_FREERTOS \ + void early_start_freertos_on_header_inclusion() { \ + _start_freertos_on_header_inclusion_impl(true); \ + } +#define AUTOSTART_FREERTOS \ + void start_freertos_on_header_inclusion() { \ + _start_freertos_on_header_inclusion_impl(false); \ + } + #ifdef __cplusplus } diff --git a/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c b/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c index c0b5938d0..a4d3c6fef 100644 --- a/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c +++ b/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c @@ -32,6 +32,7 @@ #include "FreeRTOSConfig.h" #include "../../lib/FreeRTOS-Kernel-v10.5.1/FreeRTOS.h" #include "../../lib/FreeRTOS-Kernel-v10.5.1/task.h" +#include "portmacro.h" #if BSP_TZ_NONSECURE_BUILD #include "tz_context.h" @@ -225,6 +226,33 @@ static void prvTaskExitError(void); #endif + +static void sketch_thread_func(void* arg) { + bool early_start = (bool)arg; + if (early_start) { + setup(); + } + while (1) + { + loop(); + } +} + +void _start_freertos_on_header_inclusion_impl(bool early_start) { + static TaskHandle_t sketch_task; + if (xTaskGetSchedulerState() != taskSCHEDULER_RUNNING) { + xTaskCreate( + (TaskFunction_t)sketch_thread_func, + "Sketch Thread", + 4096 / 4, /* usStackDepth in words */ + (void*)early_start, /* pvParameters */ + 4, /* uxPriority */ + &sketch_task /* pxCreatedTask */ + ); + vTaskStartScheduler(); + } +} + /* Arduino specific overrides */ void delay(uint32_t ms) { if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) { From 11fb7288fabc59e5b3c5c363999caee6dc2b48e2 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 19 Feb 2025 14:48:48 +0100 Subject: [PATCH 18/80] FreeRTOS port: add setup() and loop() extern declaration --- libraries/Arduino_FreeRTOS/src/portable/FSP/port.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c b/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c index a4d3c6fef..f2b59f9b2 100644 --- a/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c +++ b/libraries/Arduino_FreeRTOS/src/portable/FSP/port.c @@ -226,6 +226,8 @@ static void prvTaskExitError(void); #endif +extern void setup(void); +extern void loop(void); static void sketch_thread_func(void* arg) { bool early_start = (bool)arg; From 1b67e53bbeef7af023706594d2ee83b3eb3d0645 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 13 Feb 2025 11:12:16 +0100 Subject: [PATCH 19/80] WiFiS3: add missing WL*_LENGTH definitions --- libraries/WiFiS3/src/WiFi.h | 2 -- libraries/WiFiS3/src/WiFiTypes.h | 46 +++++++++++++++++++------------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/libraries/WiFiS3/src/WiFi.h b/libraries/WiFiS3/src/WiFi.h index 2b733cfab..2643c2254 100644 --- a/libraries/WiFiS3/src/WiFi.h +++ b/libraries/WiFiS3/src/WiFi.h @@ -17,9 +17,7 @@ #define DEFAULT_GW_AP_ADDRESS IPAddress(192,168,1,1) #define DEFAULT_NM_AP_ADDRESS IPAddress(255,255,255,0) - #define WIFI_FIRMWARE_LATEST_VERSION "0.4.1" -#define WL_MAC_ADDR_LENGTH 6 class CAccessPoint { public: diff --git a/libraries/WiFiS3/src/WiFiTypes.h b/libraries/WiFiS3/src/WiFiTypes.h index d72acd95a..8848e4c26 100644 --- a/libraries/WiFiS3/src/WiFiTypes.h +++ b/libraries/WiFiS3/src/WiFiTypes.h @@ -1,19 +1,30 @@ #ifndef WIFI_S3_TYPES_H #define WIFI_S3_TYPES_H +// Maximum size of a SSID +#define WL_SSID_MAX_LENGTH 32 +// Length of passphrase. Valid lengths are 8-63. +#define WL_WPA_KEY_MAX_LENGTH 63 +// Length of key in bytes. Valid values are 5 and 13. +#define WL_WEP_KEY_MAX_LENGTH 13 +// Size of a MAC-address or BSSID +#define WL_MAC_ADDR_LENGTH 6 +// Size of a MAC-address or BSSID +#define WL_IPV4_LENGTH 4 + typedef enum { - WL_NO_SHIELD = 255, - WL_NO_MODULE = WL_NO_SHIELD, - WL_IDLE_STATUS = 0, - WL_NO_SSID_AVAIL, - WL_SCAN_COMPLETED, - WL_CONNECTED, - WL_CONNECT_FAILED, - WL_CONNECTION_LOST, - WL_DISCONNECTED, - WL_AP_LISTENING, - WL_AP_CONNECTED, - WL_AP_FAILED + WL_NO_SHIELD = 255, + WL_NO_MODULE = WL_NO_SHIELD, + WL_IDLE_STATUS = 0, + WL_NO_SSID_AVAIL, + WL_SCAN_COMPLETED, + WL_CONNECTED, + WL_CONNECT_FAILED, + WL_CONNECTION_LOST, + WL_DISCONNECTED, + WL_AP_LISTENING, + WL_AP_CONNECTED, + WL_AP_FAILED } wl_status_t; /* Encryption modes */ @@ -27,15 +38,14 @@ enum wl_enc_type { ENC_TYPE_WPA3, ENC_TYPE_NONE, ENC_TYPE_AUTO, - ENC_TYPE_UNKNOWN = 255 }; typedef enum { - WL_PING_DEST_UNREACHABLE = -1, - WL_PING_TIMEOUT = -2, - WL_PING_UNKNOWN_HOST = -3, - WL_PING_ERROR = -4 -} wl_ping_result_t; + WL_PING_DEST_UNREACHABLE = -1, + WL_PING_TIMEOUT = -2, + WL_PING_UNKNOWN_HOST = -3, + WL_PING_ERROR = -4 +}wl_ping_result_t; #endif \ No newline at end of file From 3581fc2471091e2f928caebbcd784be8bacb8b23 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 13 Feb 2025 11:13:14 +0100 Subject: [PATCH 20/80] WiFiC3: add missing WL*_LENGTH definitions --- libraries/lwIpWrapper/src/CNetIf.cpp | 6 +++--- libraries/lwIpWrapper/src/CNetIf.h | 11 +++++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libraries/lwIpWrapper/src/CNetIf.cpp b/libraries/lwIpWrapper/src/CNetIf.cpp index 680b1f992..86b02edce 100644 --- a/libraries/lwIpWrapper/src/CNetIf.cpp +++ b/libraries/lwIpWrapper/src/CNetIf.cpp @@ -537,17 +537,17 @@ int CLwipIf::getMacAddress(NetIfType_t type, uint8_t* mac) MAC.mode = WIFI_MODE_STA; if (CEspControl::getInstance().getWifiMacAddress(MAC) == ESP_CONTROL_OK) { CNetUtilities::macStr2macArray(mac, MAC.mac); - rv = MAC_ADDRESS_DIM; + rv = WL_MAC_ADDR_LENGTH; } } else if (type == NI_WIFI_SOFTAP) { MAC.mode = WIFI_MODE_AP; if (CEspControl::getInstance().getWifiMacAddress(MAC) == ESP_CONTROL_OK) { CNetUtilities::macStr2macArray(mac, MAC.mac); - rv = MAC_ADDRESS_DIM; + rv = WL_MAC_ADDR_LENGTH; } } else { eth_get_mac_address(mac); - rv = MAC_ADDRESS_DIM; + rv = WL_MAC_ADDR_LENGTH; } CLwipIf::getInstance().restartAsyncRequest(); diff --git a/libraries/lwIpWrapper/src/CNetIf.h b/libraries/lwIpWrapper/src/CNetIf.h index 2fa090bba..0616b724b 100644 --- a/libraries/lwIpWrapper/src/CNetIf.h +++ b/libraries/lwIpWrapper/src/CNetIf.h @@ -34,14 +34,21 @@ #endif #define MAX_SOFAT_CONNECTION_DEF 5 - -#define MAC_ADDRESS_DIM 6 #define NETWORK_INTERFACES_MAX_NUM 3 #define MAX_HOSTNAME_DIM 253 #define WIFI_INIT_TIMEOUT_MS 10000 +// Maximum size of a SSID +#define WL_SSID_MAX_LENGTH 32 +// Length of passphrase. Valid lengths are 8-63. +#define WL_WPA_KEY_MAX_LENGTH 63 +// Length of key in bytes. Valid values are 5 and 13. +#define WL_WEP_KEY_MAX_LENGTH 13 +// Size of a MAC-address or BSSID #define WL_MAC_ADDR_LENGTH 6 +// Size of a MAC-address or BSSID +#define WL_IPV4_LENGTH 4 /* DEFAULT ADDRESS FOR ETHERNET CONFIGURATION */ From f65e3ef881930b482e04841ef51a34d4dfd591ff Mon Sep 17 00:00:00 2001 From: Mattia Pennasilico Date: Wed, 19 Feb 2025 17:37:53 +0100 Subject: [PATCH 21/80] WiFiS3: fix comment about IP4 address length Co-authored-by: Daniele <34984733+maidnl@users.noreply.github.com> --- libraries/WiFiS3/src/WiFiTypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/WiFiS3/src/WiFiTypes.h b/libraries/WiFiS3/src/WiFiTypes.h index 8848e4c26..8bd0b8d08 100644 --- a/libraries/WiFiS3/src/WiFiTypes.h +++ b/libraries/WiFiS3/src/WiFiTypes.h @@ -9,7 +9,7 @@ #define WL_WEP_KEY_MAX_LENGTH 13 // Size of a MAC-address or BSSID #define WL_MAC_ADDR_LENGTH 6 -// Size of a MAC-address or BSSID +// Size of a IP4 address #define WL_IPV4_LENGTH 4 typedef enum { From b5bb105cb66dea94f9e8971c303a8e8d83ac97b6 Mon Sep 17 00:00:00 2001 From: Mattia Pennasilico Date: Wed, 19 Feb 2025 17:38:22 +0100 Subject: [PATCH 22/80] lwIpWrapper: fix comment about IP4 address length Co-authored-by: Daniele <34984733+maidnl@users.noreply.github.com> --- libraries/lwIpWrapper/src/CNetIf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/lwIpWrapper/src/CNetIf.h b/libraries/lwIpWrapper/src/CNetIf.h index 0616b724b..9f8bd404a 100644 --- a/libraries/lwIpWrapper/src/CNetIf.h +++ b/libraries/lwIpWrapper/src/CNetIf.h @@ -47,7 +47,7 @@ #define WL_WEP_KEY_MAX_LENGTH 13 // Size of a MAC-address or BSSID #define WL_MAC_ADDR_LENGTH 6 -// Size of a MAC-address or BSSID +// Size of a IP4 address #define WL_IPV4_LENGTH 4 /* DEFAULT ADDRESS FOR ETHERNET CONFIGURATION */ From ced8e5bd1ff6915bd1dafd04c4c781e0734d75d9 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 14 Feb 2025 10:41:34 +0100 Subject: [PATCH 23/80] EspSpiDriver: remove empty unused function --- libraries/ESPhost/src/EspSpiDriver.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/libraries/ESPhost/src/EspSpiDriver.cpp b/libraries/ESPhost/src/EspSpiDriver.cpp index 26b3a4532..5644f6cf3 100644 --- a/libraries/ESPhost/src/EspSpiDriver.cpp +++ b/libraries/ESPhost/src/EspSpiDriver.cpp @@ -124,7 +124,6 @@ static spi_event_t _spi_cb_status = SPI_EVENT_TRANSFER_ABORTED; * ############################# */ static void spi_callback(spi_callback_args_t *p_args); -static void ext_irq_callback(void); /* execute SPI communication, send the content of tx_buffer to ESP32, put the @@ -534,9 +533,3 @@ static void spi_callback(spi_callback_args_t *p_args) { _spi_cb_status = SPI_EVENT_TRANSFER_ABORTED; } } - -/* -------------------------------------------------------------------------- */ -static void ext_irq_callback(void) { -/* -------------------------------------------------------------------------- */ - -} \ No newline at end of file From bb7b0f44b64c44bd161f041ae4a415b924531369 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 14 Feb 2025 10:42:09 +0100 Subject: [PATCH 24/80] CMsg: fix ctor initialization order --- libraries/ESPhost/src/CMsg.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/ESPhost/src/CMsg.cpp b/libraries/ESPhost/src/CMsg.cpp index 1b71dac93..66e2055da 100644 --- a/libraries/ESPhost/src/CMsg.cpp +++ b/libraries/ESPhost/src/CMsg.cpp @@ -85,16 +85,16 @@ void CMsg::reset_without_delete() { /* -------------------------------------------------------------------------- */ -CMsg::CMsg() : buf{nullptr}, dim{0}, payload_header{nullptr}, proto_dim{0}, tlv_size(esp_tlv_header_size) { +CMsg::CMsg() : buf{nullptr}, dim{0}, proto_dim{0}, payload_header{nullptr}, tlv_size(esp_tlv_header_size) { } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -CMsg::CMsg(uint16_t proto_size, bool use_tlv /*= true*/) : buf{nullptr}, - dim{0}, - payload_header{nullptr}, - proto_dim{proto_size} { +CMsg::CMsg(uint16_t proto_size, bool use_tlv /*= true*/) : buf{nullptr}, + dim{0}, + proto_dim{proto_size}, + payload_header{nullptr} { /* -------------------------------------------------------------------------- */ uint16_t request_size = 0; if(use_tlv) { From 44c347af266564206e34f0a076cde6e2f50f0662 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 14 Feb 2025 10:42:36 +0100 Subject: [PATCH 25/80] CMsg: add missing return value to move operator --- libraries/ESPhost/src/CMsg.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/ESPhost/src/CMsg.cpp b/libraries/ESPhost/src/CMsg.cpp index 66e2055da..68ecc037d 100644 --- a/libraries/ESPhost/src/CMsg.cpp +++ b/libraries/ESPhost/src/CMsg.cpp @@ -204,6 +204,7 @@ CMsg& CMsg::operator=(CMsg&& m) { Serial.println(" bad!"); #endif } + return *this; } From c1d6de3eb8e2d9993005a4e26dc110e5cc2f6701 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 14 Feb 2025 10:43:00 +0100 Subject: [PATCH 26/80] CMsg: suppress unused variable warning --- libraries/ESPhost/src/CMsg.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/ESPhost/src/CMsg.cpp b/libraries/ESPhost/src/CMsg.cpp index 68ecc037d..b2e0f5297 100644 --- a/libraries/ESPhost/src/CMsg.cpp +++ b/libraries/ESPhost/src/CMsg.cpp @@ -443,6 +443,7 @@ void CMsg::debug_print(const char* title) { /* -------------------------------------------------------------------------- */ bool CMsg::store_rx_buffer(const uint8_t *buffer, uint32_t d) { /* -------------------------------------------------------------------------- */ + (void)d; /* rx_payload_len is TLV + PROTO (tlv can be present or not) */ uint16_t rx_payload_len = verify_payload_header(buffer); From 2a8b191a89ada3900e3eb8b36f42b133c1147921 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 14 Feb 2025 10:43:28 +0100 Subject: [PATCH 27/80] CMsg: add missing return value to add_msg --- libraries/ESPhost/src/CMsg.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/ESPhost/src/CMsg.cpp b/libraries/ESPhost/src/CMsg.cpp index b2e0f5297..bc7c71959 100644 --- a/libraries/ESPhost/src/CMsg.cpp +++ b/libraries/ESPhost/src/CMsg.cpp @@ -500,6 +500,7 @@ bool CMsg::add_msg(CMsg &msg) { return false; } } + return true; } /* -------------------------------------------------------------------------- */ From a07302437a589d76563232f97c4a7bfda4c25902 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 13 Feb 2025 12:35:21 +0100 Subject: [PATCH 28/80] CEthernet: suppress unused variable warning --- libraries/Ethernet/src/Ethernet.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/Ethernet/src/Ethernet.cpp b/libraries/Ethernet/src/Ethernet.cpp index c63635096..993ea2372 100644 --- a/libraries/Ethernet/src/Ethernet.cpp +++ b/libraries/Ethernet/src/Ethernet.cpp @@ -123,6 +123,8 @@ int CEthernet::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_ser /* -------------------------------------------------------------------------- */ int CEthernet::begin(uint8_t *mac, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet, unsigned long timeout, unsigned long responseTimeout) { /* -------------------------------------------------------------------------- */ + (void)responseTimeout; + (void)timeout; CLwipIf::getInstance().setMacAddress(NI_ETHERNET, mac); return begin(local_ip, dns_server, gateway, subnet); } From c36e24a435a27b4f6b1b82938e66b4c59c03cbb6 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 13 Feb 2025 12:36:01 +0100 Subject: [PATCH 29/80] EthernetDriver: remove line with no effect --- libraries/Ethernet/src/EthernetDriver.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/Ethernet/src/EthernetDriver.cpp b/libraries/Ethernet/src/EthernetDriver.cpp index 70eaf43d1..4a1115d82 100644 --- a/libraries/Ethernet/src/EthernetDriver.cpp +++ b/libraries/Ethernet/src/EthernetDriver.cpp @@ -195,7 +195,6 @@ void eth_reset_due_to_ADE_bit() { /* -------------------------------------------------------------------------- */ void EthernetDriver::irq_callback(ether_callback_args_t * p_args) { /* -------------------------------------------------------------------------- */ - p_args->status_ecsr; uint32_t reg_eesr = p_args->status_eesr; if(p_args->channel == ETHERNET_CHANNEL) { if(p_args->event == ETHER_EVENT_WAKEON_LAN) { From c439b6e4f2b1811ba6f841f3b0df18c9497f27ee Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 13 Feb 2025 12:37:33 +0100 Subject: [PATCH 30/80] EthernetClock: fix stop() logic to avoid missing return value warning --- libraries/Ethernet/src/EthernetClock.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/libraries/Ethernet/src/EthernetClock.cpp b/libraries/Ethernet/src/EthernetClock.cpp index a38fbe5ea..aa5e3f39f 100644 --- a/libraries/Ethernet/src/EthernetClock.cpp +++ b/libraries/Ethernet/src/EthernetClock.cpp @@ -49,17 +49,14 @@ fsp_err_t EthernetClock::stop() { fsp_err_t err = R_AGT_Stop(&this->TIMER_ETHERNET_ctrl); if (err != FSP_SUCCESS) { return err; - } else { - err = R_AGT_Close(&this->TIMER_ETHERNET_ctrl); - if (err != FSP_SUCCESS) { - return err; - } else { - err = R_AGT_Disable(&this->TIMER_ETHERNET_ctrl); - if (err != FSP_SUCCESS) { - return err; - } - } } + + err = R_AGT_Close(&this->TIMER_ETHERNET_ctrl); + if (err != FSP_SUCCESS) { + return err; + } + + return R_AGT_Disable(&this->TIMER_ETHERNET_ctrl); } #else From 1710f5193e7b55c8b2a8725c96859a10e73eb879 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 13 Feb 2025 09:06:51 +0100 Subject: [PATCH 31/80] CNetIf: suppress unused variable warning in getBSSID dummy implementation --- libraries/lwIpWrapper/src/CNetIf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/lwIpWrapper/src/CNetIf.h b/libraries/lwIpWrapper/src/CNetIf.h index 9f8bd404a..407501b72 100644 --- a/libraries/lwIpWrapper/src/CNetIf.h +++ b/libraries/lwIpWrapper/src/CNetIf.h @@ -215,7 +215,7 @@ class CNetIf { /* default dummy implementation because ethernet does not have that */ virtual const char* getSSID() { return nullptr; } - virtual uint8_t* getBSSID(uint8_t* bssid) { return nullptr; } + virtual uint8_t* getBSSID(uint8_t* bssid) { (void)bssid; return nullptr; } virtual int32_t getRSSI() { return 0; } virtual uint8_t getEncryptionType() { return 0; } From bb800ba347abad19651b62565bcc56eeff220158 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 13 Feb 2025 09:11:04 +0100 Subject: [PATCH 32/80] CNetIf: remove unused static variable --- libraries/lwIpWrapper/src/CNetIf.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/lwIpWrapper/src/CNetIf.cpp b/libraries/lwIpWrapper/src/CNetIf.cpp index 86b02edce..134b613d0 100644 --- a/libraries/lwIpWrapper/src/CNetIf.cpp +++ b/libraries/lwIpWrapper/src/CNetIf.cpp @@ -224,7 +224,6 @@ CNetIf* CLwipIf::get(NetIfType_t type, IPAddress _nm) { /* -------------------------------------------------------------------------- */ - static int id = 0; CNetIf* rv = nullptr; bool isStation = true; bool isEth = false; From 0603b0c5c692a7d5a55b7ccda172044181d52e0b Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 13 Feb 2025 09:18:33 +0100 Subject: [PATCH 33/80] CNetIf: fix ctor initializers order --- libraries/lwIpWrapper/src/CNetIf.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/lwIpWrapper/src/CNetIf.cpp b/libraries/lwIpWrapper/src/CNetIf.cpp index 134b613d0..ee8b97a0e 100644 --- a/libraries/lwIpWrapper/src/CNetIf.cpp +++ b/libraries/lwIpWrapper/src/CNetIf.cpp @@ -1024,11 +1024,11 @@ uint8_t CLwipIf::getEncryptionType(NetIfType_t type) /* -------------------------------------------------------------------------- */ CNetIf::CNetIf() - : dhcp_timeout(30000) + : id(0) + , dhcp_timeout(30000) + , dhcp_st(DHCP_IDLE_STATUS) , dhcp_started(false) , dhcp_acquired(false) - , id(0) - , dhcp_st(DHCP_IDLE_STATUS) , _dhcp_lease_state(DHCP_CHECK_NONE) { /* -------------------------------------------------------------------------- */ From 8b1513f802e23dea018ab1dba776f48a1e0d123d Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 13 Feb 2025 15:51:32 +0100 Subject: [PATCH 34/80] lwipClient: suppress unused variable warning --- libraries/lwIpWrapper/src/lwipClient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/lwIpWrapper/src/lwipClient.cpp b/libraries/lwIpWrapper/src/lwipClient.cpp index 745f4d504..9172db35f 100644 --- a/libraries/lwIpWrapper/src/lwipClient.cpp +++ b/libraries/lwIpWrapper/src/lwipClient.cpp @@ -19,6 +19,7 @@ sketches but sock is ignored. */ lwipClient::lwipClient(uint8_t sock) : _tcp_client(NULL) { + (void)sock; } /* -------------------------------------------------------------------------- */ From ee4551305c841b0ace0f5225b2c5934638daa8cf Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 13 Feb 2025 16:15:51 +0100 Subject: [PATCH 35/80] lwipDhcpServer: delete unused variables --- libraries/lwIpWrapper/src/lwipDhcpServer.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/libraries/lwIpWrapper/src/lwipDhcpServer.c b/libraries/lwIpWrapper/src/lwipDhcpServer.c index 9589c2847..e68edfa4c 100644 --- a/libraries/lwIpWrapper/src/lwipDhcpServer.c +++ b/libraries/lwIpWrapper/src/lwipDhcpServer.c @@ -74,13 +74,6 @@ static struct netif *dhcps_netif = NULL; static struct udp_pcb *dhcps_pcb; static DHCP_Address dhcp_address; - -static uint8_t xid[4]; - - -//static list_node *plist = NULL; -static bool renew = false; - static dhcps_lease_t dhcps_poll; static dhcps_time_t dhcps_lease_time = DHCPS_LEASE_TIME_DEF; //minute static dhcps_offer_t dhcps_offer = 0xFF; @@ -350,9 +343,7 @@ static void send_offer(struct dhcps_msg *msg, uint16_t len) struct pbuf *p, *q; uint8_t *data; uint16_t cnt = 0; - uint8_t CopyFinished=0; uint16_t i; - uint32_t endptr , dataptr = NULL; #if DHCPS_DEBUG err_t SendOffer_err_t; #endif @@ -666,8 +657,6 @@ static void handle_dhcp(void *arg, { struct dhcps_msg *pmsg_dhcps = NULL; int16_t tlen, malloc_len; - uint16_t i; - uint16_t dhcps_msg_cnt = 0; uint8_t *p_dhcps_msg = NULL; struct pbuf *q; From da684a43d73be24503039d7197151979d7b5859c Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 13 Feb 2025 16:17:13 +0100 Subject: [PATCH 36/80] lwipDhcpServer: avoid redefinitions --- libraries/lwIpWrapper/src/lwipDhcpServer.c | 52 +++++----------------- 1 file changed, 12 insertions(+), 40 deletions(-) diff --git a/libraries/lwIpWrapper/src/lwipDhcpServer.c b/libraries/lwIpWrapper/src/lwipDhcpServer.c index e68edfa4c..dc00d3cc0 100644 --- a/libraries/lwIpWrapper/src/lwipDhcpServer.c +++ b/libraries/lwIpWrapper/src/lwipDhcpServer.c @@ -1,8 +1,5 @@ #include #include - - - #include "lwipDhcpServer.h" #include "lwipDhcpServerPriv.h" @@ -11,37 +8,12 @@ static const u32_t magic_cookie = 0x63538263; #define BOOTP_BROADCAST 0x8000 -#define DHCP_REQUEST 1 -#define DHCP_REPLY 2 #define DHCP_HTYPE_ETHERNET 1 -#define DHCP_HLEN_ETHERNET 6 -#define DHCP_MSG_LEN 236 #define DHCPS_SERVER_PORT 67 #define DHCPS_CLIENT_PORT 68 -#define DHCPDISCOVER 1 -#define DHCPOFFER 2 -#define DHCPREQUEST 3 -#define DHCPDECLINE 4 -#define DHCPACK 5 -#define DHCPNAK 6 -#define DHCPRELEASE 7 - -#define DHCP_OPTION_SUBNET_MASK 1 -#define DHCP_OPTION_ROUTER 3 -#define DHCP_OPTION_DNS_SERVER 6 -#define DHCP_OPTION_REQ_IPADDR 50 -#define DHCP_OPTION_LEASE_TIME 51 -#define DHCP_OPTION_MSG_TYPE 53 -#define DHCP_OPTION_SERVER_ID 54 -#define DHCP_OPTION_INTERFACE_MTU 26 #define DHCP_OPTION_PERFORM_ROUTER_DISCOVERY 31 -#define DHCP_OPTION_BROADCAST_ADDRESS 28 -#define DHCP_OPTION_REQ_LIST 55 -#define DHCP_OPTION_END 255 - - #ifdef DHCPS_DEBUG /* function defined in CNetIf.cpp */ @@ -184,7 +156,7 @@ void dhcps_set_option_info(uint8_t op_id, void *opt_info, u32_t opt_len) *******************************************************************************/ static uint8_t *add_msg_type(uint8_t *optptr, uint8_t type) { - *optptr++ = DHCP_OPTION_MSG_TYPE; + *optptr++ = DHCP_OPTION_MESSAGE_TYPE; *optptr++ = 1; *optptr++ = type; return optptr; @@ -253,7 +225,7 @@ static uint8_t *add_offer_options(uint8_t *optptr) } - *optptr++ = DHCP_OPTION_INTERFACE_MTU; + *optptr++ = DHCP_OPTION_MTU; *optptr++ = 2; *optptr++ = 0x05; *optptr++ = 0xdc; @@ -294,7 +266,7 @@ static uint8_t *add_end(uint8_t *optptr) *******************************************************************************/ static void create_msg(struct dhcps_msg *m) { - m->op = DHCP_REPLY; + m->op = DHCP_BOOTREPLY; m->htype = DHCP_HTYPE_ETHERNET; @@ -348,7 +320,7 @@ static void send_offer(struct dhcps_msg *msg, uint16_t len) err_t SendOffer_err_t; #endif create_msg(msg); - end = add_msg_type(&msg->options[4], DHCPOFFER); + end = add_msg_type(&msg->options[4], DHCP_OFFER); end = add_offer_options(end); end = add_end(end); @@ -418,7 +390,7 @@ static void send_nak(struct dhcps_msg *m, uint16_t len) #endif create_msg(m); - end = add_msg_type(&m->options[4], DHCPNAK); + end = add_msg_type(&m->options[4], DHCP_NAK); end = add_end(end); p = dhcps_pbuf_alloc(len); @@ -482,7 +454,7 @@ static void send_ack(struct dhcps_msg *m, uint16_t len) err_t SendAck_err_t; create_msg(m); - end = add_msg_type(&m->options[4], DHCPACK); + end = add_msg_type(&m->options[4], DHCP_ACK); end = add_offer_options(end); end = add_end(end); @@ -564,10 +536,10 @@ static uint8_t parse_options(uint8_t *OptionsPtr, int16_t len) DHCPS_LOG("dhcps: (int16_t)*optptr = %d\n", (int16_t)*OptionsPtr); #endif switch ((int16_t) *OptionsPtr) { - case DHCP_OPTION_MSG_TYPE: //53 + case DHCP_OPTION_MESSAGE_TYPE://53 type = *(OptionsPtr + 2); break; - case DHCP_OPTION_REQ_IPADDR://50 + case DHCP_OPTION_REQUESTED_IP://50 s.state = DHCPS_STATE_ACK; break; case DHCP_OPTION_END: { @@ -583,26 +555,26 @@ static uint8_t parse_options(uint8_t *OptionsPtr, int16_t len) } switch (type) { - case DHCPDISCOVER://1 + case DHCP_DISCOVER://1 #if DHCPS_DEBUG DHCPS_LOG("dhcps: DHCPD_STATE_DHCPDISCOVER -- SEND_OFFER\n"); #endif s.state = DHCPS_STATE_OFFER; break; - case DHCPREQUEST://3 + case DHCP_REQUEST://3 #if DHCPS_DEBUG DHCPS_LOG("dhcps: DHCPD_STATE_DHCPREQUEST -- SEND_ACK\n"); #endif s.state = DHCPS_STATE_ACK; break; - case DHCPDECLINE://4 + case DHCP_DECLINE://4 s.state = DHCPS_STATE_IDLE; #if DHCPS_DEBUG DHCPS_LOG("dhcps: DHCPD_STATE_IDLE\n"); #endif break; - case DHCPRELEASE://7 + case DHCP_RELEASE://7 s.state = DHCPS_STATE_RELEASE; #if DHCPS_DEBUG DHCPS_LOG("dhcps: DHCPD_STATE_IDLE\n"); From 6c3359f4e0bf81075834977026acbf70d64925d1 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 13 Feb 2025 16:18:37 +0100 Subject: [PATCH 37/80] lwipDhcpServer: suppress unused variable warning --- libraries/lwIpWrapper/src/lwipDhcpServer.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libraries/lwIpWrapper/src/lwipDhcpServer.c b/libraries/lwIpWrapper/src/lwipDhcpServer.c index dc00d3cc0..64f6846a0 100644 --- a/libraries/lwIpWrapper/src/lwipDhcpServer.c +++ b/libraries/lwIpWrapper/src/lwipDhcpServer.c @@ -311,6 +311,7 @@ struct pbuf * dhcps_pbuf_alloc(uint16_t len) *******************************************************************************/ static void send_offer(struct dhcps_msg *msg, uint16_t len) { + (void)len; uint8_t *end; struct pbuf *p, *q; uint8_t *data; @@ -380,6 +381,7 @@ static void send_offer(struct dhcps_msg *msg, uint16_t len) *******************************************************************************/ static void send_nak(struct dhcps_msg *m, uint16_t len) { + (void)len; uint8_t *end; struct pbuf *p, *q; uint8_t *data; @@ -446,6 +448,7 @@ static void send_nak(struct dhcps_msg *m, uint16_t len) *******************************************************************************/ static void send_ack(struct dhcps_msg *m, uint16_t len) { + (void)len; uint8_t *end; struct pbuf *p, *q; uint8_t *data; @@ -627,6 +630,10 @@ static void handle_dhcp(void *arg, const ip_addr_t *addr, uint16_t port) { + (void)arg; + (void)pcb; + (void)addr; + (void)port; struct dhcps_msg *pmsg_dhcps = NULL; int16_t tlen, malloc_len; uint8_t *p_dhcps_msg = NULL; From fb2c94ad3b26c0f949a984a404b010f7ad3398d0 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 13 Feb 2025 17:09:47 +0100 Subject: [PATCH 38/80] CNetIf: fix limited variable range warning --- libraries/lwIpWrapper/src/CNetIf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/lwIpWrapper/src/CNetIf.cpp b/libraries/lwIpWrapper/src/CNetIf.cpp index ee8b97a0e..810b14075 100644 --- a/libraries/lwIpWrapper/src/CNetIf.cpp +++ b/libraries/lwIpWrapper/src/CNetIf.cpp @@ -228,7 +228,7 @@ CNetIf* CLwipIf::get(NetIfType_t type, bool isStation = true; bool isEth = false; - if (type >= 0 && type < NETWORK_INTERFACES_MAX_NUM) { + if (type == NI_WIFI_STATION || type == NI_WIFI_SOFTAP || type == NI_ETHERNET) { if (net_ifs[type] == nullptr) { switch (type) { case NI_WIFI_STATION: From b594eff890deda768850f2041b45325e6b1e31ad Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 13 Feb 2025 08:58:12 +0100 Subject: [PATCH 39/80] RTC: add structs missing initializers --- libraries/RTC/src/RTC.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/RTC/src/RTC.cpp b/libraries/RTC/src/RTC.cpp index 843af650c..4f5d5d240 100644 --- a/libraries/RTC/src/RTC.cpp +++ b/libraries/RTC/src/RTC.cpp @@ -435,6 +435,11 @@ void __attribute__((weak)) rtc_callback(rtc_callback_args_t *p_args) { rtc_instance_ctrl_t rtc_ctrl = { .open = 0, + .p_cfg = nullptr, + .carry_isr_triggered = false, + .p_callback = nullptr, + .p_callback_memory = nullptr, + .p_context = nullptr, }; #ifndef RTC_CLOCK_SOURCE @@ -458,6 +463,7 @@ rtc_cfg_t rtc_cfg = { .carry_irq = FSP_INVALID_VECTOR, .p_callback = rtc_callback, .p_context = NULL, + .p_extend = NULL, }; #ifdef __cplusplus From 46232cdf474e181f07c1a89105fd6778cd149a30 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 12 Feb 2025 17:03:34 +0100 Subject: [PATCH 40/80] ssl_client: remove unused parameters from ssl_stop --- libraries/SSLClient/src/SSLClient.cpp | 2 +- libraries/SSLClient/src/ssl_client.cpp | 4 ++-- libraries/SSLClient/src/ssl_client.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/SSLClient/src/SSLClient.cpp b/libraries/SSLClient/src/SSLClient.cpp index f763923a9..9496ce314 100644 --- a/libraries/SSLClient/src/SSLClient.cpp +++ b/libraries/SSLClient/src/SSLClient.cpp @@ -102,7 +102,7 @@ void SSLClient::stop() _connected = false; _peek = -1; } - stop_ssl_socket(sslclient, _CA_cert, _cert, _private_key); + stop_ssl_socket(sslclient); } int SSLClient::connect(IPAddress ip, uint16_t port) diff --git a/libraries/SSLClient/src/ssl_client.cpp b/libraries/SSLClient/src/ssl_client.cpp index 5a334ecdf..3d870bd8c 100644 --- a/libraries/SSLClient/src/ssl_client.cpp +++ b/libraries/SSLClient/src/ssl_client.cpp @@ -336,7 +336,7 @@ int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t p memset(buf, 0, sizeof(buf)); mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags); log_e("Failed to verify peer certificate! verification info: %s", buf); - stop_ssl_socket(ssl_client, rootCABuff, cli_cert, cli_key); //It's not safe continue. + stop_ssl_socket(ssl_client); //It's not safe continue. return handle_error(ret); } else { @@ -361,7 +361,7 @@ int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t p } -void stop_ssl_socket(sslclient_context *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key) +void stop_ssl_socket(sslclient_context *ssl_client) { log_v("Cleaning SSL connection."); diff --git a/libraries/SSLClient/src/ssl_client.h b/libraries/SSLClient/src/ssl_client.h index 2951e1193..93e7bbbbc 100644 --- a/libraries/SSLClient/src/ssl_client.h +++ b/libraries/SSLClient/src/ssl_client.h @@ -43,7 +43,7 @@ typedef struct sslclient_context { void ssl_init(sslclient_context *ssl_client, Client *client, const char *ca_path); int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *rootCAPath, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey, bool insecure); -void stop_ssl_socket(sslclient_context *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key); +void stop_ssl_socket(sslclient_context *ssl_client); int data_to_read(sslclient_context *ssl_client); int send_ssl_data(sslclient_context *ssl_client, const uint8_t *data, uint16_t len); int get_ssl_receive(sslclient_context *ssl_client, uint8_t *data, int length); From b0f6711fb99bfd1e6654c405830a673685e6701e Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 12 Feb 2025 17:06:07 +0100 Subject: [PATCH 41/80] ssl_client: trim text --- libraries/SSLClient/src/ssl_client.cpp | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/libraries/SSLClient/src/ssl_client.cpp b/libraries/SSLClient/src/ssl_client.cpp index 3d870bd8c..7ad11cf9a 100644 --- a/libraries/SSLClient/src/ssl_client.cpp +++ b/libraries/SSLClient/src/ssl_client.cpp @@ -52,11 +52,11 @@ static int _handle_error(int err, const char * file, int line) */ static int client_net_recv( void *ctx, unsigned char *buf, size_t len ) { Client *client = (Client*)ctx; - if (!client) { + if (!client) { log_e("Uninitialised!"); return -1; } - + //if (!client->connected()) { // log_e("Not connected!"); // return -2; @@ -68,14 +68,14 @@ static int client_net_recv( void *ctx, unsigned char *buf, size_t len ) { if (result > 0) { //esp_log_buffer_hexdump_internal("SSL.RD", buf, (uint16_t)result, ESP_LOG_VERBOSE); } - + return result; } int client_net_recv_timeout( void *ctx, unsigned char *buf, size_t len, uint32_t timeout ) { Client *client = (Client*)ctx; - if (!client) { + if (!client) { log_e("Uninitialised!"); return -1; } @@ -90,9 +90,9 @@ int client_net_recv_timeout( void *ctx, unsigned char *buf, delay(1); } else break; } while (millis() < tms); - + int result = client->read(buf, len); - + // lwIP interface return -1 if there is no data to read // report without throwing errors or block if (result <= 0) return MBEDTLS_ERR_SSL_WANT_READ; @@ -102,7 +102,7 @@ int client_net_recv_timeout( void *ctx, unsigned char *buf, if (result > 0) { //esp_log_buffer_hexdump_internal("SSL.RD", buf, (uint16_t)result, ESP_LOG_VERBOSE); } - + return result; } @@ -121,20 +121,20 @@ int client_net_recv_timeout( void *ctx, unsigned char *buf, */ static int client_net_send( void *ctx, const unsigned char *buf, size_t len ) { Client *client = (Client*)ctx; - if (!client) { + if (!client) { log_e("Uninitialised!"); return -1; } - + //if (!client->connected()) { // log_e("Not connected!"); // return -2; //} - + //esp_log_buffer_hexdump_internal("SSL.WR", buf, (uint16_t)len, ESP_LOG_VERBOSE); - + int result = client->write(buf, len); - + log_d("SSL client TX res=%d len=%d", result, len); return result; } @@ -342,7 +342,7 @@ int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t p } else { log_v("Certificate verified."); } - + if ((rootCABuff != NULL) || ((rootCAPath != NULL))) { log_d("free buffer"); mbedtls_x509_crt_free(&ssl_client->ca_cert); @@ -354,7 +354,7 @@ int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t p if (cli_key != NULL) { mbedtls_pk_free(&ssl_client->client_key); - } + } //return ssl_client->socket; return 1; From 92a80225f44c49a78a1cbcb7c1a1fa258c47ca5e Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 12 Feb 2025 17:19:58 +0100 Subject: [PATCH 42/80] sslclient: do not compile unused static function --- libraries/SSLClient/src/ssl_client.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/SSLClient/src/ssl_client.cpp b/libraries/SSLClient/src/ssl_client.cpp index 7ad11cf9a..18157066e 100644 --- a/libraries/SSLClient/src/ssl_client.cpp +++ b/libraries/SSLClient/src/ssl_client.cpp @@ -38,6 +38,7 @@ static int _handle_error(int err, const char * file, int line) #define handle_error(e) _handle_error(e, __FUNCTION__, __LINE__) +#if defined(SSL_CLIENT_RECV_DISABLE_TIMEOUT) /** * \brief Read at most 'len' characters. If no error occurs, * the actual amount read is returned. @@ -71,8 +72,8 @@ static int client_net_recv( void *ctx, unsigned char *buf, size_t len ) { return result; } - -int client_net_recv_timeout( void *ctx, unsigned char *buf, +#else +static int client_net_recv_timeout( void *ctx, unsigned char *buf, size_t len, uint32_t timeout ) { Client *client = (Client*)ctx; if (!client) { @@ -105,7 +106,7 @@ int client_net_recv_timeout( void *ctx, unsigned char *buf, return result; } - +#endif /** * \brief Write at most 'len' characters. If no error occurs, From d25db7f1d743423523ca1acf24ba1328b87c1270 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 12 Feb 2025 17:20:40 +0100 Subject: [PATCH 43/80] ssl_client: fix unsigned comparison --- libraries/SSLClient/src/ssl_client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/SSLClient/src/ssl_client.cpp b/libraries/SSLClient/src/ssl_client.cpp index 18157066e..ab02914a9 100644 --- a/libraries/SSLClient/src/ssl_client.cpp +++ b/libraries/SSLClient/src/ssl_client.cpp @@ -226,7 +226,7 @@ int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t p } unsigned char psk[MBEDTLS_PSK_MAX_LEN]; size_t psk_len = strlen(psKey)/2; - for (int j=0; j= '0' && c <= '9') c -= '0'; else if (c >= 'A' && c <= 'F') c -= 'A' - 10; From a2fbb049d47ba4e64942973961561aef50b3d2b2 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 12 Feb 2025 17:38:54 +0100 Subject: [PATCH 44/80] SSLClient: fix stop() --- libraries/SSLClient/src/SSLClient.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libraries/SSLClient/src/SSLClient.cpp b/libraries/SSLClient/src/SSLClient.cpp index 9496ce314..d62baa1fd 100644 --- a/libraries/SSLClient/src/SSLClient.cpp +++ b/libraries/SSLClient/src/SSLClient.cpp @@ -97,12 +97,9 @@ void SSLClient::setClient(Client& client) void SSLClient::stop() { - if (sslclient->client >= 0) { - //sslclient->client->stop(); - _connected = false; - _peek = -1; - } stop_ssl_socket(sslclient); + _connected = false; + _peek = -1; } int SSLClient::connect(IPAddress ip, uint16_t port) From 7922c8bc8597203101500a27237aaa159cd3c573 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 12 Feb 2025 17:40:06 +0100 Subject: [PATCH 45/80] ssl_debug: suppress unused variable warning --- libraries/SSLClient/src/ssl_debug.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/SSLClient/src/ssl_debug.cpp b/libraries/SSLClient/src/ssl_debug.cpp index e22ef0429..32f6964c3 100644 --- a/libraries/SSLClient/src/ssl_debug.cpp +++ b/libraries/SSLClient/src/ssl_debug.cpp @@ -20,7 +20,7 @@ #include "ssl_debug.h" void ssl_debug_print(const char *format, ...) { - char debug_buf[1024]; + char debug_buf[1024]; va_list argptr; va_start(argptr, format); vsnprintf(debug_buf, sizeof(debug_buf), format, argptr); @@ -29,7 +29,7 @@ void ssl_debug_print(const char *format, ...) { } void ssl_debug_println(const char *format, ...) { - char debug_buf[1024]; + char debug_buf[1024]; va_list argptr; va_start(argptr, format); vsnprintf(debug_buf, sizeof(debug_buf), format, argptr); @@ -43,6 +43,7 @@ void ssl_debug_none(const char *format, ...) { void mbedtls_debug_print(void *ctx, int level, const char *file, int line, const char *str) { + ((void) ctx); ((void) level); ssl_debug_print("%s:%04d: %s", file, line, str); } From 6a66623f6bc341d3843bcfc437ac74730ff26894 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 12 Feb 2025 17:40:58 +0100 Subject: [PATCH 46/80] ssl_debug: rename DEBUG_LEVEL to SSL_DEBUG_LEVEL --- libraries/SSLClient/src/ssl_client.cpp | 2 +- libraries/SSLClient/src/ssl_debug.h | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/SSLClient/src/ssl_client.cpp b/libraries/SSLClient/src/ssl_client.cpp index ab02914a9..bb4f0aa15 100644 --- a/libraries/SSLClient/src/ssl_client.cpp +++ b/libraries/SSLClient/src/ssl_client.cpp @@ -153,7 +153,7 @@ void ssl_init(sslclient_context *ssl_client, Client *client, const char * ca_pat mbedtls_ssl_conf_ciphersuites(&ssl_client->ssl_conf, mbedtls_ssl_list_ciphersuites()); mbedtls_ssl_conf_dbg(&ssl_client->ssl_conf, mbedtls_debug_print, NULL); - mbedtls_debug_set_threshold(DEBUG_LEVEL); + mbedtls_debug_set_threshold(SSL_DEBUG_LEVEL); mbedtls_fs_init(ca_path); } diff --git a/libraries/SSLClient/src/ssl_debug.h b/libraries/SSLClient/src/ssl_debug.h index 02d632399..7560e6f5f 100644 --- a/libraries/SSLClient/src/ssl_debug.h +++ b/libraries/SSLClient/src/ssl_debug.h @@ -29,33 +29,33 @@ * 4: DEBUG * 5: VERBOSE */ -#define DEBUG_LEVEL 1 +#define SSL_DEBUG_LEVEL 1 -#if DEBUG_LEVEL > 0 +#if SSL_DEBUG_LEVEL > 0 #define log_e ssl_debug_println #else #define log_e ssl_debug_none #endif -#if DEBUG_LEVEL > 1 +#if SSL_DEBUG_LEVEL > 1 #define log_w ssl_debug_println #else #define log_w ssl_debug_none #endif -#if DEBUG_LEVEL > 2 +#if SSL_DEBUG_LEVEL > 2 #define log_i ssl_debug_println #else #define log_i ssl_debug_none #endif -#if DEBUG_LEVEL > 3 +#if SSL_DEBUG_LEVEL > 3 #define log_d ssl_debug_println #else #define log_d ssl_debug_none #endif - -#if DEBUG_LEVEL > 4 + +#if SSL_DEBUG_LEVEL > 4 #define log_v ssl_debug_println #else #define log_v ssl_debug_none From 01cf5704648016322f29e264ece4145e5d820a3a Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 12 Feb 2025 17:49:51 +0100 Subject: [PATCH 47/80] SSLClient: fix connect using pre shared key --- libraries/SSLClient/src/SSLClient.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/SSLClient/src/SSLClient.cpp b/libraries/SSLClient/src/SSLClient.cpp index d62baa1fd..e5968cf1e 100644 --- a/libraries/SSLClient/src/SSLClient.cpp +++ b/libraries/SSLClient/src/SSLClient.cpp @@ -147,12 +147,12 @@ int SSLClient::connect(const char *host, uint16_t port, const char *_CA_cert, co } int SSLClient::connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey) { - return connect(ip.toString().c_str(), port,_pskIdent, _psKey); + return connect(ip.toString().c_str(), port, pskIdent, psKey); } int SSLClient::connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey) { log_v("start_ssl_client with PSK"); - int ret = start_ssl_client(sslclient, host, port, _timeout, NULL, NULL, NULL, NULL, _pskIdent, _psKey, _use_insecure); + int ret = start_ssl_client(sslclient, host, port, _timeout, NULL, NULL, NULL, NULL, pskIdent, psKey, _use_insecure); _lastError = ret; if (ret < 0) { log_e("start_ssl_client: %d", ret); From deca0abb6534d1ab517225fa4f6f38a2841bf311 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 14 Feb 2025 12:22:48 +0100 Subject: [PATCH 48/80] ssl_client: change type to uint16_t to store client->available() return value --- libraries/SSLClient/src/ssl_client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/SSLClient/src/ssl_client.cpp b/libraries/SSLClient/src/ssl_client.cpp index bb4f0aa15..8cbe57f2d 100644 --- a/libraries/SSLClient/src/ssl_client.cpp +++ b/libraries/SSLClient/src/ssl_client.cpp @@ -82,11 +82,11 @@ static int client_net_recv_timeout( void *ctx, unsigned char *buf, } unsigned long start = millis(); unsigned long tms = start + timeout; - int pending = client->available(); + uint16_t pending = client->available(); // If there is data in the client, wait for message completion if((pending > 0) && (pending < len)) do { - int pending = client->available(); + uint16_t pending = client->available(); if (pending < len && timeout > 0) { delay(1); } else break; From a8d4998df53303fe334c22d31ba42b77043c7371 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 14 Feb 2025 12:14:57 +0100 Subject: [PATCH 49/80] QSPIFlashBlockDevice: fix ctor init order --- libraries/BlockDevices/QSPIFlashBlockDevice.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/libraries/BlockDevices/QSPIFlashBlockDevice.h b/libraries/BlockDevices/QSPIFlashBlockDevice.h index 75f8187da..0fe19dee0 100644 --- a/libraries/BlockDevices/QSPIFlashBlockDevice.h +++ b/libraries/BlockDevices/QSPIFlashBlockDevice.h @@ -70,25 +70,27 @@ class QSPIFlashBlockDevice : public BlockDevice { private: - bool opened; - + + pin_t ck; + pin_t cs; + pin_t io0; + pin_t io1; + pin_t io2; + pin_t io3; + bd_addr_t base_address; bd_size_t total_size; bd_size_t read_block_size; bd_size_t erase_block_size; bd_size_t write_block_size; + bool opened; + bool is_address_correct(bd_addr_t add); qspi_instance_ctrl_t ctrl; spi_flash_cfg_t cfg; qspi_extended_cfg_t ext_cfg; - pin_t ck; - pin_t cs; - pin_t io0; - pin_t io1; - pin_t io2; - pin_t io3; fsp_err_t get_flash_status(); From de06a61fc9574fb5a346472af2ffb1c741bb1d8b Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 14 Feb 2025 12:15:35 +0100 Subject: [PATCH 50/80] QSPIFlashBlockDevice: fix pointer aritmetic --- libraries/BlockDevices/QSPIFlashBlockDevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/BlockDevices/QSPIFlashBlockDevice.cpp b/libraries/BlockDevices/QSPIFlashBlockDevice.cpp index 85d6de958..44c5cc094 100644 --- a/libraries/BlockDevices/QSPIFlashBlockDevice.cpp +++ b/libraries/BlockDevices/QSPIFlashBlockDevice.cpp @@ -287,7 +287,7 @@ int QSPIFlashBlockDevice::write(const void *buffer, bd_addr_t add, bd_size_t _si R_QSPI_BankSet(&ctrl, bank); rv = R_QSPI_Write(&ctrl, (uint8_t *)(buffer), (uint8_t*)address, chunk); address += chunk; - buffer += chunk; + buffer = (uint8_t *)(buffer) + chunk; if(rv == FSP_SUCCESS) { rv = get_flash_status(); From 87c7070774c13025d6ec9d7596b4e31612756d16 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 14 Feb 2025 12:16:05 +0100 Subject: [PATCH 51/80] QSPIFlashBlockDevice: fix signed/unsigned comparison --- libraries/BlockDevices/QSPIFlashBlockDevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/BlockDevices/QSPIFlashBlockDevice.cpp b/libraries/BlockDevices/QSPIFlashBlockDevice.cpp index 44c5cc094..6d8de4c6a 100644 --- a/libraries/BlockDevices/QSPIFlashBlockDevice.cpp +++ b/libraries/BlockDevices/QSPIFlashBlockDevice.cpp @@ -328,7 +328,7 @@ int QSPIFlashBlockDevice::erase(bd_addr_t add, bd_size_t _size) { uint32_t num_of_blocks = (_size / erase_block_size); - for(int i = 0; i < num_of_blocks && rv == FSP_SUCCESS; i++) { + for(uint32_t i = 0; i < num_of_blocks && rv == FSP_SUCCESS; i++) { /* set bank */ uint32_t bank = add / READ_PAGE_SIZE; uint32_t address = base_address + ((add + i * erase_block_size) % READ_PAGE_SIZE); From 2fe862edb19891d270d9e9423bfee0b50dfa8ad5 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 14 Feb 2025 12:16:31 +0100 Subject: [PATCH 52/80] SDCardBlockDevice: remove unused variable --- libraries/BlockDevices/SDCardBlockDevice.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/BlockDevices/SDCardBlockDevice.cpp b/libraries/BlockDevices/SDCardBlockDevice.cpp index 9649e0e5c..2561f9526 100644 --- a/libraries/BlockDevices/SDCardBlockDevice.cpp +++ b/libraries/BlockDevices/SDCardBlockDevice.cpp @@ -166,7 +166,6 @@ SDCardBlockDevice::~SDCardBlockDevice() { /* CALLBACK */ /* -------------------------------------------------------------------------- */ void SDCardBlockDevice::SDCardBlockDeviceCbk(sdmmc_callback_args_t *arg) { - int open_status = -1; if(arg != nullptr) { sdmmc_event_t event = arg->event; From 12b34e36b930e4bd3c17abb0972fe222caef2a3e Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 14 Feb 2025 12:16:59 +0100 Subject: [PATCH 53/80] SDCardBlockDevice: fix signed/unsigned comparison --- libraries/BlockDevices/SDCardBlockDevice.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/BlockDevices/SDCardBlockDevice.cpp b/libraries/BlockDevices/SDCardBlockDevice.cpp index 2561f9526..b410aaeaf 100644 --- a/libraries/BlockDevices/SDCardBlockDevice.cpp +++ b/libraries/BlockDevices/SDCardBlockDevice.cpp @@ -367,8 +367,8 @@ int SDCardBlockDevice::read(void *buffer, bd_addr_t add, bd_size_t _size) { uint32_t num_of_blocks = (_size / read_block_size); uint32_t start_add_of_block = (add / read_block_size); rv = FSP_SUCCESS; - for(int i = 0; i < num_of_blocks && rv == FSP_SUCCESS; i++) { - rv = R_SDHI_Read (&ctrl, (uint8_t *)(buffer + (i * read_block_size)), start_add_of_block + i, 1); + for(uint32_t i = 0; i < num_of_blocks && rv == FSP_SUCCESS; i++) { + rv = R_SDHI_Read (&ctrl, (uint8_t *)((uint8_t *)buffer + (i * read_block_size)), start_add_of_block + i, 1); if(rv == FSP_SUCCESS) { rv = wait_for_completition(); } @@ -403,8 +403,8 @@ int SDCardBlockDevice::write(const void *buffer, bd_addr_t add, bd_size_t _size) uint32_t num_of_blocks = (_size / write_block_size); uint32_t start_block_number = (add / write_block_size); rv = FSP_SUCCESS; - for(int i = 0; i < num_of_blocks && rv == FSP_SUCCESS; i++) { - rv = R_SDHI_Write (&ctrl, (uint8_t *)(buffer + (i * write_block_size)), start_block_number + i, 1); + for(uint32_t i = 0; i < num_of_blocks && rv == FSP_SUCCESS; i++) { + rv = R_SDHI_Write (&ctrl, (uint8_t *)((uint8_t *)buffer + (i * write_block_size)), start_block_number + i, 1); if(rv == FSP_SUCCESS) { rv = wait_for_completition(); } @@ -438,7 +438,7 @@ int SDCardBlockDevice::erase(bd_addr_t add, bd_size_t _size) { uint32_t num_of_blocks = (_size / erase_block_size); uint32_t start_block_number = (add / erase_block_size); rv = FSP_SUCCESS; - for(int i = 0; i < num_of_blocks && rv == FSP_SUCCESS; i++) { + for(uint32_t i = 0; i < num_of_blocks && rv == FSP_SUCCESS; i++) { rv = R_SDHI_Erase (&ctrl, start_block_number + i, 1); if(rv == FSP_SUCCESS) { rv = wait_for_completition(); From c265d86b1aedbb36a215f7f1a5a2c1790a713a40 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 14 Feb 2025 12:17:27 +0100 Subject: [PATCH 54/80] SDCardBlockDevice: fix ctor initialization order --- libraries/BlockDevices/SDCardBlockDevice.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/libraries/BlockDevices/SDCardBlockDevice.h b/libraries/BlockDevices/SDCardBlockDevice.h index 14979719a..6007e9144 100644 --- a/libraries/BlockDevices/SDCardBlockDevice.h +++ b/libraries/BlockDevices/SDCardBlockDevice.h @@ -60,13 +60,22 @@ enum class CmdStatus { class SDCardBlockDevice : public BlockDevice { private: - sdmmc_device_t sd_card_info; + pin_t ck; + pin_t cmd; + pin_t d0; + pin_t d1; + pin_t d2; + pin_t d3; + pin_t cd; + pin_t wp; bd_addr_t base_address; bd_size_t total_size; bd_size_t read_block_size; bd_size_t erase_block_size; bd_size_t write_block_size; + bool opened; sdhi_instance_ctrl_t ctrl; + sdmmc_device_t sd_card_info; sdmmc_cfg_t cfg; #ifdef USE_DMAC @@ -84,14 +93,7 @@ class SDCardBlockDevice : public BlockDevice { transfer_cfg_t dtc_cfg; transfer_instance_t dtc_instance; #endif - pin_t ck; - pin_t cmd; - pin_t d0; - pin_t d1; - pin_t d2; - pin_t d3; - pin_t cd; - pin_t wp; + static volatile bool initialized; static volatile bool card_inserted; static volatile CmdStatus st; @@ -99,7 +101,7 @@ class SDCardBlockDevice : public BlockDevice { virtual int write(const void *buffer, bd_addr_t addr, bd_size_t size) override; virtual int open() override; virtual int close() override; - bool opened; + fsp_err_t wait_for_completition(); public: From 1cee16bc2c449762f999714dcc0d5ff00e30156b Mon Sep 17 00:00:00 2001 From: Mattia Pennasilico Date: Mon, 24 Feb 2025 09:28:25 +0100 Subject: [PATCH 55/80] SDCardBlockDevice: avoid double cast Co-authored-by: Daniele <34984733+maidnl@users.noreply.github.com> --- libraries/BlockDevices/SDCardBlockDevice.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/BlockDevices/SDCardBlockDevice.cpp b/libraries/BlockDevices/SDCardBlockDevice.cpp index b410aaeaf..4a40b5976 100644 --- a/libraries/BlockDevices/SDCardBlockDevice.cpp +++ b/libraries/BlockDevices/SDCardBlockDevice.cpp @@ -368,7 +368,8 @@ int SDCardBlockDevice::read(void *buffer, bd_addr_t add, bd_size_t _size) { uint32_t start_add_of_block = (add / read_block_size); rv = FSP_SUCCESS; for(uint32_t i = 0; i < num_of_blocks && rv == FSP_SUCCESS; i++) { - rv = R_SDHI_Read (&ctrl, (uint8_t *)((uint8_t *)buffer + (i * read_block_size)), start_add_of_block + i, 1); + uint8_t *buf = (uint8_t *)buffer; + rv = R_SDHI_Read (&ctrl, buf + (i * read_block_size), start_add_of_block + i, 1); if(rv == FSP_SUCCESS) { rv = wait_for_completition(); } From e79d4ff90d720dbf1eb0fee84ae9ac43f7f005bc Mon Sep 17 00:00:00 2001 From: Mattia Pennasilico Date: Mon, 24 Feb 2025 09:29:32 +0100 Subject: [PATCH 56/80] SDCardBlockDevice: avoid double cast Co-authored-by: Daniele <34984733+maidnl@users.noreply.github.com> --- libraries/BlockDevices/SDCardBlockDevice.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/BlockDevices/SDCardBlockDevice.cpp b/libraries/BlockDevices/SDCardBlockDevice.cpp index 4a40b5976..275b5cfae 100644 --- a/libraries/BlockDevices/SDCardBlockDevice.cpp +++ b/libraries/BlockDevices/SDCardBlockDevice.cpp @@ -405,7 +405,8 @@ int SDCardBlockDevice::write(const void *buffer, bd_addr_t add, bd_size_t _size) uint32_t start_block_number = (add / write_block_size); rv = FSP_SUCCESS; for(uint32_t i = 0; i < num_of_blocks && rv == FSP_SUCCESS; i++) { - rv = R_SDHI_Write (&ctrl, (uint8_t *)((uint8_t *)buffer + (i * write_block_size)), start_block_number + i, 1); + uint8_t *buf = (uint8_t *)buffer; + rv = R_SDHI_Write (&ctrl, buf + (i * write_block_size), start_block_number + i, 1); if(rv == FSP_SUCCESS) { rv = wait_for_completition(); } From e8858c0dd62a648cc9908659c51e8ced239751af Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 24 Feb 2025 09:32:50 +0100 Subject: [PATCH 57/80] storage_common: fix signed comparison --- libraries/Storage/storage_common.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/Storage/storage_common.h b/libraries/Storage/storage_common.h index ab5258116..332472259 100644 --- a/libraries/Storage/storage_common.h +++ b/libraries/Storage/storage_common.h @@ -7,8 +7,8 @@ extern "C" { #endif -//#define STORAGE_DEBUG -//#define STORAGE_ASSERT +#define STORAGE_DEBUG +#define STORAGE_ASSERT /* -------------------------------------------------------------------------- */ /* STORAGE DEBUG */ @@ -61,7 +61,7 @@ static inline void rns_storage_dbg_mem(uint8_t *b, uint32_t _size) { if (b != nullptr) { Serial.println(""); - for(int i = 0; i < _size; i++) { + for(uint32_t i = 0; i < _size; i++) { if(i != 0 && i % PRINT_SIZE == 0) { if(i != 0) Serial.println(); From 051c8ad0b1fe34ee4afa6316b76f749c9c6eb1e7 Mon Sep 17 00:00:00 2001 From: Andrea Gilardoni Date: Tue, 8 Oct 2024 10:18:24 +0200 Subject: [PATCH 58/80] Adding KVStore api from mbedos: interface --- libraries/KVStore/src/KVStore.h | 229 ++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 libraries/KVStore/src/KVStore.h diff --git a/libraries/KVStore/src/KVStore.h b/libraries/KVStore/src/KVStore.h new file mode 100644 index 000000000..08e0bae61 --- /dev/null +++ b/libraries/KVStore/src/KVStore.h @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2018 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBED_KVSTORE_H +#define MBED_KVSTORE_H + +#include +#include + +#define KVSTORE_SUCCESS 0 +#define KVSTORE_ERROR_READ_FAILED 283 +#define KVSTORE_ERROR_WRITE_FAILED 284 +#define KVSTORE_ERROR_INVALID_DATA_DETECTED 258 +#define KVSTORE_ERROR_INVALID_SIZE 261 +#define KVSTORE_ERROR_INVALID_ARGUMENT 257 +#define KVSTORE_ERROR_ITEM_NOT_FOUND 263 +#define KVSTORE_ERROR_MEDIA_FULL 267 +#define KVSTORE_ERROR_WRITE_PROTECTED 274 +#define KVSTORE_ERROR_OUT_OF_RESOURCES 288 +#define KVSTORE_ERROR_NOT_READY 270 +#define KVSTORE_ERROR_FAILED_OPERATION 271 + +namespace mbed { + +/** KVStore class + * + * Interface class for Key Value Storage + */ +class KVStore { +public: + enum create_flags { + WRITE_ONCE_FLAG = (1 << 0), + REQUIRE_CONFIDENTIALITY_FLAG = (1 << 1), + RESERVED_FLAG = (1 << 2), + REQUIRE_REPLAY_PROTECTION_FLAG = (1 << 3), + }; + + static const uint32_t MAX_KEY_SIZE = 128; + + typedef struct _opaque_set_handle *set_handle_t; + + typedef struct _opaque_key_iterator *iterator_t; + + /** + * Holds key information + */ + typedef struct info { + /** + * The key size + */ + size_t size; + /* + * The Key flags, possible flags combination: + * WRITE_ONCE_FLAG, + * REQUIRE_CONFIDENTIALITY_FLAG, + * REQUIRE_REPLAY_PROTECTION_FLAG + */ + uint32_t flags; + } info_t; + + virtual ~KVStore() {}; + + /** + * @brief Initialize KVStore + * + * @returns KVSTORE_SUCCESS on success or an error code on failure + */ + virtual int init() = 0; + + /** + * @brief Deinitialize KVStore + * + * @returns KVSTORE_SUCCESS on success or an error code on failure + */ + virtual int deinit() = 0; + + + /** + * @brief Reset KVStore contents (clear all keys) + * + * @returns KVSTORE_SUCCESS on success or an error code on failure + */ + virtual int reset() = 0; + + /** + * @brief Set one KVStore item, given key and value. + * + * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'. + * @param[in] buffer Value data buffer. + * @param[in] size Value data size. + * @param[in] create_flags Flag mask. + * + * @returns KVSTORE_SUCCESS on success or an error code on failure + */ + virtual int set(const char *key, const void *buffer, size_t size, uint32_t create_flags) = 0; + + /** + * @brief Get one KVStore item, given key. + * + * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'. + * @param[in] buffer Value data buffer. + * @param[in] buffer_size Value data buffer size. + * @param[out] actual_size Actual read size (NULL to pass nothing). + * @param[in] offset Offset to read from in data. + * + * @returns KVSTORE_SUCCESS on success or an error code on failure + */ + virtual int get(const char *key, void *buffer, size_t buffer_size, size_t *actual_size = NULL, size_t offset = 0) = 0; + + /** + * @brief Get information of a given key. + * + * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'. + * @param[out] info Returned information structure (NULL to pass nothing). + * + * @returns KVSTORE_SUCCESS on success or an error code on failure + */ + virtual int get_info(const char *key, info_t *info = NULL) = 0; + + /** + * @brief Remove a KVStore item, given key. + * + * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'. + * + * @returns KVSTORE_SUCCESS on success or an error code on failure + */ + virtual int remove(const char *key) = 0; + + + /** + * @brief Start an incremental KVStore set sequence. + * + * @param[out] handle Returned incremental set handle. + * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'. + * @param[in] final_data_size Final value data size. + * @param[in] create_flags Flag mask. + * + * @returns KVSTORE_SUCCESS on success or an error code on failure + */ + virtual int set_start(set_handle_t *handle, const char *key, size_t final_data_size, uint32_t create_flags) = 0; + + /** + * @brief Add data to incremental KVStore set sequence. + * + * @param[in] handle Incremental set handle. + * @param[in] value_data Value data to add. + * @param[in] data_size Value data size. + * + * @returns KVSTORE_SUCCESS on success or an error code on failure + */ + virtual int set_add_data(set_handle_t handle, const void *value_data, size_t data_size) = 0; + + /** + * @brief Finalize an incremental KVStore set sequence. + * + * @param[in] handle Incremental set handle. + * + * @returns KVSTORE_SUCCESS on success or an error code on failure + */ + virtual int set_finalize(set_handle_t handle) = 0; + + /** + * @brief Start an iteration over KVStore keys. + * + * @param[out] it Returned iterator handle. + * @param[in] prefix Key prefix (null for all keys). + * + * @returns KVSTORE_SUCCESS on success or an error code on failure + */ + virtual int iterator_open(iterator_t *it, const char *prefix = NULL) = 0; + + /** + * @brief Get next key in iteration. + * + * @param[in] it Iterator handle. + * @param[in] key Buffer for returned key. + * @param[in] key_size Key buffer size. + * + * @returns KVSTORE_SUCCESS on success or an error code on failure + */ + virtual int iterator_next(iterator_t it, char *key, size_t key_size) = 0; + + /** + * @brief Close iteration. + * + * @param[in] it Iterator handle. + * + * @returns KVSTORE_SUCCESS on success or an error code on failure + */ + virtual int iterator_close(iterator_t it) = 0; + + /** Convenience function for checking key validity. + * Key must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'. + * + * @param[in] key Key buffer. + * + * @returns KVSTORE_SUCCESS on success or an error code on failure + */ + bool is_valid_key(const char *key) const + { + if (!key || !strlen(key) || (strlen(key) > MAX_KEY_SIZE)) { + return false; + } + + if (strpbrk(key, " */?:;\"|<>\\")) { + return false; + } + return true; + } + +}; +/** @}*/ + +} // namespace mbed + +#endif From 5a6140225a3490116a3cc4ba5a6e67552d9829d8 Mon Sep 17 00:00:00 2001 From: Andrea Gilardoni Date: Tue, 8 Oct 2024 10:19:30 +0200 Subject: [PATCH 59/80] Adding KVStore api from mbedos: TDBStore --- libraries/KVStore/src/TDBStore.cpp | 1512 ++++++++++++++++++++++++++++ libraries/KVStore/src/TDBStore.h | 548 ++++++++++ 2 files changed, 2060 insertions(+) create mode 100644 libraries/KVStore/src/TDBStore.cpp create mode 100644 libraries/KVStore/src/TDBStore.h diff --git a/libraries/KVStore/src/TDBStore.cpp b/libraries/KVStore/src/TDBStore.cpp new file mode 100644 index 000000000..ab28ec12e --- /dev/null +++ b/libraries/KVStore/src/TDBStore.cpp @@ -0,0 +1,1512 @@ +/* + * Copyright (c) 2018 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ----------------------------------------------------------- Includes ----------------------------------------------------------- + +#include "TDBStore.h" + +#include +#include +#include +#include "MbedCRC.h" + +using namespace mbed; + +// --------------------------------------------------------- Definitions ---------------------------------------------------------- + +static const uint32_t delete_flag = (1UL << 31); +static const uint32_t internal_flags = delete_flag; +// Only write once flag is supported, other two are kept in storage but ignored +static const uint32_t supported_flags = KVStore::WRITE_ONCE_FLAG | KVStore::REQUIRE_CONFIDENTIALITY_FLAG | KVStore::REQUIRE_REPLAY_PROTECTION_FLAG; + +namespace { + +typedef struct { + uint32_t magic; + uint16_t header_size; + uint16_t revision; + uint32_t flags; + uint16_t key_size; + uint16_t reserved; + uint32_t data_size; + uint32_t crc; +} record_header_t; + +typedef struct { + uint32_t hash; + bd_size_t bd_offset; +} ram_table_entry_t; + +static const char *master_rec_key = "TDBS"; +static const uint32_t tdbstore_magic = 0x54686683; +static const uint32_t tdbstore_revision = 1; + +typedef struct { + uint16_t version; + uint16_t tdbstore_revision; + uint32_t reserved; +} master_record_data_t; + +typedef enum { + TDBSTORE_AREA_STATE_NONE = 0, + TDBSTORE_AREA_STATE_ERASED, + TDBSTORE_AREA_STATE_INVALID, + TDBSTORE_AREA_STATE_VALID, +} area_state_e; + +typedef struct { + uint16_t trailer_size; + uint16_t data_size; + uint32_t crc; +} reserved_trailer_t; + +static const size_t min_work_buf_size = 64; +static const uint32_t initial_crc = 0xFFFFFFFF; +static const uint32_t initial_max_keys = 16; + +// incremental set handle +typedef struct { + record_header_t header; + bd_size_t bd_base_offset; + bd_size_t bd_curr_offset; + uint32_t offset_in_data; + uint32_t ram_table_ind; + uint32_t hash; + bool new_key; +} inc_set_handle_t; + +// iterator handle +typedef struct { + int iterator_num; + uint32_t ram_table_ind; + char *prefix; +} key_iterator_handle_t; + +} // anonymous namespace + + +// -------------------------------------------------- Local Functions Declaration ---------------------------------------------------- + +// -------------------------------------------------- Functions Implementation ---------------------------------------------------- + +static inline uint32_t align_up(uint32_t val, uint32_t size) +{ + return (((val - 1) / size) + 1) * size; +} + +static inline uint32_t align_down(uint64_t val, uint64_t size) +{ + return (((val) / size)) * size; +} + + +static uint32_t calc_crc(uint32_t init_crc, uint32_t data_size, const void *data_buf) +{ + uint32_t crc; + MbedCRC ct(init_crc, 0x0, true, false); + ct.compute(data_buf, data_size, &crc); + return crc; +} + +// Class member functions + +TDBStore::TDBStore(BlockDevice *bd) : _ram_table(0), _max_keys(0), + _num_keys(0), _bd(bd), _buff_bd(0), _free_space_offset(0), _master_record_offset(0), + _master_record_size(0), _is_initialized(false), _active_area(0), _active_area_version(0), _size(0), + _area_params{}, _prog_size(0), _work_buf(0), _work_buf_size(0), _key_buf(0), _inc_set_handle(0) +{ + for (int i = 0; i < _num_areas; i++) { + _area_params[i] = { 0 }; + } + for (int i = 0; i < _max_open_iterators; i++) { + _iterator_table[i] = { 0 }; + } +} + +TDBStore::~TDBStore() +{ + deinit(); +} + +int TDBStore::read_area(uint8_t area, uint32_t offset, uint32_t size, void *buf) +{ + //Check that we are not crossing area boundary + if (offset + size > _size) { + return KVSTORE_ERROR_READ_FAILED; + } + int os_ret = _buff_bd->read(buf, _area_params[area].address + offset, size); + + if (os_ret) { + return KVSTORE_ERROR_READ_FAILED; + } + + return KVSTORE_SUCCESS; +} + +int TDBStore::write_area(uint8_t area, uint32_t offset, uint32_t size, const void *buf) +{ + int os_ret = _buff_bd->program(buf, _area_params[area].address + offset, size); + if (os_ret) { + return KVSTORE_ERROR_WRITE_FAILED; + } + + return KVSTORE_SUCCESS; +} + +int TDBStore::erase_area(uint8_t area, uint32_t offset, uint32_t size) +{ + uint32_t bd_offset = _area_params[area].address + offset; + + int ret = _buff_bd->erase(bd_offset, size); + if (ret) { + return ret; + } + + if (_buff_bd->get_erase_value() == -1) { + // We need to simulate erase to wipe records, as our block device + // may not do it. Program in chunks of _work_buf_size if the minimum + // program size is too small (e.g. one-byte) to avoid performance + // issues. + MBED_ASSERT(_work_buf != nullptr); + MBED_ASSERT(_work_buf_size != 0); + memset(_work_buf, 0xFF, _work_buf_size); + while (size) { + uint32_t chunk = std::min(_work_buf_size, size); + ret = _buff_bd->program(_work_buf, bd_offset, chunk); + if (ret) { + return ret; + } + size -= chunk; + bd_offset += chunk; + } + } + return KVSTORE_SUCCESS; +} + +void TDBStore::calc_area_params() +{ + // TDBStore can't exceed 32 bits + bd_size_t bd_size = std::min(_bd->size(), 0x80000000L); + + memset(_area_params, 0, sizeof(_area_params)); + size_t area_0_size = 0; + size_t area_1_size = 0; + + // The size calculations are a bit complex because we need to make sure we're + // always aligned to an erase block boundary (whose size may not be uniform + // across the address space), and we also need to make sure that the first + // area never goes over half of the total size even if bd_size is an odd + // number of sectors. + while (true) { + bd_size_t erase_unit_size = _bd->get_erase_size(area_0_size); + if (area_0_size + erase_unit_size <= (bd_size / 2)) { + area_0_size += erase_unit_size; + } else { + break; + } + } + + while (true) { + bd_size_t erase_unit_size = _bd->get_erase_size(area_0_size + area_1_size); + if (area_1_size + erase_unit_size <= (bd_size / 2)) { + area_1_size += erase_unit_size; + } else { + break; + } + } + + _area_params[0].address = 0; + _area_params[0].size = area_0_size; + _area_params[1].address = area_0_size; + _area_params[1].size = area_1_size; + + // The areas must be of same size + MBED_ASSERT(_area_params[0].size == _area_params[1].size); +} + + +// This function, reading a record from the BD, is used for multiple purposes: +// - Init (scan all records, no need to return file name and data) +// - Get (return file data) +// - Get first/next file (check whether name matches, return name if so) +int TDBStore::read_record(uint8_t area, uint32_t offset, char *key, + void *data_buf, uint32_t data_buf_size, + uint32_t &actual_data_size, size_t data_offset, bool copy_key, + bool copy_data, bool check_expected_key, bool calc_hash, + uint32_t &hash, uint32_t &flags, uint32_t &next_offset) +{ + int ret; + record_header_t header; + uint32_t total_size, key_size, data_size; + uint32_t curr_data_offset; + char *user_key_ptr; + uint32_t crc = initial_crc; + // Upper layers typically use non zero offsets for reading the records chunk by chunk, + // so only validate entire record at first chunk (otherwise we'll have a serious performance penalty). + bool validate = (data_offset == 0); + + ret = KVSTORE_SUCCESS; + // next offset should only be updated to the end of record if successful + next_offset = offset; + + ret = read_area(area, offset, sizeof(header), &header); + if (ret) { + return ret; + } + + if (header.magic != tdbstore_magic) { + return KVSTORE_ERROR_INVALID_DATA_DETECTED; + } + + offset += align_up(sizeof(header), _prog_size); + + key_size = header.key_size; + data_size = header.data_size; + flags = header.flags; + + if ((!key_size) || (key_size >= MAX_KEY_SIZE)) { + return KVSTORE_ERROR_INVALID_DATA_DETECTED; + } + + total_size = key_size + data_size; + + // Make sure our read sizes didn't cause any wraparounds + if ((total_size < key_size) || (total_size < data_size)) { + return KVSTORE_ERROR_INVALID_DATA_DETECTED; + } + + if (offset + total_size >= _size) { + return KVSTORE_ERROR_INVALID_DATA_DETECTED; + } + + if (data_offset > data_size) { + return KVSTORE_ERROR_INVALID_SIZE; + } + + actual_data_size = std::min(data_buf_size, data_size - data_offset); + + if (copy_data && actual_data_size && !data_buf) { + return KVSTORE_ERROR_INVALID_ARGUMENT; + } + + if (validate) { + // Calculate CRC on header (excluding CRC itself) + crc = calc_crc(crc, sizeof(record_header_t) - sizeof(crc), &header); + curr_data_offset = 0; + } else { + // Non validation case: No need to read the key, nor the parts before data_offset + // or after the actual part requested by the user. + total_size = actual_data_size; + curr_data_offset = data_offset; + offset += data_offset + key_size; + // Mark code that key handling is finished + key_size = 0; + } + + user_key_ptr = key; + hash = initial_crc; + + while (total_size) { + uint8_t *dest_buf; + uint32_t chunk_size; + if (key_size) { + // This means that we're on the key part + if (copy_key) { + dest_buf = reinterpret_cast(user_key_ptr); + chunk_size = key_size; + user_key_ptr[key_size] = '\0'; + } else { + dest_buf = _work_buf; + chunk_size = std::min(key_size, _work_buf_size); + } + } else { + // This means that we're on the data part + // We have four cases that need different handling: + // 1. Before data_offset - read to work buffer + // 2. After data_offset, but before actual part is finished - read to user buffer + // 3. After actual part is finished - read to work buffer + // 4. Copy data flag not set - read to work buffer + if (curr_data_offset < data_offset) { + chunk_size = std::min(_work_buf_size, (data_offset - curr_data_offset)); + dest_buf = _work_buf; + } else if (copy_data && (curr_data_offset < data_offset + actual_data_size)) { + chunk_size = actual_data_size; + dest_buf = static_cast(data_buf); + } else { + chunk_size = std::min(_work_buf_size, total_size); + dest_buf = _work_buf; + } + } + ret = read_area(area, offset, chunk_size, dest_buf); + if (ret) { + goto end; + } + + if (validate) { + // calculate CRC on current read chunk + crc = calc_crc(crc, chunk_size, dest_buf); + } + + if (key_size) { + // We're on key part. May need to calculate hash or check whether key is the expected one + if (check_expected_key) { + if (memcmp(user_key_ptr, dest_buf, chunk_size)) { + ret = KVSTORE_ERROR_ITEM_NOT_FOUND; + } + } + + if (calc_hash) { + hash = calc_crc(hash, chunk_size, dest_buf); +#ifdef KVSTORE_RAM_TABLE_NO_CRC_CHECK + next_offset = align_up(offset + total_size, _prog_size); + return ret; +#endif /* KVSTORE_RAM_TABLE_NO_CRC_CHECK */ + } + + user_key_ptr += chunk_size; + key_size -= chunk_size; + if (!key_size) { + offset += data_offset; + } + } else { + curr_data_offset += chunk_size; + } + + total_size -= chunk_size; + offset += chunk_size; + } + + if (validate && (crc != header.crc)) { + ret = KVSTORE_ERROR_INVALID_DATA_DETECTED; + goto end; + } + + next_offset = align_up(offset, _prog_size); + +end: + return ret; +} + +int TDBStore::find_record(uint8_t area, const char *key, uint32_t &offset, + uint32_t &ram_table_ind, uint32_t &hash) +{ + ram_table_entry_t *ram_table = (ram_table_entry_t *) _ram_table; + ram_table_entry_t *entry; + int ret = KVSTORE_ERROR_ITEM_NOT_FOUND; + uint32_t actual_data_size; + uint32_t flags, dummy_hash, next_offset; + + + hash = calc_crc(initial_crc, strlen(key), key); + + for (ram_table_ind = 0; ram_table_ind < _num_keys; ram_table_ind++) { + entry = &ram_table[ram_table_ind]; + offset = entry->bd_offset; + if (hash < entry->hash) { + continue; + } + if (hash > entry->hash) { + return KVSTORE_ERROR_ITEM_NOT_FOUND; + } + ret = read_record(_active_area, offset, const_cast(key), 0, 0, actual_data_size, 0, + false, false, true, false, dummy_hash, flags, next_offset); + // not found return code here means that hash doesn't belong to name. Continue searching. + if (ret != KVSTORE_ERROR_ITEM_NOT_FOUND) { + break; + } + } + + return ret; +} + +uint32_t TDBStore::record_size(const char *key, uint32_t data_size) +{ + return align_up(sizeof(record_header_t), _prog_size) + + align_up(strlen(key) + data_size, _prog_size); +} + + +int TDBStore::set_start(set_handle_t *handle, const char *key, size_t final_data_size, + uint32_t create_flags) +{ + int ret; + uint32_t offset = 0; + uint32_t hash = 0, ram_table_ind = 0; + inc_set_handle_t *ih; + bool need_gc = false; + + if (!is_valid_key(key)) { + return KVSTORE_ERROR_INVALID_ARGUMENT; + } + + if (create_flags & ~(supported_flags | internal_flags)) { + return KVSTORE_ERROR_INVALID_ARGUMENT; + } + + *handle = reinterpret_cast(_inc_set_handle); + ih = reinterpret_cast(*handle); + + if (!strcmp(key, master_rec_key)) { + // Master record - special case (no need to protect by the mutex, as it is already covered + // in the upper layers). + ih->bd_base_offset = _master_record_offset; + ih->new_key = false; + ram_table_ind = 0; + hash = 0; + } else { + + _mutex.lock(); + + // A valid magic in the header means that this function has been called after an aborted + // incremental set process. This means that our media may be in a bad state - call GC. + if (ih->header.magic == tdbstore_magic) { + ret = garbage_collection(); + if (ret) { + goto fail; + } + } + + // If we have no room for the record, perform garbage collection + uint32_t rec_size = record_size(key, final_data_size); + if (_free_space_offset + rec_size > _size) { + ret = garbage_collection(); + if (ret) { + goto fail; + } + } + + // If even after GC we have no room for the record, return error + if (_free_space_offset + rec_size > _size) { + ret = KVSTORE_ERROR_MEDIA_FULL; + goto fail; + } + + ret = find_record(_active_area, key, offset, ram_table_ind, hash); + + if (ret == KVSTORE_SUCCESS) { + ret = read_area(_active_area, offset, sizeof(ih->header), &ih->header); + if (ret) { + goto fail; + } + if (ih->header.flags & WRITE_ONCE_FLAG) { + ret = KVSTORE_ERROR_WRITE_PROTECTED; + goto fail; + } + ih->new_key = false; + } else if (ret == KVSTORE_ERROR_ITEM_NOT_FOUND) { + if (create_flags & delete_flag) { + goto fail; + } + if (_num_keys >= _max_keys) { + increment_max_keys(); + } + ih->new_key = true; + } else { + goto fail; + } + ih->bd_base_offset = _free_space_offset; + + check_erase_before_write(_active_area, ih->bd_base_offset, rec_size); + } + + ret = KVSTORE_SUCCESS; + + // Fill handle and header fields + // Jump to offset after header (header will be written at finalize phase) + ih->bd_curr_offset = ih->bd_base_offset + align_up(sizeof(record_header_t), _prog_size); + ih->offset_in_data = 0; + ih->hash = hash; + ih->ram_table_ind = ram_table_ind; + ih->header.magic = tdbstore_magic; + ih->header.header_size = sizeof(record_header_t); + ih->header.revision = tdbstore_revision; + ih->header.flags = create_flags; + ih->header.key_size = strlen(key); + ih->header.reserved = 0; + ih->header.data_size = final_data_size; + // Calculate CRC on header and key + ih->header.crc = calc_crc(initial_crc, sizeof(record_header_t) - sizeof(ih->header.crc), &ih->header); + ih->header.crc = calc_crc(ih->header.crc, ih->header.key_size, key); + + // Write key now + ret = write_area(_active_area, ih->bd_curr_offset, ih->header.key_size, key); + if (ret) { + need_gc = true; + goto fail; + } + ih->bd_curr_offset += ih->header.key_size; + goto end; + +fail: + if ((need_gc) && (ih->bd_base_offset != _master_record_offset)) { + garbage_collection(); + } + // mark handle as invalid by clearing magic field in header + ih->header.magic = 0; + + _mutex.unlock(); + +end: + return ret; +} + +int TDBStore::set_add_data(set_handle_t handle, const void *value_data, size_t data_size) +{ + int ret = KVSTORE_SUCCESS; + inc_set_handle_t *ih; + bool need_gc = false; + + if (handle != _inc_set_handle) { + return KVSTORE_ERROR_INVALID_ARGUMENT; + } + + if (!value_data && data_size) { + return KVSTORE_ERROR_INVALID_ARGUMENT; + } + + _inc_set_mutex.lock(); + + ih = reinterpret_cast(handle); + + if (!ih->header.magic) { + ret = KVSTORE_ERROR_INVALID_ARGUMENT; + goto end; + } + + if (ih->offset_in_data + data_size > ih->header.data_size) { + ret = KVSTORE_ERROR_INVALID_SIZE; + goto end; + } + + // Update CRC with data chunk + ih->header.crc = calc_crc(ih->header.crc, data_size, value_data); + + // Write the data chunk + ret = write_area(_active_area, ih->bd_curr_offset, data_size, value_data); + if (ret) { + need_gc = true; + goto end; + } + ih->bd_curr_offset += data_size; + ih->offset_in_data += data_size; + +end: + if ((need_gc) && (ih->bd_base_offset != _master_record_offset)) { + garbage_collection(); + } + + _inc_set_mutex.unlock(); + return ret; +} + +int TDBStore::set_finalize(set_handle_t handle) +{ + int os_ret, ret = KVSTORE_SUCCESS; + inc_set_handle_t *ih; + ram_table_entry_t *ram_table = (ram_table_entry_t *) _ram_table; + ram_table_entry_t *entry; + bool need_gc = false; + uint32_t actual_data_size, hash, flags, next_offset; + + if (handle != _inc_set_handle) { + return KVSTORE_ERROR_INVALID_ARGUMENT; + } + + ih = reinterpret_cast(handle); + + if (!ih->header.magic) { + return KVSTORE_ERROR_INVALID_ARGUMENT; + } + + _inc_set_mutex.lock(); + + if (ih->offset_in_data != ih->header.data_size) { + ret = KVSTORE_ERROR_INVALID_SIZE; + need_gc = true; + goto end; + } + + // Write header + ret = write_area(_active_area, ih->bd_base_offset, sizeof(record_header_t), &ih->header); + if (ret) { + need_gc = true; + goto end; + } + + // Need to flush buffered BD as our record is totally written now + os_ret = _buff_bd->sync(); + if (os_ret) { + ret = KVSTORE_ERROR_WRITE_FAILED; + need_gc = true; + goto end; + } + + // In master record case we don't update RAM table + if (ih->bd_base_offset == _master_record_offset) { + goto end; + } + + // Writes may fail without returning a failure (especially in flash components). Reread the record + // to ensure write success (this won't read the data anywhere - just use the CRC calculation). + ret = read_record(_active_area, ih->bd_base_offset, 0, 0, (uint32_t) -1, + actual_data_size, 0, false, false, false, false, + hash, flags, next_offset); + if (ret) { + need_gc = true; + goto end; + } + + // Update RAM table + if (ih->header.flags & delete_flag) { + _num_keys--; + if (ih->ram_table_ind < _num_keys) { + memmove(&ram_table[ih->ram_table_ind], &ram_table[ih->ram_table_ind + 1], + sizeof(ram_table_entry_t) * (_num_keys - ih->ram_table_ind)); + } + update_all_iterators(false, ih->ram_table_ind); + } else { + if (ih->new_key) { + if (ih->ram_table_ind < _num_keys) { + memmove(&ram_table[ih->ram_table_ind + 1], &ram_table[ih->ram_table_ind], + sizeof(ram_table_entry_t) * (_num_keys - ih->ram_table_ind)); + } + _num_keys++; + update_all_iterators(true, ih->ram_table_ind); + } + entry = &ram_table[ih->ram_table_ind]; + entry->hash = ih->hash; + entry->bd_offset = ih->bd_base_offset; + } + + _free_space_offset = align_up(ih->bd_curr_offset, _prog_size); + + // Safety check: If there seems to be valid keys on the free space + // we should erase one sector more, just to ensure that in case of power failure + // next init() would not extend the scan phase to that section as well. + os_ret = read_record(_active_area, _free_space_offset, 0, 0, 0, actual_data_size, 0, + false, false, false, false, hash, flags, next_offset); + if (os_ret == KVSTORE_SUCCESS) { + check_erase_before_write(_active_area, _free_space_offset, sizeof(record_header_t)); + } + +end: + // mark handle as invalid by clearing magic field in header + ih->header.magic = 0; + + _inc_set_mutex.unlock(); + + if (ih->bd_base_offset != _master_record_offset) { + if (need_gc) { + garbage_collection(); + } + _mutex.unlock(); + } + return ret; +} + +int TDBStore::set(const char *key, const void *buffer, size_t size, uint32_t create_flags) +{ + int ret; + set_handle_t handle; + + // Don't wait till we get to set_add_data to catch this + if (!buffer && size) { + return KVSTORE_ERROR_INVALID_ARGUMENT; + } + + ret = set_start(&handle, key, size, create_flags); + if (ret) { + return ret; + } + + ret = set_add_data(handle, buffer, size); + if (ret) { + return ret; + } + + ret = set_finalize(handle); + return ret; +} + +int TDBStore::remove(const char *key) +{ + return set(key, 0, 0, delete_flag); +} + +int TDBStore::get(const char *key, void *buffer, size_t buffer_size, size_t *actual_size, size_t offset) +{ + int ret; + uint32_t actual_data_size; + uint32_t bd_offset, next_bd_offset; + uint32_t flags, hash, ram_table_ind; + + if (!is_valid_key(key)) { + return KVSTORE_ERROR_INVALID_ARGUMENT; + } + + _mutex.lock(); + + ret = find_record(_active_area, key, bd_offset, ram_table_ind, hash); + + if (ret != KVSTORE_SUCCESS) { + goto end; + } + + ret = read_record(_active_area, bd_offset, const_cast(key), buffer, buffer_size, + actual_data_size, offset, false, true, false, false, hash, flags, next_bd_offset); + + if (actual_size) { + *actual_size = actual_data_size; + } + +end: + _mutex.unlock(); + return ret; +} + +int TDBStore::get_info(const char *key, info_t *info) +{ + int ret; + uint32_t bd_offset, next_bd_offset; + uint32_t flags, hash, ram_table_ind; + uint32_t actual_data_size; + + if (!is_valid_key(key)) { + return KVSTORE_ERROR_INVALID_ARGUMENT; + } + + _mutex.lock(); + + ret = find_record(_active_area, key, bd_offset, ram_table_ind, hash); + + if (ret) { + goto end; + } + + // Give a large dummy buffer size in order to achieve actual data size + // (as copy_data flag is not set, data won't be copied anywhere) + ret = read_record(_active_area, bd_offset, const_cast(key), 0, (uint32_t) -1, + actual_data_size, 0, false, false, false, false, hash, flags, + next_bd_offset); + + if (ret) { + goto end; + } + + if (info) { + info->flags = flags; + info->size = actual_data_size; + } + +end: + _mutex.unlock(); + return ret; +} + +int TDBStore::write_master_record(uint8_t area, uint16_t version, uint32_t &next_offset) +{ + master_record_data_t master_rec; + + master_rec.version = version; + master_rec.tdbstore_revision = tdbstore_revision; + master_rec.reserved = 0; + next_offset = _master_record_offset + _master_record_size; + return set(master_rec_key, &master_rec, sizeof(master_rec), 0); +} + +int TDBStore::copy_record(uint8_t from_area, uint32_t from_offset, uint32_t to_offset, + uint32_t &to_next_offset) +{ + int ret; + record_header_t header; + uint32_t total_size; + uint16_t chunk_size; + + ret = read_area(from_area, from_offset, sizeof(header), &header); + if (ret) { + return ret; + } + + total_size = align_up(sizeof(record_header_t), _prog_size) + + align_up(header.key_size + header.data_size, _prog_size);; + + + if (to_offset + total_size > _size) { + // We are trying to copy more that the are can hold + return KVSTORE_ERROR_MEDIA_FULL; + } + ret = check_erase_before_write(1 - from_area, to_offset, total_size); + if (ret) { + return ret; + } + + chunk_size = align_up(sizeof(record_header_t), _prog_size); + // The record header takes up whole program units + memset(_work_buf, 0, chunk_size); + memcpy(_work_buf, &header, sizeof(record_header_t)); + ret = write_area(1 - from_area, to_offset, chunk_size, _work_buf); + if (ret) { + return ret; + } + + from_offset += chunk_size; + to_offset += chunk_size; + total_size -= chunk_size; + + while (total_size) { + chunk_size = std::min(total_size, _work_buf_size); + ret = read_area(from_area, from_offset, chunk_size, _work_buf); + if (ret) { + return ret; + } + + ret = write_area(1 - from_area, to_offset, chunk_size, _work_buf); + if (ret) { + return ret; + } + + from_offset += chunk_size; + to_offset += chunk_size; + total_size -= chunk_size; + } + + to_next_offset = align_up(to_offset, _prog_size); + return KVSTORE_SUCCESS; +} + +int TDBStore::garbage_collection() +{ + ram_table_entry_t *ram_table = (ram_table_entry_t *) _ram_table; + uint32_t to_offset, to_next_offset; + int ret; + size_t ind; + + // Reset the standby area + ret = reset_area(1 - _active_area); + if (ret) { + return ret; + } + + to_offset = _master_record_offset + _master_record_size; + + // Initialize in case table is empty + to_next_offset = to_offset; + + // Go over ram table and copy all entries to opposite area + for (ind = 0; ind < _num_keys; ind++) { + uint32_t from_offset = ram_table[ind].bd_offset; + ret = copy_record(_active_area, from_offset, to_offset, to_next_offset); + if (ret) { + return ret; + } + // Update RAM table + ram_table[ind].bd_offset = to_offset; + to_offset = to_next_offset; + } + + to_offset = to_next_offset; + _free_space_offset = to_next_offset; + + // Now we can switch to the new active area + _active_area = 1 - _active_area; + + // Now write master record, with version incremented by 1. + _active_area_version++; + ret = write_master_record(_active_area, _active_area_version, to_offset); + if (ret) { + return ret; + } + + return KVSTORE_SUCCESS; +} + + +int TDBStore::build_ram_table() +{ + ram_table_entry_t *ram_table = (ram_table_entry_t *) _ram_table; + uint32_t offset, next_offset = 0, dummy; + int ret = KVSTORE_SUCCESS; + uint32_t hash; + uint32_t flags; + uint32_t actual_data_size; + uint32_t ram_table_ind; + + _num_keys = 0; + offset = _master_record_offset; + + while (offset + sizeof(record_header_t) < _free_space_offset) { + ret = read_record(_active_area, offset, _key_buf, 0, 0, actual_data_size, 0, + true, false, false, true, hash, flags, next_offset); + + if (ret) { + goto end; + } + + ret = find_record(_active_area, _key_buf, dummy, ram_table_ind, hash); + + if ((ret != KVSTORE_SUCCESS) && (ret != KVSTORE_ERROR_ITEM_NOT_FOUND)) { + goto end; + } + + uint32_t save_offset = offset; + offset = next_offset; + + if (ret == KVSTORE_ERROR_ITEM_NOT_FOUND) { + // Key doesn't exist, need to add it to RAM table + ret = KVSTORE_SUCCESS; + + if (flags & delete_flag) { + continue; + } + if (_num_keys >= _max_keys) { + // In order to avoid numerous reallocations of ram table, + // Add a chunk of entries now + increment_max_keys(reinterpret_cast(&ram_table)); + } + memmove(&ram_table[ram_table_ind + 1], &ram_table[ram_table_ind], + sizeof(ram_table_entry_t) * (_num_keys - ram_table_ind)); + + _num_keys++; + } else if (flags & delete_flag) { + _num_keys--; + memmove(&ram_table[ram_table_ind], &ram_table[ram_table_ind + 1], + sizeof(ram_table_entry_t) * (_num_keys - ram_table_ind)); + + continue; + } + + // update record parameters + ram_table[ram_table_ind].hash = hash; + ram_table[ram_table_ind].bd_offset = save_offset; + } + +end: + _free_space_offset = next_offset; + return ret; +} + +int TDBStore::increment_max_keys(void **ram_table) +{ + // Reallocate ram table with new size + ram_table_entry_t *old_ram_table = (ram_table_entry_t *) _ram_table; + ram_table_entry_t *new_ram_table = new ram_table_entry_t[_max_keys + 1]; + memset(new_ram_table, 0, sizeof(ram_table_entry_t) * (_max_keys + 1)); + + // Copy old content to new table + memcpy(new_ram_table, old_ram_table, sizeof(ram_table_entry_t) * _max_keys); + _max_keys++; + + _ram_table = new_ram_table; + delete[] old_ram_table; + + if (ram_table) { + *ram_table = _ram_table; + } + return KVSTORE_SUCCESS; +} + + +int TDBStore::init() +{ + ram_table_entry_t *ram_table; + area_state_e area_state[_num_areas]; + uint32_t next_offset; + uint32_t flags, hash; + uint32_t actual_data_size; + int ret = KVSTORE_SUCCESS; + uint16_t versions[_num_areas]; + + _mutex.lock(); + + if (_is_initialized) { + goto end; + } + + _max_keys = initial_max_keys; + + ram_table = new ram_table_entry_t[_max_keys]; + memset(ram_table, 0, sizeof(ram_table_entry_t) * _max_keys); + _ram_table = ram_table; + _num_keys = 0; + + _size = (size_t) -1; + + _buff_bd = new BufferedBlockDevice(_bd); + ret = _buff_bd->init(); + if (ret) { + goto fail; + } + + _prog_size = _bd->get_program_size(); + _work_buf_size = std::max(_prog_size, min_work_buf_size); + _work_buf = new uint8_t[_work_buf_size]; + _key_buf = new char[MAX_KEY_SIZE]; + _inc_set_handle = new inc_set_handle_t; + memset(_inc_set_handle, 0, sizeof(inc_set_handle_t)); + memset(_iterator_table, 0, sizeof(_iterator_table)); + + _master_record_offset = align_up(RESERVED_AREA_SIZE + sizeof(reserved_trailer_t), _prog_size); + _master_record_size = record_size(master_rec_key, sizeof(master_record_data_t)); + + calc_area_params(); + + /* Minimum space required by Reserved area and master record */ + MBED_ASSERT(_bd->size() + >= (align_up(RESERVED_AREA_SIZE + sizeof(reserved_trailer_t), _prog_size) + + record_size(master_rec_key, sizeof(master_record_data_t)))); + + for (uint8_t area = 0; area < _num_areas; area++) { + area_state[area] = TDBSTORE_AREA_STATE_NONE; + versions[area] = 0; + + _size = std::min(_size, _area_params[area].size); + + // Check validity of master record + master_record_data_t master_rec; + ret = read_record(area, _master_record_offset, const_cast(master_rec_key), + &master_rec, sizeof(master_rec), actual_data_size, 0, false, true, true, false, + hash, flags, next_offset); + if ((ret != KVSTORE_SUCCESS) && (ret != KVSTORE_ERROR_INVALID_DATA_DETECTED)) { + // KVSTORE_ERROR(ret, "TDBSTORE: Unable to read record at init"); // FIXME + } + + // Master record may be either corrupt or erased + if (ret == KVSTORE_ERROR_INVALID_DATA_DETECTED) { + area_state[area] = TDBSTORE_AREA_STATE_INVALID; + continue; + } + + versions[area] = master_rec.version; + + area_state[area] = TDBSTORE_AREA_STATE_VALID; + + // Unless both areas are valid (a case handled later), getting here means + // that we found our active area. + _active_area = area; + _active_area_version = versions[area]; + } + + // In case we have two empty areas, arbitrarily use area 0 as the active one. + if ((area_state[0] == TDBSTORE_AREA_STATE_INVALID) && (area_state[1] == TDBSTORE_AREA_STATE_INVALID)) { + reset_area(0); + _active_area = 0; + _active_area_version = 1; + area_state[0] = TDBSTORE_AREA_STATE_ERASED; + ret = write_master_record(_active_area, _active_area_version, _free_space_offset); + if (ret) { + // KVSTORE_ERROR(ret, "TDBSTORE: Unable to write master record at init"); // FIXME + } + // Nothing more to do here if active area is empty + goto end; + } + + // In case we have two valid areas, choose the one having the higher version (or 0 + // in case of wrap around). + if ((area_state[0] == TDBSTORE_AREA_STATE_VALID) && (area_state[1] == TDBSTORE_AREA_STATE_VALID)) { + if ((versions[0] > versions[1]) || (!versions[0])) { + _active_area = 0; + } else { + _active_area = 1; + } + _active_area_version = versions[_active_area]; + } + + // Currently set free space offset pointer to the end of free space. + // Ram table build process needs it, but will update it. + _free_space_offset = _size; + ret = build_ram_table(); + + // build_ram_table() scans all keys, until invalid data found. + // Therefore INVALID_DATA is not considered error. + if ((ret != KVSTORE_SUCCESS) && (ret != KVSTORE_ERROR_INVALID_DATA_DETECTED)) { + goto fail; + } + +end: + _is_initialized = true; + _mutex.unlock(); + return KVSTORE_SUCCESS; +fail: + delete[] ram_table; + delete _buff_bd; + delete[] _work_buf; + delete[] _key_buf; + delete reinterpret_cast(_inc_set_handle); + _ram_table = nullptr; + _buff_bd = nullptr; + _work_buf = nullptr; + _key_buf = nullptr; + _inc_set_handle = nullptr; + _mutex.unlock(); + return ret; +} + +int TDBStore::deinit() +{ + _mutex.lock(); + if (_is_initialized) { + _buff_bd->deinit(); + delete _buff_bd; + + ram_table_entry_t *ram_table = (ram_table_entry_t *) _ram_table; + delete[] ram_table; + delete[] _work_buf; + delete[] _key_buf; + delete reinterpret_cast(_inc_set_handle); + } + + _is_initialized = false; + _mutex.unlock(); + + return KVSTORE_SUCCESS; +} + +int TDBStore::reset_area(uint8_t area) +{ + uint8_t buf[RESERVED_AREA_SIZE + sizeof(reserved_trailer_t)]; + int ret; + bool copy_reserved_data = do_reserved_data_get(buf, sizeof(buf), 0, buf + RESERVED_AREA_SIZE) == KVSTORE_SUCCESS; + + // Erase reserved area and master record + ret = check_erase_before_write(area, 0, _master_record_offset + _master_record_size + _prog_size, true); + if (ret) { + return ret; + } + if (copy_reserved_data) { + ret = write_area(area, 0, sizeof(buf), buf); + } + return ret; +} + +int TDBStore::reset() +{ + uint8_t area; + int ret; + + if (!_is_initialized) { + return KVSTORE_ERROR_NOT_READY; + } + + _mutex.lock(); + + // Reset both areas + for (area = 0; area < _num_areas; area++) { + ret = check_erase_before_write(area, 0, _master_record_offset + _master_record_size + _prog_size, true); + if (ret) { + goto end; + } + } + + _active_area = 0; + _num_keys = 0; + _free_space_offset = _master_record_offset; + _active_area_version = 1; + memset(_ram_table, 0, sizeof(ram_table_entry_t) * _max_keys); + // Write an initial master record on active area + ret = write_master_record(_active_area, _active_area_version, _free_space_offset); + +end: + _mutex.unlock(); + return ret; +} + +int TDBStore::iterator_open(iterator_t *it, const char *prefix) +{ + key_iterator_handle_t *handle; + int ret = KVSTORE_SUCCESS; + + if (!_is_initialized) { + return KVSTORE_ERROR_NOT_READY; + } + + if (!it) { + return KVSTORE_ERROR_INVALID_ARGUMENT; + } + + _mutex.lock(); + + int it_num; + for (it_num = 0; it_num < _max_open_iterators; it_num++) { + if (!_iterator_table[it_num]) { + break; + } + } + + if (it_num == _max_open_iterators) { + ret = KVSTORE_ERROR_OUT_OF_RESOURCES; + goto end; + } + + handle = new key_iterator_handle_t; + *it = reinterpret_cast(handle); + + if (prefix && strcmp(prefix, "")) { + handle->prefix = new char[strlen(prefix) + 1]; + strcpy(handle->prefix, prefix); + } else { + handle->prefix = 0; + } + handle->ram_table_ind = 0; + handle->iterator_num = it_num; + _iterator_table[it_num] = handle; + +end: + _mutex.unlock(); + return ret; +} + +int TDBStore::iterator_next(iterator_t it, char *key, size_t key_size) +{ + ram_table_entry_t *ram_table = (ram_table_entry_t *) _ram_table; + key_iterator_handle_t *handle; + int ret; + uint32_t actual_data_size, hash, flags, next_offset; + + if (!_is_initialized) { + return KVSTORE_ERROR_NOT_READY; + } + + _mutex.lock(); + + handle = reinterpret_cast(it); + + ret = KVSTORE_ERROR_ITEM_NOT_FOUND; + + while (ret && (handle->ram_table_ind < _num_keys)) { + ret = read_record(_active_area, ram_table[handle->ram_table_ind].bd_offset, _key_buf, + 0, 0, actual_data_size, 0, true, false, false, false, hash, flags, next_offset); + if (ret) { + goto end; + } + if (!handle->prefix || (strstr(_key_buf, handle->prefix) == _key_buf)) { + if (strlen(_key_buf) >= key_size) { + ret = KVSTORE_ERROR_INVALID_SIZE; + goto end; + } + strcpy(key, _key_buf); + } else { + ret = KVSTORE_ERROR_ITEM_NOT_FOUND; + } + handle->ram_table_ind++; + } + +end: + _mutex.unlock(); + return ret; +} + +int TDBStore::iterator_close(iterator_t it) +{ + key_iterator_handle_t *handle; + + if (!_is_initialized) { + return KVSTORE_ERROR_NOT_READY; + } + + _mutex.lock(); + + handle = reinterpret_cast(it); + delete[] handle->prefix; + _iterator_table[handle->iterator_num] = 0; + delete handle; + + _mutex.unlock(); + + return KVSTORE_SUCCESS; +} + +void TDBStore::update_all_iterators(bool added, uint32_t ram_table_ind) +{ + for (int it_num = 0; it_num < _max_open_iterators; it_num++) { + key_iterator_handle_t *handle = static_cast (_iterator_table[it_num]); + if (!handle) { + continue; + } + + if (ram_table_ind >= handle->ram_table_ind) { + continue; + } + + if (added) { + handle->ram_table_ind++; + } else { + handle->ram_table_ind--; + } + } +} + +int TDBStore::reserved_data_set(const void *reserved_data, size_t reserved_data_buf_size) +{ + reserved_trailer_t trailer; + int ret; + + if (reserved_data_buf_size > RESERVED_AREA_SIZE) { + return KVSTORE_ERROR_INVALID_SIZE; + } + + _mutex.lock(); + + ret = do_reserved_data_get(0, 0); + if (ret == KVSTORE_SUCCESS) { + ret = KVSTORE_ERROR_WRITE_FAILED; + goto end; + } + + trailer.trailer_size = sizeof(trailer); + trailer.data_size = reserved_data_buf_size; + trailer.crc = calc_crc(initial_crc, reserved_data_buf_size, reserved_data); + + // Erase the header of non-active area, just to make sure that we can write to it + // In case garbage collection has not yet been run, the area can be un-erased + ret = reset_area(1 - _active_area); + if (ret) { + goto end; + } + + /* + * Write to both areas + * Both must success, as they are required to be erased when TDBStore initializes + * its area + */ + for (int i = 0; i < _num_areas; ++i) { + ret = write_area(i, 0, reserved_data_buf_size, reserved_data); + if (ret) { + goto end; + } + ret = write_area(i, RESERVED_AREA_SIZE, sizeof(trailer), &trailer); + if (ret) { + goto end; + } + ret = _buff_bd->sync(); + if (ret) { + goto end; + } + } + ret = KVSTORE_SUCCESS; +end: + _mutex.unlock(); + return ret; +} + +int TDBStore::do_reserved_data_get(void *reserved_data, size_t reserved_data_buf_size, size_t *actual_data_size, void *copy_trailer) +{ + reserved_trailer_t trailer; + uint8_t buf[RESERVED_AREA_SIZE]; + int ret; + uint32_t crc; + + /* + * Try to keep reserved data identical on both areas, therefore + * we can return any of these data, if the checmsum is correct. + */ + for (int i = 0; i < _num_areas; ++i) { + ret = read_area(i, RESERVED_AREA_SIZE, sizeof(trailer), &trailer); + if (ret) { + return ret; + } + + // First validy check: is the trailer header size correct + if (trailer.trailer_size != sizeof(trailer)) { + continue; + } + // Second validy check: Is the data too big (corrupt header) + if (trailer.data_size > RESERVED_AREA_SIZE) { + continue; + } + + // Next, verify the checksum + ret = read_area(i, 0, trailer.data_size, buf); + if (ret) { + return ret; + } + crc = calc_crc(initial_crc, trailer.data_size, buf); + if (crc == trailer.crc) { + // Correct data, copy it and return to caller + if (reserved_data) { + if (reserved_data_buf_size < trailer.data_size) { + return KVSTORE_ERROR_INVALID_SIZE; + } + memcpy(reserved_data, buf, trailer.data_size); + } + if (actual_data_size) { + *actual_data_size = trailer.data_size; + } + if (copy_trailer) { + memcpy(copy_trailer, &trailer, sizeof(trailer)); + } + return KVSTORE_SUCCESS; + } + } + + return KVSTORE_ERROR_ITEM_NOT_FOUND; +} + +int TDBStore::reserved_data_get(void *reserved_data, size_t reserved_data_buf_size, size_t *actual_data_size) +{ + _mutex.lock(); + int ret = do_reserved_data_get(reserved_data, reserved_data_buf_size, actual_data_size); + _mutex.unlock(); + return ret; +} + +void TDBStore::offset_in_erase_unit(uint8_t area, uint32_t offset, + uint32_t &offset_from_start, uint32_t &dist_to_end) +{ + uint32_t bd_offset = _area_params[area].address + offset; + + // The parameter of `BlockDevice::get_erase_size(bd_addr_t addr)` + // does not need to be aligned. + uint32_t erase_unit = _buff_bd->get_erase_size(bd_offset); + + // Even on a flash device with multiple regions, the start address of + // an erase unit is aligned to the current region's unit size. + offset_from_start = bd_offset % erase_unit; + dist_to_end = erase_unit - offset_from_start; +} + +int TDBStore::check_erase_before_write(uint8_t area, uint32_t offset, uint32_t size, bool force_check) +{ + // In order to save init time, we don't check that the entire area is erased. + // Instead, whenever reaching an erase unit start erase it. + bool erase = false; + uint32_t start_offset; + uint32_t end_offset; + while (size) { + uint32_t dist, offset_from_start; + int ret; + offset_in_erase_unit(area, offset, offset_from_start, dist); + uint32_t chunk = std::min(size, dist); + + if (offset_from_start == 0 || force_check) { + if (!erase) { + erase = true; + start_offset = offset - offset_from_start; + } + end_offset = offset + dist; + } + offset += chunk; + size -= chunk; + } + + if (erase) { + int ret = erase_area(area, start_offset, end_offset - start_offset); + if (ret != KVSTORE_SUCCESS) { + return KVSTORE_ERROR_WRITE_FAILED; + } + } + + return KVSTORE_SUCCESS; +} diff --git a/libraries/KVStore/src/TDBStore.h b/libraries/KVStore/src/TDBStore.h new file mode 100644 index 000000000..ab5fdc441 --- /dev/null +++ b/libraries/KVStore/src/TDBStore.h @@ -0,0 +1,548 @@ +/* + * Copyright (c) 2018 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBED_TDBSTORE_H +#define MBED_TDBSTORE_H + +#include +#include "KVStore.h" +#include +#include + +// namespace mbed { + +/** TDBStore class + * + * Lightweight Key Value storage over a block device + */ + +class TDBStore : public mbed::KVStore { +public: + + static const uint32_t RESERVED_AREA_SIZE = 64; + + /** + * @brief Class constructor + * + * @param[in] bd Underlying block device. + * + * @returns none + */ + TDBStore(BlockDevice *bd); + + /** + * @brief Class destructor + * + * @returns none + */ + virtual ~TDBStore(); + + /** + * @brief Initialize TDBStore. If data exists, TDBStore will check the data integrity + * on initialize. If the integrity checks fails, the TDBStore will use GC to collect + * the available data and clean corrupted and erroneous records. + * + * @returns KVSTORE_SUCCESS Success. + * @returns Negative error code on failure. + */ + virtual int init(); + + /** + * @brief Deinitialize TDBStore, release and free resources. + * + * @returns KVSTORE_SUCCESS Success. + */ + virtual int deinit(); + + + /** + * @brief Reset TDBStore contents (clear all keys) and reserved data + * + * @returns KVSTORE_SUCCESS Success. + * KVSTORE_ERROR_NOT_READY Not initialized. + * KVSTORE_ERROR_READ_FAILED Unable to read from media. + * KVSTORE_ERROR_WRITE_FAILED Unable to write to media. + */ + virtual int reset(); + + /** + * @brief Set one TDBStore item, given key and value. + * + * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'. + * @param[in] buffer Value data buffer. + * @param[in] size Value data size. + * @param[in] create_flags Flag mask. + * + * @returns KVSTORE_SUCCESS Success. + * KVSTORE_ERROR_NOT_READY Not initialized. + * KVSTORE_ERROR_READ_FAILED Unable to read from media. + * KVSTORE_ERROR_WRITE_FAILED Unable to write to media. + * KVSTORE_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments. + * KVSTORE_ERROR_INVALID_SIZE Invalid size given in function arguments. + * KVSTORE_ERROR_MEDIA_FULL Not enough room on media. + * KVSTORE_ERROR_WRITE_PROTECTED Already stored with "write once" flag. + */ + virtual int set(const char *key, const void *buffer, size_t size, uint32_t create_flags); + + /** + * @brief Get one TDBStore item by given key. + * + * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'. + * @param[in] buffer Value data buffer. + * @param[in] buffer_size Value data buffer size. + * @param[out] actual_size Actual read size. + * @param[in] offset Offset to read from in data. + * + * @returns KVSTORE_SUCCESS Success. + * KVSTORE_ERROR_NOT_READY Not initialized. + * KVSTORE_ERROR_READ_FAILED Unable to read from media. + * KVSTORE_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments. + * KVSTORE_ERROR_INVALID_SIZE Invalid size given in function arguments. + * KVSTORE_ERROR_INVALID_DATA_DETECTED Data is corrupt. + * KVSTORE_ERROR_ITEM_NOT_FOUND No such key. + */ + virtual int get(const char *key, void *buffer, size_t buffer_size, size_t *actual_size = NULL, + size_t offset = 0); + + /** + * @brief Get information of a given key. The returned info contains size and flags + * + * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'. + * @param[out] info Returned information structure. + * + * @returns KVSTORE_SUCCESS Success. + * KVSTORE_ERROR_NOT_READY Not initialized. + * KVSTORE_ERROR_READ_FAILED Unable to read from media. + * KVSTORE_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments. + * KVSTORE_ERROR_INVALID_DATA_DETECTED Data is corrupt. + * KVSTORE_ERROR_ITEM_NOT_FOUND No such key. + */ + virtual int get_info(const char *key, info_t *info); + + /** + * @brief Remove a TDBStore item by given key. + * + * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'. + * + * @returns KVSTORE_SUCCESS Success. + * KVSTORE_ERROR_NOT_READY Not initialized. + * KVSTORE_ERROR_READ_FAILED Unable to read from media. + * KVSTORE_ERROR_WRITE_FAILED Unable to write to media. + * KVSTORE_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments. + * KVSTORE_ERROR_MEDIA_FULL Not enough room on media. + * KVSTORE_ERROR_ITEM_NOT_FOUND No such key. + * KVSTORE_ERROR_WRITE_PROTECTED Already stored with "write once" flag. + */ + virtual int remove(const char *key); + + + /** + * @brief Start an incremental TDBStore set sequence. This operation is blocking other operations. + * Any get/set/remove/iterator operation will be blocked until set_finalize is called. + * + * @param[out] handle Returned incremental set handle. + * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'. + * @param[in] final_data_size Final value data size. + * @param[in] create_flags Flag mask. + * + * @returns KVSTORE_SUCCESS Success. + * KVSTORE_ERROR_NOT_READY Not initialized. + * KVSTORE_ERROR_READ_FAILED Unable to read from media. + * KVSTORE_ERROR_WRITE_FAILED Unable to write to media. + * KVSTORE_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments. + * KVSTORE_ERROR_INVALID_SIZE Invalid size given in function arguments. + * KVSTORE_ERROR_MEDIA_FULL Not enough room on media. + * KVSTORE_ERROR_WRITE_PROTECTED Already stored with "write once" flag. + */ + virtual int set_start(set_handle_t *handle, const char *key, size_t final_data_size, uint32_t create_flags); + + /** + * @brief Add data to incremental TDBStore set sequence. This operation is blocking other operations. + * Any get/set/remove operation will be blocked until set_finalize will be called. + * + * @param[in] handle Incremental set handle. + * @param[in] value_data Value data to add. + * @param[in] data_size Value data size. + * + * @returns KVSTORE_SUCCESS Success. + * KVSTORE_ERROR_NOT_READY Not initialized. + * KVSTORE_ERROR_WRITE_FAILED Unable to write to media. + * KVSTORE_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments. + * KVSTORE_ERROR_INVALID_SIZE Invalid size given in function arguments. + */ + virtual int set_add_data(set_handle_t handle, const void *value_data, size_t data_size); + + /** + * @brief Finalize an incremental KVStore set sequence. + * + * @param[in] handle Incremental set handle. + * + * @returns KVSTORE_SUCCESS Success. + * KVSTORE_ERROR_NOT_READY Not initialized. + * KVSTORE_ERROR_WRITE_FAILED Unable to write to media. + * KVSTORE_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments. + */ + virtual int set_finalize(set_handle_t handle); + + /** + * @brief Start an iteration over KVStore keys. + * There are no issues with any other operations while iterator is open. + * + * @param[out] it Returned iterator handle. + * @param[in] prefix Key prefix (null for all keys). + * + * @returns KVSTORE_SUCCESS Success. + * KVSTORE_ERROR_NOT_READY Not initialized. + * KVSTORE_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments. + */ + virtual int iterator_open(iterator_t *it, const char *prefix = NULL); + + /** + * @brief Get next key in iteration. + * There are no issues with any other operations while iterator is open. + * + * @param[in] it Iterator handle. + * @param[in] key Buffer for returned key. + * @param[in] key_size Key buffer size. + * + * @returns KVSTORE_SUCCESS Success. + * KVSTORE_ERROR_NOT_READY Not initialized. + * KVSTORE_ERROR_READ_FAILED Unable to read from block device. + * KVSTORE_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments. + * KVSTORE_ERROR_INVALID_SIZE Invalid size given in function arguments. + * KVSTORE_ERROR_INVALID_DATA_DETECTED Data is corrupt. + * KVSTORE_ERROR_ITEM_NOT_FOUND No more keys found. + */ + virtual int iterator_next(iterator_t it, char *key, size_t key_size); + + /** + * @brief Close iteration. + * + * @param[in] it Iterator handle. + * + * @returns KVSTORE_SUCCESS Success. + * KVSTORE_ERROR_NOT_READY Not initialized. + * KVSTORE_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments. + */ + virtual int iterator_close(iterator_t it); + + /** + * @brief Set data in reserved area, which is a special location for special data, such as ROT. + * The data written to reserved area can't be overwritten. + * + * @param[in] reserved_data Reserved data buffer. + * @param[in] reserved_data_buf_size + * Reserved data buffer size. + * + * @returns KVSTORE_SUCCESS Success. + * KVSTORE_ERROR_NOT_READY Not initialized. + * KVSTORE_ERROR_READ_FAILED Unable to read from media. + * KVSTORE_ERROR_WRITE_FAILED Unable to write to media. + * KVSTORE_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments. + * KVSTORE_ERROR_INVALID_SIZE Invalid size given in function arguments. + */ + virtual int reserved_data_set(const void *reserved_data, size_t reserved_data_buf_size); + + /** + * @brief Get data from reserved area, which is a special location for special data, such as ROT. + * + * @param[in] reserved_data Reserved data buffer. + * @param[in] reserved_data_buf_size + * Reserved data buffer size. + * @param[in] actual_data_size Return data size. + * + * @returns KVSTORE_SUCCESS Success. + * KVSTORE_ERROR_NOT_READY Not initialized. + * KVSTORE_ERROR_READ_FAILED Unable to read from media. + * KVSTORE_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments. + * KVSTORE_ERROR_INVALID_DATA_DETECTED Data is corrupt. + * KVSTORE_ERROR_ITEM_NOT_FOUND No reserved data was written. + */ + virtual int reserved_data_get(void *reserved_data, size_t reserved_data_buf_size, + size_t *actual_data_size = 0); + +#if !defined(DOXYGEN_ONLY) +private: + + typedef struct { + uint32_t address; + size_t size; + } tdbstore_area_data_t; + + static const int _num_areas = 2; + static const int _max_open_iterators = 16; + + PlatformMutex _mutex; + PlatformMutex _inc_set_mutex; + void *_ram_table; + size_t _max_keys; + size_t _num_keys; + BlockDevice *_bd; + BufferedBlockDevice *_buff_bd; + uint32_t _free_space_offset; + uint32_t _master_record_offset; + uint32_t _master_record_size; + bool _is_initialized; + int _active_area; + uint16_t _active_area_version; + size_t _size; + tdbstore_area_data_t _area_params[_num_areas]; + uint32_t _prog_size; + uint8_t *_work_buf; + size_t _work_buf_size; + char *_key_buf; + void *_inc_set_handle; + void *_iterator_table[_max_open_iterators]; + + /** + * @brief Read a block from an area. + * + * @param[in] area Area. + * @param[in] offset Offset in area. + * @param[in] size Number of bytes to read. + * @param[in] buf Output buffer. + * + * @returns 0 for success, nonzero for failure. + */ + int read_area(uint8_t area, uint32_t offset, uint32_t size, void *buf); + + /** + * @brief Write a block to an area. + * + * @param[in] area Area. + * @param[in] offset Offset in area. + * @param[in] size Number of bytes to write. + * @param[in] buf Input buffer. + * + * @returns 0 for success, non-zero for failure. + */ + int write_area(uint8_t area, uint32_t offset, uint32_t size, const void *buf); + + /** + * @brief Reset an area (erase its start). + * This erases master record, but preserves the + * reserved area data. + * + * @param[in] area Area. + * + * @returns 0 for success, nonzero for failure. + */ + int reset_area(uint8_t area); + + /** + * @brief Erase an area. + * + * @param[in] area Area. + * @param[in] offset Offset in area. + * @param[in] size Number of bytes to erase. + * + * @returns 0 for success, nonzero for failure. + */ + int erase_area(uint8_t area, uint32_t offset, uint32_t size); + + /** + * @brief Calculate addresses and sizes of areas. + */ + void calc_area_params(); + + /** + * @brief Read a TDBStore record from a given location. + * + * @param[in] area Area. + * @param[in] offset Offset of record in area. + * @param[out] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'. + * @param[out] data_buf Data buffer. + * @param[in] data_buf_size Data buffer size. + * @param[out] actual_data_size Actual data size. + * @param[in] data_offset Offset in data. + * @param[in] copy_key Copy key to user buffer. + * @param[in] copy_data Copy data to user buffer. + * @param[in] check_expected_key Check whether key belongs to this record. + * @param[in] calc_hash Calculate hash (on key). + * @param[out] hash Calculated hash. + * @param[out] flags Record flags. + * @param[out] next_offset Offset of next record. + * + * @returns 0 for success, nonzero for failure. + */ + int read_record(uint8_t area, uint32_t offset, char *key, + void *data_buf, uint32_t data_buf_size, + uint32_t &actual_data_size, size_t data_offset, bool copy_key, + bool copy_data, bool check_expected_key, bool calc_hash, + uint32_t &hash, uint32_t &flags, uint32_t &next_offset); + + /** + * @brief Write a master record of a given area. + * + * @param[in] area Area. + * @param[in] version Area version. + * @param[out] next_offset Offset of next record. + * + * @returns 0 for success, nonzero for failure. + */ + int write_master_record(uint8_t area, uint16_t version, uint32_t &next_offset); + + /** + * @brief Copy a record from one area to the opposite one. + * + * @param[in] from_area Area to copy record from. + * @param[in] from_offset Offset in source area. + * @param[in] to_offset Offset in destination area. + * @param[out] to_next_offset Offset of next record in destination area. + * + * @returns 0 for success, nonzero for failure. + */ + int copy_record(uint8_t from_area, uint32_t from_offset, uint32_t to_offset, + uint32_t &to_next_offset); + + /** + * @brief Garbage collection (compact all records from active area to the standby one). + * + * @returns 0 for success, nonzero for failure. + */ + int garbage_collection(); + + /** + * @brief Return record size given key and data size. + * + * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'. + * @param[in] data_size Data size. + * + * @returns record size. + */ + uint32_t record_size(const char *key, uint32_t data_size); + + /** + * @brief Find a record given key + * + * @param[in] area Area. + * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'. + * @param[out] offset Offset of record. + * @param[out] ram_table_ind Index in RAM table (target one if not found). + * @param[out] hash Calculated key hash. + * + * @returns 0 for success, nonzero for failure. + */ + int find_record(uint8_t area, const char *key, uint32_t &offset, + uint32_t &ram_table_ind, uint32_t &hash); + /** + * @brief Actual logics of get API (also covers all other get APIs). + * + * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'. + * @param[in] copy_data Copy data to user buffer. + * @param[in] data_buf Buffer to store data on. + * @param[in] data_buf_size Data buffer size (bytes). + * @param[out] actual_data_size Actual data size (bytes). + * @param[out] flags Flags. + * + * @returns 0 for success, nonzero for failure. + */ + int do_get(const char *key, bool copy_data, + void *data_buf, uint32_t data_buf_size, uint32_t &actual_data_size, + uint32_t &flags); + + /** + * @brief Actual logics of set API (covers also the remove API). + * + * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'. + * @param[in] data_buf Data buffer. + * @param[in] data_buf_size Data buffer size (bytes). + * @param[in] flags Flags. + * + * @returns 0 for success, nonzero for failure. + */ + int do_set(const char *key, const void *data_buf, uint32_t data_buf_size, uint32_t flags); + + /** + * @brief Build RAM table and update _free_space_offset (scanning all the records in the area). + * + * @returns 0 for success, nonzero for failure. + */ + int build_ram_table(); + + /** + * @brief Increment maximum number of keys and reallocate RAM table accordingly. + * + * @param[out] ram_table Updated RAM table. + * + * @returns 0 for success, nonzero for failure. + */ + int increment_max_keys(void **ram_table = 0); + + /** + * @brief Calculate offset from start of erase unit. + * + * @param[in] area Area. + * @param[in] offset Offset in area. + * @param[out] offset_from_start Offset from start of erase unit. + * @param[out] dist_to_end Distance to end of erase unit. + * + * @returns offset in erase unit. + */ + void offset_in_erase_unit(uint8_t area, uint32_t offset, uint32_t &offset_from_start, + uint32_t &dist_to_end); + + /** + * @brief Before writing a record, check whether you are crossing an erase unit. + * If you do, check if it's erased, and erase it if not. + * + * @param[in] area Area. + * @param[in] offset Offset in area. + * @param[in] size Write size. + * @param[in] force_check Force checking. + * + * @returns 0 for success, nonzero for failure. + */ + int check_erase_before_write(uint8_t area, uint32_t offset, uint32_t size, + bool force_check = false); + + /** + * @brief Get data from reserved area - worker function. + * This verifies that reserved data on both areas have + * correct checksums. If given pointer is not NULL, also + * write the reserved data to buffer. If checksums are not + * valid, return error code, and don't write anything to any + * pointers. + * + * @param[out] reserved_data Reserved data buffer (NULL to return nothing). + * @param[in] reserved_data_buf_size + * Reserved data buffer size. + * @param[out] actual_data_size If not NULL, return actual data size. + * @param[out] copy_trailer If not NULL, copy the trailer content to given buffer. + * + * @returns 0 on success or a negative error code on failure + */ + int do_reserved_data_get(void *reserved_data, size_t reserved_data_buf_size, + size_t *actual_data_size = 0, void *copy_trailer = 0); + + /** + * @brief Update all iterators after adding or deleting of keys. + * + * @param[in] added True if added, false if deleted. + * @param[in] ram_table_ind RAM table index. + * + * @returns none + */ + void update_all_iterators(bool added, uint32_t ram_table_ind); + +#endif + +}; +/** @}*/ + +// } // namespace mbed + +#endif From 29072034797a01e249c0c90196067b985621b3c7 Mon Sep 17 00:00:00 2001 From: Andrea Gilardoni Date: Tue, 8 Oct 2024 16:18:30 +0200 Subject: [PATCH 60/80] Imported crc calculation from MbedOS --- libraries/KVStore/src/MbedCRC.h | 892 ++++++++++++++++++++++++++++++++ 1 file changed, 892 insertions(+) create mode 100644 libraries/KVStore/src/MbedCRC.h diff --git a/libraries/KVStore/src/MbedCRC.h b/libraries/KVStore/src/MbedCRC.h new file mode 100644 index 000000000..ce6b3f530 --- /dev/null +++ b/libraries/KVStore/src/MbedCRC.h @@ -0,0 +1,892 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_CRC_API_H +#define MBED_CRC_API_H + +// #include "cmsis.h" +// #include "hal/crc_api.h" +#ifdef DEVICE_CRC +#include "device.h" +#endif +// #include "platform/mbed_assert.h" + +#ifdef __cplusplus + +// #include "platform/SingletonPtr.h" +// #include "platform/PlatformMutex.h" + +// #include + +// namespace mbed { +/** \addtogroup drivers-public-api */ +/** @{*/ +/** + * \defgroup drivers_MbedCRC MbedCRC class + * @{ + */ + +// extern SingletonPtr mbed_crc_mutex; + +/** CRC Polynomial value + * + * Different polynomial values supported + */ +typedef enum crc_polynomial { + POLY_7BIT_SD = 0x09, ///< x7+x3+1 + POLY_8BIT_CCITT = 0x07, ///< x8+x2+x+1 + POLY_16BIT_CCITT = 0x1021, ///< x16+x12+x5+1 + POLY_16BIT_IBM = 0x8005, ///< x16+x15+x2+1 + POLY_32BIT_ANSI = 0x04C11DB7 ///< x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 +} crc_polynomial_t; + +/** CRC mode selection + */ +enum class CrcMode { + HARDWARE, /// Use hardware (if available), else table-based computation + TABLE, /// Use table-based computation (if table available), else bitwise + BITWISE /// Always use bitwise manual computation +}; + +#ifndef DOXYGEN_ONLY +namespace impl { +template +class MbedCRC; + +constexpr bool have_crc_table(uint32_t polynomial, uint8_t width) +{ +#if MBED_CRC_TABLE_SIZE > 0 + return (polynomial == POLY_32BIT_ANSI && width == 32) || + (polynomial == POLY_16BIT_IBM && width == 16) || + (polynomial == POLY_16BIT_CCITT && width == 16) || + (polynomial == POLY_8BIT_CCITT && width == 8) || + (polynomial == POLY_7BIT_SD && width == 7); +#else + return false; +#endif +} + +constexpr CrcMode choose_crc_mode(uint32_t polynomial, uint8_t width, CrcMode mode_limit) +{ + return +#if DEVICE_CRC + mode_limit == CrcMode::HARDWARE && HAL_CRC_IS_SUPPORTED(polynomial, width) ? CrcMode::HARDWARE : +#endif + mode_limit <= CrcMode::TABLE && have_crc_table(polynomial, width) ? CrcMode::TABLE : + CrcMode::BITWISE; +} +#endif // DOXYGEN_ONLY + +} // namespace impl + +/** CRC object provides CRC generation through hardware or software + * + * CRC sums can be generated using three different methods: hardware, software ROM tables + * and bitwise computation. The mode used is normally selected automatically based on required + * polynomial and hardware capabilities. Any polynomial in standard form (`x^3 + x + 1`) + * can be used for computation, but custom ones can affect the performance. + * + * First choice is the hardware mode. The supported polynomials are hardware specific, and + * you need to consult your MCU manual to discover them. Next, ROM polynomial tables + * are tried (you can find list of supported polynomials here ::crc_polynomial). If the selected + * configuration is supported, it will accelerate the software computations. If ROM tables + * are not available for the selected polynomial, then CRC is computed at run time bit by bit + * for all data input. + * + * If desired, the mode can be manually limited for a given instance by specifying the mode_limit + * template parameter. This might be appropriate to ensure a table is not pulled in for a + * non-speed-critical CRC, or to avoid the hardware set-up overhead if you know you will be + * calling `compute` with very small data sizes. + * + * @note Synchronization level: Thread safe + * + * @tparam polynomial CRC polynomial value in hex + * @tparam width CRC polynomial width + * @tparam mode_limit Maximum amount of acceleration to use + * + * Example: Compute CRC data + * @code + * + * #include "mbed.h" + * + * int main() { + * MbedCRC ct; + * + * char test[] = "123456789"; + * uint32_t crc = 0; + * + * printf("\nPolynomial = 0x%lx Width = %d \n", ct.get_polynomial(), ct.get_width()); + * + * ct.compute((void *)test, strlen((const char*)test), &crc); + * + * printf("The CRC of data \"123456789\" is : 0x%lx\n", crc); + * return 0; + * } + * @endcode + * Example: Compute CRC with data available in parts + * @code + * + * #include "mbed.h" + * int main() { + * MbedCRC ct; + * + * char test[] = "123456789"; + * uint32_t crc = 0; + * + * printf("\nPolynomial = 0x%lx Width = %d \n", ct.get_polynomial(), ct.get_width()); + * ct.compute_partial_start(&crc); + * ct.compute_partial((void *)&test, 4, &crc); + * ct.compute_partial((void *)&test[4], 5, &crc); + * ct.compute_partial_stop(&crc); + * printf("The CRC of data \"123456789\" is : 0x%lx\n", crc); + * return 0; + * } + * @endcode + */ +template +class MbedCRC { + impl::MbedCRC crc_impl; + +public: + /* Backwards compatibility */ + enum CrcMode { +#if DEVICE_CRC + HARDWARE = int(::CrcMode::HARDWARE), +#endif + TABLE = int(::CrcMode::TABLE), + BITWISE = int(::CrcMode::BITWISE) + }; + + typedef size_t crc_data_size_t; + + /** Lifetime of CRC object + * + * @param initial_xor Initial value/seed to Xor + * @param final_xor Final Xor value + * @param reflect_data + * @param reflect_remainder + * @note Default constructor without any arguments is valid only for supported CRC polynomials. :: crc_polynomial_t + * MbedCRC ct; --- Valid POLY_7BIT_SD + * MbedCRC <0x1021, 16> ct; --- Valid POLY_16BIT_CCITT + * MbedCRC ct; --- Invalid, compilation error + * MbedCRC ct (i,f,rd,rr) Constructor can be used for not supported polynomials + * MbedCRC sd(0, 0, false, false); Constructor can also be used for supported + * polynomials with different initial/final/reflect values + * + */ + constexpr + MbedCRC(uint32_t initial_xor, uint32_t final_xor, bool reflect_data, bool reflect_remainder) : + crc_impl(initial_xor, final_xor, reflect_data, reflect_remainder) + { + } + + /* Default values for different types of polynomials + */ + // *INDENT-OFF* + template = 0> + constexpr MbedCRC() : MbedCRC(0xFFFFFFFF, 0xFFFFFFFF, true, true) + { + } + + template = 0> + constexpr MbedCRC() : MbedCRC(0, 0, true, true) + { + } + + template = 0> + constexpr MbedCRC() : MbedCRC(0xFFFF, 0, false, false) + { + } + + template = 0> + constexpr MbedCRC() : MbedCRC(0, 0, false, false) + { + } + + template = 0> + constexpr MbedCRC() : MbedCRC(0, 0, false, false) + { + } + // *INDENT-ON* + + /** Compute CRC for the data input + * Compute CRC performs the initialization, computation and collection of + * final CRC. + * + * @param buffer Data bytes + * @param size Size of data + * @param crc CRC is the output value + * @return 0 on success, negative error code on failure + */ + int32_t compute(const void *buffer, crc_data_size_t size, uint32_t *crc) + { + return crc_impl.compute(buffer, size, crc); + } + + /** Compute partial CRC for the data input. + * + * CRC data if not available fully, CRC can be computed in parts with available data. + * + * In case of hardware, intermediate values and states are saved by hardware. Mutex + * locking is used to serialize access to hardware CRC. + * + * In case of software CRC, previous CRC output should be passed as argument to the + * current compute_partial call. Please note the intermediate CRC value is maintained by + * application and not the driver. + * + * @pre: Call `compute_partial_start` to start the partial CRC calculation. + * @post: Call `compute_partial_stop` to get the final CRC value. + * + * @param buffer Data bytes + * @param size Size of data + * @param crc CRC value is intermediate CRC value filled by API. + * @return 0 on success or a negative error code on failure + * @note: CRC as output in compute_partial is not final CRC value, call `compute_partial_stop` + * to get final correct CRC value. + */ + int32_t compute_partial(const void *buffer, crc_data_size_t size, uint32_t *crc) + { + return crc_impl.compute_partial(buffer, size, crc); + } + + /** Compute partial start, indicate start of partial computation. + * + * This API should be called before performing any partial computation + * with compute_partial API. + * + * @param crc Initial CRC value set by the API + * @return 0 on success or a negative in case of failure + * @note: CRC is an out parameter and must be reused with compute_partial + * and `compute_partial_stop` without any modifications in application. + */ + int32_t compute_partial_start(uint32_t *crc) + { + return crc_impl.compute_partial_start(crc); + } + + /** Get the final CRC value of partial computation. + * + * CRC value available in partial computation is not correct CRC, as some + * algorithms require remainder to be reflected and final value to be XORed + * This API is used to perform final computation to get correct CRC value. + * + * @param crc CRC result + * @return 0 on success or a negative in case of failure. + */ + int32_t compute_partial_stop(uint32_t *crc) + { + return crc_impl.compute_partial_stop(crc); + } + + /** Get the current CRC polynomial. + * + * @return Polynomial value + */ + static constexpr uint32_t get_polynomial() + { + return polynomial; + } + + /** Get the current CRC width + * + * @return CRC width + */ + static constexpr uint8_t get_width() + { + return width; + } +}; + +#if !defined(DOXYGEN_ONLY) +/* Internal implementation - basically same as public, but actual mode locked in */ +namespace impl { + +template +class MbedCRC { +public: + typedef size_t crc_data_size_t; + + constexpr + MbedCRC(uint32_t initial_xor, uint32_t final_xor, bool reflect_data, bool reflect_remainder) : + _initial_value(adjust_initial_value(initial_xor, reflect_data)), + _final_xor(final_xor), + _reflect_data(reflect_data), + _reflect_remainder(reflect_remainder) + { + static_assert(width <= 32, "Max 32-bit CRC supported"); + } + + /** Compute CRC for the data input + * Compute CRC performs the initialization, computation and collection of + * final CRC. + * + * @param buffer Data bytes + * @param size Size of data + * @param crc CRC is the output value + * @return 0 on success, negative error code on failure + */ + int32_t compute(const void *buffer, crc_data_size_t size, uint32_t *crc) + { + int32_t status; + + status = compute_partial_start(crc); + if (0 != status) { + return status; + } + + status = compute_partial(buffer, size, crc); + if (0 != status) { + return status; + } + + status = compute_partial_stop(crc); + return status; + } + + /** Compute partial CRC for the data input. + * + * CRC data if not available fully, CRC can be computed in parts with available data. + * + * In case of hardware, intermediate values and states are saved by hardware. Mutex + * locking is used to serialize access to hardware CRC. + * + * In case of software CRC, previous CRC output should be passed as argument to the + * current compute_partial call. Please note the intermediate CRC value is maintained by + * application and not the driver. + * + * @pre: Call `compute_partial_start` to start the partial CRC calculation. + * @post: Call `compute_partial_stop` to get the final CRC value. + * + * @param buffer Data bytes + * @param size Size of data + * @param crc CRC value is intermediate CRC value filled by API. + * @return 0 on success or a negative error code on failure + * @note: CRC as output in compute_partial is not final CRC value, call `compute_partial_stop` + * to get final correct CRC value. + */ + int32_t compute_partial(const void *buffer, crc_data_size_t size, uint32_t *crc) + { + const uint8_t *data = static_cast(buffer); + return do_compute_partial(data, size, crc); + } + + /** Compute partial start, indicate start of partial computation. + * + * This API should be called before performing any partial computation + * with compute_partial API. + * + * @param crc Initial CRC value set by the API + * @return 0 on success or a negative in case of failure + * @note: CRC is an out parameter and must be reused with compute_partial + * and `compute_partial_stop` without any modifications in application. + */ + int32_t compute_partial_start(uint32_t *crc) + { +#if DEVICE_CRC + if (mode == CrcMode::HARDWARE) { + lock(); + crc_mbed_config_t config; + config.polynomial = polynomial; + config.width = width; + config.initial_xor = _initial_value; + config.final_xor = _final_xor; + config.reflect_in = _reflect_data; + config.reflect_out = _reflect_remainder; + + hal_crc_compute_partial_start(&config); + } +#endif + + *crc = _initial_value; + return 0; + } + + /** Get the final CRC value of partial computation. + * + * CRC value available in partial computation is not correct CRC, as some + * algorithms require remainder to be reflected and final value to be XORed + * This API is used to perform final computation to get correct CRC value. + * + * @param crc CRC result + * @return 0 on success or a negative in case of failure. + */ + int32_t compute_partial_stop(uint32_t *crc) + { +#if DEVICE_CRC + if (mode == CrcMode::HARDWARE) { + *crc = hal_crc_get_result(); + unlock(); + return 0; + } +#endif + uint_fast32_t p_crc = *crc; + if (mode == CrcMode::BITWISE) { + if (_reflect_data) { + /* CRC has MSB in bottom bit of register */ + if (!_reflect_remainder) { + p_crc = reflect_crc(p_crc); + } + } else { + /* CRC has MSB in top bit of register */ + p_crc = _reflect_remainder ? reflect(p_crc) : shift_right(p_crc); + } + } else { // TABLE + /* CRC has MSB in bottom bit of register */ + if (!_reflect_remainder) { + p_crc = reflect_crc(p_crc); + } + } + + p_crc ^= _final_xor; + p_crc &= get_crc_mask(); + *crc = p_crc; + + return 0; + } + +private: + /** Guaranteed constexpr reflection (all toolchains) + * + * @note This should never be run-time evaluated - very inefficient + * @param Register value to be reflected (full 32-bit value) + * @return Reflected value (full 32-bit value) + */ + static constexpr uint32_t reflect_constant(uint32_t data) + { + /* Doing this hard way to keep it C++11 constexpr and hence ARM C 5 compatible */ + return ((data & 0x00000001) << 31) | + ((data & 0x00000002) << 29) | + ((data & 0x00000004) << 27) | + ((data & 0x00000008) << 25) | + ((data & 0x00000010) << 23) | + ((data & 0x00000020) << 21) | + ((data & 0x00000040) << 19) | + ((data & 0x00000080) << 17) | + ((data & 0x00000100) << 15) | + ((data & 0x00000200) << 13) | + ((data & 0x00000400) << 11) | + ((data & 0x00000800) << 9) | + ((data & 0x00001000) << 7) | + ((data & 0x00002000) << 5) | + ((data & 0x00004000) << 3) | + ((data & 0x00008000) << 1) | + ((data & 0x00010000) >> 1) | + ((data & 0x00020000) >> 3) | + ((data & 0x00040000) >> 5) | + ((data & 0x00080000) >> 7) | + ((data & 0x00100000) >> 9) | + ((data & 0x00200000) >> 11) | + ((data & 0x00400000) >> 13) | + ((data & 0x00800000) >> 15) | + ((data & 0x01000000) >> 17) | + ((data & 0x02000000) >> 19) | + ((data & 0x04000000) >> 21) | + ((data & 0x08000000) >> 23) | + ((data & 0x10000000) >> 25) | + ((data & 0x20000000) >> 27) | + ((data & 0x40000000) >> 29) | + ((data & 0x80000000) >> 31); + } + + /** General reflection + * + * @note This is used when we may need to perform run-time computation, so + * we need the possibility to produce the optimal run-time RBIT instruction. But + * if the compiler doesn't treat RBIT as a built-in, it's useful to have a C fallback + * for the constant case, avoiding runtime RBIT(0) computations. This is an + * optimization only available for some toolchains; others will always use runtime + * RBIT. If we require a constant expression, use reflect_constant instead. + * + * @param Register value to be reflected (full 32-bit value) + * @return Reflected value (full 32-bit value) + */ +#ifdef MSTD_HAS_IS_CONSTANT_EVALUATED + static constexpr uint32_t reflect(uint32_t data) + { + return mstd::is_constant_evaluated() ? reflect_constant(data) : __RBIT(data); + } +#else + static uint32_t reflect(uint32_t data) + { + return __RBIT(data); + } +#endif + + /** Data bytes may need to be reflected. + * + * @param data value to be reflected (bottom 8 bits) + * @return Reflected value (bottom 8 bits) + */ + static + uint_fast32_t reflect_byte(uint_fast32_t data) + { + return reflect(data) >> 24; + } + + /** Get the current CRC polynomial, reflected at bottom of register. + * + * @return Reflected polynomial value (so x^width term would be at bit -1) + */ + static constexpr uint32_t get_reflected_polynomial() + { + return shift_right(reflect_constant(polynomial)); + } + + /** Get the current CRC polynomial, at top of register. + * + * @return Shifted polynomial value (so x^width term would be at bit 32) + */ + static constexpr uint32_t get_top_polynomial() + { + return shift_left(polynomial); + } + + const uint32_t _initial_value; + const uint32_t _final_xor; + const bool _reflect_data; + const bool _reflect_remainder; + + // *INDENT-OFF* + using crc_table_t = std::conditional_t>; + // *INDENT-ON* + +#if MBED_CRC_TABLE_SIZE > 0 + /* Tables only actually defined for mode == TABLE, and certain polynomials - see below */ + static const crc_table_t _crc_table[MBED_CRC_TABLE_SIZE]; +#endif + + static constexpr uint32_t adjust_initial_value(uint32_t initial_xor, bool reflect_data) + { + if (mode == CrcMode::BITWISE) { + /* For bitwise calculation, CRC register is reflected if data is, to match input. + * (MSB at bottom of register). If not reflected, it is at the top of the register + * (MSB at top of register). + */ + return reflect_data ? reflect_crc(initial_xor) : shift_left(initial_xor); + } else if (mode == CrcMode::TABLE) { + /* For table calculation, CRC value is reflected, to match tables. + * (MSB at bottom of register). */ + return reflect_crc(initial_xor); + } else { // CrcMode::HARDWARE + return initial_xor; + } + } + + /** Acquire exclusive access to CRC hardware/software. + */ + static void lock() + { +// #if DEVICE_CRC +// if (mode == CrcMode::HARDWARE) { +// mbed_crc_mutex->lock(); +// } +// #endif + } + + /** Release exclusive access to CRC hardware/software. + */ + static void unlock() + { +// #if DEVICE_CRC +// if (mode == CrcMode::HARDWARE) { +// mbed_crc_mutex->unlock(); +// } +// #endif + } + + /** Get the CRC data mask. + * + * @return CRC data mask is generated based on current CRC width + */ + static constexpr uint32_t get_crc_mask() + { + return (uint32_t)((uint32_t)2U << (width - 1)) - 1U; + } + + /** CRC values may need to be reflected. + * + * @param CRC value to be reflected (width bits at bottom of 32-bit word) + * @return Reflected value (still at bottom of 32-bit word) + */ + static + uint32_t reflect_crc(uint32_t data) + { + return reflect(data) >> (32 - width); + } + + /** Register values may need to be shifted left. + * + * @param Register value to be shifted up (in bottom width bits) + * @return Shifted value (in top width bits) + */ + static constexpr uint32_t shift_left(uint32_t data) + { + return data << (32 - width); + } + + /** Register values may need to be shifted right. + * + * @param Register value to be shifted right (in top width bits) + * @return Shifted value (in bottom width bits) + */ + static constexpr uint32_t shift_right(uint32_t data) + { + return data >> (32 - width); + } + + /* Check to see if we can do assembler optimizations */ +#if (defined __GNUC__ || defined __clang__) && \ + (defined __arm__ || defined __ARM_ARCH) +#if (__ARM_ARCH_7M__ == 1U) || \ + (__ARM_ARCH_7EM__ == 1U) || \ + (__ARM_ARCH_8M_MAIN__ == 1U) || \ + (__ARM_ARCH_8_1M_MAIN__ == 1U) || \ + (__ARM_ARCH_7A__ == 1U) + /* ARM that has Thumb-2 - same unified assembly is good for either ARM or Thumb state (LSRS; IT CS; EORCS reg/imm) */ +#define MBED_CRC_ARM_THUMB2 1 +#define MBED_CRC_THUMB1 0 +#elif (__ARM_ARCH_6M__ == 1U) || \ + (__ARM_ARCH_8M_BASE__ == 1U) + /* Thumb-1-only ARM-M device - use Thumb-1 compatible assembly with branch (LSRS; BCC; EORS reg) */ +#define MBED_CRC_ARM_THUMB2 0 +#define MBED_CRC_THUMB1 1 +#else // __ARM_ARCH_xxx +#error "Unknown ARM architecture for CRC optimization" +#endif // __ARM_ARCH_xxx +#else // __arm__ || defined __ICC_ARM__ || defined __ARM_ARCH + /* Seem to be compiling for non-ARM, or an unsupported toolchain, so stick with C implementations */ +#define MBED_CRC_ARM_THUMB2 0 +#define MBED_CRC_THUMB1 0 +#endif + + // *INDENT-OFF* + /** Process 1 bit of non-reflected CRC + * + * Shift the p_crc register left 1 bit - if a one is shifted + * out, exclusive-or with the polynomial mask. + * + * Assembler optimizations can be applied here, to make + * use of the CPU's carry output from shifts. + * + * @param p_crc input register value + * @return updated register value + */ + static uint_fast32_t do_1_bit_normal(uint_fast32_t p_crc) + { +#if MBED_CRC_ARM_THUMB2 + __asm(".syntax unified\n\t" + "LSLS" "\t%[p_crc], %[p_crc], #1\n\t" + "IT" "\tCS\n\t" + "EORCS" "\t%[p_crc], %[poly]" + : [p_crc] "+&r" (p_crc) + : [poly] "rI" (get_top_polynomial()) + : "cc"); +#elif MBED_CRC_THUMB1 + __asm(".syntax unified\n\t" + "LSLS" "\t%[p_crc], %[p_crc], #1\n\t" + "BCC" "\t%=f\n\t" + "EORS" "\t%[p_crc], %[poly]\n" + "%=:" + : [p_crc] "+&l" (p_crc) + : [poly] "l" (get_top_polynomial()) + : "cc"); +#else + if (p_crc & 0x80000000) { + p_crc = (p_crc << 1) ^ get_top_polynomial(); + } else { + p_crc = (p_crc << 1); + } +#endif + return p_crc; + } + + /** Process 1 bit of reflected CRC + * + * Shift the p_crc register right 1 bit - if a one is shifted + * out, exclusive-or with the polynomial mask. + * + * Assembler optimizations can be applied here, to make + * use of the CPU's carry output from shifts. + * + * @param p_crc input register value + * @return updated register value + */ + static uint_fast32_t do_1_bit_reflected(uint_fast32_t p_crc) + { +#if MBED_CRC_ARM_THUMB2 + __asm(".syntax unified\n\t" + "LSRS" "\t%[p_crc], %[p_crc], #1\n\t" + "IT" "\tCS\n\t" + "EORCS" "\t%[p_crc], %[poly]" + : [p_crc] "+&r" (p_crc) + : [poly] "rI" (get_reflected_polynomial()) + : "cc"); +#elif MBED_CRC_THUMB1 + __asm(".syntax unified\n\t" + "LSRS" "\t%[p_crc], %[p_crc], #1\n\t" + "BCC" "\t%=f\n\t" + "EORS" "\t%[p_crc], %[poly]\n" + "%=:" + : [p_crc] "+&l" (p_crc) + : [poly] "l" (get_reflected_polynomial()) + : "cc"); +#else + if (p_crc & 1) { + p_crc = (p_crc >> 1) ^ get_reflected_polynomial(); + } else { + p_crc = (p_crc >> 1); + } +#endif + return p_crc; + } + // *INDENT-ON* + + /** Bitwise CRC computation. + * + * @param buffer data buffer + * @param size size of the data + * @param crc CRC value is filled in, but the value is not the final + * @return 0 on success or a negative error code on failure + */ + template + std::enable_if_t + do_compute_partial(const uint8_t *data, crc_data_size_t size, uint32_t *crc) const + { + uint_fast32_t p_crc = *crc; + + if (_reflect_data) { + /* Everything is reflected to match data - MSB of polynomial at bottom of 32-bit register */ + for (crc_data_size_t byte = 0; byte < size; byte++) { + p_crc ^= data[byte]; + + // Perform modulo-2 division, a bit at a time + for (unsigned int bit = 8; bit > 0; --bit) { + p_crc = do_1_bit_reflected(p_crc); + } + } + } else { + /* Polynomial is shifted to put MSB of polynomial at top of 32-bit register */ + for (crc_data_size_t byte = 0; byte < size; byte++) { + p_crc ^= (uint_fast32_t) data[byte] << 24; + + // Perform modulo-2 division, a bit at a time + for (unsigned int bit = 8; bit > 0; --bit) { + p_crc = do_1_bit_normal(p_crc); + } + } + } + + *crc = p_crc; + + return 0; + } + +#if MBED_CRC_TABLE_SIZE > 0 + /** CRC computation using ROM tables. + * + * @param buffer data buffer + * @param size size of the data + * @param crc CRC value is filled in, but the value is not the final + * @return 0 on success or a negative error code on failure + */ + template + std::enable_if_t + do_compute_partial(const uint8_t *data, crc_data_size_t size, uint32_t *crc) const + { + uint_fast32_t p_crc = *crc; + // GCC has been observed to not hoist the load of _reflect_data out of the loop + // Note the inversion because table and CRC are reflected - data must be + bool reflect = !_reflect_data; + + for (crc_data_size_t byte = 0; byte < size; byte++) { + uint_fast32_t data_byte = data[byte]; + if (reflect) { + data_byte = reflect_byte(data_byte); + } +#if MBED_CRC_TABLE_SIZE == 16 + p_crc = _crc_table[(data_byte ^ p_crc) & 0xF] ^ (p_crc >> 4); + data_byte >>= 4; + p_crc = _crc_table[(data_byte ^ p_crc) & 0xF] ^ (p_crc >> 4); +#else + p_crc = _crc_table[(data_byte ^ p_crc) & 0xFF] ^ (p_crc >> 8); +#endif + } + *crc = p_crc; + return 0; + } +#endif + +#ifdef DEVICE_CRC + /** Hardware CRC computation. + * + * @param buffer data buffer + * @param size size of the data + * @return 0 on success or a negative error code on failure + */ + template + std::enable_if_t + do_compute_partial(const uint8_t *data, crc_data_size_t size, uint32_t *) const + { + hal_crc_compute_partial(data, size); + return 0; + } +#endif + +}; + +#if MBED_CRC_TABLE_SIZE > 0 +/* Declarations of the tables we provide. (Not strictly needed, but compilers + * can warn if they see us using the template without a generic definition, so + * let it know we have provided these specialisations.) + */ +template<> +const uint8_t MbedCRC::_crc_table[MBED_CRC_TABLE_SIZE]; + +template<> +const uint8_t MbedCRC::_crc_table[MBED_CRC_TABLE_SIZE]; + +template<> +const uint16_t MbedCRC::_crc_table[MBED_CRC_TABLE_SIZE]; + +template<> +const uint16_t MbedCRC::_crc_table[MBED_CRC_TABLE_SIZE]; + +template<> +const uint32_t MbedCRC::_crc_table[MBED_CRC_TABLE_SIZE]; + +#endif // MBED_CRC_TABLE_SIZE > 0 + +} // namespace impl + +#endif // !defined(DOXYGEN_ONLY) + +/** @}*/ +/** @}*/ + +// } // namespace mbed + +#endif // __cplusplus + +/* Internal helper for mbed_error.c crash recovery */ +#ifdef __cplusplus +extern "C" +#endif +uint32_t mbed_tiny_compute_crc32(const void *data, int datalen); + +#endif From 822ed5ce016919d5a72aa9b72b637bd2b3a5359a Mon Sep 17 00:00:00 2001 From: Andrea Gilardoni Date: Tue, 18 Feb 2025 17:16:12 +0100 Subject: [PATCH 61/80] KVStore added library.properties --- libraries/KVStore/library.properties | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 libraries/KVStore/library.properties diff --git a/libraries/KVStore/library.properties b/libraries/KVStore/library.properties new file mode 100644 index 000000000..b4320d4b6 --- /dev/null +++ b/libraries/KVStore/library.properties @@ -0,0 +1,9 @@ +name=KVStore +version=1.0.0 +author=Arduino +maintainer=Arduino +sentence=KVStore for arduino core renesas +paragraph= +category=Storage +url=https://github.com/arduino/ArduinoCore-renesas/tree/master/libraries/KVStore +architectures=renesas,renesas_portenta From 5b4190cf61f6fb072b8b1130d6915fa007a21dc7 Mon Sep 17 00:00:00 2001 From: Andrea Gilardoni Date: Thu, 13 Feb 2025 10:08:24 +0100 Subject: [PATCH 62/80] added .portenta_only to kvstore library --- libraries/KVStore/.portenta_only | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 libraries/KVStore/.portenta_only diff --git a/libraries/KVStore/.portenta_only b/libraries/KVStore/.portenta_only new file mode 100644 index 000000000..e69de29bb From 4c6df4f4822713e4e874e3a99e51a2874bc0c7e0 Mon Sep 17 00:00:00 2001 From: Andrea Gilardoni Date: Tue, 18 Feb 2025 16:17:19 +0100 Subject: [PATCH 63/80] C33 QSPIformat added partition for kvstore --- libraries/Storage/examples/QSPIFormat/QSPIFormat.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/Storage/examples/QSPIFormat/QSPIFormat.ino b/libraries/Storage/examples/QSPIFormat/QSPIFormat.ino index 26af854d4..9af2f8598 100644 --- a/libraries/Storage/examples/QSPIFormat/QSPIFormat.ino +++ b/libraries/Storage/examples/QSPIFormat/QSPIFormat.ino @@ -53,7 +53,8 @@ void setup() { if (true == waitResponse()) { MBRBlockDevice::partition(root, 1, 0x0B, 0, 5 * 1024 * 1024); - MBRBlockDevice::partition(root, 2, 0x0B, 5 * 1024 * 1024, 16 * 1024 * 1024); + MBRBlockDevice::partition(root, 2, 0x0B, 5 * 1024 * 1024, 15 * 1024 * 1024); + MBRBlockDevice::partition(root, 3, 0x0B, 15 * 1024 * 1024, 16 * 1024 * 1024); int err = sys_fs.reformat(&sys_bd); if (err) { From 0baf2b80dd48337a998e6b0dee7d4ed225f8611d Mon Sep 17 00:00:00 2001 From: Andrea Gilardoni Date: Tue, 18 Feb 2025 15:04:23 +0100 Subject: [PATCH 64/80] C33 kvstore: added example --- .../examples/StartCounter/StartCounter.ino | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 libraries/KVStore/examples/StartCounter/StartCounter.ino diff --git a/libraries/KVStore/examples/StartCounter/StartCounter.ino b/libraries/KVStore/examples/StartCounter/StartCounter.ino new file mode 100644 index 000000000..41dedeba1 --- /dev/null +++ b/libraries/KVStore/examples/StartCounter/StartCounter.ino @@ -0,0 +1,72 @@ +/* + * Microcontroller startup counter example with Portenta c33 kvstore library + * This simple example demonstrates using the KVStore library to store how many times + * the microcontroller has booted. The KVStore library is based on mbed OS KVStore library + * + * This example is based on Martin Sloup (Arcao) StartCounter example for arduino-esp32 + */ + +#include +#include +#include + +auto root = BlockDevice::get_default_instance(); +MBRBlockDevice bd(root, 3); +TDBStore kvstore(&bd); + +void setup() { + Serial.begin(115200); + Serial.println(); + + while(!Serial); + + // Init KVStore + if (kvstore.init() != KVSTORE_SUCCESS) { + Serial.println("Cannot initialize kvstore"); + while(1) {}; + } + + // Remove all values stored in the kvstore + // kvstore.reset(); + + // Or remove the counter key only + // kvstore.remove("counter"); + + // Get the counter value, if it doesn't exist it returns KVSTORE_ERROR_ITEM_NOT_FOUND + unsigned int counter; + auto res = kvstore.get("counter", (void*)&counter, sizeof(counter)); + + if (res == KVSTORE_ERROR_ITEM_NOT_FOUND) { + counter = 0; + } else if (res == KVSTORE_SUCCESS) { + // Increase counter by 1 + counter++; + } else { + Serial.print("Error getting counter from kvstore: "); + Serial.println(res); + } + + // Print the counter to Serial Monitor + Serial.print("Current counter value: "); + Serial.println(counter); + + // Store the updated counter value to the kvstore + if (kvstore.set("counter",(void*)&counter, sizeof(counter), 0) != KVSTORE_SUCCESS) { + Serial.println("Error setting counter from kvstore"); + } + + // Close the kvstore + if (kvstore.deinit() != KVSTORE_SUCCESS) { + Serial.println("Cannot deinitialize kvstore"); + while(1) {}; + } + + // Wait 10 seconds + Serial.println("Restarting in 10 seconds..."); + delay(10000); + + // Reset + NVIC_SystemReset(); +} + +void loop() {} From d71dc8839a97a7f435a9d330bbe93a1b64997209 Mon Sep 17 00:00:00 2001 From: Andrea Gilardoni Date: Mon, 24 Feb 2025 09:45:40 +0100 Subject: [PATCH 65/80] [C33] Added kvstore examples to CI --- .github/workflows/compile-examples.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml index 39e02488f..16cc2005b 100644 --- a/.github/workflows/compile-examples.yml +++ b/.github/workflows/compile-examples.yml @@ -76,6 +76,7 @@ jobs: - libraries/RTC/examples/RTC_NTPSync - libraries/RTC/examples/RTC_Alarm - libraries/SFU + - libraries/KVStore/examples/StartCounter - board: fqbn: "arduino-git:renesas:portenta_c33" additional-sketch-paths: | @@ -91,6 +92,7 @@ jobs: - libraries/RTC/examples/RTC_NTPSync - libraries/RTC/examples/RTC_Alarm - libraries/SFU + - libraries/KVStore/examples/StartCounter - board: fqbn: "arduino:renesas_uno:unor4wifi" additional-sketch-paths: | From 9c192d8421f4f10d37c23de34dcb1323c779cfa0 Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 24 Feb 2025 11:46:02 +0100 Subject: [PATCH 66/80] UNO R4 WiFi USB Bridge 0.5.2 --- extras/uno-r4-wifi-usb-bridge | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/uno-r4-wifi-usb-bridge b/extras/uno-r4-wifi-usb-bridge index 54e83e406..4394ba03c 160000 --- a/extras/uno-r4-wifi-usb-bridge +++ b/extras/uno-r4-wifi-usb-bridge @@ -1 +1 @@ -Subproject commit 54e83e406f5fb57642747aca8002a60eca64d8c5 +Subproject commit 4394ba03c6bd1afb661da2944de68359ec5b415a From 4896422a901b5db89a43273559985eaa7de0e839 Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 24 Feb 2025 11:47:02 +0100 Subject: [PATCH 67/80] WIFI_FIRMWARE_LATEST_VERSION: 0.5.2 --- libraries/WiFiS3/src/WiFi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/WiFiS3/src/WiFi.h b/libraries/WiFiS3/src/WiFi.h index 2643c2254..0e2999b7c 100644 --- a/libraries/WiFiS3/src/WiFi.h +++ b/libraries/WiFiS3/src/WiFi.h @@ -17,7 +17,7 @@ #define DEFAULT_GW_AP_ADDRESS IPAddress(192,168,1,1) #define DEFAULT_NM_AP_ADDRESS IPAddress(255,255,255,0) -#define WIFI_FIRMWARE_LATEST_VERSION "0.4.1" +#define WIFI_FIRMWARE_LATEST_VERSION "0.5.2" class CAccessPoint { public: From 21a3dfd7430209c91710a543ce9a6265b4191aca Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 24 Feb 2025 11:59:40 +0100 Subject: [PATCH 68/80] adc: analogReadResolution fix adc1 resolution --- cores/arduino/analog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/arduino/analog.cpp b/cores/arduino/analog.cpp index 37d3d6cc7..a457bc2a3 100644 --- a/cores/arduino/analog.cpp +++ b/cores/arduino/analog.cpp @@ -645,7 +645,7 @@ void analogReadResolution(int bits) { default: _analogRequestedReadResolution = 12; adc.cfg.resolution = ADC_RESOLUTION_12_BIT; - adc1.cfg.resolution = ADC_RESOLUTION_10_BIT; + adc1.cfg.resolution = ADC_RESOLUTION_12_BIT; break; } From 34dd6a4bd624e29c6168fcb03bd09ef60c1614c5 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 26 Feb 2025 16:23:42 +0100 Subject: [PATCH 69/80] RTC: change on interrupt PIN to D7 --- libraries/RTC/examples/Test_RTC/Test_RTC.ino | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/RTC/examples/Test_RTC/Test_RTC.ino b/libraries/RTC/examples/Test_RTC/Test_RTC.ino index 0fcbc5132..eca534eda 100644 --- a/libraries/RTC/examples/Test_RTC/Test_RTC.ino +++ b/libraries/RTC/examples/Test_RTC/Test_RTC.ino @@ -11,8 +11,8 @@ // Include the RTC library #include "RTC.h" -// Define the interrupt pin for LED control during interrupts -const int LED_ON_INTERRUPT = 22; +// Define the pin to toggle on interrupt +const int PIN_ON_INTERRUPT = D7; bool periodicFlag = false; bool alarmFlag = false; @@ -37,7 +37,7 @@ void setup() { // Set LED pins as outputs pinMode(LED_BUILTIN, OUTPUT); - pinMode(LED_ON_INTERRUPT, OUTPUT); + pinMode(PIN_ON_INTERRUPT, OUTPUT); // Initialize the RTC RTC.begin(); @@ -83,10 +83,10 @@ void loop() { // Toggle the LED based on callback state if (clb_st) { - digitalWrite(LED_ON_INTERRUPT, HIGH); + digitalWrite(PIN_ON_INTERRUPT, HIGH); } else { - digitalWrite(LED_ON_INTERRUPT, LOW); + digitalWrite(PIN_ON_INTERRUPT, LOW); } clb_st = !clb_st; // Toggle callback state From 68bdf786b8a9a2e3bf35305a7f4267684e7208a2 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 26 Feb 2025 16:43:52 +0100 Subject: [PATCH 70/80] WiFiS3: remove retries to get localIP --- libraries/WiFiS3/src/WiFi.cpp | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/libraries/WiFiS3/src/WiFi.cpp b/libraries/WiFiS3/src/WiFi.cpp index 7e73b94f1..249a9ef05 100644 --- a/libraries/WiFiS3/src/WiFi.cpp +++ b/libraries/WiFiS3/src/WiFi.cpp @@ -332,27 +332,18 @@ IPAddress CWifi::localIP() { int attempts = 0; IPAddress local_IP(0,0,0,0); - do { - delay(100); - if(modem.write(string(PROMPT(_MODE)),res, "%s" , CMD_READ(_MODE))) { - if(atoi(res.c_str()) == 1) { - if(modem.write(string(PROMPT(_IPSTA)),res, "%s%d\r\n" , CMD_WRITE(_IPSTA), IP_ADDR)) { - - local_IP.fromString(res.c_str()); - - } + if(modem.write(string(PROMPT(_MODE)),res, "%s" , CMD_READ(_MODE))) { + if(atoi(res.c_str()) == 1) { + if(modem.write(string(PROMPT(_IPSTA)),res, "%s%d\r\n" , CMD_WRITE(_IPSTA), IP_ADDR)) { + local_IP.fromString(res.c_str()); } - else if(atoi(res.c_str()) == 2) { - if(modem.write(string(PROMPT(_IPSOFTAP)),res, CMD(_IPSOFTAP))) { - - local_IP.fromString(res.c_str()); - } + } + else if(atoi(res.c_str()) == 2) { + if(modem.write(string(PROMPT(_IPSOFTAP)),res, CMD(_IPSOFTAP))) { + local_IP.fromString(res.c_str()); } } - attempts++; } - while(local_IP == IPAddress(0,0,0,0) && attempts < 50); - return local_IP; } From 3c9ef2862374c4c500d47a1dc4a461c15446b116 Mon Sep 17 00:00:00 2001 From: fabik111 Date: Mon, 24 Feb 2025 16:32:17 +0100 Subject: [PATCH 71/80] lwIpWrapper: rebuild lwip library to enable LWIP_RAW --- extras/net/lwipopts.h | 4 ++-- .../lwIpWrapper/src/cortex-m33/liblwIP.a | Bin 274428 -> 278314 bytes libraries/lwIpWrapper/src/lwipopts.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extras/net/lwipopts.h b/extras/net/lwipopts.h index 87d0d9a5c..3d8022920 100644 --- a/extras/net/lwipopts.h +++ b/extras/net/lwipopts.h @@ -277,7 +277,7 @@ * (requires the LWIP_RAW option) */ #ifndef MEMP_NUM_RAW_PCB -#define MEMP_NUM_RAW_PCB 0 +#define MEMP_NUM_RAW_PCB 1 #endif /** @@ -642,7 +642,7 @@ * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. */ #ifndef LWIP_RAW -#define LWIP_RAW 0 +#define LWIP_RAW 1 #endif /* diff --git a/libraries/lwIpWrapper/src/cortex-m33/liblwIP.a b/libraries/lwIpWrapper/src/cortex-m33/liblwIP.a index adaabfb1cd45db2e25e5800f1377a10dcf103d47..687e03a87e792d87c96efb5d6cfc284b98329b2b 100644 GIT binary patch delta 9761 zcmc&Z3s{s@+UNbg85l-JKNys&FgVB{C=C}8yp({Bng-r#DKkJoArXd)R{pdjyT2FI z3_Y92TrJ(Sr)_N?aI(qYOS)OvmK(IzYPVlg*IO!-e^Tq_|DNyr24-OBY5(?l{_mOh zd(V44?{{wRIcIMFxAgK4QggUtOu98Ib4>aetI32vd_3PK)9B2sOqp#e(h~w>2pP7a ze@Ln#q(7MaEg^lup)hCOOUV7p2r2l)H0S0ke>sNpJV*T zD}?;3@J2Kt9NrORaJUQqPZ;}OjpV0bfK<{A37ZN0Um^c{0x~$<1s`}pG=ZN3k8dLI zW3Xm60SABmR5*}9;HSVx$pqYR{$m0^0uJcNBfUW&Uz2Vay@3dBn6Q-yo{;|q5jgCd zO@y`=eZ$o&MCczJvQV6Qh4c%{9wnk18aEU1$Drj!BKC%l|4c+*aBTw-uMOs}4MZb6 zpg>eA(Ts~=8?7+Z8K5l}bW6&X*b8T8|H4`6e^qeQ7C%;4QDt9RPk3oTMOA5cp|Gl~ zzG9(FmQ+_&m6a$ur4@CaWNlf=GFhjttg5uWy0BtlVO?#B2dBFz7i!CvR4*%&i&bTh z5hJe^3xyT-!uludvViVzgwp)IL!3+WGYmR)InQ9RV+A8*xXxw>mEg<{e;@jYTAvq| zfOB)yJAFlp)rFY8R?ZW#$8^12IbTVvjPPb^Gty0_RF<6$NzT&A0eWvKWH_7hC9OBp zkDFv#X>w$u^ZeX!(OZfp;RRg-yqP*~lAfNDO0AIz#)mOO;iFBLQ34rBl4x~lEa>UR z(lPjcw{)q9JxR05EPmyv6GiAFW%FoDxW>7^Y>o&6SavhS43e$Ymq-$5WJQzzNTh?v zaQcUeyC9N&T5;E`aPn7GM<>f-$r&#?hTQa`hvLGeFcf_=8R$iaI;TH62-4ldt#D>; z4j}{4LT@Exh>8;s3nK{eLmZt(2zM2oM%OORr_U~yW=|wU!!_L7)3mLs zo{q28!3cU^^^}0e{go<4(CyVz=*T+GzlNm-xirCU20Jabo9Rh=7~N)<0=A$&4}JvQ zXOE$AHDUBCyJXnm=AtBs9o+>+8damC^(Y=+BN<-u5E~g>7mTzL#m7**zD5dYaf|8h zniv{V8%95?k-}ehbJ1rg0&gH*a}K?~*23D3h*J0w50!8amHBixsuXMzgLG~U`b=#M z)zpR2_iLr_Ha8b-hI-ghI=Rlmx;BYYz$v#19bFfror^uLW7%&(D7DuG2At^@uB?k; zFKrPd+EA^d2kWH7OKuUmHG8nVpj!3Pdi6g43m&6p>ZOzN70=Tk=nU9^df0Zy;(aI zTQP{iBGE|q)CYObOUPg;2F+cpc@9W4Y-t#NaLUrb&bybU3L!dYZh1+o#!6zL`Od8$ z?jYXcYgK_f2tMvOa9ZalTS$(*_ zF-Y@9<`6`_zLNvQAv+91MljC0IjRFbAA@l|m-RBJQ{{28JdCVB+Wqhf)~NCfEC-Va zoS1H@GV%7P@^V=oMfL;kthkO6Ks0%;m%$~~K#`ls?OyT-?0U{p0vbj}sdT(tK^)0O z+WqhVr>pXrSPmxfLd!aSPdSS4ZtbMA0_3wgX=JuXZpj&Y$%;20OKRE{SiAdb#e zmcZyq>QabIZYS7!WBNs7r~|oq+ta-8E#)$6_La+$9# zw6l7!74@R$C{4_xm7~UJO~~ibCUZQSkRrs>1$0n~1zrIki_s6LxIi)Be4IW+{~*dZ zo~H&dpAZzucD&K_53B3$g863Rq^l}+KNP&fqt?oo(1OPB$QT%2?++8xH_Jh>On*2u8tF|2D*H8JY1qX zS6hTk1N}1+6KUsa3(Tb9Yb+2*v+=!xR^U61Zp8N*x*y+GdUlP4b~Odkkftb@OH-OG zu!TO@WMPt7qk(c-Q*ESMnk4N@212a#l_oRXr0uA5ihkE*(FWo=6UIM^X0Das44t-? zyRX6bCHgGBr_!VN?x2_PZKpx&ECLxw$F7TqBeWO^X&_yT#D}zXokja0`jQtg+ObZ8 z85GuAv}-hkbkI@j&DzItyj1fg%B&5;RQiCjS~ailvs%$Z>vux{EqUtfAiaq%O4lz! zlF$ye06J&G)1Y^r+b|^Bdx=xF9@flEzV&dJ24JUnY&~MIgGXJyl|TGGf7^)i@(S(~ znu%$J?LW$6^JrHUi4RFnw}z`>^Gyt&7WPSEd!xKHa-DXLvjO zc3Anmjtw4dw>X*tkI1`TeTV;gIWwe4_JoSM?y`Z}_-ZRg65 zcLiG0%F~O^6@lr4izM+(+u{nE^Lg72+xhahFAApbFOoOpaPeho4R0M#E*24!eM)tQ zme{9+w{Gmplpy8Zy-;hPGO;xa<+(+<4Y?g4=GOP<5p!;lSex5mM!qAr-ah5XWo@v1 z%Bag7xhq=?wq{$5O=J7K%i2s5X10;Uyf%_FqisKiIIS(aA*e&}liC(H8Iy8O6Z14% zge}2#;xb7S7;hDo3`c%r}I1Rq;`HJ5 z5#>=uUly5cnTL2c>9}w7!A=#xDA#v6xUZ*29u9$RbZ2@JYxtWefj^C19z#v@B{s4O zOl-z=aUji`A51G34P=j2K`J#(li0y3uxfEekdYKJlH^hXYn%sJ?2~yg1QKXUd1Mfm z_dMamz+ei*&|RA)2j7J9jIawK7&Dy-vHRf}0C$ny52v#cxW1B>{m8v4jWZE>{sdP+ zSso$NI#Q<6+%_1uGxaLXmrTsz!Q@Gmaad*yAWyTb^Fj=~!Wt{Z7-s*AAhDK8QRB5& zIHTI+$u^XYMoF&DTmDME#%XMYS z@wV4tl(iK>m;)0P(c|888)6}mkR2SGmF=lMg^&eYj)~sRF&<-9aEzz6%^aircN~u< zWDm!<$yARAyB zS84flLk)Kac%18#>&qUmPv&hR_kcI4p7DE_?xTGV$K$-;!<0|`$+cybJuI*Dzk~P^ z`e62AslDZG%r6T1aJp{{dQ0%mqOgMMzLW+msH>B|8wVtXs$6zG6E?sub~FUc0fBhB z;Cr7a+BzpRfHyCHPT`&-lpXv6_ZLTA(7-^R)S;9XpEp7TFArXZN_>8}4T6!7WXZZ- zl3^(ElO@mfk|dzyFqhDl7c^}ALI@0q!)W*zh+-EW5o5G}M~ytL!J-O9$?&i{R@5-C z;%h=AvzCDdWcTb~fJQRZql%6@Kp4athd`uuJdO=3+c^Zxh6a@Kp~R&@?Alm}6exdZSp#_9h?v4Wc2!VUz;B{zL)zfPg)_BSmcINy5nmqB>9GwGu| z10wq6+k<-I>Z#mnO--jMkrwB!ufr|g3V7B$9S++;<9aLtUXJf0oREzfOy^pe4cP!X z_D&AmgQR~h+%5IibrsKnG%WyorT~TmxDFJ+551J+ZC_dnMuXcvm*!Cz9@xi=e6i-* z`xtoMto3|LYF0)j{}$J=Cm?Vrq`BHRL(l-k=XSz!kBhSG!~6!1J+TMogTL!pWiP=yzMu8fmjajCNKkKv{kQrMj<5amkz z3>*L{u9rWD_dKrQxT<_fm!8V17Kush=vjCZTx{i+a28guMdzRfO4;diurDIZCUy)G ze@hZ<&PKkofrMY%qT8}@m&dlAhpD4({QYFtach|k$QhDAZ$ zdt96yd^&%~CR~BLXl14;Ww1ICMN1R;EKRg;JqAU3Vej)BusT2W4_`mh8{E0?>NSV z<~5FS=W>{1%yZ`v3$cV;;uz=mR~*Omq`>tUhCWVBm5BLeBTt~IIfeTGUm0oNrz_RK992Y#;hThQQfQ{FQ> zD#7)UpK#n``SX$u*Y_jCS+&d{c+U17JCwaG`I5YA3J6u8L5>b17D3 ziru~lUv@ad@f!l7eZ{Hxd@#0upS$CH`Ftu~=)peMG>UJC~16*($) zU#8&idTE?+v~Tk^4iqbaE9hL`-R&#(&nF5y`qrj=t#-OE3uO&{AkSCJD=o2mR{t&0 zIoDT9DD_P)@T#wIq}csGi|d(rUUsTXvAg_;FFPfctOZ`NsCJ5MWtlIT;#?fPQJ(x7FpVC9>0a&(t3Dnk#CZ%GVx!qtDmM z8=;J>RI9uZI(bz1&f_0I)%fyfLaE2*MCAtE5^BKpNvE&s6j}2B^ds}pjktC!1J|ej z5Z?9}4jXsMlk(6%g-IR*Smi1fR1kewD6*?sU$PVa;>7;EJs;@H0=1P7*b4tRH3HhKnEc{nE3MqG#Kv7D{WrXc9eBQ%~EVx9`p3U;BE)xKZ|y z#a9&BBYf4QSokIPV}ajWnBwbuap-wY3N^Nk8NS->a+X*+swWYtx)qB=$>U#P&XtE| zR(e{7JT#BhiYMawm?`5r{8`a6+p8{drNYmz+UBd-P}aMll~D lrf0mm-Q$$NRQqncCWt;Cs&$P^)cmQt|J^#_BQ@v5{{`v)m7o9s delta 8838 zcmbta3v?7!60LeYlg}g}lYsdVk|BecNkB45Cc{Lcgx?s%BVhpn0f`(07Lg=?2ntR( zx{4A7dAiLCN6{5UVdXPw>xQ!dL5T8G@V6e0;QC{afQYQ070K4??wJhGnP#<5s;ghU z`>NijUcKs`yma1v?x=l5cFzBG;broB@{FgUZ$*h1;Fp6;BQs1*$W`(^{n4T z!QZRkH?==g1E5h5Fni-~r-61rGaBUu?39ABD)qWQt_O@o3ugfSKeX`%z%T{F4@P|V z5Wp~fZ~`zEeKr;FV)||upiZo?4kFZd7BHQH>O=KrV1l0S1#HIxV>+@8mZ1`@BkOfX%{CNzOiujVt*R-htecV+k$ovC{;r>f|LkaiM=Y zc6VS)4eW#;f9$+j?Rm z58l>~?#gX>2=zsIAhZtUo}qC|?a=7rYXno8W!`irm2Z0ptqq18@jl0nkfuZ>ZspO5|_O{|PLsN<)UQ&`^)|2$wIa%EHusv~HMA}NyN9Sb8SJzAS z#JY$$b#6ZYl)!B(l5gkbTSt=(H@|gQS6+Chy?7O=swEYoKh7vsM+rrL;2{#%B2qduBmFqZB!C7@ z2=D{)W5tCj9tLoX~5%2&v1otAX|@~|$Ughj6* zjtjLeuE!pt@6;(shj>^+T$IyQN`Uq9UK`5~?$E`;57WU0hlqzS;a8s$iDp`TGMv7k z+y#Es%j1ZrlP4wu1}Fc+TI1zHF4V9P}f4qQ<0fPY<7 zFJ@SXv$%fI#{aL*V1!(HzH|6-t>bPKk;W3{9>V4QK?_QvUt_=nciJ*(UI{E^p|>{Y>I#in_@M_Dgo_W^$b@p1IV? z<^yjSl#zZ9A;k&_mEu|e^7dz>41V`gJ8Mhk%}Wcd%_PoMsP4P(HO4 z?d*6m@AFWhRZNHmo%xWRolfS99x7zVK;HZ;sr);MeoE&12VfJerj1Vw-LoP=UUIH(t|%_@@t!uaTOol?6P*F*wjna z@Nlyo*YefPF6Nhb!{`kD2?^HoZwORJpjs7F{D_^sp2DjhDa6fk>oZa&zndg&DZKfS zLiVP_*AB_x?~sHZMNkZoMQYnXv!h;B77-M!3oH~AdC8+r>p1ehF>>n&bPj!&dVdq) z!z?dr(+ zj5-i1+0zpd`N+0)$U;B14Mvng{oi@RLZ$y47$#BGfJ3gHs1DB($ZF9B8ZLkQMuJ*{ z{J}#m#L%Wg_oiV*sP7jyrVv~F-R{)by_}3#3S+}v zwRj!IEA_QF5HVifG7<++@w<_DtvzN#W%v{beO$ue%z6!Z^3Kq*NTd*(2DLYzll0-be z6)PCV$zyilP%5t8fzNe~Sf^%}zI06Z0INF2UM!j&=Ps&_gHhq4`03iQ=6wUfaUJME_xC>@}wMp7K@lW zAbZYYj#Y@-l;LM_fW&q&Zub={ulDC}wt6V^!n!J~A5}x8Jm?ar+!KuYO`VbH-IsE90cD%%{W?yu)^*&Z{ED)4N+DNuduR|Y#-)Tac) zKC0)BA{Vl#bHWg)Y5cs%RHHUM{jM?{wPyN3&t;lETyAQ*rGlM~k3^^ngJ?%XEA#l| zTR*@e<%et7ukn%CXoMCYWc(e$+Yq7+_u%!>!!-nM>LHQaOZW(>|&iWzuL>+Ga+3 zb_}(dvrW}%Bbwf5IwB1inr8~sM$~@SWttvwkGaOhEGjuL9B;766hZ^=T$YzUxHP)! zK7;+C2e*%wnF51SNIZFoaBgJbD0zkP%NYa^#%9u(wUjwLfWU zj&w!sYD06Rr2&<$e~n&2L!jmplb<)8FAccqMN^>Wj_n&wO&@*PbfhI)O(DTo+31ca zXgJ1ix0z}gu-z20e5Wbo=x)=6sUIZVZtdRaIMJ_jNB;Hz&3EKPFapwv;HxatP6YNI z`#Hx9?X6UEQzdYMRdl4*MyizoaZ)2H2`ELK>oI^6Etdm~a$Q4Rbk592B{4~g`r2;@ z{3cl%(h)WcA)2loX{Nd~VD=TJz+WdP{^zq_d}GFoM#i&kI`DhmrPM;9&CzAL4u zaAr6qGynqjDv}O%1R_IVYH!JGsWkt1za)Cu{YK7AOGQTA<x=`B}ZTF)$z_V Date: Mon, 24 Feb 2025 16:33:12 +0100 Subject: [PATCH 72/80] lwIpWrapper: CNetIf add ping command --- libraries/Ethernet/src/Ethernet.cpp | 23 ++++++ libraries/Ethernet/src/EthernetC33.h | 6 ++ libraries/WiFi/src/WiFi.cpp | 25 ++++++- libraries/WiFi/src/WiFiC3.h | 7 +- libraries/lwIpWrapper/src/CNetIf.cpp | 105 +++++++++++++++++++++++++++ libraries/lwIpWrapper/src/CNetIf.h | 10 +++ 6 files changed, 173 insertions(+), 3 deletions(-) diff --git a/libraries/Ethernet/src/Ethernet.cpp b/libraries/Ethernet/src/Ethernet.cpp index 993ea2372..c2570d13f 100644 --- a/libraries/Ethernet/src/Ethernet.cpp +++ b/libraries/Ethernet/src/Ethernet.cpp @@ -223,4 +223,27 @@ IPAddress CEthernet::dnsServerIP() { return CLwipIf::getInstance().getDns(); } +/* -------------------------------------------------------------------------- */ +int CEthernet::ping(IPAddress ip, uint8_t ttl) { +/* -------------------------------------------------------------------------- */ + return CLwipIf::getInstance().ping(ip, ttl); +} + +/* -------------------------------------------------------------------------- */ +int CEthernet::ping(const String &hostname, uint8_t ttl) +/* -------------------------------------------------------------------------- */ +{ + return ping(hostname.c_str(), ttl); +} + +/* -------------------------------------------------------------------------- */ +int CEthernet::ping(const char* host, uint8_t ttl) { +/* -------------------------------------------------------------------------- */ + IPAddress ip; + if(CLwipIf::getInstance().getHostByName(host,ip)) { + return CLwipIf::getInstance().ping(ip, ttl); + } + return -1; +} + CEthernet Ethernet; diff --git a/libraries/Ethernet/src/EthernetC33.h b/libraries/Ethernet/src/EthernetC33.h index 5c684fe63..5147d0464 100644 --- a/libraries/Ethernet/src/EthernetC33.h +++ b/libraries/Ethernet/src/EthernetC33.h @@ -69,6 +69,12 @@ class CEthernet { IPAddress gatewayIP(); IPAddress dnsServerIP(); + /* + * PING + */ + int ping(IPAddress ip, uint8_t ttl = 128); + int ping(const String &hostname, uint8_t ttl = 128); + int ping(const char* host, uint8_t ttl = 128); friend class EthernetClient; friend class EthernetServer; diff --git a/libraries/WiFi/src/WiFi.cpp b/libraries/WiFi/src/WiFi.cpp index ba19f311c..db773d457 100644 --- a/libraries/WiFi/src/WiFi.cpp +++ b/libraries/WiFi/src/WiFi.cpp @@ -321,12 +321,33 @@ unsigned long CWifi::getTime() { return 0; } - - void CWifi::setTimeout(unsigned long timeout) { (void)(timeout); } +/* -------------------------------------------------------------------------- */ +int CWifi::ping(IPAddress ip, uint8_t ttl) { +/* -------------------------------------------------------------------------- */ + return CLwipIf::getInstance().ping(ip, ttl); +} + +/* -------------------------------------------------------------------------- */ +int CWifi::ping(const String &hostname, uint8_t ttl) +/* -------------------------------------------------------------------------- */ +{ + return ping(hostname.c_str(), ttl); +} + +/* -------------------------------------------------------------------------- */ +int CWifi::ping(const char* host, uint8_t ttl) { +/* -------------------------------------------------------------------------- */ + IPAddress ip; + if(hostByName(host,ip)) { + return CLwipIf::getInstance().ping(ip, ttl); + } + return -1; +} + CWifi WiFi; diff --git a/libraries/WiFi/src/WiFiC3.h b/libraries/WiFi/src/WiFiC3.h index 2995cdcf9..2ff804d42 100644 --- a/libraries/WiFi/src/WiFiC3.h +++ b/libraries/WiFi/src/WiFiC3.h @@ -254,7 +254,12 @@ class CWifi { void setTimeout(unsigned long timeout); - + /* + * PING + */ + int ping(IPAddress ip, uint8_t ttl = 128); + int ping(const String &hostname, uint8_t ttl = 128); + int ping(const char* host, uint8_t ttl = 128); }; diff --git a/libraries/lwIpWrapper/src/CNetIf.cpp b/libraries/lwIpWrapper/src/CNetIf.cpp index 810b14075..94aa7eb11 100644 --- a/libraries/lwIpWrapper/src/CNetIf.cpp +++ b/libraries/lwIpWrapper/src/CNetIf.cpp @@ -1,5 +1,9 @@ #include "CNetIf.h" #include +#include "lwip/include/lwip/raw.h" +#include "lwip/include/lwip/icmp.h" +#include "lwip/include/lwip/ip_addr.h" +#include "lwip/include/lwip/inet_chksum.h" IPAddress CNetIf::default_ip("192.168.0.10"); IPAddress CNetIf::default_nm("255.255.255.0"); @@ -14,6 +18,32 @@ bool CLwipIf::pending_eth_rx = false; FspTimer CLwipIf::timer; +u8_t icmp_receive_callback(void* arg, struct raw_pcb* pcb, struct pbuf* p, const ip_addr_t* addr) +{ + struct ping_data *d = (struct ping_data*)arg; + struct __attribute__((__packed__)) { + struct ip_hdr ipHeader; + struct icmp_echo_hdr header; + } response; + + if(d->s == pcb) { + if(p->len < sizeof(response)) { + pbuf_free(p); + return 1; + } + + pbuf_copy_partial(p, &response, sizeof(response), 0); + + if(response.header.id == d->echo_req.id && response.header.seqno == d->echo_req.seqno) { + d->endMillis = millis(); + } + pbuf_free(p); + return 1; + } + + return 0; +} + ip_addr_t* u8_to_ip_addr(uint8_t* ipu8, ip_addr_t* ipaddr) { IP_ADDR4(ipaddr, ipu8[0], ipu8[1], ipu8[2], ipu8[3]); @@ -120,6 +150,81 @@ void CLwipIf::lwip_task() } } +int CLwipIf::ping(IPAddress ip, uint8_t ttl) +{ + uint32_t result = -1; + uint32_t timeout = 5000; + uint32_t sendTime = 0; + uint32_t startWait = 0; + struct pbuf *p; + struct raw_pcb* s; + struct ping_data *d = new ping_data; + if (!d){ + goto exit; + } + + //Create a raw socket + s = raw_new(IP_PROTO_ICMP); + if(!s) { + goto exit; + } + + struct __attribute__((__packed__)) { + struct icmp_echo_hdr header; + uint8_t data[32]; + } request; + + ICMPH_TYPE_SET(&request.header, ICMP_ECHO); + ICMPH_CODE_SET(&request.header, 0); + request.header.chksum = 0; + request.header.id = 0xAFAF; + request.header.seqno = random(0xffff); + + d->echo_req = request.header; + + for (size_t i = 0; i < sizeof(request.data); i++) { + request.data[i] = i; + } + + request.header.chksum = inet_chksum(&request, sizeof(request)); + + ip_addr_t addr; + addr.addr = ip; + + d->endMillis = 0; + + raw_recv(s, icmp_receive_callback, d); + + // Build the packet + p = pbuf_alloc(PBUF_IP, sizeof(request), PBUF_RAM); + if (!p) { + goto exit; + } + + //Load payload into buffer + pbuf_take(p, &request, sizeof(request)); + + // Send the echo request + sendTime = millis(); + raw_sendto(s, p, &addr); + + // Wait for response + startWait = millis(); + do { + lwip_task(); + } while (d->endMillis == 0 && (millis() - startWait) < timeout); + + if (d->endMillis != 0) { + result = d->endMillis - sendTime; + } + +exit: + pbuf_free(p); + delete d; + raw_remove(s); + return result; +} + /* -------------------------------------------------------------------------- */ /* GET INSTANCE SINGLETONE FUNCTION */ /* -------------------------------------------------------------------------- */ diff --git a/libraries/lwIpWrapper/src/CNetIf.h b/libraries/lwIpWrapper/src/CNetIf.h index 407501b72..7606d6993 100644 --- a/libraries/lwIpWrapper/src/CNetIf.h +++ b/libraries/lwIpWrapper/src/CNetIf.h @@ -131,6 +131,12 @@ ip_addr_t* u8_to_ip_addr(uint8_t* ipu8, ip_addr_t* ipaddr); uint32_t ip_addr_to_u32(ip_addr_t* ipaddr); +struct ping_data{ + uint32_t endMillis; + icmp_echo_hdr echo_req; + struct raw_pcb* s; +}; + /* Base class implements DHCP, derived class will switch it on or off */ /* -------------------------------------------------------------------------- */ class CNetIf { @@ -436,6 +442,10 @@ class CLwipIf { int setWifiMode(WifiMode_t mode); void lwip_task(); + /* + * PING + */ + int ping(IPAddress ip, uint8_t ttl = 128); }; #endif From f5374059b08a3e0d76b98d58b5eb34b505e04a6c Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 19 Feb 2025 14:15:42 +0100 Subject: [PATCH 73/80] lwIpWrapper: CNetIf fix ping command --- libraries/lwIpWrapper/src/CNetIf.cpp | 139 ++++++++++++--------------- libraries/lwIpWrapper/src/CNetIf.h | 8 +- 2 files changed, 68 insertions(+), 79 deletions(-) diff --git a/libraries/lwIpWrapper/src/CNetIf.cpp b/libraries/lwIpWrapper/src/CNetIf.cpp index 94aa7eb11..e80065459 100644 --- a/libraries/lwIpWrapper/src/CNetIf.cpp +++ b/libraries/lwIpWrapper/src/CNetIf.cpp @@ -18,30 +18,30 @@ bool CLwipIf::pending_eth_rx = false; FspTimer CLwipIf::timer; -u8_t icmp_receive_callback(void* arg, struct raw_pcb* pcb, struct pbuf* p, const ip_addr_t* addr) +static u8_t icmp_receive_callback(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) { - struct ping_data *d = (struct ping_data*)arg; - struct __attribute__((__packed__)) { - struct ip_hdr ipHeader; - struct icmp_echo_hdr header; - } response; + struct icmp_echo_hdr *iecho; + (void)(pcb); + (void)(addr); + LWIP_ASSERT("p != NULL", p != NULL); - if(d->s == pcb) { - if(p->len < sizeof(response)) { - pbuf_free(p); - return 1; - } + recv_callback_data* request = (recv_callback_data*)arg; - pbuf_copy_partial(p, &response, sizeof(response), 0); + if ((p->tot_len >= (PBUF_IP_HLEN + sizeof(struct icmp_echo_hdr))) && + pbuf_remove_header(p, PBUF_IP_HLEN) == 0) { + iecho = (struct icmp_echo_hdr *)p->payload; - if(response.header.id == d->echo_req.id && response.header.seqno == d->echo_req.seqno) { - d->endMillis = millis(); + if ((iecho->id == 0xAFAF) && (iecho->seqno == lwip_htons(request->seqNum))) { + /* do some ping result processing */ + request->endMillis = millis(); + pbuf_free(p); + return 1; /* eat the packet */ } - pbuf_free(p); - return 1; + /* not eaten, restore original packet */ + pbuf_add_header(p, PBUF_IP_HLEN); } - return 0; + return 0; /* don't eat the packet */ } ip_addr_t* u8_to_ip_addr(uint8_t* ipu8, ip_addr_t* ipaddr) @@ -150,79 +150,68 @@ void CLwipIf::lwip_task() } } + int CLwipIf::ping(IPAddress ip, uint8_t ttl) { - uint32_t result = -1; - uint32_t timeout = 5000; - uint32_t sendTime = 0; - uint32_t startWait = 0; - struct pbuf *p; - struct raw_pcb* s; - struct ping_data *d = new ping_data; - if (!d){ - goto exit; - } + /* ttl is not supported. Default value used is 255 */ + (void)ttl; + ip_addr_t addr; + addr.addr = ip; + recv_callback_data requestCbkData = { 0, 0, (uint16_t)random(0xffff) }; //Create a raw socket - s = raw_new(IP_PROTO_ICMP); - if(!s) { - goto exit; - } - - struct __attribute__((__packed__)) { - struct icmp_echo_hdr header; - uint8_t data[32]; - } request; - - ICMPH_TYPE_SET(&request.header, ICMP_ECHO); - ICMPH_CODE_SET(&request.header, 0); - request.header.chksum = 0; - request.header.id = 0xAFAF; - request.header.seqno = random(0xffff); - - d->echo_req = request.header; - - for (size_t i = 0; i < sizeof(request.data); i++) { - request.data[i] = i; + struct raw_pcb* s = raw_new(IP_PROTO_ICMP); + if (!s) { + return -1; } - request.header.chksum = inet_chksum(&request, sizeof(request)); - - ip_addr_t addr; - addr.addr = ip; - - d->endMillis = 0; + raw_recv(s, icmp_receive_callback, (void*)&requestCbkData); + raw_bind(s, IP_ADDR_ANY); - raw_recv(s, icmp_receive_callback, d); + struct pbuf *p; + struct icmp_echo_hdr *iecho; + size_t ping_size = sizeof(struct icmp_echo_hdr) + 32; - // Build the packet - p = pbuf_alloc(PBUF_IP, sizeof(request), PBUF_RAM); + p = pbuf_alloc(PBUF_IP, (u16_t)ping_size, PBUF_RAM); if (!p) { - goto exit; + raw_remove(s); + return -1; } - //Load payload into buffer - pbuf_take(p, &request, sizeof(request)); + if ((p->len == p->tot_len) && (p->next == NULL)) { + iecho = (struct icmp_echo_hdr *)p->payload; - // Send the echo request - sendTime = millis(); - raw_sendto(s, p, &addr); + size_t i; + size_t data_len = ping_size - sizeof(struct icmp_echo_hdr); - // Wait for response - startWait = millis(); - do { - lwip_task(); - } while (d->endMillis == 0 && (millis() - startWait) < timeout); - - if (d->endMillis != 0) { - result = d->endMillis - sendTime; + ICMPH_TYPE_SET(iecho, ICMP_ECHO); + ICMPH_CODE_SET(iecho, 0); + iecho->chksum = 0; + iecho->id = 0xAFAF; + iecho->seqno = lwip_htons(requestCbkData.seqNum); + + /* fill the additional data buffer with some data */ + for(i = 0; i < data_len; i++) { + ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; + } + + iecho->chksum = inet_chksum(iecho, ping_size); + requestCbkData.startMillis = millis(); + raw_sendto(s, p, &addr); + + } + pbuf_free(p); + + bool timeout = false; + while (!requestCbkData.endMillis && !timeout) { + timeout = (millis() - requestCbkData.startMillis) > 5000; + } + + if (timeout) { + return -1; } -exit: - pbuf_free(p); - delete d; - raw_remove(s); - return result; + return requestCbkData.endMillis - requestCbkData.startMillis; } /* -------------------------------------------------------------------------- */ diff --git a/libraries/lwIpWrapper/src/CNetIf.h b/libraries/lwIpWrapper/src/CNetIf.h index 7606d6993..21a1ebaf9 100644 --- a/libraries/lwIpWrapper/src/CNetIf.h +++ b/libraries/lwIpWrapper/src/CNetIf.h @@ -131,10 +131,10 @@ ip_addr_t* u8_to_ip_addr(uint8_t* ipu8, ip_addr_t* ipaddr); uint32_t ip_addr_to_u32(ip_addr_t* ipaddr); -struct ping_data{ - uint32_t endMillis; - icmp_echo_hdr echo_req; - struct raw_pcb* s; +struct recv_callback_data{ + u32_t startMillis; + u32_t endMillis; + u16_t seqNum; }; /* Base class implements DHCP, derived class will switch it on or off */ From 489d637270f671878a780fb26a052d82dd87241a Mon Sep 17 00:00:00 2001 From: fabik111 Date: Thu, 27 Feb 2025 16:33:05 +0100 Subject: [PATCH 74/80] lwIpWrapper: CNetIf refactor ping functions --- libraries/Ethernet/src/Ethernet.cpp | 14 +++++------ libraries/WiFi/src/WiFi.cpp | 2 +- libraries/lwIpWrapper/src/CNetIf.cpp | 35 +++++++++++++++++----------- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/libraries/Ethernet/src/Ethernet.cpp b/libraries/Ethernet/src/Ethernet.cpp index c2570d13f..35bbd4fd3 100644 --- a/libraries/Ethernet/src/Ethernet.cpp +++ b/libraries/Ethernet/src/Ethernet.cpp @@ -226,24 +226,24 @@ IPAddress CEthernet::dnsServerIP() { /* -------------------------------------------------------------------------- */ int CEthernet::ping(IPAddress ip, uint8_t ttl) { /* -------------------------------------------------------------------------- */ - return CLwipIf::getInstance().ping(ip, ttl); + return CLwipIf::getInstance().ping(ip, ttl); } /* -------------------------------------------------------------------------- */ int CEthernet::ping(const String &hostname, uint8_t ttl) /* -------------------------------------------------------------------------- */ { - return ping(hostname.c_str(), ttl); + return ping(hostname.c_str(), ttl); } /* -------------------------------------------------------------------------- */ int CEthernet::ping(const char* host, uint8_t ttl) { /* -------------------------------------------------------------------------- */ - IPAddress ip; - if(CLwipIf::getInstance().getHostByName(host,ip)) { - return CLwipIf::getInstance().ping(ip, ttl); - } - return -1; + IPAddress ip; + if(CLwipIf::getInstance().getHostByName(host,ip)) { + return CLwipIf::getInstance().ping(ip, ttl); + } + return -1; } CEthernet Ethernet; diff --git a/libraries/WiFi/src/WiFi.cpp b/libraries/WiFi/src/WiFi.cpp index db773d457..fe4a7e7b1 100644 --- a/libraries/WiFi/src/WiFi.cpp +++ b/libraries/WiFi/src/WiFi.cpp @@ -335,7 +335,7 @@ int CWifi::ping(IPAddress ip, uint8_t ttl) { int CWifi::ping(const String &hostname, uint8_t ttl) /* -------------------------------------------------------------------------- */ { - return ping(hostname.c_str(), ttl); + return ping(hostname.c_str(), ttl); } /* -------------------------------------------------------------------------- */ diff --git a/libraries/lwIpWrapper/src/CNetIf.cpp b/libraries/lwIpWrapper/src/CNetIf.cpp index e80065459..01a2c169d 100644 --- a/libraries/lwIpWrapper/src/CNetIf.cpp +++ b/libraries/lwIpWrapper/src/CNetIf.cpp @@ -26,22 +26,24 @@ static u8_t icmp_receive_callback(void *arg, struct raw_pcb *pcb, struct pbuf *p LWIP_ASSERT("p != NULL", p != NULL); recv_callback_data* request = (recv_callback_data*)arg; + if ((p->tot_len < (PBUF_IP_HLEN + sizeof(struct icmp_echo_hdr))) || + pbuf_remove_header(p, PBUF_IP_HLEN) != 0) { + return 0; /* don't consume the packet */ + } - if ((p->tot_len >= (PBUF_IP_HLEN + sizeof(struct icmp_echo_hdr))) && - pbuf_remove_header(p, PBUF_IP_HLEN) == 0) { - iecho = (struct icmp_echo_hdr *)p->payload; + iecho = (struct icmp_echo_hdr *)p->payload; - if ((iecho->id == 0xAFAF) && (iecho->seqno == lwip_htons(request->seqNum))) { - /* do some ping result processing */ - request->endMillis = millis(); - pbuf_free(p); - return 1; /* eat the packet */ - } + if(iecho->id != 0xAFAF || iecho->seqno != lwip_htons(request->seqNum)) { /* not eaten, restore original packet */ pbuf_add_header(p, PBUF_IP_HLEN); + return 0; } - return 0; /* don't eat the packet */ + /* do some ping result processing */ + request->endMillis = millis(); + pbuf_free(p); + return 1; /* consume the packet */ + } ip_addr_t* u8_to_ip_addr(uint8_t* ipu8, ip_addr_t* ipaddr) @@ -202,12 +204,17 @@ int CLwipIf::ping(IPAddress ip, uint8_t ttl) } pbuf_free(p); - bool timeout = false; - while (!requestCbkData.endMillis && !timeout) { - timeout = (millis() - requestCbkData.startMillis) > 5000; + CLwipIf::getInstance().startSyncRequest(); + + while (!requestCbkData.endMillis && (millis() - requestCbkData.startMillis) <= 5000) { + CLwipIf::getInstance().lwip_task(); } - if (timeout) { + CLwipIf::getInstance().restartAsyncRequest(); + + raw_remove(s); + + if (!requestCbkData.endMillis) { return -1; } From 7f6ad1ea9b24b4e7cad0c67d62d7272c17a6fbe3 Mon Sep 17 00:00:00 2001 From: fabik111 Date: Thu, 27 Feb 2025 16:33:35 +0100 Subject: [PATCH 75/80] add ping examples --- .../examples/EthernetPing/EthernetPing.ino | 83 ++++++++++++ libraries/WiFi/examples/WiFiPing/WiFiPing.ino | 120 ++++++++++++++++++ .../WiFi/examples/WiFiPing/arduino_secrets.h | 2 + 3 files changed, 205 insertions(+) create mode 100644 libraries/Ethernet/examples/EthernetPing/EthernetPing.ino create mode 100644 libraries/WiFi/examples/WiFiPing/WiFiPing.ino create mode 100644 libraries/WiFi/examples/WiFiPing/arduino_secrets.h diff --git a/libraries/Ethernet/examples/EthernetPing/EthernetPing.ino b/libraries/Ethernet/examples/EthernetPing/EthernetPing.ino new file mode 100644 index 000000000..2baadaadd --- /dev/null +++ b/libraries/Ethernet/examples/EthernetPing/EthernetPing.ino @@ -0,0 +1,83 @@ +/* + Web ICMP Ping + + This sketch pings a device based on the IP address or the hostname + using the Ethernet module. + + created 14 February 2024 + by paulvha + + updated 27 February 2025 + by Fabik111 + + */ + +#include "EthernetC33.h" + +int status = WL_IDLE_STATUS; + +// Set the static IP address to use if the DHCP fails to assign +IPAddress ip(10, 130, 22, 84); + +/* -------------------------------------------------------------------------- */ +void setup() { +/* -------------------------------------------------------------------------- */ + //Initialize serial and wait for port to open: + Serial.begin(115200); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // start the Ethernet connection: + if (Ethernet.begin() == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // try to configure using IP address instead of DHCP: + // IN THAT CASE YOU SHOULD CONFIGURE manually THE DNS or USE the IPAddress Server variable above + // that is what is automatically done here... + Ethernet.begin(ip); + } + // give the Ethernet shield a second to initialize: + delay(2000); +} + +/* -------------------------------------------------------------------------- */ +void loop() { +/* -------------------------------------------------------------------------- */ + + // Ping IP + const IPAddress remote_ip(140,82,121,4); + Serial.print("Trying to ping github.com on IP: "); + Serial.println(remote_ip); + + // using default ping count of 1 + int res = Ethernet.ping(remote_ip); + + if (res > 0) { + Serial.print("Ping response time: "); + Serial.print(res); + Serial.println(" ms"); + } + else { + Serial.println("Timeout on IP!"); + } + + // Ping Host + const char* remote_host = "www.google.com"; + Serial.print("Trying to ping host: "); + Serial.println(remote_host); + + // setting ttl to 128 and ping count to 10 + int res1 = Ethernet.ping(remote_host); + + if (res1 > 0) { + Serial.print("Ping average response time: "); + Serial.print(res1); + Serial.println(" ms"); + } + else { + Serial.println("Timeout on host!"); + } + + Serial.println(); + delay(1000); +} diff --git a/libraries/WiFi/examples/WiFiPing/WiFiPing.ino b/libraries/WiFi/examples/WiFiPing/WiFiPing.ino new file mode 100644 index 000000000..a8f9ee979 --- /dev/null +++ b/libraries/WiFi/examples/WiFiPing/WiFiPing.ino @@ -0,0 +1,120 @@ +/* + Web ICMP Ping + + This sketch pings a device based on the IP address or the hostname + using the WiFi module. By default the attempt is performed 5 times, but can + be changed to max. 255 + + It requires at least version 0.5.0 of USB Wifi bridge firmware and WiFiS3 library. + + This example is written for a network using WPA encryption. For + WEP or WPA, change the WiFi.begin() call accordingly. + + created 14 February 2024 + by paulvha + + updated 27 February 2025 + by Fabik111 + + */ + +#include "WiFiC3.h" +#include "arduino_secrets.h" + +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key index number (needed only for WEP) + +int status = WL_IDLE_STATUS; + +/* -------------------------------------------------------------------------- */ +void setup() { +/* -------------------------------------------------------------------------- */ + //Initialize serial and wait for port to open: + Serial.begin(115200); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed."); + // don't continue + while (true); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + + printWifiStatus(); +} + +/* -------------------------------------------------------------------------- */ +void loop() { +/* -------------------------------------------------------------------------- */ + + // Ping IP + const IPAddress remote_ip(140,82,121,4); + Serial.print("Trying to ping github.com on IP: "); + Serial.println(remote_ip); + + // using default ping count of 1 + int res = WiFi.ping(remote_ip); + + if (res > 0) { + Serial.print("Ping response time: "); + Serial.print(res); + Serial.println(" ms"); + } + else { + Serial.println("Timeout on IP!"); + } + + // Ping Host + const char* remote_host = "www.google.com"; + Serial.print("Trying to ping host: "); + Serial.println(remote_host); + + // setting ttl to 128 and ping count to 10 + int res1 = WiFi.ping(remote_host); + + if (res1 > 0) { + Serial.print("Ping average response time: "); + Serial.print(res1); + Serial.println(" ms"); + } + else { + Serial.println("Timeout on host!"); + } + + Serial.println(); + delay(1000); +} + +/* -------------------------------------------------------------------------- */ +void printWifiStatus() { +/* -------------------------------------------------------------------------- */ + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/libraries/WiFi/examples/WiFiPing/arduino_secrets.h b/libraries/WiFi/examples/WiFiPing/arduino_secrets.h new file mode 100644 index 000000000..0c9fdd556 --- /dev/null +++ b/libraries/WiFi/examples/WiFiPing/arduino_secrets.h @@ -0,0 +1,2 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" From 8094f719bf74c5327438902b9883e8abcef73c9e Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 3 Mar 2025 09:05:20 +0100 Subject: [PATCH 76/80] lwIpWrapper: CNetIf make recv_callback_data a static data structure This ensure access to existing data if icmp callback is fired after ping timeout --- libraries/lwIpWrapper/src/CNetIf.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libraries/lwIpWrapper/src/CNetIf.cpp b/libraries/lwIpWrapper/src/CNetIf.cpp index 01a2c169d..ca1495f50 100644 --- a/libraries/lwIpWrapper/src/CNetIf.cpp +++ b/libraries/lwIpWrapper/src/CNetIf.cpp @@ -43,7 +43,6 @@ static u8_t icmp_receive_callback(void *arg, struct raw_pcb *pcb, struct pbuf *p request->endMillis = millis(); pbuf_free(p); return 1; /* consume the packet */ - } ip_addr_t* u8_to_ip_addr(uint8_t* ipu8, ip_addr_t* ipaddr) @@ -159,9 +158,15 @@ int CLwipIf::ping(IPAddress ip, uint8_t ttl) (void)ttl; ip_addr_t addr; addr.addr = ip; - recv_callback_data requestCbkData = { 0, 0, (uint16_t)random(0xffff) }; - //Create a raw socket + /* ICMP ping callback data structure */ + static recv_callback_data requestCbkData; + + /* initialize callback data for a new request */ + memset(&requestCbkData, 0, sizeof(recv_callback_data)); + requestCbkData.seqNum = (uint16_t)random(0xffff); + + /* Create a raw socket */ struct raw_pcb* s = raw_new(IP_PROTO_ICMP); if (!s) { return -1; From e18bdeaaaa799169e6c4a7fdba91d945a0f12bad Mon Sep 17 00:00:00 2001 From: fabik111 Date: Wed, 23 Oct 2024 13:57:24 +0200 Subject: [PATCH 77/80] WiFiS3: make scanNetworks return the first 10 AP with higer RSSI --- libraries/WiFiS3/src/WiFi.cpp | 142 ++++++++++++++++++++++------------ libraries/WiFiS3/src/WiFi.h | 35 +++++++-- 2 files changed, 119 insertions(+), 58 deletions(-) diff --git a/libraries/WiFiS3/src/WiFi.cpp b/libraries/WiFiS3/src/WiFi.cpp index 249a9ef05..8be758fd3 100644 --- a/libraries/WiFiS3/src/WiFi.cpp +++ b/libraries/WiFiS3/src/WiFi.cpp @@ -1,5 +1,7 @@ #include "WiFi.h" +#define SSID_MAX_COUNT 12 + using namespace std; /* -------------------------------------------------------------------------- */ @@ -256,6 +258,42 @@ uint8_t* CWifi::macAddress(uint8_t* _mac) { return _mac; } +/* -------------------------------------------------------------------------- */ +void CWifi::_sortAPlist(uint8_t num) { +/* -------------------------------------------------------------------------- */ + for(uint8_t i = 0; i < num; i++) { + for(uint8_t j = i+1; j < num; j++) { + if(access_points[j].rssi > access_points[i].rssi) { + CAccessPoint temp = access_points[i]; + access_points[i] = access_points[j]; + access_points[j] = temp; + } + } + } +} + +static uint8_t Encr2wl_enc(string e) { + if (e == string("open")) { + return ENC_TYPE_NONE; + } else if (e == string("WEP")) { + return ENC_TYPE_WEP; + } else if (e == string("WPA")) { + return ENC_TYPE_WPA; + } else if (e == string("WPA2")) { + return ENC_TYPE_WPA2; + } else if (e == string("WPA+WPA2")) { + return ENC_TYPE_WPA2; + } else if (e == string("WPA2-EAP")) { + return ENC_TYPE_WPA2_ENTERPRISE; + } else if (e == string("WPA2+WPA3")) { + return ENC_TYPE_WPA3; + } else if (e == string("WPA3")) { + return ENC_TYPE_WPA3; + } else { + return ENC_TYPE_UNKNOWN; + } +} + /* -------------------------------------------------------------------------- */ int8_t CWifi::scanNetworks() { /* -------------------------------------------------------------------------- */ @@ -264,30 +302,56 @@ int8_t CWifi::scanNetworks() { modem.avoid_trim_results(); modem.read_using_size(); - access_points.clear(); + memset(access_points,0x00,sizeof(access_points)); + _apsFound = 0; string res; - - vector aps; if(modem.write(string(PROMPT(_WIFISCAN)),res,CMD(_WIFISCAN))) { - - split(aps, res, string("\r\n")); - for(uint16_t i = 0; i < aps.size(); i++) { + char *startAp = (char*)res.c_str(); + char *endAP = strstr(startAp, "\r\n"); + for(; endAP != NULL; startAp = endAP, endAP = strstr(startAp, "\r\n")) { CAccessPoint ap; - vector tokens; - split(tokens, aps[i], string("|")); - if(tokens.size() >= 5) { - ap.ssid = tokens[0]; - ap.bssid = tokens[1]; - macStr2macArray(ap.uint_bssid, ap.bssid.c_str()); - ap.rssi = tokens[2]; - ap.channel = tokens[3]; - ap.encryption_mode = tokens[4]; - access_points.push_back(ap); + char *token[5]; + *endAP++ = '\0'; // Replace \r with \0 + endAP++; + char *startToken = startAp; + char *endToken = strstr(startAp, " | "); + uint8_t i = 0; + for(; i < 5 && endToken != NULL; i++){ + token[i] = startToken; + *endToken++ = '\0'; + endToken = endToken + 2; + startToken = endToken; + endToken = strstr(startToken, " | "); + if(endToken == NULL){ + token[++i] = startToken; + } + } + + if(i>=5) { + if(strlen(token[0]) > WL_SSID_MAX_LENGTH || strlen(token[1]) != WL_MAX_BSSID_LENGTH){ + continue; + } + strcpy(ap.ssid, token[0]); + macStr2macArray(ap.uint_bssid, token[1]); + ap.rssi = atoi(token[2]); + ap.channel = atoi(token[3]); + ap.encryption_mode = Encr2wl_enc(token[4]); + // insert in list + if( _apsFound < WL_MAX_AP_LIST ){ + access_points[_apsFound] = ap; + _apsFound++; + _sortAPlist(_apsFound); + }else{ + if (ap.rssi > access_points[WL_MAX_AP_LIST-1].rssi){ + access_points[WL_MAX_AP_LIST-1] = ap; + _sortAPlist(WL_MAX_AP_LIST); + } + } } } } - return (int8_t)access_points.size(); + return _apsFound; } /* -------------------------------------------------------------------------- */ @@ -376,8 +440,8 @@ IPAddress CWifi::gatewayIP() { /* -------------------------------------------------------------------------- */ const char* CWifi::SSID(uint8_t networkItem) { /* -------------------------------------------------------------------------- */ - if(networkItem < access_points.size()) { - return access_points[networkItem].ssid.c_str(); + if(networkItem < _apsFound) { + return access_points[networkItem].ssid; } return nullptr; } @@ -385,42 +449,20 @@ const char* CWifi::SSID(uint8_t networkItem) { /* -------------------------------------------------------------------------- */ int32_t CWifi::RSSI(uint8_t networkItem) { /* -------------------------------------------------------------------------- */ - if(networkItem < access_points.size()) { - return atoi(access_points[networkItem].rssi.c_str()); + if(networkItem < _apsFound) { + return access_points[networkItem].rssi; } return -1000; } -static uint8_t Encr2wl_enc(string e) { - if (e == string("open")) { - return ENC_TYPE_NONE; - } else if (e == string("WEP")) { - return ENC_TYPE_WEP; - } else if (e == string("WPA")) { - return ENC_TYPE_WPA; - } else if (e == string("WPA2")) { - return ENC_TYPE_WPA2; - } else if (e == string("WPA+WPA2")) { - return ENC_TYPE_WPA2; - } else if (e == string("WPA2-EAP")) { - return ENC_TYPE_WPA2_ENTERPRISE; - } else if (e == string("WPA2+WPA3")) { - return ENC_TYPE_WPA3; - } else if (e == string("WPA3")) { - return ENC_TYPE_WPA3; - } else { - return ENC_TYPE_UNKNOWN; - } -} - /* -------------------------------------------------------------------------- */ uint8_t CWifi::encryptionType() { /* -------------------------------------------------------------------------- */ scanNetworks(); string myssid(SSID()); - for(unsigned int i = 0; i < access_points.size(); i++) { + for(unsigned int i = 0; i < _apsFound; i++) { if(myssid == access_points[i].ssid) { - return Encr2wl_enc(access_points[i].encryption_mode); + return access_points[i].encryption_mode; } } return ENC_TYPE_UNKNOWN; @@ -429,8 +471,8 @@ uint8_t CWifi::encryptionType() { /* -------------------------------------------------------------------------- */ uint8_t CWifi::encryptionType(uint8_t networkItem) { /* -------------------------------------------------------------------------- */ - if(networkItem < access_points.size()) { - return Encr2wl_enc(access_points[networkItem].encryption_mode); + if(networkItem < _apsFound) { + return access_points[networkItem].encryption_mode; } return 0; } @@ -438,7 +480,7 @@ uint8_t CWifi::encryptionType(uint8_t networkItem) { /* -------------------------------------------------------------------------- */ uint8_t* CWifi::BSSID(uint8_t networkItem, uint8_t* bssid) { /* -------------------------------------------------------------------------- */ - if(networkItem < access_points.size()) { + if(networkItem < _apsFound) { for(int i = 0; i < 6; i++) { *(bssid + i) = access_points[networkItem].uint_bssid[i]; } @@ -450,8 +492,8 @@ uint8_t* CWifi::BSSID(uint8_t networkItem, uint8_t* bssid) { /* -------------------------------------------------------------------------- */ uint8_t CWifi::channel(uint8_t networkItem) { /* -------------------------------------------------------------------------- */ - if(networkItem < access_points.size()) { - return atoi(access_points[networkItem].channel.c_str()); + if(networkItem < _apsFound) { + return access_points[networkItem].channel; } return 0; } diff --git a/libraries/WiFiS3/src/WiFi.h b/libraries/WiFiS3/src/WiFi.h index 0e2999b7c..22888a735 100644 --- a/libraries/WiFiS3/src/WiFi.h +++ b/libraries/WiFiS3/src/WiFi.h @@ -19,24 +19,43 @@ #define WIFI_FIRMWARE_LATEST_VERSION "0.5.2" +#define WL_MAX_AP_LIST 10 +#define WL_MAX_BSSID_LENGTH 17 +#define WL_MAX_SSID_LENGHT_S WL_SSID_MAX_LENGTH + 1 // +1 for null terminator + class CAccessPoint { public: - std::string ssid; - std::string bssid; + CAccessPoint() {} + CAccessPoint(const CAccessPoint &obj) + { + strcpy(ssid, obj.ssid); + rssi = obj.rssi; + channel = obj.channel; + encryption_mode = obj.encryption_mode; + memcpy(uint_bssid, obj.uint_bssid, sizeof(uint_bssid)); + } + CAccessPoint &operator=(const CAccessPoint &obj) { + strcpy(ssid, obj.ssid); + rssi = obj.rssi; + channel = obj.channel; + encryption_mode = obj.encryption_mode; + memcpy(uint_bssid, obj.uint_bssid, sizeof(uint_bssid)); + } + char ssid[WL_MAX_SSID_LENGHT_S]; uint8_t uint_bssid[6]; - std::string rssi; - std::string channel; - std::string encryption_mode; + int rssi; + uint8_t channel; + uint8_t encryption_mode; }; - - class CWifi { private: void _config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2); + void _sortAPlist(uint8_t num); unsigned long _timeout; - std::vector access_points; + CAccessPoint access_points[WL_MAX_AP_LIST]; + uint8_t _apsFound = 0; std::string ssid; std::string apssid; From 2850297ab0766c4fb59b1b02638b31f1e4df9366 Mon Sep 17 00:00:00 2001 From: fabik111 Date: Wed, 5 Feb 2025 15:42:40 +0100 Subject: [PATCH 78/80] WiFiS3: remove unused define --- libraries/WiFiS3/src/WiFi.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/WiFiS3/src/WiFi.cpp b/libraries/WiFiS3/src/WiFi.cpp index 8be758fd3..0ee42a4c5 100644 --- a/libraries/WiFiS3/src/WiFi.cpp +++ b/libraries/WiFiS3/src/WiFi.cpp @@ -1,7 +1,5 @@ #include "WiFi.h" -#define SSID_MAX_COUNT 12 - using namespace std; /* -------------------------------------------------------------------------- */ From ec15716f021847999fb79baff31129941f1fb17e Mon Sep 17 00:00:00 2001 From: fabik111 Date: Thu, 27 Feb 2025 12:13:27 +0100 Subject: [PATCH 79/80] WiFiS3: scanNetwors refactor --- libraries/WiFiS3/src/WiFi.cpp | 72 +++++++++++++++++++---------------- libraries/WiFiS3/src/WiFi.h | 10 ++--- 2 files changed, 44 insertions(+), 38 deletions(-) diff --git a/libraries/WiFiS3/src/WiFi.cpp b/libraries/WiFiS3/src/WiFi.cpp index 0ee42a4c5..9cb2b5c03 100644 --- a/libraries/WiFiS3/src/WiFi.cpp +++ b/libraries/WiFiS3/src/WiFi.cpp @@ -1,5 +1,7 @@ #include "WiFi.h" +#define WIFI_MAX_BSSID_STRING_LENGTH 17 + using namespace std; /* -------------------------------------------------------------------------- */ @@ -306,44 +308,48 @@ int8_t CWifi::scanNetworks() { if(modem.write(string(PROMPT(_WIFISCAN)),res,CMD(_WIFISCAN))) { char *startAp = (char*)res.c_str(); char *endAP = strstr(startAp, "\r\n"); - for(; endAP != NULL; startAp = endAP, endAP = strstr(startAp, "\r\n")) { - CAccessPoint ap; + for(; endAP != NULL; startAp = endAP + 2, endAP = strstr(startAp, "\r\n")) { + /* split the modem response in multiple lines and parse once at time. + * The output will be something like: + * SSID | BSSID | RSSI | CHANNEL | SECURITY + */ + *endAP = '\0'; // Replace \r with \0 + char *token[5]; - *endAP++ = '\0'; // Replace \r with \0 - endAP++; - char *startToken = startAp; - char *endToken = strstr(startAp, " | "); - uint8_t i = 0; - for(; i < 5 && endToken != NULL; i++){ - token[i] = startToken; - *endToken++ = '\0'; - endToken = endToken + 2; - startToken = endToken; - endToken = strstr(startToken, " | "); + uint8_t i = 1; + token[0] = startAp; + for(; i < 5; i++){ + char *endToken = strstr(token[i-1], " | "); if(endToken == NULL){ - token[++i] = startToken; + break; } + memset(endToken, '\0', 3); + token[i] = endToken + 3; } - if(i>=5) { - if(strlen(token[0]) > WL_SSID_MAX_LENGTH || strlen(token[1]) != WL_MAX_BSSID_LENGTH){ - continue; - } - strcpy(ap.ssid, token[0]); - macStr2macArray(ap.uint_bssid, token[1]); - ap.rssi = atoi(token[2]); - ap.channel = atoi(token[3]); - ap.encryption_mode = Encr2wl_enc(token[4]); - // insert in list - if( _apsFound < WL_MAX_AP_LIST ){ - access_points[_apsFound] = ap; - _apsFound++; - _sortAPlist(_apsFound); - }else{ - if (ap.rssi > access_points[WL_MAX_AP_LIST-1].rssi){ - access_points[WL_MAX_AP_LIST-1] = ap; - _sortAPlist(WL_MAX_AP_LIST); - } + if(i < 5 || strlen(token[0]) == 0 || strlen(token[0]) > WL_SSID_MAX_LENGTH || + strlen(token[1]) != WIFI_MAX_BSSID_STRING_LENGTH || + strlen(token[2]) == 0 || strlen(token[3]) == 0 || strlen(token[4]) == 0){ + /* Skip the row and process the next one */ + continue; + } + + CAccessPoint ap; + strcpy(ap.ssid, token[0]); + macStr2macArray(ap.uint_bssid, token[1]); + ap.rssi = atoi(token[2]); + ap.channel = atoi(token[3]); + ap.encryption_mode = Encr2wl_enc(token[4]); + + // insert in list + if( _apsFound < WIFI_MAX_SSID_COUNT ){ + access_points[_apsFound] = ap; + _apsFound++; + _sortAPlist(_apsFound); + }else{ + if (ap.rssi > access_points[WIFI_MAX_SSID_COUNT-1].rssi){ + access_points[WIFI_MAX_SSID_COUNT-1] = ap; + _sortAPlist(WIFI_MAX_SSID_COUNT); } } } diff --git a/libraries/WiFiS3/src/WiFi.h b/libraries/WiFiS3/src/WiFi.h index 22888a735..cfb8bf011 100644 --- a/libraries/WiFiS3/src/WiFi.h +++ b/libraries/WiFiS3/src/WiFi.h @@ -19,9 +19,9 @@ #define WIFI_FIRMWARE_LATEST_VERSION "0.5.2" -#define WL_MAX_AP_LIST 10 -#define WL_MAX_BSSID_LENGTH 17 -#define WL_MAX_SSID_LENGHT_S WL_SSID_MAX_LENGTH + 1 // +1 for null terminator +#ifndef WIFI_MAX_SSID_COUNT + #define WIFI_MAX_SSID_COUNT 10 +#endif class CAccessPoint { public: @@ -41,7 +41,7 @@ class CAccessPoint { encryption_mode = obj.encryption_mode; memcpy(uint_bssid, obj.uint_bssid, sizeof(uint_bssid)); } - char ssid[WL_MAX_SSID_LENGHT_S]; + char ssid[WL_SSID_MAX_LENGTH + 1]; // +1 for null terminator uint8_t uint_bssid[6]; int rssi; uint8_t channel; @@ -54,7 +54,7 @@ class CWifi { void _config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2); void _sortAPlist(uint8_t num); unsigned long _timeout; - CAccessPoint access_points[WL_MAX_AP_LIST]; + CAccessPoint access_points[WIFI_MAX_SSID_COUNT]; uint8_t _apsFound = 0; std::string ssid; std::string apssid; From 936d04864b723271db984c99d7cfabf17c14524d Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 4 Mar 2025 08:40:02 +0100 Subject: [PATCH 80/80] Publish 1.4.0 --- platform.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform.txt b/platform.txt index 19740871b..8b46d2841 100644 --- a/platform.txt +++ b/platform.txt @@ -3,7 +3,7 @@ # https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification name=Arduino Renesas fsp Boards -version=1.3.2 +version=1.4.0 # Compile variables # ------------------------