nvs: Support for handling multiple NVS partitions

This commit adds support for multiple NVS partitions. This provides application a flexibility to have multiple NVS
partitions such as separate partition with read-only manufacturing data and read-write partition with configuration.
Application can also use this to separate out application's configuration storage from system configuration.

This feature does not change any of the basic property of NVS subsystem. The same-named namespaces across partitions are
considered to be different namespaces. The original NVS API available for the applications remains unchanged. The only
difference is that instead of first NVS partition in the partition table, it now operates on the partition with label
"nvs" (which is default in the IDF provided partition table files). Additional APIs are provided to open a handle and
erase NVS with partition name as a parameter.

A test case is added in the host tests and it is made sure that all the host tests pass. nvs_rw_value app is also tested
with multiple partitions.

Signed-off-by: Amey Inamdar <amey.inamdar@gmail.com>
This commit is contained in:
Amey Inamdar 2017-08-21 15:26:16 +05:30
parent 3e4e4dd07a
commit a2dcf7faa8
7 changed files with 206 additions and 52 deletions

View file

@ -9,7 +9,7 @@ Non-volatile storage (NVS) library is designed to store key-value pairs in flash
Underlying storage
^^^^^^^^^^^^^^^^^^
Currently NVS uses a portion of main flash memory through ``spi_flash_{read|write|erase}`` APIs. The library uses the first partition with ``data`` type and ``nvs`` subtype.
Currently NVS uses a portion of main flash memory through ``spi_flash_{read|write|erase}`` APIs. The library uses the all the partitions with ``data`` type and ``nvs`` subtype. The application can choose to use the partition with label ``nvs`` through ``nvs_open`` API or any of the other partition by specifying its name through ``nvs_open_from_part`` API.
Future versions of this library may add other storage backends to keep data in another flash chip (SPI or I2C), RTC, FRAM, etc.
@ -41,7 +41,8 @@ Data type check is also performed when reading a value. An error is returned if
Namespaces
^^^^^^^^^^
To mitigate potential conflicts in key names between different components, NVS assigns each key-value pair to one of namespaces. Namespace names follow the same rules as key names, i.e. 15 character maximum length. Namespace name is specified in the ``nvs_open`` call. This call returns an opaque handle, which is used in subsequent calls to ``nvs_read_*``, ``nvs_write_*``, and ``nvs_commit`` functions. This way, handle is associated with a namespace, and key names will not collide with same names in other namespaces.
To mitigate potential conflicts in key names between different components, NVS assigns each key-value pair to one of namespaces. Namespace names follow the same rules as key names, i.e. 15 character maximum length. Namespace name is specified in the ``nvs_open`` or ``nvs_open_from_part`` call. This call returns an opaque handle, which is used in subsequent calls to ``nvs_read_*``, ``nvs_write_*``, and ``nvs_commit`` functions. This way, handle is associated with a namespace, and key names will not collide with same names in other namespaces.
Please note that the namespaces with same name in different NVS partitions are considered as separate namespaces.
Security, tampering, and robustness
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -43,7 +43,9 @@ typedef uint32_t nvs_handle;
#define ESP_ERR_NVS_INVALID_LENGTH (ESP_ERR_NVS_BASE + 0x0c) /*!< String or blob length is not sufficient to store data */
#define ESP_ERR_NVS_NO_FREE_PAGES (ESP_ERR_NVS_BASE + 0x0d) /*!< NVS partition doesn't contain any empty pages. This may happen if NVS partition was truncated. Erase the whole partition and call nvs_flash_init again. */
#define ESP_ERR_NVS_VALUE_TOO_LONG (ESP_ERR_NVS_BASE + 0x0e) /*!< String or blob length is longer than supported by the implementation */
#define ESP_ERR_NVS_PART_NOT_FOUND (ESP_ERR_NVS_BASE + 0x0f) /*!< Partition with specified name is not found in the partition table */
#define NVS_DEFAULT_PART_NAME "nvs" /*!< Default partition name of the NVS partition in the partition table */
/**
* @brief Mode of opening the non-volatile storage
*
@ -54,15 +56,45 @@ typedef enum {
} nvs_open_mode;
/**
* @brief Open non-volatile storage with a given namespace
* @brief Open non-volatile storage with a given namespace from the default NVS partition
*
* Multiple internal ESP-IDF and third party application modules can store
* their key-value pairs in the NVS module. In order to reduce possible
* conflicts on key names, each module can use its own namespace.
* The default NVS partition is the one that is labelled "nvs" in the partition
* table.
*
* @param[in] name Namespace name. Maximal length is determined by the
* underlying implementation, but is guaranteed to be
* at least 15 characters. Shouldn't be empty.
* @param[in] open_mode NVS_READWRITE or NVS_READONLY. If NVS_READONLY, will
* open a handle for reading only. All write requests will
* be rejected for this handle.
* @param[out] out_handle If successful (return code is zero), handle will be
* returned in this argument.
*
* @return
* - ESP_OK if storage handle was opened successfully
* - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized
* - ESP_ERR_NVS_PART_NOT_FOUND if the partition with label "nvs" is not found
* - ESP_ERR_NVS_NOT_FOUND id namespace doesn't exist yet and
* mode is NVS_READONLY
* - ESP_ERR_NVS_INVALID_NAME if namespace name doesn't satisfy constraints
* - other error codes from the underlying storage driver
*/
esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_handle);
/**
* @brief Open non-volatile storage with a given namespace from specified partition
*
* The behaviour is same as nvs_open() API. However this API can operate on a specified NVS
* partition instead of default NVS partition. Note that the specified partition must be registered
* with NVS using nvs_flash_init_partition() API.
*
* @param[in] part_name Label (name) of the partition of interest for object read/write/erase
* @param[in] name Namespace name. Maximal length is determined by the
* underlying implementation, but is guaranteed to be
* at least 15 characters. Shouldn't be empty.
* @param[in] open_mode NVS_READWRITE or NVS_READONLY. If NVS_READONLY, will
* open a handle for reading only. All write requests will
* be rejected for this handle.
@ -72,12 +104,13 @@ typedef enum {
* @return
* - ESP_OK if storage handle was opened successfully
* - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized
* - ESP_ERR_NVS_PART_NOT_FOUND if the partition with specified name is not found
* - ESP_ERR_NVS_NOT_FOUND id namespace doesn't exist yet and
* mode is NVS_READONLY
* - ESP_ERR_NVS_INVALID_NAME if namespace name doesn't satisfy constraints
* - other error codes from the underlying storage driver
*/
esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_handle);
esp_err_t nvs_open_from_partition(const char *part_name, const char* name, nvs_open_mode open_mode, nvs_handle *out_handle);
/**@{*/
/**

View file

@ -21,28 +21,61 @@ extern "C" {
#include "nvs.h"
/**
* @brief Initialize NVS flash storage with layout given in the partition table.
* @brief Initialize the default NVS partition.
*
* This API initialises the default NVS partition. The default NVS partition
* is the one that is labelled "nvs" in the partition table.
*
* @return
* - ESP_OK if storage was successfully initialized.
* - ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages
* (which may happen if NVS partition was truncated)
* - ESP_ERR_NOT_FOUND if no partition with label "nvs" is found in the partition table
* - one of the error codes from the underlying flash storage driver
*/
esp_err_t nvs_flash_init(void);
/**
* @brief Initialize NVS flash storage for the specified partition.
*
* @param[in] partition_name Name (label) of the partition. Note that internally a reference to
* passed value is kept and it should be accessible for future operations
*
* @return
* - ESP_OK if storage was successfully initialized.
* - ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages
* (which may happen if NVS partition was truncated)
* - ESP_ERR_NOT_FOUND if specified partition is not found in the partition table
* - one of the error codes from the underlying flash storage driver
*/
esp_err_t nvs_flash_init_partition(const char *partition_name);
/**
* @brief Erase NVS partition
* @brief Erase the default NVS partition
*
* This function erases all contents of NVS partition
* This function erases all contents of the default NVS partition (one with label "nvs")
*
* @return
* - ESP_OK on success
* - ESP_ERR_NOT_FOUND if there is no NVS partition in the partition table
* - ESP_ERR_NOT_FOUND if there is no NVS partition labeled "nvs" in the
* partition table
*/
esp_err_t nvs_flash_erase(void);
/**
* @brief Erase specified NVS partition
*
* This function erases all contents of specified NVS partition
*
* @param[in] part_name Name (label) of the partition to be erased
*
* @return
* - ESP_OK on success
* - ESP_ERR_NOT_FOUND if there is no NVS partition with the specified name
* in the partition table
*/
esp_err_t nvs_flash_erase_partition(const char *part_name);
#ifdef __cplusplus
}
#endif

