diff --git a/components/nvs_flash/host_test/nvs_host_test/main/test_nvs.cpp b/components/nvs_flash/host_test/nvs_host_test/main/test_nvs.cpp index 444f18c14b..f7f9c6f7f5 100644 --- a/components/nvs_flash/host_test/nvs_host_test/main/test_nvs.cpp +++ b/components/nvs_flash/host_test/nvs_host_test/main/test_nvs.cpp @@ -761,6 +761,21 @@ TEST_CASE("nvs iterators tests", "[nvs]") return count; }; + auto entry_count_handle = [](nvs_handle_t handle, nvs_type_t type)-> int { + int count = 0; + nvs_iterator_t it = nullptr; + esp_err_t res = nvs_entry_find_in_handle(handle, type, &it); + for (count = 0; res == ESP_OK; count++) + { + res = nvs_entry_next(&it); + } + CHECK(res == ESP_ERR_NVS_NOT_FOUND); // after finishing the loop or if no entry was found to begin with, + // res has to be ESP_ERR_NVS_NOT_FOUND or some internal error + // or programming error occurred + nvs_release_iterator(it); // unneccessary call but emphasizes the programming pattern + return count; + }; + SECTION("No partition found return ESP_ERR_NVS_NOT_FOUND") { CHECK(nvs_entry_find("", NULL, NVS_TYPE_ANY, &it) == ESP_ERR_NVS_NOT_FOUND); } @@ -805,6 +820,15 @@ TEST_CASE("nvs iterators tests", "[nvs]") CHECK(entry_count(NVS_DEFAULT_PART_NAME, NULL, NVS_TYPE_U64) == 1); } + + SECTION("Number of entries found for specified handle and type is correct") { + CHECK(entry_count_handle(handle_1, NVS_TYPE_ANY) == 11); + CHECK(entry_count_handle(handle_1, NVS_TYPE_I32) == 3); + CHECK(entry_count_handle(handle_2, NVS_TYPE_ANY) == 4); + CHECK(entry_count_handle(handle_2, NVS_TYPE_I32) == 2); + CHECK(entry_count_handle(handle_2, NVS_TYPE_U64) == 1); + } + SECTION("New entry is not created when existing key-value pair is set") { CHECK(entry_count(NVS_DEFAULT_PART_NAME, name_2, NVS_TYPE_ANY) == 4); TEST_ESP_OK(nvs_set_i32(handle_2, "value1", -222)); diff --git a/components/nvs_flash/include/nvs.h b/components/nvs_flash/include/nvs.h index e45a641343..49fe9b7d60 100644 --- a/components/nvs_flash/include/nvs.h +++ b/components/nvs_flash/include/nvs.h @@ -675,14 +675,53 @@ esp_err_t nvs_entry_find(const char *part_name, nvs_type_t type, nvs_iterator_t *output_iterator); +/** + * @brief Create an iterator to enumerate NVS entries based on a handle and type + * + * \code{c} + * // Example of listing all the key-value pairs of any type under specified handle (which defines a partition and namespace) + * nvs_iterator_t it = NULL; + * esp_err_t res = nvs_entry_find_in_handle(, NVS_TYPE_ANY, &it); + * while(res == ESP_OK) { + * nvs_entry_info_t info; + * nvs_entry_info(it, &info); // Can omit error check if parameters are guaranteed to be non-NULL + * printf("key '%s', type '%d' \n", info.key, info.type); + * res = nvs_entry_next(&it); + * } + * nvs_release_iterator(it); + * \endcode + * + * @param[in] handle Handle obtained from nvs_open function. + * + * @param[in] type One of nvs_type_t values. + * + * @param[out] output_iterator + * Set to a valid iterator to enumerate all the entries found. + * Set to NULL if no entry for specified criteria was found. + * If any other error except ESP_ERR_INVALID_ARG occurs, \c output_iterator is NULL, too. + * If ESP_ERR_INVALID_ARG occurs, \c output_iterator is not changed. + * If a valid iterator is obtained through this function, it has to be released + * using \c nvs_release_iterator when not used any more, unless ESP_ERR_INVALID_ARG is returned. + * + * @return + * - ESP_OK if no internal error or programming error occurred. + * - ESP_ERR_NVS_NOT_FOUND if no element of specified criteria has been found. + * - ESP_ERR_NO_MEM if memory has been exhausted during allocation of internal structures. + * - ESP_ERR_NVS_INVALID_HANDLE if unknown handle was specified. + * - ESP_ERR_INVALID_ARG if output_iterator parameter is NULL. + * Note: don't release \c output_iterator in case ESP_ERR_INVALID_ARG has been returned + */ +esp_err_t nvs_entry_find_in_handle(nvs_handle_t handle, nvs_type_t type, nvs_iterator_t *output_iterator); + /** * @brief Advances the iterator to next item matching the iterator criteria. * * Note that any copies of the iterator will be invalid after this call. * - * @param[inout] iterator Iterator obtained from nvs_entry_find function. Must be non-NULL. - * If any error except ESP_ERR_INVALID_ARG occurs, \c iterator is set to NULL. - * If ESP_ERR_INVALID_ARG occurs, \c iterator is not changed. + * @param[inout] iterator Iterator obtained from nvs_entry_find or nvs_entry_find_in_handle + * function. Must be non-NULL. If any error except ESP_ERR_INVALID_ARG + * occurs, \c iterator is set to NULL. If ESP_ERR_INVALID_ARG occurs, \c + * iterator is not changed. * * @return * - ESP_OK if no internal error or programming error occurred. @@ -695,7 +734,8 @@ esp_err_t nvs_entry_next(nvs_iterator_t *iterator); /** * @brief Fills nvs_entry_info_t structure with information about entry pointed to by the iterator. * - * @param[in] iterator Iterator obtained from nvs_entry_find function. Must be non-NULL. + * @param[in] iterator Iterator obtained from nvs_entry_find or nvs_entry_find_in_handle + * function. Must be non-NULL. * * @param[out] out_info Structure to which entry information is copied. * @@ -708,7 +748,9 @@ esp_err_t nvs_entry_info(const nvs_iterator_t iterator, nvs_entry_info_t *out_in /** * @brief Release iterator * - * @param[in] iterator Release iterator obtained from nvs_entry_find function. NULL argument is allowed. + * @param[in] iterator Release iterator obtained from nvs_entry_find or + * nvs_entry_find_in_handle or nvs_entry_next function. NULL argument is + * allowed. * */ void nvs_release_iterator(nvs_iterator_t iterator); diff --git a/components/nvs_flash/src/nvs_api.cpp b/components/nvs_flash/src/nvs_api.cpp index beb9e868ea..6472a80819 100644 --- a/components/nvs_flash/src/nvs_api.cpp +++ b/components/nvs_flash/src/nvs_api.cpp @@ -786,6 +786,46 @@ extern "C" esp_err_t nvs_entry_find(const char *part_name, const char *namespace return ESP_OK; } +extern "C" esp_err_t nvs_entry_find_in_handle(nvs_handle_t handle, nvs_type_t type, nvs_iterator_t *output_iterator) +{ + if (output_iterator == nullptr) { + return ESP_ERR_INVALID_ARG; + } + + esp_err_t lock_result = Lock::init(); + if (lock_result != ESP_OK) { + *output_iterator = nullptr; + return lock_result; + } + + Lock lock; + nvs::Storage *pStorage; + NVSHandleSimple *handle_obj; + + auto err = nvs_find_ns_handle(handle, &handle_obj); + if (err != ESP_OK) { + *output_iterator = nullptr; + return err; + } + + pStorage = handle_obj->get_storage(); + nvs_iterator_t it = create_iterator(pStorage, type); + if (it == nullptr) { + *output_iterator = nullptr; + return ESP_ERR_NO_MEM; + } + + bool entryFound = handle_obj->findEntryNs(it); + if (!entryFound) { + free(it); + *output_iterator = nullptr; + return ESP_ERR_NVS_NOT_FOUND; + } + + *output_iterator = it; + return ESP_OK; +} + extern "C" esp_err_t nvs_entry_next(nvs_iterator_t *iterator) { if (iterator == nullptr) { diff --git a/components/nvs_flash/src/nvs_handle_simple.cpp b/components/nvs_flash/src/nvs_handle_simple.cpp index 348e197b7c..658c811aad 100644 --- a/components/nvs_flash/src/nvs_handle_simple.cpp +++ b/components/nvs_flash/src/nvs_handle_simple.cpp @@ -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 #include "nvs_handle.hpp" #include "nvs_partition_manager.hpp" @@ -126,6 +118,10 @@ bool NVSHandleSimple::findEntry(nvs_opaque_iterator_t* it, const char* name) { return mStoragePtr->findEntry(it, name); } +bool NVSHandleSimple::findEntryNs(nvs_opaque_iterator_t* it) { + return mStoragePtr->findEntryNs(it, mNsIndex); +} + bool NVSHandleSimple::nextEntry(nvs_opaque_iterator_t* it) { return mStoragePtr->nextEntry(it); } @@ -134,4 +130,8 @@ const char *NVSHandleSimple::get_partition_name() const { return mStoragePtr->getPartName(); } +Storage *NVSHandleSimple::get_storage() const { + return mStoragePtr; +} + } diff --git a/components/nvs_flash/src/nvs_handle_simple.hpp b/components/nvs_flash/src/nvs_handle_simple.hpp index ff0e93a3d6..fe93f9f706 100644 --- a/components/nvs_flash/src/nvs_handle_simple.hpp +++ b/components/nvs_flash/src/nvs_handle_simple.hpp @@ -69,10 +69,14 @@ public: bool findEntry(nvs_opaque_iterator_t *it, const char *name); + bool findEntryNs(nvs_opaque_iterator_t *it); + bool nextEntry(nvs_opaque_iterator_t *it); const char *get_partition_name() const; + Storage *get_storage() const; + private: /** * The underlying storage's object. diff --git a/components/nvs_flash/src/nvs_storage.cpp b/components/nvs_flash/src/nvs_storage.cpp index ccba2263f7..48c8a20fc0 100644 --- a/components/nvs_flash/src/nvs_storage.cpp +++ b/components/nvs_flash/src/nvs_storage.cpp @@ -782,6 +782,15 @@ bool Storage::findEntry(nvs_opaque_iterator_t* it, const char* namespace_name) return nextEntry(it); } +bool Storage::findEntryNs(nvs_opaque_iterator_t* it, uint8_t nsIndex) +{ + it->entryIndex = 0; + it->nsIndex = nsIndex; + it->page = mPageManager.begin(); + + return nextEntry(it); +} + inline bool isIterableItem(Item& item) { return (item.nsIndex != 0 && diff --git a/components/nvs_flash/src/nvs_storage.hpp b/components/nvs_flash/src/nvs_storage.hpp index c2df7dc470..9e64ac9bb5 100644 --- a/components/nvs_flash/src/nvs_storage.hpp +++ b/components/nvs_flash/src/nvs_storage.hpp @@ -125,7 +125,9 @@ public: esp_err_t calcEntriesInNamespace(uint8_t nsIndex, size_t& usedEntries); - bool findEntry(nvs_opaque_iterator_t*, const char* name); + bool findEntry(nvs_opaque_iterator_t* it, const char* name); + + bool findEntryNs(nvs_opaque_iterator_t* it, uint8_t nsIndex); bool nextEntry(nvs_opaque_iterator_t* it); diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index 0b8933a300..fbf6e8ea21 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -596,7 +596,6 @@ 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_handle_simple.cpp components/nvs_flash/src/nvs_item_hash_list.cpp components/nvs_flash/src/nvs_pagemanager.hpp components/nvs_flash/src/nvs_partition.cpp