mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
NVS: expose C++ API
Closes https://github.com/espressif/esp-idf/issues/3540
This commit is contained in:
parent
6655fa8a93
commit
d286876d34
@ -1,9 +1,13 @@
|
||||
set(srcs "src/nvs_api.cpp"
|
||||
"src/nvs_cxx_api.cpp"
|
||||
"src/nvs_item_hash_list.cpp"
|
||||
"src/nvs_ops.cpp"
|
||||
"src/nvs_page.cpp"
|
||||
"src/nvs_pagemanager.cpp"
|
||||
"src/nvs_storage.cpp"
|
||||
"src/nvs_handle_simple.cpp"
|
||||
"src/nvs_handle_locked.cpp"
|
||||
"src/nvs_partition_manager.cpp"
|
||||
"src/nvs_types.cpp")
|
||||
if(CONFIG_NVS_ENCRYPTION)
|
||||
list(APPEND srcs "src/nvs_encr.cpp")
|
||||
|
@ -47,7 +47,7 @@ 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., the maximum length is 15 characters. 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 the ``nvs_read_*``, ``nvs_write_*``, and ``nvs_commit`` functions. This way, a 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., the maximum length is 15 characters. 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 the ``nvs_get_*``, ``nvs_set_*``, and ``nvs_commit`` functions. This way, a handle is associated with a namespace, and key names will not collide with same names in other namespaces.
|
||||
Please note that the namespaces with the same name in different NVS partitions are considered as separate namespaces.
|
||||
|
||||
|
||||
@ -282,7 +282,7 @@ It is possible for an application to use different keys for different NVS partit
|
||||
Encrypted Read/Write
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The same NVS API functions ``nvs_read_*`` or ``nvs_write_*`` can be used for reading of, and writing to an encrypted nvs partition as well. However, the API functions for initialising NVS partitions are different: ``nvs_flash_secure_init`` and ``nvs_flash_secure_init_partition`` instead of ``nvs_flash_init`` and ``nvs_flash_init_partition`` respectively. The ``nvs_sec_cfg_t`` structure required for these API functions can be populated using ``nvs_flash_generate_keys`` or ``nvs_flash_read_security_cfg``.
|
||||
The same NVS API functions ``nvs_get_*`` or ``nvs_set_*`` can be used for reading of, and writing to an encrypted nvs partition as well. However, the API functions for initialising NVS partitions are different: ``nvs_flash_secure_init`` and ``nvs_flash_secure_init_partition`` instead of ``nvs_flash_init`` and ``nvs_flash_init_partition`` respectively. The ``nvs_sec_cfg_t`` structure required for these API functions can be populated using ``nvs_flash_generate_keys`` or ``nvs_flash_read_security_cfg``.
|
||||
|
||||
Applications are expected to follow the steps below in order to perform NVS read/write operations with encryption enabled.
|
||||
|
||||
@ -290,7 +290,7 @@ Applications are expected to follow the steps below in order to perform NVS read
|
||||
2. Populate the ``nvs_sec_cfg_t`` struct using the ``nvs_flash_read_security_cfg`` or ``nvs_flash_generate_keys`` API functions.
|
||||
3. Initialise NVS flash partition using the ``nvs_flash_secure_init`` or ``nvs_flash_secure_init_partition`` API functions.
|
||||
4. Open a namespace using the ``nvs_open`` or ``nvs_open_from_part`` API functions.
|
||||
5. Perform NVS read/write operations using ``nvs_read_*`` or ``nvs_write_*``.
|
||||
5. Perform NVS read/write operations using ``nvs_get_*`` or ``nvs_set_*``.
|
||||
6. Deinitialise an NVS partition using ``nvs_flash_deinit``.
|
||||
|
||||
NVS iterators
|
||||
|
@ -46,7 +46,7 @@ NVS 的操作对象为键值对,其中键是 ASCII 字符串,当前支持最
|
||||
命名空间
|
||||
^^^^^^^^^^
|
||||
|
||||
为了减少不同组件之间键名的潜在冲突,NVS 将每个键值对分配给一个命名空间。命名空间的命名规则遵循键名的命名规则,即最多可占 15 个字符。命名空间的名称在调用 ``nvs_open`` 或 ``nvs_open_from_part`` 中指定,调用后将返回一个不透明句柄,用于后续调用 ``nvs_read_*``、``nvs_write_*`` 和 ``nvs_commit`` 函数。这样,一个句柄关联一个命名空间,键名便不会与其他命名空间中相同键名冲突。请注意,不同 NVS 分区中具有相同名称的命名空间将被视为不同的命名空间。
|
||||
为了减少不同组件之间键名的潜在冲突,NVS 将每个键值对分配给一个命名空间。命名空间的命名规则遵循键名的命名规则,即最多可占 15 个字符。命名空间的名称在调用 ``nvs_open`` 或 ``nvs_open_from_part`` 中指定,调用后将返回一个不透明句柄,用于后续调用 ``nvs_get_*``、``nvs_set_*`` 和 ``nvs_commit`` 函数。这样,一个句柄关联一个命名空间,键名便不会与其他命名空间中相同键名冲突。请注意,不同 NVS 分区中具有相同名称的命名空间将被视为不同的命名空间。
|
||||
|
||||
|
||||
安全性、篡改性及鲁棒性
|
||||
@ -277,7 +277,7 @@ NVS 密钥分区
|
||||
加密读取/写入
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
``nvs_read_*`` 和 ``nvs_write_*`` 等 NVS API 函数同样可以对 NVS 加密分区执行读写操作。但用于初始化 NVS 非加密分区和加密分区的 API 则有所不同:初始化 NVS 非加密分区可以使用 ``nvs_flash_init`` 和 ``nvs_flash_init_partition``,但初始化 NVS 加密分区则需调用 ``nvs_flash_secure_init`` 和 ``nvs_flash_secure_init_partition``。上述 API 函数所需的 ``nvs_sec_cfg_t`` 结构可使用 ``nvs_flash_generate_keys`` 或者 ``nvs_flash_read_security_cfg`` 进行填充。
|
||||
``nvs_get_*`` 和 ``nvs_set_*`` 等 NVS API 函数同样可以对 NVS 加密分区执行读写操作。但用于初始化 NVS 非加密分区和加密分区的 API 则有所不同:初始化 NVS 非加密分区可以使用 ``nvs_flash_init`` 和 ``nvs_flash_init_partition``,但初始化 NVS 加密分区则需调用 ``nvs_flash_secure_init`` 和 ``nvs_flash_secure_init_partition``。上述 API 函数所需的 ``nvs_sec_cfg_t`` 结构可使用 ``nvs_flash_generate_keys`` 或者 ``nvs_flash_read_security_cfg`` 进行填充。
|
||||
|
||||
应用程序如需在加密状态下执行 NVS 读写操作,应遵循以下步骤:
|
||||
|
||||
@ -285,7 +285,7 @@ NVS 密钥分区
|
||||
2. 使用 ``nvs_flash_read_security_cfg`` 或 ``nvs_flash_generate_keys`` API 填充 ``nvs_sec_cfg_t`` 结构;
|
||||
3. 使用 ``nvs_flash_secure_init`` 或 ``nvs_flash_secure_init_partition`` API 初始化 NVS flash 分区;
|
||||
4. 使用 ``nvs_open`` 或 ``nvs_open_from_part`` API 打开命名空间;
|
||||
5. 使用 ``nvs_read_*`` 或 ``nvs_write_*`` API 执行 NVS 读取/写入操作;
|
||||
5. 使用 ``nvs_get_*`` 或 ``nvs_set_*`` API 执行 NVS 读取/写入操作;
|
||||
6. 使用 ``nvs_flash_deinit`` API 释放已初始化的 NVS 分区。
|
||||
|
||||
NVS 迭代器
|
||||
|
@ -289,7 +289,7 @@ esp_err_t nvs_get_u64 (nvs_handle_t handle, const char* key, uint64_t* out_value
|
||||
/**
|
||||
* @brief get value for given key
|
||||
*
|
||||
* These functions retrieve value for the key, given its name. If key does not
|
||||
* These functions retrieve the data of an entry, given its key. If key does not
|
||||
* exist, or the requested variable type doesn't match the type which was used
|
||||
* when setting a value, an error is returned.
|
||||
*
|
||||
@ -491,7 +491,7 @@ esp_err_t nvs_get_stats(const char *part_name, nvs_stats_t *nvs_stats);
|
||||
* Return param used_entries will be filled 0.
|
||||
* - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL.
|
||||
* Return param used_entries will be filled 0.
|
||||
* - ESP_ERR_INVALID_ARG if nvs_stats equal to NULL.
|
||||
* - ESP_ERR_INVALID_ARG if used_entries equal to NULL.
|
||||
* - Other error codes from the underlying storage driver.
|
||||
* Return param used_entries will be filled 0.
|
||||
*/
|
||||
|
262
components/nvs_flash/include/nvs_handle.hpp
Normal file
262
components/nvs_flash/include/nvs_handle.hpp
Normal file
@ -0,0 +1,262 @@
|
||||
#ifndef NVS_HANDLE_HPP_
|
||||
#define NVS_HANDLE_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "nvs.h"
|
||||
|
||||
namespace nvs {
|
||||
|
||||
/**
|
||||
* The possible blob types. This is a helper definition for template functions.
|
||||
*/
|
||||
enum class ItemType : uint8_t {
|
||||
U8 = NVS_TYPE_U8,
|
||||
I8 = NVS_TYPE_I8,
|
||||
U16 = NVS_TYPE_U16,
|
||||
I16 = NVS_TYPE_I16,
|
||||
U32 = NVS_TYPE_U32,
|
||||
I32 = NVS_TYPE_I32,
|
||||
U64 = NVS_TYPE_U64,
|
||||
I64 = NVS_TYPE_I64,
|
||||
SZ = NVS_TYPE_STR,
|
||||
BLOB = 0x41,
|
||||
BLOB_DATA = NVS_TYPE_BLOB,
|
||||
BLOB_IDX = 0x48,
|
||||
ANY = NVS_TYPE_ANY
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief A handle allowing nvs-entry related operations on the NVS.
|
||||
*
|
||||
* @note The scope of this handle may vary depending on the implementation, but normally would be the namespace of
|
||||
* a particular partition. Outside that scope, nvs entries can't be accessed/altered.
|
||||
*/
|
||||
class NVSHandle {
|
||||
public:
|
||||
virtual ~NVSHandle() { }
|
||||
|
||||
/**
|
||||
* @brief set value for given key
|
||||
*
|
||||
* Sets value for key. Note that physical storage will not be updated until nvs_commit function is called.
|
||||
*
|
||||
* @param[in] key Key name. Maximal length is determined by the underlying
|
||||
* implementation, but is guaranteed to be at least
|
||||
* 15 characters. Shouldn't be empty.
|
||||
* @param[in] value The value to set. Allowed types are the ones declared in ItemType.
|
||||
* For strings, the maximum length (including null character) is
|
||||
* 4000 bytes.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if value was set successfully
|
||||
* - ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only
|
||||
* - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints
|
||||
* - ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is not enough space in the
|
||||
* underlying storage to save the value
|
||||
* - ESP_ERR_NVS_REMOVE_FAILED if the value wasn't updated because flash
|
||||
* write operation has failed. The value was written however, and
|
||||
* update will be finished after re-initialization of nvs, provided that
|
||||
* flash operation doesn't fail again.
|
||||
* - ESP_ERR_NVS_VALUE_TOO_LONG if the string value is too long
|
||||
*/
|
||||
template<typename T>
|
||||
esp_err_t set_item(const char *key, T value);
|
||||
virtual
|
||||
esp_err_t set_string(const char *key, const char* value) = 0;
|
||||
|
||||
/**
|
||||
* @brief get value for given key
|
||||
*
|
||||
* These functions retrieve value for the key, given its name. If key does not
|
||||
* exist, or the requested variable type doesn't match the type which was used
|
||||
* when setting a value, an error is returned.
|
||||
*
|
||||
* In case of any error, out_value is not modified.
|
||||
*
|
||||
* @param[in] key Key name. Maximal length is determined by the underlying
|
||||
* implementation, but is guaranteed to be at least
|
||||
* 15 characters. Shouldn't be empty.
|
||||
* @param value The output value.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if the value was retrieved successfully
|
||||
* - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist
|
||||
* - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints
|
||||
* - ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data
|
||||
*/
|
||||
template<typename T>
|
||||
esp_err_t get_item(const char *key, T &value);
|
||||
|
||||
/**
|
||||
* @brief set variable length binary value for given key
|
||||
*
|
||||
* This family of functions set value for the key, given its name. Note that
|
||||
* actual storage will not be updated until nvs_commit function is called.
|
||||
*
|
||||
* @param[in] key Key name. Maximal length is 15 characters. Shouldn't be empty.
|
||||
* @param[in] blob The blob value to set.
|
||||
* @param[in] len length of binary value to set, in bytes; Maximum length is
|
||||
* 508000 bytes or (97.6% of the partition size - 4000) bytes
|
||||
* whichever is lower.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if value was set successfully
|
||||
* - ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only
|
||||
* - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints
|
||||
* - ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is not enough space in the
|
||||
* underlying storage to save the value
|
||||
* - ESP_ERR_NVS_REMOVE_FAILED if the value wasn't updated because flash
|
||||
* write operation has failed. The value was written however, and
|
||||
* update will be finished after re-initialization of nvs, provided that
|
||||
* flash operation doesn't fail again.
|
||||
* - ESP_ERR_NVS_VALUE_TOO_LONG if the value is too long
|
||||
*
|
||||
* @note compare to \ref nvs_set_blob in nvs.h
|
||||
*/
|
||||
virtual esp_err_t set_blob(const char *key, const void* blob, size_t len) = 0;
|
||||
|
||||
/**
|
||||
* @brief get value for given key
|
||||
*
|
||||
* These functions retrieve the data of an entry, given its key. If key does not
|
||||
* exist, or the requested variable type doesn't match the type which was used
|
||||
* when setting a value, an error is returned.
|
||||
*
|
||||
* In case of any error, out_value is not modified.
|
||||
*
|
||||
* Both functions expect out_value to be a pointer to an already allocated variable
|
||||
* of the given type.
|
||||
*
|
||||
* It is suggested that nvs_get/set_str is used for zero-terminated C strings, and
|
||||
* nvs_get/set_blob used for arbitrary data structures.
|
||||
*
|
||||
* @param[in] key Key name. Maximal length is determined by the underlying
|
||||
* implementation, but is guaranteed to be at least
|
||||
* 15 characters. Shouldn't be empty.
|
||||
* @param out_str/ Pointer to the output value.
|
||||
* out_blob
|
||||
* @param[inout] length A non-zero pointer to the variable holding the length of out_value.
|
||||
* It will be set to the actual length of the value
|
||||
* written. For nvs_get_str this includes the zero terminator.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if the value was retrieved successfully
|
||||
* - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist
|
||||
* - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints
|
||||
* - ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data
|
||||
*/
|
||||
virtual esp_err_t get_string(const char *key, char* out_str, size_t len) = 0;
|
||||
virtual esp_err_t get_blob(const char *key, void* out_blob, size_t len) = 0;
|
||||
|
||||
/**
|
||||
* @brief Looks up the size of an entry's data.
|
||||
*
|
||||
* For strings, this size includes the zero terminator.
|
||||
*/
|
||||
virtual esp_err_t get_item_size(ItemType datatype, const char *key, size_t &size) = 0;
|
||||
|
||||
/**
|
||||
* @brief Erases an entry.
|
||||
*/
|
||||
virtual esp_err_t erase_item(const char* key) = 0;
|
||||
|
||||
/**
|
||||
* Erases all entries in the scope of this handle. The scope may vary, depending on the implementation.
|
||||
*
|
||||
* @not If you want to erase the whole nvs flash (partition), refer to \ref
|
||||
*/
|
||||
virtual esp_err_t erase_all() = 0;
|
||||
|
||||
/**
|
||||
* Commits all changes done through this handle so far.
|
||||
*/
|
||||
virtual esp_err_t commit() = 0;
|
||||
|
||||
/**
|
||||
* @brief Calculate all entries in the scope of the handle.
|
||||
*
|
||||
* @param[out] used_entries Returns amount of used entries from a namespace on success.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if the changes have been written successfully.
|
||||
* Return param used_entries will be filled valid value.
|
||||
* - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized.
|
||||
* Return param used_entries will be filled 0.
|
||||
* - ESP_ERR_INVALID_ARG if nvs_stats equal to NULL.
|
||||
* - Other error codes from the underlying storage driver.
|
||||
* Return param used_entries will be filled 0.
|
||||
*/
|
||||
virtual esp_err_t get_used_entry_count(size_t& usedEntries) = 0;
|
||||
|
||||
protected:
|
||||
virtual esp_err_t set_typed_item(ItemType datatype, const char *key, const void* data, size_t dataSize) = 0;
|
||||
|
||||
virtual esp_err_t get_typed_item(ItemType datatype, const char *key, void* data, size_t dataSize) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Opens non-volatile storage and returns a handle object.
|
||||
*
|
||||
* The handle is automatically closed on desctruction. The scope of the handle is the namespace ns_name
|
||||
* in a particular partition partition_name.
|
||||
* The parameters partition_name, ns_name and open_mode have the same meaning and restrictions as the parameters
|
||||
* part_name, name and open_mode in \ref nvs_open_from_partition, respectively.
|
||||
*
|
||||
* @param err an optional pointer to an esp_err_t result of the open operation, having the same meaning as the return
|
||||
* value in \ref nvs_open_from_partition:
|
||||
* - 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
|
||||
*
|
||||
* @return shared pointer of an nvs handle on success, an empty shared pointer otherwise
|
||||
*/
|
||||
std::unique_ptr<NVSHandle> open_nvs_handle_from_partition(const char *partition_name,
|
||||
const char *ns_name,
|
||||
nvs_open_mode_t open_mode,
|
||||
esp_err_t *err = nullptr);
|
||||
|
||||
/**
|
||||
* @brief This function does the same as \ref open_nvs_handle_from_partition but uses the default nvs partition
|
||||
* instead of a partition_name parameter.
|
||||
*/
|
||||
std::unique_ptr<NVSHandle> open_nvs_handle(const char *ns_name,
|
||||
nvs_open_mode_t open_mode,
|
||||
esp_err_t *err = nullptr);
|
||||
|
||||
// Helper functions for template usage
|
||||
template<typename T, typename std::enable_if<std::is_integral<T>::value, void*>::type = nullptr>
|
||||
constexpr ItemType itemTypeOf()
|
||||
{
|
||||
return static_cast<ItemType>(((std::is_signed<T>::value)?0x10:0x00) | sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr ItemType itemTypeOf(const T&)
|
||||
{
|
||||
return itemTypeOf<T>();
|
||||
}
|
||||
|
||||
// Template Implementations
|
||||
template<typename T>
|
||||
esp_err_t NVSHandle::set_item(const char *key, T value) {
|
||||
return set_typed_item(itemTypeOf(value), key, &value, sizeof(value));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
esp_err_t NVSHandle::get_item(const char *key, T &value) {
|
||||
return get_typed_item(itemTypeOf(value), key, &value, sizeof(value));
|
||||
}
|
||||
|
||||
} // nvs
|
||||
|
||||
#endif // NVS_HANDLE_HPP_
|
||||
|
@ -16,8 +16,10 @@
|
||||
#include "nvs_storage.hpp"
|
||||
#include "intrusive_list.h"
|
||||
#include "nvs_platform.hpp"
|
||||
#include "nvs_partition_manager.hpp"
|
||||
#include "esp_partition.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "nvs_handle_simple.hpp"
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
#include "nvs_encr.hpp"
|
||||
#endif
|
||||
@ -34,6 +36,26 @@ static const char* TAG = "nvs";
|
||||
#define ESP_LOGD(...)
|
||||
#endif
|
||||
|
||||
class NVSHandleEntry : public intrusive_list_node<NVSHandleEntry> {
|
||||
public:
|
||||
NVSHandleEntry(nvs::NVSHandleSimple *handle, const char* part_name)
|
||||
: nvs_handle(handle),
|
||||
mHandle(++s_nvs_next_handle),
|
||||
handle_part_name(part_name) { }
|
||||
|
||||
~NVSHandleEntry() {
|
||||
delete nvs_handle;
|
||||
}
|
||||
|
||||
nvs::NVSHandleSimple *nvs_handle;
|
||||
nvs_handle_t mHandle;
|
||||
const char* handle_part_name;
|
||||
private:
|
||||
static uint32_t s_nvs_next_handle;
|
||||
};
|
||||
|
||||
uint32_t NVSHandleEntry::s_nvs_next_handle;
|
||||
|
||||
extern "C" void nvs_dump(const char *partName);
|
||||
extern "C" esp_err_t nvs_flash_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount);
|
||||
|
||||
@ -41,26 +63,6 @@ extern "C" esp_err_t nvs_flash_init_custom(const char *partName, uint32_t baseSe
|
||||
extern "C" esp_err_t nvs_flash_secure_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount, nvs_sec_cfg_t* cfg);
|
||||
#endif
|
||||
|
||||
class HandleEntry : public intrusive_list_node<HandleEntry>
|
||||
{
|
||||
static uint32_t s_nvs_next_handle;
|
||||
public:
|
||||
HandleEntry() {}
|
||||
|
||||
HandleEntry(bool readOnly, uint8_t nsIndex, nvs::Storage* StoragePtr) :
|
||||
mHandle(++s_nvs_next_handle), // Begin the handle value with 1
|
||||
mReadOnly(readOnly),
|
||||
mNsIndex(nsIndex),
|
||||
mStoragePtr(StoragePtr)
|
||||
{
|
||||
}
|
||||
|
||||
nvs_handle_t mHandle;
|
||||
uint8_t mReadOnly;
|
||||
uint8_t mNsIndex;
|
||||
nvs::Storage* mStoragePtr;
|
||||
};
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
SemaphoreHandle_t nvs::Lock::mSemaphore = NULL;
|
||||
#endif
|
||||
@ -68,20 +70,11 @@ SemaphoreHandle_t nvs::Lock::mSemaphore = NULL;
|
||||
using namespace std;
|
||||
using namespace nvs;
|
||||
|
||||
static intrusive_list<HandleEntry> s_nvs_handles;
|
||||
uint32_t HandleEntry::s_nvs_next_handle;
|
||||
static intrusive_list<nvs::Storage> s_nvs_storage_list;
|
||||
static intrusive_list<NVSHandleEntry> s_nvs_handles;
|
||||
|
||||
static nvs::Storage* lookup_storage_from_name(const char *name)
|
||||
{
|
||||
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;
|
||||
return NVSPartitionManager::get_instance()->lookup_storage_from_name(name);
|
||||
}
|
||||
|
||||
extern "C" void nvs_dump(const char *partName)
|
||||
@ -102,24 +95,7 @@ extern "C" esp_err_t nvs_flash_init_custom(const char *partName, uint32_t baseSe
|
||||
{
|
||||
ESP_LOGD(TAG, "nvs_flash_init_custom partition=%s start=%d count=%d", partName, baseSector, sectorCount);
|
||||
|
||||
if (strlen(partName) > NVS_PART_NAME_MAX_SIZE) return ESP_ERR_INVALID_ARG;
|
||||
|
||||
nvs::Storage* new_storage = NULL;
|
||||
nvs::Storage* storage = lookup_storage_from_name(partName);
|
||||
if (storage == NULL) {
|
||||
new_storage = new nvs::Storage((const char *)partName);
|
||||
storage = new_storage;
|
||||
}
|
||||
|
||||
esp_err_t err = storage->init(baseSector, sectorCount);
|
||||
if (new_storage != NULL) {
|
||||
if (err == ESP_OK) {
|
||||
s_nvs_storage_list.push_back(new_storage);
|
||||
} else {
|
||||
delete new_storage;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
return nvs::NVSPartitionManager::get_instance()->init_custom(partName, baseSector, sectorCount);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
@ -145,21 +121,8 @@ extern "C" esp_err_t nvs_flash_init_partition(const char *part_name)
|
||||
{
|
||||
Lock::init();
|
||||
Lock lock;
|
||||
nvs::Storage* mStorage;
|
||||
|
||||
mStorage = lookup_storage_from_name(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, part_name);
|
||||
if (partition == NULL) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return nvs_flash_init_custom(part_name, partition->address / SPI_FLASH_SEC_SIZE,
|
||||
partition->size / SPI_FLASH_SEC_SIZE);
|
||||
return nvs::NVSPartitionManager::get_instance()->init_partition(part_name);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_flash_init(void)
|
||||
@ -217,37 +180,11 @@ extern "C" esp_err_t nvs_flash_deinit_partition(const char* partition_name)
|
||||
Lock::init();
|
||||
Lock lock;
|
||||
|
||||
nvs::Storage* storage = lookup_storage_from_name(partition_name);
|
||||
if (!storage) {
|
||||
return ESP_ERR_NVS_NOT_INITIALIZED;
|
||||
}
|
||||
// Delete all corresponding open handles
|
||||
s_nvs_handles.clearAndFreeNodes();
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
if(EncrMgr::isEncrActive()) {
|
||||
auto encrMgr = EncrMgr::getInstance();
|
||||
encrMgr->removeSecurityContext(storage->getBaseSector());
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Clean up handles related to the storage being deinitialized */
|
||||
auto it = s_nvs_handles.begin();
|
||||
auto next = it;
|
||||
while(it != s_nvs_handles.end()) {
|
||||
next++;
|
||||
if (it->mStoragePtr == storage) {
|
||||
ESP_LOGD(TAG, "Deleting handle %d (ns=%d) related to partition \"%s\" (missing call to nvs_close?)",
|
||||
it->mHandle, it->mNsIndex, partition_name);
|
||||
s_nvs_handles.erase(it);
|
||||
delete static_cast<HandleEntry*>(it);
|
||||
}
|
||||
it = next;
|
||||
}
|
||||
|
||||
/* Finally delete the storage itself */
|
||||
s_nvs_storage_list.erase(storage);
|
||||
delete storage;
|
||||
|
||||
return ESP_OK;
|
||||
// Deinit partition
|
||||
return nvs::NVSPartitionManager::get_instance()->deinit_partition(partition_name);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_flash_deinit(void)
|
||||
@ -255,15 +192,15 @@ extern "C" esp_err_t nvs_flash_deinit(void)
|
||||
return nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME);
|
||||
}
|
||||
|
||||
static esp_err_t nvs_find_ns_handle(nvs_handle_t handle, HandleEntry& entry)
|
||||
static esp_err_t nvs_find_ns_handle(nvs_handle_t c_handle, NVSHandleSimple** handle)
|
||||
{
|
||||
auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](HandleEntry& e) -> bool {
|
||||
return e.mHandle == handle;
|
||||
auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](NVSHandleEntry& e) -> bool {
|
||||
return e.mHandle == c_handle;
|
||||
});
|
||||
if (it == end(s_nvs_handles)) {
|
||||
return ESP_ERR_NVS_INVALID_HANDLE;
|
||||
}
|
||||
entry = *it;
|
||||
*handle = it->nvs_handle;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -271,33 +208,25 @@ extern "C" esp_err_t nvs_open_from_partition(const char *part_name, const char*
|
||||
{
|
||||
Lock lock;
|
||||
ESP_LOGD(TAG, "%s %s %d", __func__, name, open_mode);
|
||||
uint8_t nsIndex;
|
||||
nvs::Storage* sHandle;
|
||||
|
||||
sHandle = lookup_storage_from_name(part_name);
|
||||
if (sHandle == NULL) {
|
||||
return ESP_ERR_NVS_PART_NOT_FOUND;
|
||||
NVSHandleSimple *handle;
|
||||
esp_err_t result = nvs::NVSPartitionManager::get_instance()->open_handle(part_name, name, open_mode, &handle);
|
||||
if (result == ESP_OK) {
|
||||
NVSHandleEntry *entry = new NVSHandleEntry(handle, part_name);
|
||||
if (entry) {
|
||||
s_nvs_handles.push_back(entry);
|
||||
*out_handle = entry->mHandle;
|
||||
} else {
|
||||
delete handle;
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
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, sHandle);
|
||||
s_nvs_handles.push_back(handle_entry);
|
||||
|
||||
*out_handle = handle_entry->mHandle;
|
||||
|
||||
return ESP_OK;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_open(const char* name, nvs_open_mode_t open_mode, nvs_handle_t *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);
|
||||
}
|
||||
|
||||
@ -305,60 +234,54 @@ extern "C" void nvs_close(nvs_handle_t handle)
|
||||
{
|
||||
Lock lock;
|
||||
ESP_LOGD(TAG, "%s %d", __func__, handle);
|
||||
auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](HandleEntry& e) -> bool {
|
||||
auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](NVSHandleEntry& e) -> bool {
|
||||
return e.mHandle == handle;
|
||||
});
|
||||
if (it == end(s_nvs_handles)) {
|
||||
return;
|
||||
}
|
||||
s_nvs_handles.erase(it);
|
||||
delete static_cast<HandleEntry*>(it);
|
||||
delete static_cast<NVSHandleEntry*>(it);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_erase_key(nvs_handle_t handle, const char* key)
|
||||
extern "C" esp_err_t nvs_erase_key(nvs_handle_t c_handle, const char* key)
|
||||
{
|
||||
Lock lock;
|
||||
ESP_LOGD(TAG, "%s %s\r\n", __func__, key);
|
||||
HandleEntry entry;
|
||||
auto err = nvs_find_ns_handle(handle, entry);
|
||||
NVSHandleSimple *handle;
|
||||
auto err = nvs_find_ns_handle(c_handle, &handle);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
if (entry.mReadOnly) {
|
||||
return ESP_ERR_NVS_READ_ONLY;
|
||||
}
|
||||
return entry.mStoragePtr->eraseItem(entry.mNsIndex, key);
|
||||
|
||||
return handle->erase_item(key);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_erase_all(nvs_handle_t handle)
|
||||
extern "C" esp_err_t nvs_erase_all(nvs_handle_t c_handle)
|
||||
{
|
||||
Lock lock;
|
||||
ESP_LOGD(TAG, "%s\r\n", __func__);
|
||||
HandleEntry entry;
|
||||
auto err = nvs_find_ns_handle(handle, entry);
|
||||
NVSHandleSimple *handle;
|
||||
auto err = nvs_find_ns_handle(c_handle, &handle);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
if (entry.mReadOnly) {
|
||||
return ESP_ERR_NVS_READ_ONLY;
|
||||
}
|
||||
return entry.mStoragePtr->eraseNamespace(entry.mNsIndex);
|
||||
|
||||
return handle->erase_all();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static esp_err_t nvs_set(nvs_handle_t handle, const char* key, T value)
|
||||
static esp_err_t nvs_set(nvs_handle_t c_handle, const char* key, T value)
|
||||
{
|
||||
Lock lock;
|
||||
ESP_LOGD(TAG, "%s %s %d %d", __func__, key, sizeof(T), (uint32_t) value);
|
||||
HandleEntry entry;
|
||||
auto err = nvs_find_ns_handle(handle, entry);
|
||||
NVSHandleSimple *handle;
|
||||
auto err = nvs_find_ns_handle(c_handle, &handle);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
if (entry.mReadOnly) {
|
||||
return ESP_ERR_NVS_READ_ONLY;
|
||||
}
|
||||
return entry.mStoragePtr->writeItem(entry.mNsIndex, key, value);
|
||||
|
||||
return handle->set_item(key, value);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_set_i8 (nvs_handle_t handle, const char* key, int8_t value)
|
||||
@ -401,110 +324,108 @@ extern "C" esp_err_t nvs_set_u64 (nvs_handle_t handle, const char* key, uint64_t
|
||||
return nvs_set(handle, key, value);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_commit(nvs_handle_t handle)
|
||||
extern "C" esp_err_t nvs_commit(nvs_handle_t c_handle)
|
||||
{
|
||||
Lock lock;
|
||||
// no-op for now, to be used when intermediate cache is added
|
||||
HandleEntry entry;
|
||||
return nvs_find_ns_handle(handle, entry);
|
||||
NVSHandleSimple *handle;
|
||||
auto err = nvs_find_ns_handle(c_handle, &handle);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
return handle->commit();
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_set_str(nvs_handle_t handle, const char* key, const char* value)
|
||||
extern "C" esp_err_t nvs_set_str(nvs_handle_t c_handle, const char* key, const char* value)
|
||||
{
|
||||
Lock lock;
|
||||
ESP_LOGD(TAG, "%s %s %s", __func__, key, value);
|
||||
HandleEntry entry;
|
||||
auto err = nvs_find_ns_handle(handle, entry);
|
||||
NVSHandleSimple *handle;
|
||||
auto err = nvs_find_ns_handle(c_handle, &handle);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
if (entry.mReadOnly) {
|
||||
return ESP_ERR_NVS_READ_ONLY;
|
||||
}
|
||||
return entry.mStoragePtr->writeItem(entry.mNsIndex, nvs::ItemType::SZ, key, value, strlen(value) + 1);
|
||||
return handle->set_string(key, value);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_set_blob(nvs_handle_t handle, const char* key, const void* value, size_t length)
|
||||
extern "C" esp_err_t nvs_set_blob(nvs_handle_t c_handle, const char* key, const void* value, size_t length)
|
||||
{
|
||||
Lock lock;
|
||||
ESP_LOGD(TAG, "%s %s %d", __func__, key, length);
|
||||
HandleEntry entry;
|
||||
auto err = nvs_find_ns_handle(handle, entry);
|
||||
NVSHandleSimple *handle;
|
||||
auto err = nvs_find_ns_handle(c_handle, &handle);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
if (entry.mReadOnly) {
|
||||
return ESP_ERR_NVS_READ_ONLY;
|
||||
}
|
||||
return entry.mStoragePtr->writeItem(entry.mNsIndex, nvs::ItemType::BLOB, key, value, length);
|
||||
return handle->set_blob(key, value, length);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
static esp_err_t nvs_get(nvs_handle_t handle, const char* key, T* out_value)
|
||||
static esp_err_t nvs_get(nvs_handle_t c_handle, const char* key, T* out_value)
|
||||
{
|
||||
Lock lock;
|
||||
ESP_LOGD(TAG, "%s %s %d", __func__, key, sizeof(T));
|
||||
HandleEntry entry;
|
||||
auto err = nvs_find_ns_handle(handle, entry);
|
||||
NVSHandleSimple *handle;
|
||||
auto err = nvs_find_ns_handle(c_handle, &handle);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
return entry.mStoragePtr->readItem(entry.mNsIndex, key, *out_value);
|
||||
return handle->get_item(key, *out_value);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_get_i8 (nvs_handle_t handle, const char* key, int8_t* out_value)
|
||||
extern "C" esp_err_t nvs_get_i8 (nvs_handle_t c_handle, const char* key, int8_t* out_value)
|
||||
{
|
||||
return nvs_get(handle, key, out_value);
|
||||
return nvs_get(c_handle, key, out_value);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_get_u8 (nvs_handle_t handle, const char* key, uint8_t* out_value)
|
||||
extern "C" esp_err_t nvs_get_u8 (nvs_handle_t c_handle, const char* key, uint8_t* out_value)
|
||||
{
|
||||
return nvs_get(handle, key, out_value);
|
||||
return nvs_get(c_handle, key, out_value);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_get_i16 (nvs_handle_t handle, const char* key, int16_t* out_value)
|
||||
extern "C" esp_err_t nvs_get_i16 (nvs_handle_t c_handle, const char* key, int16_t* out_value)
|
||||
{
|
||||
return nvs_get(handle, key, out_value);
|
||||
return nvs_get(c_handle, key, out_value);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_get_u16 (nvs_handle_t handle, const char* key, uint16_t* out_value)
|
||||
extern "C" esp_err_t nvs_get_u16 (nvs_handle_t c_handle, const char* key, uint16_t* out_value)
|
||||
{
|
||||
return nvs_get(handle, key, out_value);
|
||||
return nvs_get(c_handle, key, out_value);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_get_i32 (nvs_handle_t handle, const char* key, int32_t* out_value)
|
||||
extern "C" esp_err_t nvs_get_i32 (nvs_handle_t c_handle, const char* key, int32_t* out_value)
|
||||
{
|
||||
return nvs_get(handle, key, out_value);
|
||||
return nvs_get(c_handle, key, out_value);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_get_u32 (nvs_handle_t handle, const char* key, uint32_t* out_value)
|
||||
extern "C" esp_err_t nvs_get_u32 (nvs_handle_t c_handle, const char* key, uint32_t* out_value)
|
||||
{
|
||||
return nvs_get(handle, key, out_value);
|
||||
return nvs_get(c_handle, key, out_value);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_get_i64 (nvs_handle_t handle, const char* key, int64_t* out_value)
|
||||
extern "C" esp_err_t nvs_get_i64 (nvs_handle_t c_handle, const char* key, int64_t* out_value)
|
||||
{
|
||||
return nvs_get(handle, key, out_value);
|
||||
return nvs_get(c_handle, key, out_value);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_get_u64 (nvs_handle_t handle, const char* key, uint64_t* out_value)
|
||||
extern "C" esp_err_t nvs_get_u64 (nvs_handle_t c_handle, const char* key, uint64_t* out_value)
|
||||
{
|
||||
return nvs_get(handle, key, out_value);
|
||||
return nvs_get(c_handle, key, out_value);
|
||||
}
|
||||
|
||||
static esp_err_t nvs_get_str_or_blob(nvs_handle_t handle, nvs::ItemType type, const char* key, void* out_value, size_t* length)
|
||||
static esp_err_t nvs_get_str_or_blob(nvs_handle_t c_handle, nvs::ItemType type, const char* key, void* out_value, size_t* length)
|
||||
{
|
||||
Lock lock;
|
||||
ESP_LOGD(TAG, "%s %s", __func__, key);
|
||||
HandleEntry entry;
|
||||
auto err = nvs_find_ns_handle(handle, entry);
|
||||
NVSHandleSimple *handle;
|
||||
auto err = nvs_find_ns_handle(c_handle, &handle);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
size_t dataSize;
|
||||
err = entry.mStoragePtr->getItemDataSize(entry.mNsIndex, type, key, dataSize);
|
||||
err = handle->get_item_size(type, key, dataSize);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
@ -520,17 +441,17 @@ static esp_err_t nvs_get_str_or_blob(nvs_handle_t handle, nvs::ItemType type, co
|
||||
}
|
||||
|
||||
*length = dataSize;
|
||||
return entry.mStoragePtr->readItem(entry.mNsIndex, type, key, out_value, dataSize);
|
||||
return handle->get_typed_item(type, key, out_value, dataSize);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_get_str(nvs_handle_t handle, const char* key, char* out_value, size_t* length)
|
||||
extern "C" esp_err_t nvs_get_str(nvs_handle_t c_handle, const char* key, char* out_value, size_t* length)
|
||||
{
|
||||
return nvs_get_str_or_blob(handle, nvs::ItemType::SZ, key, out_value, length);
|
||||
return nvs_get_str_or_blob(c_handle, nvs::ItemType::SZ, key, out_value, length);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_get_blob(nvs_handle_t handle, const char* key, void* out_value, size_t* length)
|
||||
extern "C" esp_err_t nvs_get_blob(nvs_handle_t c_handle, const char* key, void* out_value, size_t* length)
|
||||
{
|
||||
return nvs_get_str_or_blob(handle, nvs::ItemType::BLOB, key, out_value, length);
|
||||
return nvs_get_str_or_blob(c_handle, nvs::ItemType::BLOB, key, out_value, length);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_get_stats(const char* part_name, nvs_stats_t* nvs_stats)
|
||||
@ -558,7 +479,7 @@ extern "C" esp_err_t nvs_get_stats(const char* part_name, nvs_stats_t* nvs_stats
|
||||
return pStorage->fillStats(*nvs_stats);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_get_used_entry_count(nvs_handle_t handle, size_t* used_entries)
|
||||
extern "C" esp_err_t nvs_get_used_entry_count(nvs_handle_t c_handle, size_t* used_entries)
|
||||
{
|
||||
Lock lock;
|
||||
if(used_entries == NULL){
|
||||
@ -566,14 +487,14 @@ extern "C" esp_err_t nvs_get_used_entry_count(nvs_handle_t handle, size_t* used_
|
||||
}
|
||||
*used_entries = 0;
|
||||
|
||||
HandleEntry entry;
|
||||
auto err = nvs_find_ns_handle(handle, entry);
|
||||
NVSHandleSimple *handle;
|
||||
auto err = nvs_find_ns_handle(c_handle, &handle);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
size_t used_entry_count;
|
||||
err = entry.mStoragePtr->calcEntriesInNamespace(entry.mNsIndex, used_entry_count);
|
||||
err = handle->get_used_entry_count(used_entry_count);
|
||||
if(err == ESP_OK){
|
||||
*used_entries = used_entry_count;
|
||||
}
|
||||
|
68
components/nvs_flash/src/nvs_cxx_api.cpp
Normal file
68
components/nvs_flash/src/nvs_cxx_api.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
// 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.
|
||||
#include "nvs_partition_manager.hpp"
|
||||
#include "nvs_handle.hpp"
|
||||
#include "nvs_handle_simple.hpp"
|
||||
#include "nvs_handle_locked.hpp"
|
||||
#include "nvs_platform.hpp"
|
||||
|
||||
namespace nvs {
|
||||
|
||||
std::unique_ptr<NVSHandle> open_nvs_handle_from_partition(const char *partition_name,
|
||||
const char *ns_name,
|
||||
nvs_open_mode_t open_mode,
|
||||
esp_err_t *err)
|
||||
{
|
||||
if (partition_name == nullptr || ns_name == nullptr) {
|
||||
if (err) {
|
||||
*err = ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Lock lock;
|
||||
|
||||
NVSHandleSimple *handle_simple;
|
||||
esp_err_t result = nvs::NVSPartitionManager::get_instance()->
|
||||
open_handle(partition_name, ns_name, open_mode, &handle_simple);
|
||||
|
||||
if (err) {
|
||||
*err = result;
|
||||
}
|
||||
|
||||
if (result != ESP_OK) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NVSHandleLocked *locked_handle = new (nothrow) NVSHandleLocked(handle_simple);
|
||||
|
||||
if (!locked_handle) {
|
||||
if (err) {
|
||||
*err = ESP_ERR_NO_MEM;
|
||||
}
|
||||
delete handle_simple;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::unique_ptr<NVSHandleLocked>(locked_handle);
|
||||
}
|
||||
|
||||
std::unique_ptr<NVSHandle> open_nvs_handle(const char *ns_name,
|
||||
nvs_open_mode_t open_mode,
|
||||
esp_err_t *err)
|
||||
{
|
||||
return open_nvs_handle_from_partition(NVS_DEFAULT_PART_NAME, ns_name, open_mode, err);
|
||||
}
|
||||
|
||||
} // namespace nvs
|
83
components/nvs_flash/src/nvs_handle_locked.cpp
Normal file
83
components/nvs_flash/src/nvs_handle_locked.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
// 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.
|
||||
#include "nvs_handle_locked.hpp"
|
||||
|
||||
namespace nvs {
|
||||
|
||||
NVSHandleLocked::NVSHandleLocked(NVSHandleSimple *handle) : handle(handle) {
|
||||
Lock::init();
|
||||
}
|
||||
|
||||
NVSHandleLocked::~NVSHandleLocked() {
|
||||
Lock lock;
|
||||
delete handle;
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleLocked::set_string(const char *key, const char* str) {
|
||||
Lock lock;
|
||||
return handle->set_string(key, str);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleLocked::set_blob(const char *key, const void* blob, size_t len) {
|
||||
Lock lock;
|
||||
return handle->set_blob(key, blob, len);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleLocked::get_string(const char *key, char* out_str, size_t len) {
|
||||
Lock lock;
|
||||
return handle->get_string(key, out_str, len);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleLocked::get_blob(const char *key, void* out_blob, size_t len) {
|
||||
Lock lock;
|
||||
return handle->get_blob(key, out_blob, len);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleLocked::get_item_size(ItemType datatype, const char *key, size_t &size) {
|
||||
Lock lock;
|
||||
return handle->get_item_size(datatype, key, size);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleLocked::erase_item(const char* key) {
|
||||
Lock lock;
|
||||
return handle->erase_item(key);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleLocked::erase_all() {
|
||||
Lock lock;
|
||||
return handle->erase_all();
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleLocked::commit() {
|
||||
Lock lock;
|
||||
return handle->commit();
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleLocked::get_used_entry_count(size_t& usedEntries) {
|
||||
Lock lock;
|
||||
return handle->get_used_entry_count(usedEntries);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleLocked::set_typed_item(ItemType datatype, const char *key, const void* data, size_t dataSize) {
|
||||
Lock lock;
|
||||
return handle->set_typed_item(datatype, key, data, dataSize);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleLocked::get_typed_item(ItemType datatype, const char *key, void* data, size_t dataSize) {
|
||||
Lock lock;
|
||||
return handle->get_typed_item(datatype, key, data, dataSize);
|
||||
}
|
||||
|
||||
} // namespace nvs
|
||||
|
67
components/nvs_flash/src/nvs_handle_locked.hpp
Normal file
67
components/nvs_flash/src/nvs_handle_locked.hpp
Normal file
@ -0,0 +1,67 @@
|
||||
// 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.
|
||||
#ifndef NVS_HANDLE_LOCKED_HPP_
|
||||
#define NVS_HANDLE_LOCKED_HPP_
|
||||
|
||||
#include "nvs_handle_simple.hpp"
|
||||
|
||||
namespace nvs {
|
||||
|
||||
/**
|
||||
* @brief A class which behaves the same as NVSHandleSimple, except that all public member functions are locked.
|
||||
*
|
||||
* This class follows the decorator design pattern. The reason why we don't want locks in NVSHandleSimple is that
|
||||
* NVSHandleSimple can also be used by the C-API which locks its public functions already.
|
||||
* Thus, we avoid double-locking.
|
||||
*
|
||||
* @note this class becomes responsible for its internal NVSHandleSimple object, i.e. it deletes the handle object on
|
||||
* destruction
|
||||
*/
|
||||
class NVSHandleLocked : public NVSHandle {
|
||||
public:
|
||||
NVSHandleLocked(NVSHandleSimple *handle);
|
||||
|
||||
virtual ~NVSHandleLocked();
|
||||
|
||||
esp_err_t set_string(const char *key, const char* str) override;
|
||||
|
||||
esp_err_t set_blob(const char *key, const void* blob, size_t len) override;
|
||||
|
||||
esp_err_t get_string(const char *key, char* out_str, size_t len) override;
|
||||
|
||||
esp_err_t get_blob(const char *key, void* out_blob, size_t len) override;
|
||||
|
||||
esp_err_t get_item_size(ItemType datatype, const char *key, size_t &size) override;
|
||||
|
||||
esp_err_t erase_item(const char* key) override;
|
||||
|
||||
esp_err_t erase_all() override;
|
||||
|
||||
esp_err_t commit() override;
|
||||
|
||||
esp_err_t get_used_entry_count(size_t& usedEntries) override;
|
||||
|
||||
protected:
|
||||
esp_err_t set_typed_item(ItemType datatype, const char *key, const void* data, size_t dataSize) override;
|
||||
|
||||
esp_err_t get_typed_item(ItemType datatype, const char *key, void* data, size_t dataSize) override;
|
||||
|
||||
private:
|
||||
NVSHandleSimple *handle;
|
||||
};
|
||||
|
||||
} // namespace nvs
|
||||
|
||||
#endif // NVS_HANDLE_LOCKED_HPP_
|
||||
|
133
components/nvs_flash/src/nvs_handle_simple.cpp
Normal file
133
components/nvs_flash/src/nvs_handle_simple.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
// 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.
|
||||
#include <cstdlib>
|
||||
#include "nvs_handle.hpp"
|
||||
#include "nvs_partition_manager.hpp"
|
||||
|
||||
namespace nvs {
|
||||
|
||||
NVSHandleSimple::~NVSHandleSimple() {
|
||||
NVSPartitionManager::get_instance()->close_handle(this);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleSimple::set_typed_item(ItemType datatype, const char *key, const void* data, size_t dataSize)
|
||||
{
|
||||
if (!valid) return ESP_ERR_NVS_INVALID_HANDLE;
|
||||
if (mReadOnly) return ESP_ERR_NVS_READ_ONLY;
|
||||
|
||||
return mStoragePtr->writeItem(mNsIndex, datatype, key, data, dataSize);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleSimple::get_typed_item(ItemType datatype, const char *key, void* data, size_t dataSize)
|
||||
{
|
||||
if (!valid) return ESP_ERR_NVS_INVALID_HANDLE;
|
||||
|
||||
return mStoragePtr->readItem(mNsIndex, datatype, key, data, dataSize);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleSimple::set_string(const char *key, const char* str)
|
||||
{
|
||||
if (!valid) return ESP_ERR_NVS_INVALID_HANDLE;
|
||||
if (mReadOnly) return ESP_ERR_NVS_READ_ONLY;
|
||||
|
||||
return mStoragePtr->writeItem(mNsIndex, nvs::ItemType::SZ, key, str, strlen(str) + 1);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleSimple::set_blob(const char *key, const void* blob, size_t len)
|
||||
{
|
||||
if (!valid) return ESP_ERR_NVS_INVALID_HANDLE;
|
||||
if (mReadOnly) return ESP_ERR_NVS_READ_ONLY;
|
||||
|
||||
return mStoragePtr->writeItem(mNsIndex, nvs::ItemType::BLOB, key, blob, len);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleSimple::get_string(const char *key, char* out_str, size_t len)
|
||||
{
|
||||
if (!valid) return ESP_ERR_NVS_INVALID_HANDLE;
|
||||
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleSimple::get_blob(const char *key, void* out_blob, size_t len)
|
||||
{
|
||||
if (!valid) return ESP_ERR_NVS_INVALID_HANDLE;
|
||||
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleSimple::get_item_size(ItemType datatype, const char *key, size_t &size)
|
||||
{
|
||||
if (!valid) return ESP_ERR_NVS_INVALID_HANDLE;
|
||||
|
||||
return mStoragePtr->getItemDataSize(mNsIndex, datatype, key, size);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleSimple::erase_item(const char* key)
|
||||
{
|
||||
if (!valid) return ESP_ERR_NVS_INVALID_HANDLE;
|
||||
if (mReadOnly) return ESP_ERR_NVS_READ_ONLY;
|
||||
|
||||
return mStoragePtr->eraseItem(mNsIndex, key);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleSimple::erase_all()
|
||||
{
|
||||
if (!valid) return ESP_ERR_NVS_INVALID_HANDLE;
|
||||
if (mReadOnly) return ESP_ERR_NVS_READ_ONLY;
|
||||
|
||||
return mStoragePtr->eraseNamespace(mNsIndex);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleSimple::commit()
|
||||
{
|
||||
if (!valid) return ESP_ERR_NVS_INVALID_HANDLE;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleSimple::get_used_entry_count(size_t& used_entries)
|
||||
{
|
||||
used_entries = 0;
|
||||
|
||||
if (!valid) return ESP_ERR_NVS_INVALID_HANDLE;
|
||||
|
||||
size_t used_entry_count;
|
||||
esp_err_t err = mStoragePtr->calcEntriesInNamespace(mNsIndex, used_entry_count);
|
||||
if(err == ESP_OK){
|
||||
used_entries = used_entry_count;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void NVSHandleSimple::debugDump() {
|
||||
return mStoragePtr->debugDump();
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleSimple::fillStats(nvs_stats_t& nvsStats) {
|
||||
return mStoragePtr->fillStats(nvsStats);
|
||||
}
|
||||
|
||||
esp_err_t NVSHandleSimple::calcEntriesInNamespace(size_t& usedEntries) {
|
||||
return mStoragePtr->calcEntriesInNamespace(mNsIndex, usedEntries);
|
||||
}
|
||||
|
||||
bool NVSHandleSimple::findEntry(nvs_opaque_iterator_t* it, const char* name) {
|
||||
return mStoragePtr->findEntry(it, name);
|
||||
}
|
||||
|
||||
bool NVSHandleSimple::nextEntry(nvs_opaque_iterator_t* it) {
|
||||
return mStoragePtr->nextEntry(it);
|
||||
}
|
||||
|
||||
}
|
106
components/nvs_flash/src/nvs_handle_simple.hpp
Normal file
106
components/nvs_flash/src/nvs_handle_simple.hpp
Normal file
@ -0,0 +1,106 @@
|
||||
// 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.
|
||||
#ifndef NVS_HANDLE_SIMPLE_HPP_
|
||||
#define NVS_HANDLE_SIMPLE_HPP_
|
||||
|
||||
#include "intrusive_list.h"
|
||||
#include "nvs_storage.hpp"
|
||||
#include "nvs_platform.hpp"
|
||||
|
||||
#include "nvs_handle.hpp"
|
||||
|
||||
namespace nvs {
|
||||
|
||||
/**
|
||||
* @brief This class implements NVSHandle according to the ESP32's flash and partitioning scheme.
|
||||
*
|
||||
* It is used by both the C API and the C++ API. The main responsibility is to check whether the handle is valid
|
||||
* and in the right read/write mode and then forward the calls to the storage object.
|
||||
*
|
||||
* For more details about the general member functions, see nvs_handle.hpp.
|
||||
*/
|
||||
class NVSHandleSimple : public intrusive_list_node<NVSHandleSimple>, public NVSHandle {
|
||||
friend class NVSPartitionManager;
|
||||
public:
|
||||
NVSHandleSimple(bool readOnly, uint8_t nsIndex, Storage *StoragePtr) :
|
||||
mStoragePtr(StoragePtr),
|
||||
mNsIndex(nsIndex),
|
||||
mReadOnly(readOnly),
|
||||
valid(1)
|
||||
{ }
|
||||
|
||||
~NVSHandleSimple();
|
||||
|
||||
esp_err_t set_typed_item(ItemType datatype, const char *key, const void *data, size_t dataSize) override;
|
||||
|
||||
esp_err_t get_typed_item(ItemType datatype, const char *key, void *data, size_t dataSize) override;
|
||||
|
||||
esp_err_t set_string(const char *key, const char *str) override;
|
||||
|
||||
esp_err_t set_blob(const char *key, const void *blob, size_t len) override;
|
||||
|
||||
esp_err_t get_string(const char *key, char *out_str, size_t len) override;
|
||||
|
||||
esp_err_t get_blob(const char *key, void *out_blob, size_t len) override;
|
||||
|
||||
esp_err_t get_item_size(ItemType datatype, const char *key, size_t &size) override;
|
||||
|
||||
esp_err_t erase_item(const char *key) override;
|
||||
|
||||
esp_err_t erase_all() override;
|
||||
|
||||
esp_err_t commit() override;
|
||||
|
||||
esp_err_t get_used_entry_count(size_t &usedEntries) override;
|
||||
|
||||
esp_err_t getItemDataSize(ItemType datatype, const char *key, size_t &dataSize);
|
||||
|
||||
void debugDump();
|
||||
|
||||
esp_err_t fillStats(nvs_stats_t &nvsStats);
|
||||
|
||||
esp_err_t calcEntriesInNamespace(size_t &usedEntries);
|
||||
|
||||
bool findEntry(nvs_opaque_iterator_t *it, const char *name);
|
||||
|
||||
bool nextEntry(nvs_opaque_iterator_t *it);
|
||||
|
||||
private:
|
||||
/**
|
||||
* The underlying storage's object.
|
||||
*/
|
||||
Storage *mStoragePtr;
|
||||
|
||||
/**
|
||||
* Numeric representation of the namespace as it is saved in flash (see README.rst for further details).
|
||||
*/
|
||||
uint8_t mNsIndex;
|
||||
|
||||
/**
|
||||
* Whether this handle is marked as read-only or read-write.
|
||||
* 0 indicates read-only, any other value read-write.
|
||||
*/
|
||||
uint8_t mReadOnly;
|
||||
|
||||
/**
|
||||
* Indicates the validity of this handle.
|
||||
* Upon opening, a handle is valid. It becomes invalid if the underlying storage is de-initialized.
|
||||
*/
|
||||
uint8_t valid;
|
||||
};
|
||||
|
||||
} // nvs
|
||||
|
||||
#endif // NVS_HANDLE_SIMPLE_HPP_
|
||||
|
197
components/nvs_flash/src/nvs_partition_manager.cpp
Normal file
197
components/nvs_flash/src/nvs_partition_manager.cpp
Normal file
@ -0,0 +1,197 @@
|
||||
// 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.
|
||||
#include "esp_partition.h"
|
||||
#include "nvs_partition_manager.hpp"
|
||||
|
||||
namespace nvs {
|
||||
|
||||
NVSPartitionManager* NVSPartitionManager::instance = nullptr;
|
||||
|
||||
NVSPartitionManager* NVSPartitionManager::get_instance()
|
||||
{
|
||||
if (!instance) {
|
||||
instance = new NVSPartitionManager();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
esp_err_t NVSPartitionManager::init_partition(const char *partition_label)
|
||||
{
|
||||
Storage* mStorage;
|
||||
|
||||
mStorage = lookup_storage_from_name(partition_label);
|
||||
if (mStorage) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
assert(SPI_FLASH_SEC_SIZE != 0);
|
||||
|
||||
const esp_partition_t* partition = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, partition_label);
|
||||
if (partition == nullptr) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return init_custom(partition_label, partition->address / SPI_FLASH_SEC_SIZE,
|
||||
partition->size / SPI_FLASH_SEC_SIZE);
|
||||
}
|
||||
#endif // ESP_PLATFORM
|
||||
|
||||
esp_err_t NVSPartitionManager::init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount)
|
||||
{
|
||||
if (strlen(partName) > NVS_PART_NAME_MAX_SIZE) return ESP_ERR_INVALID_ARG;
|
||||
|
||||
Storage* new_storage = NULL;
|
||||
Storage* storage = lookup_storage_from_name(partName);
|
||||
if (storage == NULL) {
|
||||
new_storage = new Storage((const char *)partName);
|
||||
storage = new_storage;
|
||||
}
|
||||
|
||||
esp_err_t err = storage->init(baseSector, sectorCount);
|
||||
if (new_storage != NULL) {
|
||||
if (err == ESP_OK) {
|
||||
nvs_storage_list.push_back(new_storage);
|
||||
} else {
|
||||
delete new_storage;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
esp_err_t NVSPartitionManager::secure_init_partition(const char *part_name, nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
Storage* mStorage;
|
||||
|
||||
mStorage = lookup_storage_from_name(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, part_name);
|
||||
if (partition == NULL) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return secure_init_custom(part_name, partition->address / SPI_FLASH_SEC_SIZE,
|
||||
partition->size / SPI_FLASH_SEC_SIZE, cfg);
|
||||
}
|
||||
|
||||
esp_err_t NVSPartitionManager::secure_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount, nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
if(cfg) {
|
||||
auto encrMgr = EncrMgr::getInstance();
|
||||
auto err = encrMgr->setSecurityContext(baseSector, sectorCount, cfg);
|
||||
if(err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return init_custom(partName, baseSector, sectorCount);
|
||||
}
|
||||
#endif // CONFIG_NVS_ENCRYPTION
|
||||
#endif // ESP_PLATFORM
|
||||
|
||||
esp_err_t NVSPartitionManager::deinit_partition(const char *partition_label)
|
||||
{
|
||||
Storage* storage = lookup_storage_from_name(partition_label);
|
||||
if (!storage) {
|
||||
return ESP_ERR_NVS_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
if(EncrMgr::isEncrActive()) {
|
||||
auto encrMgr = EncrMgr::getInstance();
|
||||
encrMgr->removeSecurityContext(storage->getBaseSector());
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Clean up handles related to the storage being deinitialized */
|
||||
for (auto it = nvs_handles.begin(); it != nvs_handles.end(); ++it) {
|
||||
if (it->mStoragePtr == storage) {
|
||||
it->valid = false;
|
||||
nvs_handles.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally delete the storage itself */
|
||||
nvs_storage_list.erase(storage);
|
||||
delete storage;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t NVSPartitionManager::open_handle(const char *part_name,
|
||||
const char *ns_name,
|
||||
nvs_open_mode_t open_mode,
|
||||
NVSHandleSimple** handle)
|
||||
{
|
||||
uint8_t nsIndex;
|
||||
Storage* sHandle;
|
||||
|
||||
if (nvs_storage_list.size() == 0) {
|
||||
return ESP_ERR_NVS_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
sHandle = lookup_storage_from_name(part_name);
|
||||
if (sHandle == NULL) {
|
||||
return ESP_ERR_NVS_PART_NOT_FOUND;
|
||||
}
|
||||
|
||||
esp_err_t err = sHandle->createOrOpenNamespace(ns_name, open_mode == NVS_READWRITE, nsIndex);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
*handle = new NVSHandleSimple(open_mode==NVS_READONLY, nsIndex, sHandle);
|
||||
nvs_handles.push_back(*handle);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t NVSPartitionManager::close_handle(NVSHandleSimple* handle) {
|
||||
for (auto it = nvs_handles.begin(); it != nvs_handles.end(); ++it) {
|
||||
if (it == intrusive_list<NVSHandleSimple>::iterator(handle)) {
|
||||
nvs_handles.erase(it);
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_ERR_NVS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
size_t NVSPartitionManager::open_handles_size()
|
||||
{
|
||||
return nvs_handles.size();
|
||||
}
|
||||
|
||||
Storage* NVSPartitionManager::lookup_storage_from_name(const char* name)
|
||||
{
|
||||
auto it = find_if(begin(nvs_storage_list), end(nvs_storage_list), [=](Storage& e) -> bool {
|
||||
return (strcmp(e.getPartName(), name) == 0);
|
||||
});
|
||||
|
||||
if (it == end(nvs_storage_list)) {
|
||||
return NULL;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
} // nvs
|
||||
|
65
components/nvs_flash/src/nvs_partition_manager.hpp
Normal file
65
components/nvs_flash/src/nvs_partition_manager.hpp
Normal file
@ -0,0 +1,65 @@
|
||||
// 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.
|
||||
#ifndef NVS_PARTITION_MANAGER_HPP_
|
||||
#define NVS_PARTITION_MANAGER_HPP_
|
||||
|
||||
#include "nvs_handle_simple.hpp"
|
||||
#include "nvs_storage.hpp"
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
#include "nvs_encr.hpp"
|
||||
#endif
|
||||
|
||||
namespace nvs {
|
||||
|
||||
class NVSPartitionManager {
|
||||
public:
|
||||
virtual ~NVSPartitionManager() { }
|
||||
|
||||
static NVSPartitionManager* get_instance();
|
||||
|
||||
esp_err_t init_partition(const char *partition_label);
|
||||
|
||||
esp_err_t init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount);
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
esp_err_t secure_init_partition(const char *part_name, nvs_sec_cfg_t* cfg);
|
||||
|
||||
esp_err_t secure_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount, nvs_sec_cfg_t* cfg);
|
||||
#endif
|
||||
|
||||
esp_err_t deinit_partition(const char *partition_label);
|
||||
|
||||
Storage* lookup_storage_from_name(const char* name);
|
||||
|
||||
esp_err_t open_handle(const char *part_name, const char *ns_name, nvs_open_mode_t open_mode, NVSHandleSimple** handle);
|
||||
|
||||
esp_err_t close_handle(NVSHandleSimple* handle);
|
||||
|
||||
size_t open_handles_size();
|
||||
|
||||
protected:
|
||||
NVSPartitionManager() { }
|
||||
|
||||
static NVSPartitionManager* instance;
|
||||
|
||||
intrusive_list<NVSHandleSimple> nvs_handles;
|
||||
|
||||
intrusive_list<nvs::Storage> nvs_storage_list;
|
||||
};
|
||||
|
||||
} // nvs
|
||||
|
||||
#endif // NVS_PARTITION_MANAGER_HPP_
|
||||
|
@ -15,11 +15,11 @@
|
||||
#define nvs_types_h
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include "nvs.h"
|
||||
#include "nvs_handle.hpp"
|
||||
#include "compressed_enum_table.hpp"
|
||||
#include "string.h"
|
||||
|
||||
@ -28,40 +28,12 @@ using namespace std;
|
||||
namespace nvs
|
||||
{
|
||||
|
||||
enum class ItemType : uint8_t {
|
||||
U8 = NVS_TYPE_U8,
|
||||
I8 = NVS_TYPE_I8,
|
||||
U16 = NVS_TYPE_U16,
|
||||
I16 = NVS_TYPE_I16,
|
||||
U32 = NVS_TYPE_U32,
|
||||
I32 = NVS_TYPE_I32,
|
||||
U64 = NVS_TYPE_U64,
|
||||
I64 = NVS_TYPE_I64,
|
||||
SZ = NVS_TYPE_STR,
|
||||
BLOB = 0x41,
|
||||
BLOB_DATA = NVS_TYPE_BLOB,
|
||||
BLOB_IDX = 0x48,
|
||||
ANY = NVS_TYPE_ANY
|
||||
};
|
||||
|
||||
enum class VerOffset: uint8_t {
|
||||
VER_0_OFFSET = 0x0,
|
||||
VER_1_OFFSET = 0x80,
|
||||
VER_ANY = 0xff,
|
||||
};
|
||||
|
||||
template<typename T, typename std::enable_if<std::is_integral<T>::value, void*>::type = nullptr>
|
||||
constexpr ItemType itemTypeOf()
|
||||
{
|
||||
return static_cast<ItemType>(((std::is_signed<T>::value)?0x10:0x00) | sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr ItemType itemTypeOf(const T&)
|
||||
{
|
||||
return itemTypeOf<T>();
|
||||
}
|
||||
|
||||
inline bool isVariableLengthType(ItemType type)
|
||||
{
|
||||
return (type == ItemType::BLOB ||
|
||||
|
@ -18,6 +18,25 @@
|
||||
|
||||
static const char* TAG = "test_nvs";
|
||||
|
||||
// test could have different output on host tests
|
||||
TEST_CASE("nvs deinit with open handle", "[nvs]")
|
||||
{
|
||||
nvs_handle_t handle_1;
|
||||
esp_err_t err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_LOGW(TAG, "nvs_flash_init failed (0x%x), erasing partition and retrying", err);
|
||||
const esp_partition_t* nvs_partition = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
|
||||
assert(nvs_partition && "partition table must have an NVS partition");
|
||||
ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) );
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK( err );
|
||||
|
||||
TEST_ESP_OK(nvs_open("deinit_ns", NVS_READWRITE, &handle_1));
|
||||
nvs_flash_deinit();
|
||||
}
|
||||
|
||||
TEST_CASE("various nvs tests", "[nvs]")
|
||||
{
|
||||
nvs_handle_t handle_1;
|
||||
|
@ -12,12 +12,19 @@ SOURCE_FILES = \
|
||||
nvs_item_hash_list.cpp \
|
||||
nvs_encr.cpp \
|
||||
nvs_ops.cpp \
|
||||
nvs_handle_simple.cpp \
|
||||
nvs_handle_locked.cpp \
|
||||
nvs_partition_manager.cpp \
|
||||
nvs_cxx_api.cpp \
|
||||
) \
|
||||
spi_flash_emulation.cpp \
|
||||
test_compressed_enum_table.cpp \
|
||||
test_spi_flash_emulation.cpp \
|
||||
test_intrusive_list.cpp \
|
||||
test_nvs.cpp \
|
||||
test_partition_manager.cpp \
|
||||
test_nvs_handle.cpp \
|
||||
test_nvs_cxx_api.cpp \
|
||||
crc.cpp \
|
||||
main.cpp
|
||||
|
||||
@ -66,5 +73,11 @@ clean:
|
||||
rm -f ../nvs_partition_generator/partition_encrypted.bin
|
||||
rm -f ../nvs_partition_generator/partition_encrypted_using_keygen.bin
|
||||
rm -f ../nvs_partition_generator/partition_encrypted_using_keyfile.bin
|
||||
rm -f ../nvs_partition_generator/Test-1-partition-encrypted.bin
|
||||
rm -f ../nvs_partition_generator/Test-1-partition.bin
|
||||
rm -f ../../../tools/mass_mfg/samples/sample_values_multipage_blob_created.csv
|
||||
rm -f ../../../tools/mass_mfg/samples/sample_values_singlepage_blob_created.csv
|
||||
|
||||
|
||||
|
||||
.PHONY: clean all test long-test
|
||||
|
22
components/nvs_flash/test_nvs_host/README.md
Normal file
22
components/nvs_flash/test_nvs_host/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
# Build
|
||||
|
||||
```bash
|
||||
make -j 6
|
||||
```
|
||||
|
||||
# Run
|
||||
* Run particular test case:
|
||||
```bash
|
||||
./test_nvs "<particular test case>"
|
||||
|
||||
```
|
||||
* Run all quick tests:
|
||||
```bash
|
||||
./test_nvs -d yes exclude:[long]
|
||||
```
|
||||
|
||||
* Run all tests (takes several hours)
|
||||
```bash
|
||||
./test_nvs -d yes
|
||||
```
|
||||
|
132
components/nvs_flash/test_nvs_host/test_nvs_cxx_api.cpp
Normal file
132
components/nvs_flash/test_nvs_host/test_nvs_cxx_api.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
// 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.
|
||||
#include "catch.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "nvs_test_api.h"
|
||||
#include "nvs_handle_simple.hpp"
|
||||
#include "nvs_partition_manager.hpp"
|
||||
#include "spi_flash_emulation.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
TEST_CASE("NVSHandleSimple CXX api open invalid arguments", "[nvs cxx]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
esp_err_t result;
|
||||
shared_ptr<nvs::NVSHandle> handle;
|
||||
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->
|
||||
init_custom("test", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK);
|
||||
|
||||
handle = nvs::open_nvs_handle_from_partition(nullptr, "ns_1", NVS_READWRITE, &result);
|
||||
CHECK(result == ESP_ERR_INVALID_ARG);
|
||||
CHECK(!handle);
|
||||
|
||||
handle = nvs::open_nvs_handle_from_partition("test", nullptr, NVS_READWRITE, &result);
|
||||
CHECK(result == ESP_ERR_INVALID_ARG);
|
||||
CHECK(!handle);
|
||||
|
||||
nvs::NVSPartitionManager::get_instance()->deinit_partition("test");
|
||||
}
|
||||
|
||||
TEST_CASE("NVSHandleSimple CXX api open partition uninitialized", "[nvs cxx]")
|
||||
{
|
||||
SpiFlashEmulator emu(10);
|
||||
esp_err_t result;
|
||||
shared_ptr<nvs::NVSHandle> handle;
|
||||
|
||||
handle = nvs::open_nvs_handle_from_partition("test", "ns_1", NVS_READWRITE, &result);
|
||||
bool result_expected = result == ESP_ERR_NVS_NOT_INITIALIZED || result == ESP_ERR_NVS_PART_NOT_FOUND;
|
||||
CHECK(result_expected);
|
||||
CHECK(!handle);
|
||||
}
|
||||
|
||||
TEST_CASE("NVSHandleSimple CXX api open successful", "[nvs cxx]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
esp_err_t result;
|
||||
shared_ptr<nvs::NVSHandle> handle;
|
||||
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom("test", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
|
||||
handle = nvs::open_nvs_handle_from_partition("test", "ns_1", NVS_READWRITE, &result);
|
||||
CHECK(result == ESP_OK);
|
||||
CHECK(handle);
|
||||
|
||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 1);
|
||||
|
||||
handle.reset();
|
||||
|
||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
|
||||
nvs::NVSPartitionManager::get_instance()->deinit_partition("test");
|
||||
}
|
||||
|
||||
TEST_CASE("NVSHandleSimple CXX api open default part successful", "[nvs cxx]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
esp_err_t result;
|
||||
shared_ptr<nvs::NVSHandle> handle;
|
||||
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom("nvs", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
|
||||
handle = nvs::open_nvs_handle("ns_1", NVS_READWRITE, &result);
|
||||
CHECK(result == ESP_OK);
|
||||
CHECK(handle);
|
||||
|
||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 1);
|
||||
|
||||
handle.reset();
|
||||
|
||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
|
||||
nvs::NVSPartitionManager::get_instance()->deinit_partition("nvs");
|
||||
}
|
||||
|
||||
TEST_CASE("NVSHandleSimple CXX api open default part ns NULL", "[nvs cxx]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
esp_err_t result;
|
||||
shared_ptr<nvs::NVSHandle> handle;
|
||||
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom("nvs", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
|
||||
handle = nvs::open_nvs_handle(nullptr, NVS_READWRITE, &result);
|
||||
CHECK(result == ESP_ERR_INVALID_ARG);
|
||||
CHECK(!handle);
|
||||
|
||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
|
||||
nvs::NVSPartitionManager::get_instance()->deinit_partition("nvs");
|
||||
}
|
116
components/nvs_flash/test_nvs_host/test_nvs_handle.cpp
Normal file
116
components/nvs_flash/test_nvs_host/test_nvs_handle.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
// 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.
|
||||
#include "catch.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "nvs_test_api.h"
|
||||
#include "nvs_handle_simple.hpp"
|
||||
#include "nvs_partition_manager.hpp"
|
||||
#include "spi_flash_emulation.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace nvs;
|
||||
|
||||
TEST_CASE("NVSHandleSimple closes its reference in PartitionManager", "[partition_mgr]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom("test", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
|
||||
NVSHandleSimple *handle;
|
||||
REQUIRE(NVSPartitionManager::get_instance()->open_handle("test", "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
||||
|
||||
CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 1);
|
||||
|
||||
delete handle;
|
||||
|
||||
CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("NVSHandleSimple multiple open and closes with PartitionManager", "[partition_mgr]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom("test", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
|
||||
NVSHandleSimple *handle1;
|
||||
NVSHandleSimple *handle2;
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->open_handle("test", "ns_1", NVS_READWRITE, &handle1) == ESP_OK);
|
||||
|
||||
CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 1);
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->open_handle("test", "ns_1", NVS_READWRITE, &handle2) == ESP_OK);
|
||||
|
||||
CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 2);
|
||||
|
||||
delete handle1;
|
||||
|
||||
CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 1);
|
||||
|
||||
delete handle2;
|
||||
|
||||
CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("nvshandle readonly fails", "[partition_mgr]")
|
||||
{
|
||||
SpiFlashEmulator emu(10);
|
||||
|
||||
NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME);
|
||||
NVSHandleSimple *handle_1;
|
||||
NVSHandleSimple *handle_2;
|
||||
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);
|
||||
|
||||
CHECK(NVSPartitionManager::get_instance()->init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK);
|
||||
CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
|
||||
// first, creating namespace...
|
||||
REQUIRE(NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle_1) == ESP_OK);
|
||||
CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 1);
|
||||
|
||||
delete handle_1;
|
||||
|
||||
CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
REQUIRE(NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READONLY, &handle_2) == ESP_OK);
|
||||
CHECK(handle_2->set_item("key", 47) == ESP_ERR_NVS_READ_ONLY);
|
||||
CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 1);
|
||||
|
||||
delete handle_2;
|
||||
|
||||
CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
// without deinit it affects "nvs api tests"
|
||||
CHECK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK);
|
||||
}
|
||||
|
@ -0,0 +1,85 @@
|
||||
// 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.
|
||||
#include "catch.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "nvs_test_api.h"
|
||||
#include "nvs_handle_simple.hpp"
|
||||
#include "nvs_partition_manager.hpp"
|
||||
#include "spi_flash_emulation.h"
|
||||
#include "nvs_test_api.h"
|
||||
|
||||
using namespace nvs;
|
||||
|
||||
TEST_CASE("Partition manager initializes storage", "[partition_mgr]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom("test", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK);
|
||||
CHECK(NVSPartitionManager::get_instance()->lookup_storage_from_name("test") != nullptr);
|
||||
}
|
||||
|
||||
TEST_CASE("Partition manager de-initializes storage", "[partition_mgr]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom("test", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK);
|
||||
CHECK(NVSPartitionManager::get_instance()->lookup_storage_from_name("test") != nullptr);
|
||||
CHECK(NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK);
|
||||
CHECK(NVSPartitionManager::get_instance()->lookup_storage_from_name("test") == nullptr);
|
||||
}
|
||||
|
||||
TEST_CASE("Partition manager initializes multiple partitions", "[partition_mgr]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom("test1", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
// TODO: why does this work, actually? same sectors used as above
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom("test2", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
Storage *storage1 = NVSPartitionManager::get_instance()->lookup_storage_from_name("test1");
|
||||
REQUIRE(storage1 != nullptr);
|
||||
Storage *storage2 = NVSPartitionManager::get_instance()->lookup_storage_from_name("test2");
|
||||
REQUIRE(storage2 != nullptr);
|
||||
|
||||
CHECK(storage1 != storage2);
|
||||
}
|
||||
|
||||
TEST_CASE("Partition manager invalidates handle on partition de-init", "[partition_mgr]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom("test", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
NVSHandleSimple *handle;
|
||||
REQUIRE(NVSPartitionManager::get_instance()->open_handle("test", "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
||||
CHECK(handle->erase_all() == ESP_OK);
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK);
|
||||
|
||||
CHECK(handle->erase_all() == ESP_ERR_NVS_INVALID_HANDLE);
|
||||
|
||||
delete handle;
|
||||
}
|
||||
|
6
examples/storage/nvs_rw_value_cxx/CMakeLists.txt
Normal file
6
examples/storage/nvs_rw_value_cxx/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(nvs-rw-value-cxx)
|
9
examples/storage/nvs_rw_value_cxx/Makefile
Normal file
9
examples/storage/nvs_rw_value_cxx/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := nvs-rw-value-cxx
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
76
examples/storage/nvs_rw_value_cxx/README.md
Normal file
76
examples/storage/nvs_rw_value_cxx/README.md
Normal file
@ -0,0 +1,76 @@
|
||||
# Non-Volatile Storage (NVS) C++ Read and Write Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example demonstrates how to read and write a single integer value using NVS.
|
||||
It is essentially the same as the nvs_rw_value example. The only difference is that it uses the C++ NVS handle API.
|
||||
Please see [nvs_rw_value README](../nvs_rw_value/README.md) for more details about this example.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware required
|
||||
|
||||
This example does not require any special hardware, and can be run on any common development board.
|
||||
|
||||
### Build and flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
First run:
|
||||
```
|
||||
Opening Non-Volatile Storage (NVS) handle... Done
|
||||
Reading restart counter from NVS ... The value is not initialized yet!
|
||||
Updating restart counter in NVS ... Done
|
||||
Committing updates in NVS ... Done
|
||||
|
||||
Restarting in 10 seconds...
|
||||
Restarting in 9 seconds...
|
||||
Restarting in 8 seconds...
|
||||
Restarting in 7 seconds...
|
||||
Restarting in 6 seconds...
|
||||
Restarting in 5 seconds...
|
||||
Restarting in 4 seconds...
|
||||
Restarting in 3 seconds...
|
||||
Restarting in 2 seconds...
|
||||
Restarting in 1 seconds...
|
||||
Restarting in 0 seconds...
|
||||
Restarting now.
|
||||
```
|
||||
|
||||
Subsequent runs:
|
||||
|
||||
```
|
||||
Opening Non-Volatile Storage (NVS) handle... Done
|
||||
Reading restart counter from NVS ... Done
|
||||
Restart counter = 1
|
||||
Updating restart counter in NVS ... Done
|
||||
Committing updates in NVS ... Done
|
||||
|
||||
Restarting in 10 seconds...
|
||||
Restarting in 9 seconds...
|
||||
Restarting in 8 seconds...
|
||||
Restarting in 7 seconds...
|
||||
Restarting in 6 seconds...
|
||||
Restarting in 5 seconds...
|
||||
Restarting in 4 seconds...
|
||||
Restarting in 3 seconds...
|
||||
Restarting in 2 seconds...
|
||||
Restarting in 1 seconds...
|
||||
Restarting in 0 seconds...
|
||||
Restarting now.
|
||||
```
|
||||
|
||||
Restart counter will increment on each run.
|
||||
|
||||
To reset the counter, erase the contents of flash memory using `idf.py erase_flash`, then upload the program again as described above.
|
||||
|
2
examples/storage/nvs_rw_value_cxx/main/CMakeLists.txt
Normal file
2
examples/storage/nvs_rw_value_cxx/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "nvs_value_example_main.cpp"
|
||||
INCLUDE_DIRS ".")
|
5
examples/storage/nvs_rw_value_cxx/main/component.mk
Normal file
5
examples/storage/nvs_rw_value_cxx/main/component.mk
Normal file
@ -0,0 +1,5 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
|
@ -0,0 +1,84 @@
|
||||
/* Non-Volatile Storage (NVS) Read and Write a Value - Example
|
||||
|
||||
For other examples please check:
|
||||
https://github.com/espressif/esp-idf/tree/master/examples
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "nvs_flash.h"
|
||||
#include "nvs.h"
|
||||
#include "nvs_handle.hpp"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
// Initialize NVS
|
||||
esp_err_t err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
// NVS partition was truncated and needs to be erased
|
||||
// Retry nvs_flash_init
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK( err );
|
||||
|
||||
// Open
|
||||
printf("\n");
|
||||
printf("Opening Non-Volatile Storage (NVS) handle... ");
|
||||
esp_err_t result;
|
||||
// Handle will automatically close when going out of scope or when it's reset.
|
||||
std::shared_ptr<nvs::NVSHandle> handle = nvs::open_nvs_handle("storage", NVS_READWRITE, &result);
|
||||
if (err != ESP_OK) {
|
||||
printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
|
||||
} else {
|
||||
printf("Done\n");
|
||||
|
||||
// Read
|
||||
printf("Reading restart counter from NVS ... ");
|
||||
int32_t restart_counter = 0; // value will default to 0, if not set yet in NVS
|
||||
err = handle->get_item("restart_counter", restart_counter);
|
||||
switch (err) {
|
||||
case ESP_OK:
|
||||
printf("Done\n");
|
||||
printf("Restart counter = %d\n", restart_counter);
|
||||
break;
|
||||
case ESP_ERR_NVS_NOT_FOUND:
|
||||
printf("The value is not initialized yet!\n");
|
||||
break;
|
||||
default :
|
||||
printf("Error (%s) reading!\n", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
// Write
|
||||
printf("Updating restart counter in NVS ... ");
|
||||
restart_counter++;
|
||||
err = handle->set_item("restart_counter", restart_counter);
|
||||
printf((err != ESP_OK) ? "Failed!\n" : "Done\n");
|
||||
|
||||
// Commit written value.
|
||||
// After setting any values, nvs_commit() must be called to ensure changes are written
|
||||
// to flash storage. Implementations may write to storage at other times,
|
||||
// but this is not guaranteed.
|
||||
printf("Committing updates in NVS ... ");
|
||||
err = handle->commit();
|
||||
printf((err != ESP_OK) ? "Failed!\n" : "Done\n");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
// Restart module
|
||||
for (int i = 10; i >= 0; i--) {
|
||||
printf("Restarting in %d seconds...\n", i);
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
printf("Restarting now.\n");
|
||||
fflush(stdout);
|
||||
esp_restart();
|
||||
}
|
Loading…
Reference in New Issue
Block a user