View file

@ -11,6 +11,7 @@
// 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.
#include <vector>
#include "nvs.hpp"
#include "nvs_flash.h"
#include "nvs_storage.hpp"
@ -34,16 +35,18 @@ class HandleEntry : public intrusive_list_node<HandleEntry>
public:
HandleEntry() {}
HandleEntry(bool readOnly, uint8_t nsIndex) :
HandleEntry(bool readOnly, uint8_t nsIndex, nvs::Storage* StoragePtr) :
mHandle(++s_nvs_next_handle), // Begin the handle value with 1
mReadOnly(readOnly),
mNsIndex(nsIndex)
mNsIndex(nsIndex),
mStoragePtr(StoragePtr)
{
}
nvs_handle mHandle;
uint8_t mReadOnly;
uint8_t mNsIndex;
nvs::Storage* mStoragePtr;
};
#ifdef ESP_PLATFORM
@ -55,49 +58,90 @@ using namespace nvs;
static intrusive_list<HandleEntry> s_nvs_handles;
uint32_t HandleEntry::s_nvs_next_handle;
static nvs::Storage s_nvs_storage;
static intrusive_list<nvs::Storage> s_nvs_storage_list;
extern "C" void nvs_dump()
static nvs::Storage* lookup_storage_from_name(const char *name)
{
Lock lock;
s_nvs_storage.debugDump();
auto it = find_if(begin(s_nvs_storage_list), end(s_nvs_storage_list), [=](Storage& e) -> bool {
return (strcmp(e.getPartName(), name) == 0);
});
if (it == end(s_nvs_storage_list)) {
return NULL;
}
return it;
}
extern "C" esp_err_t nvs_flash_init_custom(uint32_t baseSector, uint32_t sectorCount)
extern "C" void nvs_dump(const char *partName)
{
ESP_LOGD(TAG, "nvs_flash_init_custom start=%d count=%d", baseSector, sectorCount);
s_nvs_handles.clear();
return s_nvs_storage.init(baseSector, sectorCount);
Lock lock;
nvs::Storage* pStorage;
pStorage = lookup_storage_from_name(partName);
if (pStorage == NULL) {
return;
}
pStorage->debugDump();
return;
}
extern "C" esp_err_t nvs_flash_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount)
{
ESP_LOGD(TAG, "nvs_flash_init_custom partition=%s start=%d count=%d", partName, baseSector, sectorCount);
nvs::Storage* mStorage;
mStorage = lookup_storage_from_name(partName);
if (mStorage == NULL) {
mStorage = new nvs::Storage((const char *)partName);
s_nvs_storage_list.push_back(mStorage);
}
return mStorage->init(baseSector, sectorCount);
}
#ifdef ESP_PLATFORM
extern "C" esp_err_t nvs_flash_init(void)
extern "C" esp_err_t nvs_flash_init_partition(const char *part_name)
{
Lock::init();
Lock lock;
if (s_nvs_storage.isValid()) {
nvs::Storage* mStorage;
mStorage = lookup_storage_from_name(NVS_DEFAULT_PART_NAME);
if (mStorage) {
return ESP_OK;
}
const esp_partition_t* partition = esp_partition_find_first(
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, part_name);
if (partition == NULL) {
return ESP_ERR_NOT_FOUND;
}
return nvs_flash_init_custom(partition->address / SPI_FLASH_SEC_SIZE,
return nvs_flash_init_custom(part_name, partition->address / SPI_FLASH_SEC_SIZE,
partition->size / SPI_FLASH_SEC_SIZE);
}
extern "C" esp_err_t nvs_flash_erase()
extern "C" esp_err_t nvs_flash_init(void)
{
return nvs_flash_init_partition(NVS_DEFAULT_PART_NAME);
}
extern "C" esp_err_t nvs_flash_erase_partition(const char *part_name)
{
const esp_partition_t* partition = esp_partition_find_first(
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, part_name);
if (partition == NULL) {
return ESP_ERR_NOT_FOUND;
}
return esp_partition_erase_range(partition, 0, partition->size);
}
extern "C" esp_err_t nvs_flash_erase()
{
return nvs_flash_erase_partition(NVS_DEFAULT_PART_NAME);
}
#endif
static esp_err_t nvs_find_ns_handle(nvs_handle handle, HandleEntry& entry)
@ -112,17 +156,24 @@ static esp_err_t nvs_find_ns_handle(nvs_handle handle, HandleEntry& entry)
return ESP_OK;
}
extern "C" esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_handle)
extern "C" esp_err_t nvs_open_from_partition(const char *part_name, const char* name, nvs_open_mode open_mode, nvs_handle *out_handle)
{
Lock lock;
ESP_LOGD(TAG, "%s %s %d", __func__, name, open_mode);
uint8_t nsIndex;
esp_err_t err = s_nvs_storage.createOrOpenNamespace(name, open_mode == NVS_READWRITE, nsIndex);
nvs::Storage* sHandle;
sHandle = lookup_storage_from_name(part_name);
if (sHandle == NULL) {
return ESP_ERR_NVS_PART_NOT_FOUND;
}
esp_err_t err = sHandle->createOrOpenNamespace(name, open_mode == NVS_READWRITE, nsIndex);
if (err != ESP_OK) {
return err;
}
HandleEntry *handle_entry = new HandleEntry(open_mode==NVS_READONLY, nsIndex);
HandleEntry *handle_entry = new HandleEntry(open_mode==NVS_READONLY, nsIndex, sHandle);
s_nvs_handles.push_back(handle_entry);
*out_handle = handle_entry->mHandle;
@ -130,6 +181,15 @@ extern "C" esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_han
return ESP_OK;
}
extern "C" esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_handle)
{
if (s_nvs_storage_list.size() == 0) {
return ESP_ERR_NVS_NOT_INITIALIZED;
}
return nvs_open_from_partition(NVS_DEFAULT_PART_NAME, name, open_mode, out_handle);
}
extern "C" void nvs_close(nvs_handle handle)
{
Lock lock;
@ -156,7 +216,7 @@ extern "C" esp_err_t nvs_erase_key(nvs_handle handle, const char* key)
if (entry.mReadOnly) {
return ESP_ERR_NVS_READ_ONLY;
}
return s_nvs_storage.eraseItem(entry.mNsIndex, key);
return entry.mStoragePtr->eraseItem(entry.mNsIndex, key);
}
extern "C" esp_err_t nvs_erase_all(nvs_handle handle)
@ -171,7 +231,7 @@ extern "C" esp_err_t nvs_erase_all(nvs_handle handle)
if (entry.mReadOnly) {
return ESP_ERR_NVS_READ_ONLY;
}
return s_nvs_storage.eraseNamespace(entry.mNsIndex);
return entry.mStoragePtr->eraseNamespace(entry.mNsIndex);
}
template<typename T>
@ -187,7 +247,7 @@ static esp_err_t nvs_set(nvs_handle handle, const char* key, T value)
if (entry.mReadOnly) {
return ESP_ERR_NVS_READ_ONLY;
}
return s_nvs_storage.writeItem(entry.mNsIndex, key, value);
return entry.mStoragePtr->writeItem(entry.mNsIndex, key, value);
}
extern "C" esp_err_t nvs_set_i8 (nvs_handle handle, const char* key, int8_t value)
@ -247,7 +307,7 @@ extern "C" esp_err_t nvs_set_str(nvs_handle handle, const char* key, const char*
if (err != ESP_OK) {
return err;
}
return s_nvs_storage.writeItem(entry.mNsIndex, nvs::ItemType::SZ, key, value, strlen(value) + 1);
return entry.mStoragePtr->writeItem(entry.mNsIndex, nvs::ItemType::SZ, key, value, strlen(value) + 1);
}
extern "C" esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, size_t length)
@ -259,7 +319,7 @@ extern "C" esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void
if (err != ESP_OK) {
return err;
}
return s_nvs_storage.writeItem(entry.mNsIndex, nvs::ItemType::BLOB, key, value, length);
return entry.mStoragePtr->writeItem(entry.mNsIndex, nvs::ItemType::BLOB, key, value, length);
}
@ -273,7 +333,7 @@ static esp_err_t nvs_get(nvs_handle handle, const char* key, T* out_value)
if (err != ESP_OK) {
return err;
}
return s_nvs_storage.readItem(entry.mNsIndex, key, *out_value);
return entry.mStoragePtr->readItem(entry.mNsIndex, key, *out_value);
}
extern "C" esp_err_t nvs_get_i8 (nvs_handle handle, const char* key, int8_t* out_value)
@ -327,7 +387,7 @@ static esp_err_t nvs_get_str_or_blob(nvs_handle handle, nvs::ItemType type, cons
}
size_t dataSize;
err = s_nvs_storage.getItemDataSize(entry.mNsIndex, type, key, dataSize);
err = entry.mStoragePtr->getItemDataSize(entry.mNsIndex, type, key, dataSize);
if (err != ESP_OK) {
return err;
}
@ -342,7 +402,7 @@ static esp_err_t nvs_get_str_or_blob(nvs_handle handle, nvs::ItemType type, cons
return ESP_ERR_NVS_INVALID_LENGTH;
}
return s_nvs_storage.readItem(entry.mNsIndex, type, key, out_value, dataSize);
return entry.mStoragePtr->readItem(entry.mNsIndex, type, key, out_value, dataSize);
}
extern "C" esp_err_t nvs_get_str(nvs_handle handle, const char* key, char* out_value, size_t* length)

