mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/multipart_nvs_support' into 'master'
Multiple partition support in NVS See merge request !1129
This commit is contained in:
commit
0420c4ec82
@ -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
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -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);
|
||||
|
||||
/**@{*/
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
@ -30,19 +31,22 @@ static const char* TAG = "nvs";
|
||||
|
||||
class HandleEntry : public intrusive_list_node<HandleEntry>
|
||||
{
|
||||
static uint32_t s_nvs_next_handle;
|
||||
public:
|
||||
HandleEntry() {}
|
||||
|
||||
HandleEntry(nvs_handle handle, bool readOnly, uint8_t nsIndex) :
|
||||
mHandle(handle),
|
||||
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
|
||||
@ -53,50 +57,91 @@ using namespace std;
|
||||
using namespace nvs;
|
||||
|
||||
static intrusive_list<HandleEntry> s_nvs_handles;
|
||||
static uint32_t s_nvs_next_handle = 1;
|
||||
static nvs::Storage s_nvs_storage;
|
||||
uint32_t HandleEntry::s_nvs_next_handle;
|
||||
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)
|
||||
@ -111,24 +156,40 @@ 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;
|
||||
}
|
||||
|
||||
uint32_t handle = s_nvs_next_handle;
|
||||
++s_nvs_next_handle;
|
||||
*out_handle = handle;
|
||||
HandleEntry *handle_entry = new HandleEntry(open_mode==NVS_READONLY, nsIndex, sHandle);
|
||||
s_nvs_handles.push_back(handle_entry);
|
||||
|
||||
*out_handle = handle_entry->mHandle;
|
||||
|
||||
s_nvs_handles.push_back(new HandleEntry(handle, open_mode==NVS_READONLY, nsIndex));
|
||||
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;
|
||||
@ -155,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)
|
||||
@ -170,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>
|
||||
@ -186,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)
|
||||
@ -246,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)
|
||||
@ -258,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);
|
||||
}
|
||||
|
||||
|
||||
@ -272,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)
|
||||
@ -326,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;
|
||||
}
|
||||
@ -341,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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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]")
|
||||
|
Loading…
Reference in New Issue
Block a user