From 0c83bffe4771ea9621a98a5a333fc25d320c6296 Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Tue, 26 Nov 2024 15:51:43 -0600 Subject: [PATCH] feat(nvs): Add erase key and erase namespace methods (#343) * Update `espp::NvsHandle` to support `erase(std::error_code&)` and `erase(std::string_view key, std::error_code&)` methods * Update `espp::Nvs` to support `erase(namespace, key)`, and `erase(namespace)` methods * Update example to test new methods --- components/nvs/example/main/nvs_example.cpp | 39 ++++++++++++++++- components/nvs/include/nvs.hpp | 31 +++++++++++++- components/nvs/include/nvs_errc.hpp | 8 ++++ components/nvs/include/nvs_handle_espp.hpp | 46 +++++++++++++++++++++ 4 files changed, 122 insertions(+), 2 deletions(-) diff --git a/components/nvs/example/main/nvs_example.cpp b/components/nvs/example/main/nvs_example.cpp index 0d4a0889f..1b9d752ed 100644 --- a/components/nvs/example/main/nvs_example.cpp +++ b/components/nvs/example/main/nvs_example.cpp @@ -60,7 +60,7 @@ extern "C" void app_main(void) { if (ec) { fmt::print("Error: {}\n", ec.message()); } else { - fmt::print("String = {}\n", str); + fmt::print("String = '{}'\n", str); } ec.clear(); @@ -74,9 +74,46 @@ extern "C" void app_main(void) { } ec.clear(); + // test getting the string value again + nvs.get_var("system", "string", str, ec); + if (ec) { + fmt::print("Error: {}\n", ec.message()); + } else { + fmt::print("String = '{}'\n", str); + } + ec.clear(); + + // test erasing the string value + nvs.erase("system", "string", ec); + if (ec) { + fmt::print("Error: {}\n", ec.message()); + } else { + fmt::print("String erased\n"); + } + ec.clear(); + + // now test getting it again to ensure it was erased + nvs.get_var("system", "string", str, ec); + if (ec) { + fmt::print("Sucess, got expected error when reading erased value: {}\n", ec.message()); + } else { + fmt::print("Failure, got unexpected success when reading erased value\n"); + } + ec.clear(); + counter++; if (counter > 10) { + // test erasing the whole namespace + nvs.erase("system", ec); + if (ec) { + fmt::print("Error: {}\n", ec.message()); + } else { + fmt::print("Namespace erased\n"); + } + ec.clear(); + + // now erase the wole nvs partition nvs.erase(ec); nvs.init(ec); counter = 0; diff --git a/components/nvs/include/nvs.hpp b/components/nvs/include/nvs.hpp index 5baf9432c..5ab2bf1a6 100644 --- a/components/nvs/include/nvs.hpp +++ b/components/nvs/include/nvs.hpp @@ -55,6 +55,35 @@ class Nvs : public BaseComponent { } } + /// @brief Erase a namespace from the NVS + /// @param[in] ns_name Namespace of the variable to erase + /// @param[out] ec Saves a std::error_code representing success or failure + bool erase(std::string_view ns_name, std::error_code &ec) { + NvsHandle handle(ns_name.data(), ec); + if (ec) + return false; + + if (!handle.erase(ec)) + return false; + + return true; + } + + /// @brief Erase a key from the NVS + /// @param[in] ns_name Namespace of the variable to erase + /// @param[in] key NVS Key of the variable to erase + /// @param[out] ec Saves a std::error_code representing success or failure + bool erase(std::string_view ns_name, std::string_view key, std::error_code &ec) { + NvsHandle handle(ns_name.data(), ec); + if (ec) + return false; + + if (!handle.erase(key, ec)) + return false; + + return true; + } + /// @brief Save a variable in the NVS and commit /// @param[in] ns_name Namespace of the variable to save /// @param[in] key NVS Key of the variable to save @@ -84,7 +113,7 @@ class Nvs : public BaseComponent { template void get_or_set_var(std::string_view ns_name, std::string_view key, T &value, T default_value, std::error_code &ec) { - get_var(ns_name.data(), key.data(), value, ec); + get_or_set_var(ns_name.data(), key.data(), value, default_value, ec); } /// @brief Save a variable in the NVS and commit diff --git a/components/nvs/include/nvs_errc.hpp b/components/nvs/include/nvs_errc.hpp index 23932a133..629faf8a6 100644 --- a/components/nvs/include/nvs_errc.hpp +++ b/components/nvs/include/nvs_errc.hpp @@ -19,6 +19,8 @@ enum class NvsErrc { Init_NVS_Failed, Erase_NVS_Failed, Handle_Uninitialized, + Erase_NVS_Key_Failed, + Erase_NVS_Namespace_Failed, }; struct NvsErrCategory : std::error_category { @@ -60,6 +62,12 @@ std::string NvsErrCategory::message(int ev) const { case NvsErrc::Handle_Uninitialized: return "Handle not initialized"; + case NvsErrc::Erase_NVS_Key_Failed: + return "Failed to erase NVS key"; + + case NvsErrc::Erase_NVS_Namespace_Failed: + return "Failed to erase NVS namespace"; + default: return "(unrecognized error)"; } diff --git a/components/nvs/include/nvs_handle_espp.hpp b/components/nvs/include/nvs_handle_espp.hpp index 04d92cb30..40d1958a7 100644 --- a/components/nvs/include/nvs_handle_espp.hpp +++ b/components/nvs/include/nvs_handle_espp.hpp @@ -337,6 +337,52 @@ class NvsHandle : public BaseComponent { return; } + /// @brief Erase a key from the NVS + /// @param[in] key NVS Key to erase + /// @param[out] ec Saves a std::error_code representing success or failure + /// @return true if successful, false otherwise + bool erase(std::string_view key, std::error_code &ec) { return erase(key.data(), ec); } + + /// @brief Erase a key from the NVS + /// @param[in] key NVS Key to erase + /// @param[out] ec Saves a std::error_code representing success or failure + /// @return true if successful, false otherwise + bool erase(const char *key, std::error_code &ec) { + if (!handle_) { + logger_.error("NVS Handle not initialized!"); + return false; + } + + if (!check_key(key, ec)) + return false; + + esp_err_t err = handle_->erase_item(key); + if (err != ESP_OK) { + logger_.error("Error {} erasing key '{}' from NVS!", esp_err_to_name(err), key); + ec = make_error_code(NvsErrc::Erase_NVS_Key_Failed); + return false; + } + return true; + } + + /// @brief Erase all keys from the NVS associated with the namespace / handle + /// @param[out] ec Saves a std::error_code representing success or failure + /// @return true if successful, false otherwise + bool erase(std::error_code &ec) { + if (!handle_) { + logger_.error("NVS Handle not initialized!"); + return false; + } + + esp_err_t err = handle_->erase_all(); + if (err != ESP_OK) { + logger_.error("Error {} erasing all keys from NVS!", esp_err_to_name(err)); + ec = make_error_code(NvsErrc::Erase_NVS_Namespace_Failed); + return false; + } + return true; + } + protected: std::unique_ptr handle_;