View file

@ -27,7 +27,7 @@
namespace nvs
{
class Storage
class Storage : public intrusive_list_node<Storage>
{
enum class StorageState : uint32_t {
INVALID,
@ -45,6 +45,8 @@ class Storage
public:
~Storage();
Storage(const char *pName = NVS_DEFAULT_PART_NAME) : mPartitionName(pName) { };
esp_err_t init(uint32_t baseSector, uint32_t sectorCount);
bool isValid() const;
@ -78,6 +80,11 @@ public:
esp_err_t eraseNamespace(uint8_t nsIndex);
const char *getPartName() const
{
return mPartitionName;
}
void debugDump();
void debugCheck();
@ -95,6 +102,7 @@ protected:
esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item);
protected:
const char *mPartitionName;
size_t mPageCount;
PageManager mPageManager;
TNamespaces mNamespaces;

View file

@ -25,12 +25,13 @@ extern "C" {
*
* @note This API is intended to be used in unit tests.
*
* @param partName Partition name of the NVS partition as per partition table
* @param baseSector Flash sector (units of 4096 bytes) offset to start NVS
* @param sectorCount Length (in flash sectors) of NVS region.
NVS partition must be at least 3 sectors long.
* @return ESP_OK if flash was successfully initialized
*/
esp_err_t nvs_flash_init_custom(uint32_t baseSector, uint32_t sectorCount);
esp_err_t nvs_flash_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount);
/**
@ -38,8 +39,10 @@ esp_err_t nvs_flash_init_custom(uint32_t baseSector, uint32_t sectorCount);
*
* This function may be used for debugging purposes to inspect the state
* of NVS pages. For each page, list of entries is also dumped.
*
* @param partName Partition name of the NVS partition as per partition table
*/
void nvs_dump(void);
void nvs_dump(const char *partName);
#ifdef __cplusplus

View file

@ -494,7 +494,7 @@ TEST_CASE("nvs api tests", "[nvs]")
for (uint16_t i = NVS_FLASH_SECTOR; i <NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; ++i) {
spi_flash_erase_sector(i);
}
TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND);
@ -535,7 +535,6 @@ TEST_CASE("nvs api tests", "[nvs]")
CHECK(0 == strcmp(buf, str));
}
TEST_CASE("wifi test", "[nvs]")
{
SpiFlashEmulator emu(10);
@ -545,7 +544,7 @@ TEST_CASE("wifi test", "[nvs]")
const uint32_t NVS_FLASH_SECTOR = 5;
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
nvs_handle misc_handle;
TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &misc_handle));
@ -687,7 +686,7 @@ TEST_CASE("can init storage from flash with random contents", "[nvs]")
const uint32_t NVS_FLASH_SECTOR = 5;
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &handle));
@ -708,7 +707,7 @@ TEST_CASE("nvs api tests, starting with random data in flash", "[nvs][.][long]")
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
nvs_handle handle_1;
TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND);
@ -745,7 +744,7 @@ TEST_CASE("nvs api tests, starting with random data in flash", "[nvs][.][long]")
}
}
extern "C" void nvs_dump();
extern "C" void nvs_dump(const char *partName);
class RandomTest {
@ -944,7 +943,7 @@ TEST_CASE("monkey test", "[nvs][monkey]")
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
nvs_handle handle;
TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
@ -990,7 +989,7 @@ TEST_CASE("test recovery from sudden poweroff", "[.][long][nvs][recovery][monkey
nvs_handle handle;
size_t count = iter_count;
if (nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK) {
if (nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK) {
if (nvs_open("namespace1", NVS_READWRITE, &handle) == ESP_OK) {
if(test.doRandomThings(handle, gen, count) != ESP_ERR_FLASH_OP_FAIL) {
nvs_close(handle);
@ -1000,11 +999,11 @@ TEST_CASE("test recovery from sudden poweroff", "[.][long][nvs][recovery][monkey
}
}
TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
auto res = test.doRandomThings(handle, gen, count);
if (res != ESP_OK) {
nvs_dump();
nvs_dump(NVS_DEFAULT_PART_NAME);
CHECK(0);
}
nvs_close(handle);
@ -1018,7 +1017,7 @@ TEST_CASE("test for memory leaks in open/set", "[leaks]")
const uint32_t NVS_FLASH_SECTOR = 6;
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
for (int i = 0; i < 100000; ++i) {
nvs_handle light_handle = 0;
@ -1135,7 +1134,7 @@ TEST_CASE("crc error in variable length item is handled", "[nvs]")
TEST_CASE("read/write failure (TW8406)", "[nvs]")
{
SpiFlashEmulator emu(3);
nvs_flash_init_custom(0, 3);
nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3);
for (int attempts = 0; attempts < 3; ++attempts) {
int i = 0;
nvs_handle light_handle = 0;
@ -1169,7 +1168,7 @@ TEST_CASE("nvs_flash_init checks for an empty page", "[nvs]")
const size_t blob_size = Page::BLOB_MAX_SIZE;
uint8_t blob[blob_size] = {0};
SpiFlashEmulator emu(5);
TEST_ESP_OK( nvs_flash_init_custom(0, 5) );
TEST_ESP_OK( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 5) );
nvs_handle handle;
TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) );
// Fill first page
@ -1185,7 +1184,24 @@ TEST_CASE("nvs_flash_init checks for an empty page", "[nvs]")
nvs_close(handle);
// first two pages are now full, third one is writable, last two are empty
// init should fail
TEST_ESP_ERR( nvs_flash_init_custom(0, 3), ESP_ERR_NVS_NO_FREE_PAGES );
TEST_ESP_ERR( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3), ESP_ERR_NVS_NO_FREE_PAGES );
}
TEST_CASE("multiple partitions access check", "[nvs]")
{
SpiFlashEmulator emu(10);
TEST_ESP_OK( nvs_flash_init_custom("nvs1", 0, 5) );
TEST_ESP_OK( nvs_flash_init_custom("nvs2", 5, 5) );
nvs_handle handle1, handle2;
TEST_ESP_OK( nvs_open_from_partition("nvs1", "test", NVS_READWRITE, &handle1) );
TEST_ESP_OK( nvs_open_from_partition("nvs2", "test", NVS_READWRITE, &handle2) );
TEST_ESP_OK( nvs_set_i32(handle1, "foo", 0xdeadbeef));
TEST_ESP_OK( nvs_set_i32(handle2, "foo", 0xcafebabe));
int32_t v1, v2;
TEST_ESP_OK( nvs_get_i32(handle1, "foo", &v1));
TEST_ESP_OK( nvs_get_i32(handle2, "foo", &v2));
CHECK(v1 == 0xdeadbeef);
CHECK(v2 == 0xcafebabe);
}
TEST_CASE("dump all performance data", "[nvs]")