nvs: Support for handling multiple NVS partitions

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

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

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

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

View File

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