From 18ac21e25789d274741725fe3922fc1224a9e7a6 Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Mon, 19 Jan 2026 12:55:12 +0800 Subject: [PATCH] Enhance NVSStorageHandler with filtering capabilities and update constructor to accept namespace --- main/io/io.h | 12 +++-- main/io/nvs_handler.cpp | 108 ++++++++++++++++++++++++++++++++++++++-- main/io/nvs_handler.h | 52 +++++++++++++++++-- main/main.cpp | 4 +- 4 files changed, 164 insertions(+), 12 deletions(-) diff --git a/main/io/io.h b/main/io/io.h index a25e2a8..4ac8b11 100644 --- a/main/io/io.h +++ b/main/io/io.h @@ -2,6 +2,9 @@ #include "freertos/FreeRTOS.h" #include "freertos/event_groups.h" +typedef bool(*FilterFunc)(const char* const& key); +typedef void (*KeyValueProcessor)(void* arg, const char* const& key, const char* const& value); + class KVStorageHandler { public: virtual ~KVStorageHandler() = default; @@ -9,12 +12,15 @@ public: virtual void init(const EventGroupHandle_t& system_event_group) = 0; // Store a key-value pair - virtual void put(const char*& key, const char*& value) = 0; + virtual void put(const char* const& key, const char* const& value) = 0; // Retrieve a value by key, returns nullptr if key not found // The caller is responsible for freeing the returned memory - virtual char* get(const char*& key) const = 0; + virtual char* get(const char* const& key) const = 0; + virtual esp_err_t process_all(KeyValueProcessor processor, void* arg) const = 0; + virtual esp_err_t process_filtered(const char* const& key_prefix, KeyValueProcessor processor, void* arg) const = 0; + virtual esp_err_t process_filtered(FilterFunc filter_func, KeyValueProcessor processor, void* arg) const = 0; // Delete a key-value pair - virtual void remove(const char*& key) = 0; + virtual void remove(const char* const& key) = 0; }; \ No newline at end of file diff --git a/main/io/nvs_handler.cpp b/main/io/nvs_handler.cpp index 7037d26..2803f2d 100644 --- a/main/io/nvs_handler.cpp +++ b/main/io/nvs_handler.cpp @@ -1,6 +1,11 @@ #include "common/constants.h" #include "io/nvs_handler.h" #include "nvs_flash.h" +#include "string.h" + +NVSStorageHandler::NVSStorageHandler( + const char* name_space +) : name_space(name_space) { } NVSStorageHandler::~NVSStorageHandler() { if (this->nvsHandle != 0) { @@ -17,7 +22,7 @@ void NVSStorageHandler::init(const EventGroupHandle_t& system_event_group) { } ESP_ERROR_CHECK(err); - err = nvs_open("storage", NVS_READWRITE, &this->nvsHandle); + err = nvs_open(this->name_space, NVS_READWRITE, &this->nvsHandle); if (err != ESP_OK) { printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err)); } else { @@ -26,7 +31,7 @@ void NVSStorageHandler::init(const EventGroupHandle_t& system_event_group) { } } -void NVSStorageHandler::put(const char*& key, const char*& value) { +void NVSStorageHandler::put(const char* const& key, const char* const& value) { if (this->nvsHandle == 0) { printf("NVS handle is not initialized.\n"); return; @@ -41,7 +46,7 @@ void NVSStorageHandler::put(const char*& key, const char*& value) { } } -char* NVSStorageHandler::get(const char*& key) const { +char* NVSStorageHandler::get(const char* const& key) const { if (this->nvsHandle == 0) { printf("NVS handle is not initialized.\n"); return nullptr; @@ -68,7 +73,102 @@ char* NVSStorageHandler::get(const char*& key) const { return value; } -void NVSStorageHandler::remove(const char*& key) { +NVSIteratorGuard NVSStorageHandler::create_iterator() const { + nvs_iterator_t it = nullptr; + esp_err_t err = nvs_entry_find(NVS_DEFAULT_PART_NAME, this->name_space, NVS_TYPE_ANY, &it); + if (err != ESP_OK) { + printf("Error (%s) creating NVS iterator!\n", esp_err_to_name(err)); + return NVSIteratorGuard(nullptr, err); + } + + return NVSIteratorGuard(it, ESP_OK); +} + +esp_err_t NVSStorageHandler::process_all(KeyValueProcessor processor, void* arg) const { + NVSIteratorGuard iterator_guard = this->create_iterator(); + if (!iterator_guard.is_valid()) { + return iterator_guard.get_error(); + } + const nvs_iterator_t& it = iterator_guard.get_iterator(); + + for (; it != NULL; iterator_guard.advance_iter()) { + nvs_entry_info_t info; + esp_err_t err = nvs_entry_info(it, &info); + if (err != ESP_OK) { + printf("Error (%s) getting NVS entry info!\n", esp_err_to_name(err)); + return err; + } + nvs_handle_t temp_handle; + err = nvs_open(this->name_space, NVS_READONLY, &temp_handle); + if (err != ESP_OK) { + printf("Error (%s) opening NVS handle for reading!\n", esp_err_to_name(err)); + return err; + } + + // call the processor with the key and value + processor(arg, info.key, this->get(info.key)); + } + return ESP_OK; +} +esp_err_t NVSStorageHandler::process_filtered(const char* const& key_prefix, KeyValueProcessor processor, void* arg) const { + NVSIteratorGuard iterator_guard = this->create_iterator(); + if (!iterator_guard.is_valid()) { + return iterator_guard.get_error(); + } + const nvs_iterator_t& it = iterator_guard.get_iterator(); + + for (; it != NULL; iterator_guard.advance_iter()) { + nvs_entry_info_t info; + esp_err_t err = nvs_entry_info(it, &info); + if (err != ESP_OK) { + printf("Error (%s) getting NVS entry info!\n", esp_err_to_name(err)); + return err; + } + // check if the key matches the prefix + if (strncmp(info.key, key_prefix, strlen(key_prefix)) == 0) { + nvs_handle_t temp_handle; + err = nvs_open(this->name_space, NVS_READONLY, &temp_handle); + if (err != ESP_OK) { + printf("Error (%s) opening NVS handle for reading!\n", esp_err_to_name(err)); + return err; + } + // call the processor with the key and value + processor(arg, info.key, this->get(info.key)); + } + } + return ESP_OK; +} + +esp_err_t NVSStorageHandler::process_filtered(FilterFunc filter_func, KeyValueProcessor processor, void* arg) const { + NVSIteratorGuard iterator_guard = this->create_iterator(); + if (!iterator_guard.is_valid()) { + return iterator_guard.get_error(); + } + const nvs_iterator_t& it = iterator_guard.get_iterator(); + + for (; it != NULL; iterator_guard.advance_iter()) { + nvs_entry_info_t info; + esp_err_t err = nvs_entry_info(it, &info); + if (err != ESP_OK) { + printf("Error (%s) getting NVS entry info!\n", esp_err_to_name(err)); + return err; + } + // check if the key matches the filter function + if (filter_func(info.key)) { + nvs_handle_t temp_handle; + err = nvs_open(this->name_space, NVS_READONLY, &temp_handle); + if (err != ESP_OK) { + printf("Error (%s) opening NVS handle for reading!\n", esp_err_to_name(err)); + return err; + } + // call the processor with the key and value + processor(arg, info.key, this->get(info.key)); + } + } + return ESP_OK; +} + +void NVSStorageHandler::remove(const char* const& key) { if (this->nvsHandle == 0) { printf("NVS handle is not initialized.\n"); return; diff --git a/main/io/nvs_handler.h b/main/io/nvs_handler.h index cec2968..66ae0af 100644 --- a/main/io/nvs_handler.h +++ b/main/io/nvs_handler.h @@ -5,17 +5,61 @@ class NVSStorageHandler : public KVStorageHandler { public: - NVSStorageHandler() = default; + NVSStorageHandler( + const char* name_space + ); ~NVSStorageHandler() override; void init(const EventGroupHandle_t& system_event_group) override; - void put(const char*& key, const char*& value) override; + void put(const char* const& key, const char* const& value) override; - char* get(const char*& key) const override; + char* get(const char* const& key) const override; + esp_err_t process_all(KeyValueProcessor processor, void* arg) const override; + esp_err_t process_filtered(const char* const& key_prefix, KeyValueProcessor processor, void* arg) const override; + esp_err_t process_filtered(FilterFunc filter_func, KeyValueProcessor processor, void* arg) const override; - void remove(const char*& key) override; + void remove(const char* const& key) override; private: + NVSIteratorGuard create_iterator() const; + nvs_handle_t nvsHandle = 0; + const char* name_space; +}; + +struct NVSIteratorGuard { +public: + ~NVSIteratorGuard() { + if (iterator) { + nvs_release_iterator(iterator); + } + } + const nvs_iterator_t const& get_iterator() const { + return iterator; + } + void advance_iter() { + if (iterator) { + // advance the iterator and update the internal state + esp_err_t err = nvs_entry_next(&iterator); + if (err != ESP_OK) { + error = err; + iterator = nullptr; + } + } + } + + esp_err_t get_error() const { + return error; + } + bool is_valid() const { + return iterator != nullptr && error == ESP_OK; + } + friend class NVSStorageHandler; +private: + NVSIteratorGuard(nvs_iterator_t it + , esp_err_t err + ) : iterator(it), error(err) { } + nvs_iterator_t iterator; + esp_err_t error; }; diff --git a/main/main.cpp b/main/main.cpp index 2756fdd..ff49346 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -50,7 +50,9 @@ void app_main(void) { throw std::runtime_error("Failed to create LVGL mutex"); } // - KVStorageHandler* kv_storage_handler = new NVSStorageHandler(); + KVStorageHandler* kv_storage_handler = new NVSStorageHandler( + "storage" + ); DisplayHandler* display_handler = new EInkDisplayHandler(touch_event_queue, lvgl_mutex); TouchHandler* touch_handler = new EInkTouchHandler(touch_event_queue); //