feat(nvs_flash): Added function nvs_find_key

Closes https://github.com/espressif/esp-idf/issues/12155
This commit is contained in:
radek.tandler 2023-10-13 12:55:15 +02:00
parent b486466339
commit 8740888967
11 changed files with 197 additions and 28 deletions

View File

@ -3310,7 +3310,92 @@ TEST_CASE("nvs multiple write with same key but different types", "[nvs][xxx]")
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("nvs find key tests", "[nvs]")
{
const size_t buff_len = 4096;
PartitionEmulationFixture f(0, 20);
f.randomize(100);
nvs_handle_t handle_1;
nvs_handle_t handle_2;
const uint32_t NVS_FLASH_SECTOR = 6;
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 13;
TEST_ESP_ERR(nvs_open("namespace1", NVS_READWRITE, &handle_1), ESP_ERR_NVS_NOT_INITIALIZED);
for (uint16_t i = NVS_FLASH_SECTOR; i < NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; ++i) {
f.erase(i);
}
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(),
NVS_FLASH_SECTOR,
NVS_FLASH_SECTOR_COUNT_MIN));
nvs_type_t datatype_found; // datatype of entry found
// open writeable namespace
TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle_1));
// set value, erease value, test find before and after each of steps
TEST_ESP_ERR(nvs_find_key(handle_1, "foo", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
// write "foo" as I32, should find it, first attempt without pointer to type variable
TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678));
TEST_ESP_OK(nvs_find_key(handle_1, "foo", nullptr));
// second search attempt with pointer to type variable specified
TEST_ESP_OK(nvs_find_key(handle_1, "foo", &datatype_found));
CHECK(datatype_found == NVS_TYPE_I32);
TEST_ESP_OK(nvs_erase_key(handle_1, "foo"));
TEST_ESP_ERR(nvs_find_key(handle_1, "foo", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
// set value, rewrite value, erease value, test find before and after each of steps
TEST_ESP_ERR(nvs_find_key(handle_1, "foo1", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
TEST_ESP_OK(nvs_set_i16(handle_1, "foo1", 0x1234));
TEST_ESP_OK(nvs_find_key(handle_1, "foo1", &datatype_found));
CHECK(datatype_found == NVS_TYPE_I16);
TEST_ESP_OK(nvs_set_i16(handle_1, "foo1", 0x4321));
TEST_ESP_OK(nvs_find_key(handle_1, "foo1", &datatype_found));
CHECK(datatype_found == NVS_TYPE_I16);
TEST_ESP_OK(nvs_erase_key(handle_1, "foo1"));
TEST_ESP_ERR(nvs_find_key(handle_1, "foo1", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
// set blob value, rewrite blob, delete blob, test find before and after each of steps
uint8_t *p_buff = (uint8_t *) malloc(buff_len);
CHECK(p_buff != nullptr);
TEST_ESP_ERR(nvs_find_key(handle_1, "foo2", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
for(size_t i=0; i<buff_len; i++) p_buff[i] = (uint8_t) (i%0xff);
TEST_ESP_OK(nvs_set_blob(handle_1, "foo2", p_buff, buff_len));
TEST_ESP_OK(nvs_find_key(handle_1, "foo2", &datatype_found));
CHECK(datatype_found == NVS_TYPE_BLOB);
for(size_t i=0; i<buff_len; i++) p_buff[i] = (uint8_t) ((buff_len-i-1)%0xff);
TEST_ESP_OK(nvs_set_blob(handle_1, "foo2", p_buff, buff_len));
TEST_ESP_OK(nvs_find_key(handle_1, "foo2", &datatype_found));
CHECK(datatype_found == NVS_TYPE_BLOB);
TEST_ESP_OK(nvs_erase_key(handle_1, "foo2"));
TEST_ESP_ERR(nvs_find_key(handle_1, "foo2", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
// test namespace is respected in nvs_find_key
// open second writeable namespace
TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2));
TEST_ESP_ERR(nvs_find_key(handle_1, "foon1", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
TEST_ESP_ERR(nvs_find_key(handle_2, "foon1", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
TEST_ESP_OK(nvs_set_i16(handle_1, "foon1", 0x1234));
TEST_ESP_OK(nvs_find_key(handle_1, "foon1", &datatype_found));
TEST_ESP_ERR(nvs_find_key(handle_2, "foon1", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
TEST_ESP_OK(nvs_set_i16(handle_2, "foon1", 0x1234));
TEST_ESP_OK(nvs_find_key(handle_1, "foon1", &datatype_found));
TEST_ESP_OK(nvs_find_key(handle_2, "foon1", &datatype_found));
TEST_ESP_OK(nvs_erase_key(handle_1, "foon1"));
TEST_ESP_ERR(nvs_find_key(handle_1, "foon1", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
TEST_ESP_OK(nvs_find_key(handle_2, "foon1", &datatype_found));
TEST_ESP_OK(nvs_erase_key(handle_2, "foon1"));
TEST_ESP_ERR(nvs_find_key(handle_1, "foon1", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
TEST_ESP_ERR(nvs_find_key(handle_2, "foon1", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
nvs_close(handle_1);
nvs_close(handle_2);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
/* Add new tests above */
/* This test has to be the final one */

View File

@ -481,6 +481,25 @@ esp_err_t nvs_get_str (nvs_handle_t handle, const char* key, char* out_value, si
esp_err_t nvs_get_blob(nvs_handle_t handle, const char* key, void* out_value, size_t* length);
/**@}*/
/**
* @brief Lookup key-value pair with given key name.
*
* Note that function may indicate both existence of the key as well as the data type of NVS entry if it is found.
*
* @param[in] handle Storage handle obtained with nvs_open.
* @param[in] key Key name. Maximum length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty.
* @param[out] out_type Pointer to the output variable populated with data type of NVS entry in case key was found.
* May be NULL, respective data type is then not provided.
* @return
* - ESP_OK if NVS entry for key provided was found
* - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist
* - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
* - ESP_FAIL if there is an internal error; most likely due to corrupted
* NVS partition (only if NVS assertion checks are disabled)
* - other error codes from the underlying storage driver
*/
esp_err_t nvs_find_key(nvs_handle_t handle, const char* key, nvs_type_t* out_type);
/**
* @brief Erase key-value pair with given key name.
*

View File

@ -164,6 +164,21 @@ public:
*/
virtual esp_err_t get_item_size(ItemType datatype, const char *key, size_t &size) = 0;
/**
* @brief Checks whether key exists and optionally returns also data type of associated entry.
*
* @param[in] key Key name. Maximum length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty.
* @param[out] nvstype Nvs data type to of entry, if it exists.
*
* @return - ESP_OK if NVS entry for key provided was found. Data type will be returned via \c nvstype.
* - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist.
* - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL.
* - ESP_FAIL if there is an internal error; most likely due to corrupted
* NVS partition (only if NVS assertion checks are disabled).
* - other error codes from the underlying storage driver.
*/
virtual esp_err_t find_key(const char* key, nvs_type_t &nvstype) = 0;
/**
* @brief Erases an entry.
*/

View File

@ -306,6 +306,25 @@ extern "C" void nvs_close(nvs_handle_t handle)
delete static_cast<NVSHandleEntry*>(it);
}
extern "C" esp_err_t nvs_find_key(nvs_handle_t c_handle, const char* key, nvs_type_t* out_type)
{
Lock lock;
ESP_LOGD(TAG, "%s %s", __func__, key);
NVSHandleSimple *handle;
auto err = nvs_find_ns_handle(c_handle, &handle);
if (err != ESP_OK) {
return err;
}
nvs_type_t nvstype;
err = handle->find_key(key, nvstype);
if(err == ESP_OK && out_type != nullptr)
*out_type = nvstype;
return err;
}
extern "C" esp_err_t nvs_erase_key(nvs_handle_t c_handle, const char* key)
{
Lock lock;

View File

@ -1,16 +1,8 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// 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.
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "nvs_handle_locked.hpp"
namespace nvs {
@ -47,6 +39,12 @@ esp_err_t NVSHandleLocked::get_item_size(ItemType datatype, const char *key, siz
return handle->get_item_size(datatype, key, size);
}
esp_err_t NVSHandleLocked::find_key(const char* key, nvs_type_t &nvstype)
{
Lock lock;
return handle->find_key(key, nvstype);
}
esp_err_t NVSHandleLocked::erase_item(const char* key) {
Lock lock;
return handle->erase_item(key);

View File

@ -1,16 +1,8 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// 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.
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef NVS_HANDLE_LOCKED_HPP_
#define NVS_HANDLE_LOCKED_HPP_
@ -49,6 +41,8 @@ public:
esp_err_t get_item_size(ItemType datatype, const char *key, size_t &size) override;
esp_err_t find_key(const char* key, nvs_type_t &nvstype) override;
esp_err_t erase_item(const char* key) override;
esp_err_t erase_all() override;

View File

@ -65,6 +65,23 @@ esp_err_t NVSHandleSimple::get_item_size(ItemType datatype, const char *key, siz
return mStoragePtr->getItemDataSize(mNsIndex, datatype, key, size);
}
esp_err_t NVSHandleSimple::find_key(const char* key, nvs_type_t &nvstype)
{
if (!valid) return ESP_ERR_NVS_INVALID_HANDLE;
nvs::ItemType datatype;
esp_err_t err = mStoragePtr->findKey(mNsIndex, key, &datatype);
if(err != ESP_OK)
return err;
if(datatype == ItemType::BLOB_IDX || datatype == ItemType::BLOB)
datatype = ItemType::BLOB_DATA;
nvstype = (nvs_type_t) datatype;
return err;
}
esp_err_t NVSHandleSimple::erase_item(const char* key)
{
if (!valid) return ESP_ERR_NVS_INVALID_HANDLE;

View File

@ -51,6 +51,8 @@ public:
esp_err_t get_item_size(ItemType datatype, const char *key, size_t &size) override;
esp_err_t find_key(const char *key, nvs_type_t &nvstype) override;
esp_err_t erase_item(const char *key) override;
esp_err_t erase_all() override;

View File

@ -683,6 +683,26 @@ esp_err_t Storage::eraseNamespace(uint8_t nsIndex)
}
esp_err_t Storage::findKey(const uint8_t nsIndex, const char* key, ItemType* datatype)
{
if (mState != StorageState::ACTIVE) {
return ESP_ERR_NVS_NOT_INITIALIZED;
}
Item item;
Page* findPage = nullptr;
auto err = findItem(nsIndex, ItemType::ANY, key, findPage, item);
if (err != ESP_OK) {
return err;
}
if(datatype != nullptr) {
*datatype = item.datatype;
}
return err;
}
esp_err_t Storage::getItemDataSize(uint8_t nsIndex, ItemType datatype, const char* key, size_t& dataSize)
{
if (mState != StorageState::ACTIVE) {

View File

@ -71,6 +71,8 @@ public:
esp_err_t readItem(uint8_t nsIndex, ItemType datatype, const char* key, void* data, size_t dataSize);
esp_err_t findKey(const uint8_t nsIndex, const char* key, ItemType* datatype);
esp_err_t getItemDataSize(uint8_t nsIndex, ItemType datatype, const char* key, size_t& dataSize);
esp_err_t eraseItem(uint8_t nsIndex, ItemType datatype, const char* key);

View File

@ -582,8 +582,6 @@ components/mbedtls/port/sha/parallel_engine/sha.c
components/nvs_flash/include/nvs_handle.hpp
components/nvs_flash/src/nvs_cxx_api.cpp
components/nvs_flash/src/nvs_encrypted_partition.hpp
components/nvs_flash/src/nvs_handle_locked.cpp
components/nvs_flash/src/nvs_handle_locked.hpp
components/nvs_flash/src/nvs_item_hash_list.cpp
components/nvs_flash/src/nvs_pagemanager.hpp
components/nvs_flash/src/nvs_partition_lookup.cpp