diff --git a/components/nvs_flash/include/nvs.h b/components/nvs_flash/include/nvs.h index dbcd837e1..bfcebc2e5 100644 --- a/components/nvs_flash/include/nvs.h +++ b/components/nvs_flash/include/nvs.h @@ -180,6 +180,41 @@ esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value); esp_err_t nvs_get_str (nvs_handle handle, const char* key, char* out_value, size_t* length); esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size_t* length); +/** + * @brief Erase key-value pair with given key name. + * + * Note that actual storage may not be updated until nvs_commit function is called. + * + * @param[in] handle Storage handle obtained with nvs_open. If handle has to be + * opened as not read only for this call to succeed. + * + * @param[in] key Key name. Maximal length is determined by the underlying + * implementation, but is guaranteed to be at least + * 16 characters. Shouldn't be empty. + * + * @return - ESP_OK if erase operation was successful + * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL + * - ESP_ERR_NVS_READ_ONLY if handle was opened as read only + * - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist + * - other error codes from the underlying storage driver + */ +esp_err_t nvs_erase_key(nvs_handle handle, const char* key); + +/** + * @brief Erase all key-value pairs in a namespace + * + * Note that actual storage may not be updated until nvs_commit function is called. + * + * @param[in] handle Storage handle obtained with nvs_open. If handle has to be + * opened as not read only for this call to succeed. + * + * @return - ESP_OK if erase operation was successful + * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL + * - ESP_ERR_NVS_READ_ONLY if handle was opened as read only + * - other error codes from the underlying storage driver + */ +esp_err_t nvs_erase_all(nvs_handle handle); + /** * @brief Write any pending changes to non-volatile storage * diff --git a/components/nvs_flash/src/nvs_api.cpp b/components/nvs_flash/src/nvs_api.cpp index fb9faf984..daa23325d 100644 --- a/components/nvs_flash/src/nvs_api.cpp +++ b/components/nvs_flash/src/nvs_api.cpp @@ -103,6 +103,36 @@ extern "C" void nvs_close(nvs_handle handle) s_nvs_handles.erase(it); } +extern "C" esp_err_t nvs_erase_key(nvs_handle handle, const char* key) +{ + Lock lock; + NVS_DEBUGV("%s %s\r\n", __func__, key); + HandleEntry entry; + auto err = nvs_find_ns_handle(handle, entry); + if (err != ESP_OK) { + return err; + } + if (entry.mReadOnly) { + return ESP_ERR_NVS_READ_ONLY; + } + return s_nvs_storage.eraseItem(entry.mNsIndex, key); +} + +extern "C" esp_err_t nvs_erase_all(nvs_handle handle) +{ + Lock lock; + NVS_DEBUGV("%s\r\n", __func__); + HandleEntry entry; + auto err = nvs_find_ns_handle(handle, entry); + if (err != ESP_OK) { + return err; + } + if (entry.mReadOnly) { + return ESP_ERR_NVS_READ_ONLY; + } + return s_nvs_storage.eraseNamespace(entry.mNsIndex); +} + template static esp_err_t nvs_set(nvs_handle handle, const char* key, T value) { diff --git a/components/nvs_flash/src/nvs_page.cpp b/components/nvs_flash/src/nvs_page.cpp index fed45d34d..4f6a198c6 100644 --- a/components/nvs_flash/src/nvs_page.cpp +++ b/components/nvs_flash/src/nvs_page.cpp @@ -278,19 +278,6 @@ esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key) return findItem(nsIndex, datatype, key, index, item); } -esp_err_t Page::eraseEntry(size_t index) -{ - auto state = mEntryTable.get(index); - assert(state == EntryState::WRITTEN || state == EntryState::EMPTY); - - auto rc = alterEntryState(index, EntryState::ERASED); - if (rc != ESP_OK) { - return rc; - } - - return ESP_OK; -} - esp_err_t Page::eraseEntryAndSpan(size_t index) { auto state = mEntryTable.get(index); diff --git a/components/nvs_flash/src/nvs_page.hpp b/components/nvs_flash/src/nvs_page.hpp index 63b1c4033..c1f430cae 100644 --- a/components/nvs_flash/src/nvs_page.hpp +++ b/components/nvs_flash/src/nvs_page.hpp @@ -206,8 +206,6 @@ protected: esp_err_t writeEntryData(const uint8_t* data, size_t size); - esp_err_t eraseEntry(size_t index); - esp_err_t eraseEntryAndSpan(size_t index); void updateFirstUsedEntry(size_t index, size_t span); diff --git a/components/nvs_flash/src/nvs_storage.cpp b/components/nvs_flash/src/nvs_storage.cpp index 7415ed62c..4a217ebe1 100644 --- a/components/nvs_flash/src/nvs_storage.cpp +++ b/components/nvs_flash/src/nvs_storage.cpp @@ -69,6 +69,19 @@ esp_err_t Storage::init(uint32_t baseSector, uint32_t sectorCount) return ESP_OK; } +esp_err_t Storage::findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item) +{ + size_t itemIndex = 0; + for (auto it = std::begin(mPageManager); it != std::end(mPageManager); ++it) { + auto err = it->findItem(nsIndex, datatype, key, itemIndex, item); + if (err == ESP_OK) { + page = it; + return ESP_OK; + } + } + return ESP_ERR_NVS_NOT_FOUND; +} + esp_err_t Storage::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize) { if (mState != StorageState::ACTIVE) { @@ -202,6 +215,27 @@ esp_err_t Storage::eraseItem(uint8_t nsIndex, ItemType datatype, const char* key return findPage->eraseItem(nsIndex, datatype, key); } +esp_err_t Storage::eraseNamespace(uint8_t nsIndex) +{ + if (mState != StorageState::ACTIVE) { + return ESP_ERR_NVS_NOT_INITIALIZED; + } + + for (auto it = std::begin(mPageManager); it != std::end(mPageManager); ++it) { + while (true) { + auto err = it->eraseItem(nsIndex, ItemType::ANY, nullptr); + if (err == ESP_ERR_NVS_NOT_FOUND) { + break; + } + else if (err != ESP_OK) { + return err; + } + } + } + return ESP_OK; + +} + esp_err_t Storage::getItemDataSize(uint8_t nsIndex, ItemType datatype, const char* key, size_t& dataSize) { if (mState != StorageState::ACTIVE) { diff --git a/components/nvs_flash/src/nvs_storage.hpp b/components/nvs_flash/src/nvs_storage.hpp index f99e6fbbc..f8cee9f2a 100644 --- a/components/nvs_flash/src/nvs_storage.hpp +++ b/components/nvs_flash/src/nvs_storage.hpp @@ -69,13 +69,15 @@ public: return readItem(nsIndex, itemTypeOf(value), key, &value, sizeof(value)); } - template esp_err_t eraseItem(uint8_t nsIndex, const char* key) { - return eraseItem(nsIndex, itemTypeOf(), key); + return eraseItem(nsIndex, ItemType::ANY, key); } + + esp_err_t eraseNamespace(uint8_t nsIndex); void debugDump(); + void debugCheck(); @@ -88,19 +90,7 @@ protected: void clearNamespaces(); - esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item) - { - size_t itemIndex = 0; - for (auto it = std::begin(mPageManager); it != std::end(mPageManager); ++it) { - auto err = it->findItem(nsIndex, datatype, key, itemIndex, item); - if (err == ESP_OK) { - page = it; - return ESP_OK; - } - } - return ESP_ERR_NVS_NOT_FOUND; - } - + esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item); protected: size_t mPageCount; diff --git a/components/nvs_flash/test/test_nvs.cpp b/components/nvs_flash/test/test_nvs.cpp index c496a09fd..540d977b4 100644 --- a/components/nvs_flash/test/test_nvs.cpp +++ b/components/nvs_flash/test/test_nvs.cpp @@ -386,6 +386,27 @@ TEST_CASE("can modify an item on a page which will be erased", "[nvs]") } +TEST_CASE("can erase items", "[nvs]") +{ + SpiFlashEmulator emu(3); + Storage storage; + CHECK(storage.init(0, 3) == ESP_OK); + for (size_t i = 0; i < Page::ENTRY_COUNT * 2 - 3; ++i) { + char name[Item::MAX_KEY_LENGTH + 1]; + snprintf(name, sizeof(name), "key%05d", static_cast(i)); + REQUIRE(storage.writeItem(3, name, static_cast(i)) == ESP_OK); + } + CHECK(storage.writeItem(1, "foo", 32) == ESP_OK); + CHECK(storage.writeItem(2, "foo", 64) == ESP_OK); + CHECK(storage.eraseItem(2, "foo") == ESP_OK); + int val; + CHECK(storage.readItem(1, "foo", val) == ESP_OK); + CHECK(val == 32); + CHECK(storage.eraseNamespace(3) == ESP_OK); + CHECK(storage.readItem(2, "foo", val) == ESP_ERR_NVS_NOT_FOUND); + CHECK(storage.readItem(3, "key00222", val) == ESP_ERR_NVS_NOT_FOUND); +} + #define TEST_ESP_ERR(rc, res) CHECK((rc) == (res)) #define TEST_ESP_OK(rc) CHECK((rc) == ESP_OK)