components/nvs: add erase function
This change exposes functions to erase single key and to erase all keys from namespace. TW6769, TW6839
This commit is contained in:
parent
e87d80d478
commit
2a68f60874
7 changed files with 125 additions and 30 deletions
|
@ -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_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);
|
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
|
* @brief Write any pending changes to non-volatile storage
|
||||||
*
|
*
|
||||||
|
|
|
@ -103,6 +103,36 @@ extern "C" void nvs_close(nvs_handle handle)
|
||||||
s_nvs_handles.erase(it);
|
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<typename T>
|
template<typename T>
|
||||||
static esp_err_t nvs_set(nvs_handle handle, const char* key, T value)
|
static esp_err_t nvs_set(nvs_handle handle, const char* key, T value)
|
||||||
{
|
{
|
||||||
|
|
|
@ -278,19 +278,6 @@ esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key)
|
||||||
return findItem(nsIndex, datatype, key, index, item);
|
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)
|
esp_err_t Page::eraseEntryAndSpan(size_t index)
|
||||||
{
|
{
|
||||||
auto state = mEntryTable.get(index);
|
auto state = mEntryTable.get(index);
|
||||||
|
|
|
@ -206,8 +206,6 @@ protected:
|
||||||
|
|
||||||
esp_err_t writeEntryData(const uint8_t* data, size_t size);
|
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);
|
esp_err_t eraseEntryAndSpan(size_t index);
|
||||||
|
|
||||||
void updateFirstUsedEntry(size_t index, size_t span);
|
void updateFirstUsedEntry(size_t index, size_t span);
|
||||||
|
|
|
@ -69,6 +69,19 @@ esp_err_t Storage::init(uint32_t baseSector, uint32_t sectorCount)
|
||||||
return ESP_OK;
|
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)
|
esp_err_t Storage::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize)
|
||||||
{
|
{
|
||||||
if (mState != StorageState::ACTIVE) {
|
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);
|
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)
|
esp_err_t Storage::getItemDataSize(uint8_t nsIndex, ItemType datatype, const char* key, size_t& dataSize)
|
||||||
{
|
{
|
||||||
if (mState != StorageState::ACTIVE) {
|
if (mState != StorageState::ACTIVE) {
|
||||||
|
|
|
@ -69,13 +69,15 @@ public:
|
||||||
return readItem(nsIndex, itemTypeOf(value), key, &value, sizeof(value));
|
return readItem(nsIndex, itemTypeOf(value), key, &value, sizeof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
esp_err_t eraseItem(uint8_t nsIndex, const char* key)
|
esp_err_t eraseItem(uint8_t nsIndex, const char* key)
|
||||||
{
|
{
|
||||||
return eraseItem(nsIndex, itemTypeOf<T>(), key);
|
return eraseItem(nsIndex, ItemType::ANY, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_err_t eraseNamespace(uint8_t nsIndex);
|
||||||
|
|
||||||
void debugDump();
|
void debugDump();
|
||||||
|
|
||||||
void debugCheck();
|
void debugCheck();
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,19 +90,7 @@ protected:
|
||||||
|
|
||||||
void clearNamespaces();
|
void clearNamespaces();
|
||||||
|
|
||||||
esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item)
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
size_t mPageCount;
|
size_t mPageCount;
|
||||||
|
|
|
@ -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<int>(i));
|
||||||
|
REQUIRE(storage.writeItem(3, name, static_cast<int>(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_ERR(rc, res) CHECK((rc) == (res))
|
||||||
#define TEST_ESP_OK(rc) CHECK((rc) == ESP_OK)
|
#define TEST_ESP_OK(rc) CHECK((rc) == ESP_OK)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue