mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
Merge branch 'feature/nvs_fd_support' into 'master'
feat(nvs_flash): Added support for storing flash and double types Closes IDFGH-9857 See merge request espressif/esp-idf!47045
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -18,6 +18,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstring>
|
||||||
#include "test_fixtures.hpp"
|
#include "test_fixtures.hpp"
|
||||||
#include "spi_flash_mmap.h"
|
#include "spi_flash_mmap.h"
|
||||||
|
|
||||||
@@ -5008,6 +5010,517 @@ TEST_CASE("nvs handle purge test", "[nvs]")
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// IEEE 754 float and double type tests
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
TEST_CASE("Page write and read float value", "[nvs]")
|
||||||
|
{
|
||||||
|
NVSPartitionTestHelper h(TEST_DEFAULT_PARTITION_NAME);
|
||||||
|
|
||||||
|
nvs::Page page;
|
||||||
|
TEST_ESP_OK(page.load(&h, 0));
|
||||||
|
float val = 3.14159265f;
|
||||||
|
TEST_ESP_OK(page.writeItem(1, nvs::ItemType::FLOAT, "floatval", &val, sizeof(val)));
|
||||||
|
|
||||||
|
float readVal = 0.0f;
|
||||||
|
TEST_ESP_OK(page.readItem(1, nvs::ItemType::FLOAT, "floatval", &readVal, sizeof(readVal)));
|
||||||
|
CHECK(readVal == val);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Page write and read double value", "[nvs]")
|
||||||
|
{
|
||||||
|
NVSPartitionTestHelper h(TEST_DEFAULT_PARTITION_NAME);
|
||||||
|
|
||||||
|
nvs::Page page;
|
||||||
|
TEST_ESP_OK(page.load(&h, 0));
|
||||||
|
double val = 2.718281828459045;
|
||||||
|
TEST_ESP_OK(page.writeItem(1, nvs::ItemType::DOUBLE, "dblval", &val, sizeof(val)));
|
||||||
|
|
||||||
|
double readVal = 0.0;
|
||||||
|
TEST_ESP_OK(page.readItem(1, nvs::ItemType::DOUBLE, "dblval", &readVal, sizeof(readVal)));
|
||||||
|
CHECK(readVal == val);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Page reading float with different type causes type mismatch error", "[nvs]")
|
||||||
|
{
|
||||||
|
NVSPartitionTestHelper h(TEST_DEFAULT_PARTITION_NAME);
|
||||||
|
|
||||||
|
nvs::Page page;
|
||||||
|
TEST_ESP_OK(page.load(&h, 0));
|
||||||
|
float val = 1.5f;
|
||||||
|
TEST_ESP_OK(page.writeItem(1, nvs::ItemType::FLOAT, "fval", &val, sizeof(val)));
|
||||||
|
|
||||||
|
double readDouble = 0.0;
|
||||||
|
CHECK(page.readItem(1, nvs::ItemType::DOUBLE, "fval", &readDouble, sizeof(readDouble)) == ESP_ERR_NVS_TYPE_MISMATCH);
|
||||||
|
|
||||||
|
int32_t readInt = 0;
|
||||||
|
CHECK(page.readItem(1, nvs::ItemType::I32, "fval", &readInt, sizeof(readInt)) == ESP_ERR_NVS_TYPE_MISMATCH);
|
||||||
|
|
||||||
|
uint32_t readUint = 0;
|
||||||
|
CHECK(page.readItem(1, nvs::ItemType::U32, "fval", &readUint, sizeof(readUint)) == ESP_ERR_NVS_TYPE_MISMATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Page reading i32 as float causes type mismatch error", "[nvs]")
|
||||||
|
{
|
||||||
|
NVSPartitionTestHelper h(TEST_DEFAULT_PARTITION_NAME);
|
||||||
|
|
||||||
|
nvs::Page page;
|
||||||
|
TEST_ESP_OK(page.load(&h, 0));
|
||||||
|
int32_t val = 42;
|
||||||
|
TEST_ESP_OK(page.writeItem(1, nvs::ItemType::I32, "intval", &val, sizeof(val)));
|
||||||
|
|
||||||
|
float readFloat = 0.0f;
|
||||||
|
CHECK(page.readItem(1, nvs::ItemType::FLOAT, "intval", &readFloat, sizeof(readFloat)) == ESP_ERR_NVS_TYPE_MISMATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Page reading double with different type causes type mismatch error", "[nvs]")
|
||||||
|
{
|
||||||
|
NVSPartitionTestHelper h(TEST_DEFAULT_PARTITION_NAME);
|
||||||
|
|
||||||
|
nvs::Page page;
|
||||||
|
TEST_ESP_OK(page.load(&h, 0));
|
||||||
|
double val = 9.99;
|
||||||
|
TEST_ESP_OK(page.writeItem(1, nvs::ItemType::DOUBLE, "dval", &val, sizeof(val)));
|
||||||
|
|
||||||
|
float readFloat = 0.0f;
|
||||||
|
CHECK(page.readItem(1, nvs::ItemType::FLOAT, "dval", &readFloat, sizeof(readFloat)) == ESP_ERR_NVS_TYPE_MISMATCH);
|
||||||
|
|
||||||
|
int64_t readInt64 = 0;
|
||||||
|
CHECK(page.readItem(1, nvs::ItemType::I64, "dval", &readInt64, sizeof(readInt64)) == ESP_ERR_NVS_TYPE_MISMATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("nvs api float and double positive tests", "[nvs]")
|
||||||
|
{
|
||||||
|
TEST_ESP_OK(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
TEST_ESP_OK(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
|
||||||
|
nvs_handle_t handle;
|
||||||
|
TEST_ESP_OK(nvs_open_from_partition(TEST_3SEC_PARTITION_NAME, "ns_fp", NVS_READWRITE, &handle));
|
||||||
|
|
||||||
|
SECTION("set and get float") {
|
||||||
|
float val = 3.14159265f;
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "pi", val));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
float read_val = 0.0f;
|
||||||
|
TEST_ESP_OK(nvs_get_float(handle, "pi", &read_val));
|
||||||
|
CHECK(read_val == val);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("set and get double") {
|
||||||
|
double val = 2.718281828459045;
|
||||||
|
TEST_ESP_OK(nvs_set_double(handle, "euler", val));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
double read_val = 0.0;
|
||||||
|
TEST_ESP_OK(nvs_get_double(handle, "euler", &read_val));
|
||||||
|
CHECK(read_val == val);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("overwrite float with new value") {
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "val", 1.0f));
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "val", 2.5f));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
float read_val = 0.0f;
|
||||||
|
TEST_ESP_OK(nvs_get_float(handle, "val", &read_val));
|
||||||
|
CHECK(read_val == 2.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("overwrite double with new value") {
|
||||||
|
TEST_ESP_OK(nvs_set_double(handle, "val", 1.0));
|
||||||
|
TEST_ESP_OK(nvs_set_double(handle, "val", 99.99));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
double read_val = 0.0;
|
||||||
|
TEST_ESP_OK(nvs_get_double(handle, "val", &read_val));
|
||||||
|
CHECK(read_val == 99.99);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("float special values: positive and negative infinity") {
|
||||||
|
float pos_inf = INFINITY;
|
||||||
|
float neg_inf = -INFINITY;
|
||||||
|
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "pinf", pos_inf));
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "ninf", neg_inf));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
float read_pinf = 0.0f, read_ninf = 0.0f;
|
||||||
|
TEST_ESP_OK(nvs_get_float(handle, "pinf", &read_pinf));
|
||||||
|
TEST_ESP_OK(nvs_get_float(handle, "ninf", &read_ninf));
|
||||||
|
CHECK(read_pinf == pos_inf);
|
||||||
|
CHECK(read_ninf == neg_inf);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("float special values: negative zero") {
|
||||||
|
float neg_zero = -0.0f;
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "nz", neg_zero));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
float read_val = 1.0f;
|
||||||
|
TEST_ESP_OK(nvs_get_float(handle, "nz", &read_val));
|
||||||
|
CHECK(read_val == neg_zero);
|
||||||
|
uint32_t bits;
|
||||||
|
memcpy(&bits, &read_val, sizeof(bits));
|
||||||
|
CHECK(bits == 0x80000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("float special values: smallest subnormal") {
|
||||||
|
uint32_t subnormal_bits = 0x00000001;
|
||||||
|
float subnormal;
|
||||||
|
memcpy(&subnormal, &subnormal_bits, sizeof(subnormal));
|
||||||
|
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "sub", subnormal));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
float read_val = 0.0f;
|
||||||
|
TEST_ESP_OK(nvs_get_float(handle, "sub", &read_val));
|
||||||
|
uint32_t read_bits;
|
||||||
|
memcpy(&read_bits, &read_val, sizeof(read_bits));
|
||||||
|
CHECK(read_bits == subnormal_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("double special values: positive and negative infinity") {
|
||||||
|
double pos_inf = (double)INFINITY;
|
||||||
|
double neg_inf = (double)(-INFINITY);
|
||||||
|
|
||||||
|
TEST_ESP_OK(nvs_set_double(handle, "pinf", pos_inf));
|
||||||
|
TEST_ESP_OK(nvs_set_double(handle, "ninf", neg_inf));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
double read_pinf = 0.0, read_ninf = 0.0;
|
||||||
|
TEST_ESP_OK(nvs_get_double(handle, "pinf", &read_pinf));
|
||||||
|
TEST_ESP_OK(nvs_get_double(handle, "ninf", &read_ninf));
|
||||||
|
CHECK(read_pinf == pos_inf);
|
||||||
|
CHECK(read_ninf == neg_inf);
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_close(handle);
|
||||||
|
TEST_ESP_OK(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("nvs api float and double negative tests", "[nvs]")
|
||||||
|
{
|
||||||
|
TEST_ESP_OK(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
TEST_ESP_OK(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
|
||||||
|
nvs_handle_t handle;
|
||||||
|
TEST_ESP_OK(nvs_open_from_partition(TEST_3SEC_PARTITION_NAME, "ns_fp_neg", NVS_READWRITE, &handle));
|
||||||
|
|
||||||
|
SECTION("set float NaN returns ESP_ERR_INVALID_ARG") {
|
||||||
|
float nan_val = NAN;
|
||||||
|
TEST_ESP_ERR(nvs_set_float(handle, "nan", nan_val), ESP_ERR_INVALID_ARG);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("set double NaN returns ESP_ERR_INVALID_ARG") {
|
||||||
|
double nan_val = NAN;
|
||||||
|
TEST_ESP_ERR(nvs_set_double(handle, "nan", nan_val), ESP_ERR_INVALID_ARG);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("set float quiet NaN returns ESP_ERR_INVALID_ARG") {
|
||||||
|
uint32_t qnan_bits = 0x7FC00001;
|
||||||
|
float qnan;
|
||||||
|
memcpy(&qnan, &qnan_bits, sizeof(qnan));
|
||||||
|
TEST_ESP_ERR(nvs_set_float(handle, "qnan", qnan), ESP_ERR_INVALID_ARG);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("set float signaling NaN returns ESP_ERR_INVALID_ARG") {
|
||||||
|
uint32_t snan_bits = 0x7F800001;
|
||||||
|
float snan;
|
||||||
|
memcpy(&snan, &snan_bits, sizeof(snan));
|
||||||
|
TEST_ESP_ERR(nvs_set_float(handle, "snan", snan), ESP_ERR_INVALID_ARG);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("get float for nonexistent key returns ESP_ERR_NVS_NOT_FOUND") {
|
||||||
|
float val;
|
||||||
|
TEST_ESP_ERR(nvs_get_float(handle, "nokey", &val), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("get double for nonexistent key returns ESP_ERR_NVS_NOT_FOUND") {
|
||||||
|
double val;
|
||||||
|
TEST_ESP_ERR(nvs_get_double(handle, "nokey", &val), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("type mismatch: set float, get double") {
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "fval", 1.5f));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
double read_val;
|
||||||
|
TEST_ESP_ERR(nvs_get_double(handle, "fval", &read_val), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("type mismatch: set double, get float") {
|
||||||
|
TEST_ESP_OK(nvs_set_double(handle, "dval", 1.5));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
float read_val;
|
||||||
|
TEST_ESP_ERR(nvs_get_float(handle, "dval", &read_val), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("type mismatch: set i32, get float") {
|
||||||
|
TEST_ESP_OK(nvs_set_i32(handle, "ival", 42));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
float read_val;
|
||||||
|
TEST_ESP_ERR(nvs_get_float(handle, "ival", &read_val), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("type mismatch: set float, get i32") {
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "fval2", 3.14f));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
int32_t read_val;
|
||||||
|
TEST_ESP_ERR(nvs_get_i32(handle, "fval2", &read_val), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("type mismatch: set u64, get double") {
|
||||||
|
TEST_ESP_OK(nvs_set_u64(handle, "u64v", 12345ULL));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
double read_val;
|
||||||
|
TEST_ESP_ERR(nvs_get_double(handle, "u64v", &read_val), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("type mismatch: set double, get i64") {
|
||||||
|
TEST_ESP_OK(nvs_set_double(handle, "dval2", 1.0));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
int64_t read_val;
|
||||||
|
TEST_ESP_ERR(nvs_get_i64(handle, "dval2", &read_val), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_close(handle);
|
||||||
|
TEST_ESP_OK(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("nvs api float and double read-only handle test", "[nvs]")
|
||||||
|
{
|
||||||
|
TEST_ESP_OK(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
TEST_ESP_OK(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
|
||||||
|
nvs_handle_t rw_handle;
|
||||||
|
TEST_ESP_OK(nvs_open_from_partition(TEST_3SEC_PARTITION_NAME, "ns_fp_ro", NVS_READWRITE, &rw_handle));
|
||||||
|
TEST_ESP_OK(nvs_set_float(rw_handle, "fval", 1.23f));
|
||||||
|
TEST_ESP_OK(nvs_set_double(rw_handle, "dval", 4.56));
|
||||||
|
TEST_ESP_OK(nvs_commit(rw_handle));
|
||||||
|
nvs_close(rw_handle);
|
||||||
|
|
||||||
|
nvs_handle_t ro_handle;
|
||||||
|
TEST_ESP_OK(nvs_open_from_partition(TEST_3SEC_PARTITION_NAME, "ns_fp_ro", NVS_READONLY, &ro_handle));
|
||||||
|
|
||||||
|
float fval = 0.0f;
|
||||||
|
TEST_ESP_OK(nvs_get_float(ro_handle, "fval", &fval));
|
||||||
|
CHECK(fval == 1.23f);
|
||||||
|
|
||||||
|
double dval = 0.0;
|
||||||
|
TEST_ESP_OK(nvs_get_double(ro_handle, "dval", &dval));
|
||||||
|
CHECK(dval == 4.56);
|
||||||
|
|
||||||
|
TEST_ESP_ERR(nvs_set_float(ro_handle, "fval", 9.0f), ESP_ERR_NVS_READ_ONLY);
|
||||||
|
TEST_ESP_ERR(nvs_set_double(ro_handle, "dval", 9.0), ESP_ERR_NVS_READ_ONLY);
|
||||||
|
|
||||||
|
nvs_close(ro_handle);
|
||||||
|
TEST_ESP_OK(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("nvs iterators find float and double entries", "[nvs]")
|
||||||
|
{
|
||||||
|
TEST_ESP_OK(nvs_flash_erase_partition(TEST_DEFAULT_PARTITION_NAME));
|
||||||
|
TEST_ESP_OK(nvs_flash_init_partition(TEST_DEFAULT_PARTITION_NAME));
|
||||||
|
|
||||||
|
nvs_handle_t handle;
|
||||||
|
TEST_ESP_OK(nvs_open_from_partition(TEST_DEFAULT_PARTITION_NAME, "ns_iter_fp", NVS_READWRITE, &handle));
|
||||||
|
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "fval1", 1.0f));
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "fval2", 2.0f));
|
||||||
|
TEST_ESP_OK(nvs_set_double(handle, "dval1", 3.0));
|
||||||
|
TEST_ESP_OK(nvs_set_i32(handle, "ival1", 42));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
auto entry_count = [](nvs_handle_t h, nvs_type_t type) -> int {
|
||||||
|
int count = 0;
|
||||||
|
nvs_iterator_t it = nullptr;
|
||||||
|
esp_err_t res = nvs_entry_find_in_handle(h, type, &it);
|
||||||
|
for (count = 0; res == ESP_OK; count++) {
|
||||||
|
res = nvs_entry_next(&it);
|
||||||
|
}
|
||||||
|
nvs_release_iterator(it);
|
||||||
|
return count;
|
||||||
|
};
|
||||||
|
|
||||||
|
CHECK(entry_count(handle, NVS_TYPE_FLOAT) == 2);
|
||||||
|
CHECK(entry_count(handle, NVS_TYPE_DOUBLE) == 1);
|
||||||
|
CHECK(entry_count(handle, NVS_TYPE_I32) == 1);
|
||||||
|
CHECK(entry_count(handle, NVS_TYPE_ANY) == 4);
|
||||||
|
|
||||||
|
nvs_iterator_t it = nullptr;
|
||||||
|
nvs_entry_info_t info;
|
||||||
|
TEST_ESP_OK(nvs_entry_find_in_handle(handle, NVS_TYPE_FLOAT, &it));
|
||||||
|
TEST_ESP_OK(nvs_entry_info(it, &info));
|
||||||
|
CHECK(info.type == NVS_TYPE_FLOAT);
|
||||||
|
nvs_release_iterator(it);
|
||||||
|
|
||||||
|
it = nullptr;
|
||||||
|
TEST_ESP_OK(nvs_entry_find_in_handle(handle, NVS_TYPE_DOUBLE, &it));
|
||||||
|
TEST_ESP_OK(nvs_entry_info(it, &info));
|
||||||
|
CHECK(info.type == NVS_TYPE_DOUBLE);
|
||||||
|
nvs_release_iterator(it);
|
||||||
|
|
||||||
|
nvs_close(handle);
|
||||||
|
TEST_ESP_OK(nvs_flash_deinit_partition(TEST_DEFAULT_PARTITION_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("nvs find_key reports correct type for float and double", "[nvs]")
|
||||||
|
{
|
||||||
|
TEST_ESP_OK(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
TEST_ESP_OK(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
|
||||||
|
nvs_handle_t handle;
|
||||||
|
TEST_ESP_OK(nvs_open_from_partition(TEST_3SEC_PARTITION_NAME, "ns_fk_fp", NVS_READWRITE, &handle));
|
||||||
|
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "fval", 1.0f));
|
||||||
|
TEST_ESP_OK(nvs_set_double(handle, "dval", 2.0));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
nvs_type_t out_type = NVS_TYPE_ANY;
|
||||||
|
TEST_ESP_OK(nvs_find_key(handle, "fval", &out_type));
|
||||||
|
CHECK(out_type == NVS_TYPE_FLOAT);
|
||||||
|
|
||||||
|
out_type = NVS_TYPE_ANY;
|
||||||
|
TEST_ESP_OK(nvs_find_key(handle, "dval", &out_type));
|
||||||
|
CHECK(out_type == NVS_TYPE_DOUBLE);
|
||||||
|
|
||||||
|
nvs_close(handle);
|
||||||
|
TEST_ESP_OK(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("nvs multiple write with same key but different types involving float", "[nvs]")
|
||||||
|
{
|
||||||
|
TEST_ESP_OK(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
TEST_ESP_OK(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
|
||||||
|
nvs_handle_t handle;
|
||||||
|
TEST_ESP_OK(nvs_open_from_partition(TEST_3SEC_PARTITION_NAME, "ns_fp_dup", NVS_READWRITE, &handle));
|
||||||
|
|
||||||
|
int32_t v32;
|
||||||
|
float vf;
|
||||||
|
|
||||||
|
TEST_ESP_OK(nvs_set_i32(handle, "foo", (int32_t)12345678));
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "foo", 3.14f));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
#ifdef CONFIG_NVS_LEGACY_DUP_KEYS_COMPATIBILITY
|
||||||
|
TEST_ESP_ERR(nvs_get_float(handle, "foo", &vf), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
TEST_ESP_OK(nvs_get_i32(handle, "foo", &v32));
|
||||||
|
CHECK(v32 == (int32_t)12345678);
|
||||||
|
TEST_ESP_OK(nvs_erase_key(handle, "foo"));
|
||||||
|
|
||||||
|
TEST_ESP_OK(nvs_get_float(handle, "foo", &vf));
|
||||||
|
CHECK(vf == 3.14f);
|
||||||
|
TEST_ESP_ERR(nvs_get_i32(handle, "foo", &v32), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
TEST_ESP_OK(nvs_erase_key(handle, "foo"));
|
||||||
|
|
||||||
|
TEST_ESP_ERR(nvs_erase_key(handle, "foo"), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
#else
|
||||||
|
TEST_ESP_OK(nvs_get_float(handle, "foo", &vf));
|
||||||
|
CHECK(vf == 3.14f);
|
||||||
|
TEST_ESP_ERR(nvs_get_i32(handle, "foo", &v32), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
TEST_ESP_OK(nvs_erase_key(handle, "foo"));
|
||||||
|
|
||||||
|
TEST_ESP_ERR(nvs_get_float(handle, "foo", &vf), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
TEST_ESP_ERR(nvs_get_i32(handle, "foo", &v32), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
TEST_ESP_ERR(nvs_erase_key(handle, "foo"), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
nvs_close(handle);
|
||||||
|
TEST_ESP_OK(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("nvs multiple write with same key but different types involving double", "[nvs]")
|
||||||
|
{
|
||||||
|
TEST_ESP_OK(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
TEST_ESP_OK(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
|
||||||
|
nvs_handle_t handle;
|
||||||
|
TEST_ESP_OK(nvs_open_from_partition(TEST_3SEC_PARTITION_NAME, "ns_dbl_dup", NVS_READWRITE, &handle));
|
||||||
|
|
||||||
|
int64_t v64;
|
||||||
|
double vd;
|
||||||
|
|
||||||
|
TEST_ESP_OK(nvs_set_i64(handle, "bar", (int64_t)123456789LL));
|
||||||
|
TEST_ESP_OK(nvs_set_double(handle, "bar", 2.71828));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
#ifdef CONFIG_NVS_LEGACY_DUP_KEYS_COMPATIBILITY
|
||||||
|
TEST_ESP_ERR(nvs_get_double(handle, "bar", &vd), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
TEST_ESP_OK(nvs_get_i64(handle, "bar", &v64));
|
||||||
|
CHECK(v64 == (int64_t)123456789LL);
|
||||||
|
TEST_ESP_OK(nvs_erase_key(handle, "bar"));
|
||||||
|
|
||||||
|
TEST_ESP_OK(nvs_get_double(handle, "bar", &vd));
|
||||||
|
CHECK(vd == 2.71828);
|
||||||
|
TEST_ESP_ERR(nvs_get_i64(handle, "bar", &v64), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
TEST_ESP_OK(nvs_erase_key(handle, "bar"));
|
||||||
|
|
||||||
|
TEST_ESP_ERR(nvs_erase_key(handle, "bar"), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
#else
|
||||||
|
TEST_ESP_OK(nvs_get_double(handle, "bar", &vd));
|
||||||
|
CHECK(vd == 2.71828);
|
||||||
|
TEST_ESP_ERR(nvs_get_i64(handle, "bar", &v64), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
TEST_ESP_OK(nvs_erase_key(handle, "bar"));
|
||||||
|
|
||||||
|
TEST_ESP_ERR(nvs_get_double(handle, "bar", &vd), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
TEST_ESP_ERR(nvs_get_i64(handle, "bar", &v64), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
TEST_ESP_ERR(nvs_erase_key(handle, "bar"), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
nvs_close(handle);
|
||||||
|
TEST_ESP_OK(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("nvs multiple write with same key float then double", "[nvs]")
|
||||||
|
{
|
||||||
|
TEST_ESP_OK(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
TEST_ESP_OK(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
|
||||||
|
nvs_handle_t handle;
|
||||||
|
TEST_ESP_OK(nvs_open_from_partition(TEST_3SEC_PARTITION_NAME, "ns_fd_dup", NVS_READWRITE, &handle));
|
||||||
|
|
||||||
|
float vf;
|
||||||
|
double vd;
|
||||||
|
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "baz", 1.5f));
|
||||||
|
TEST_ESP_OK(nvs_set_double(handle, "baz", 9.99));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
#ifdef CONFIG_NVS_LEGACY_DUP_KEYS_COMPATIBILITY
|
||||||
|
TEST_ESP_ERR(nvs_get_double(handle, "baz", &vd), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
TEST_ESP_OK(nvs_get_float(handle, "baz", &vf));
|
||||||
|
CHECK(vf == 1.5f);
|
||||||
|
TEST_ESP_OK(nvs_erase_key(handle, "baz"));
|
||||||
|
|
||||||
|
TEST_ESP_OK(nvs_get_double(handle, "baz", &vd));
|
||||||
|
CHECK(vd == 9.99);
|
||||||
|
TEST_ESP_ERR(nvs_get_float(handle, "baz", &vf), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
TEST_ESP_OK(nvs_erase_key(handle, "baz"));
|
||||||
|
|
||||||
|
TEST_ESP_ERR(nvs_erase_key(handle, "baz"), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
#else
|
||||||
|
TEST_ESP_OK(nvs_get_double(handle, "baz", &vd));
|
||||||
|
CHECK(vd == 9.99);
|
||||||
|
TEST_ESP_ERR(nvs_get_float(handle, "baz", &vf), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
TEST_ESP_OK(nvs_erase_key(handle, "baz"));
|
||||||
|
|
||||||
|
TEST_ESP_ERR(nvs_get_double(handle, "baz", &vd), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
TEST_ESP_ERR(nvs_get_float(handle, "baz", &vf), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
TEST_ESP_ERR(nvs_erase_key(handle, "baz"), ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
nvs_close(handle);
|
||||||
|
TEST_ESP_OK(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
// Add new tests above
|
// Add new tests above
|
||||||
// This test has to be the final one
|
// This test has to be the final one
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <cmath>
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "nvs_handle_simple.hpp"
|
#include "nvs_handle_simple.hpp"
|
||||||
#include "nvs_partition_manager.hpp"
|
#include "nvs_partition_manager.hpp"
|
||||||
@@ -259,3 +260,112 @@ TEST_CASE("NVSHandleSimple correctly sets/gets char enum", "[partition_mgr]")
|
|||||||
|
|
||||||
REQUIRE(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
REQUIRE(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("NVSHandleSimple correctly sets/gets float", "[partition_mgr]")
|
||||||
|
{
|
||||||
|
REQUIRE(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
REQUIRE(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
|
nvs::NVSHandleSimple *handle = nullptr;
|
||||||
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_3SEC_PARTITION_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
||||||
|
|
||||||
|
float test_val = 3.14159265f;
|
||||||
|
float test_val_read = 0.0f;
|
||||||
|
|
||||||
|
CHECK(handle->set_item("key", test_val) == ESP_OK);
|
||||||
|
CHECK(handle->get_item("key", test_val_read) == ESP_OK);
|
||||||
|
CHECK(test_val == test_val_read);
|
||||||
|
|
||||||
|
delete handle;
|
||||||
|
REQUIRE(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("NVSHandleSimple correctly sets/gets double", "[partition_mgr]")
|
||||||
|
{
|
||||||
|
REQUIRE(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
REQUIRE(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
|
nvs::NVSHandleSimple *handle = nullptr;
|
||||||
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_3SEC_PARTITION_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
||||||
|
|
||||||
|
double test_val = 2.718281828459045;
|
||||||
|
double test_val_read = 0.0;
|
||||||
|
|
||||||
|
CHECK(handle->set_item("key", test_val) == ESP_OK);
|
||||||
|
CHECK(handle->get_item("key", test_val_read) == ESP_OK);
|
||||||
|
CHECK(test_val == test_val_read);
|
||||||
|
|
||||||
|
delete handle;
|
||||||
|
REQUIRE(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("NVSHandleSimple float type mismatch with int", "[partition_mgr]")
|
||||||
|
{
|
||||||
|
REQUIRE(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
REQUIRE(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
|
nvs::NVSHandleSimple *handle = nullptr;
|
||||||
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_3SEC_PARTITION_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
||||||
|
|
||||||
|
float test_float = 1.5f;
|
||||||
|
CHECK(handle->set_item("key", test_float) == ESP_OK);
|
||||||
|
|
||||||
|
int32_t read_int = 0;
|
||||||
|
CHECK(handle->get_item("key", read_int) == ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
|
||||||
|
uint32_t read_uint = 0;
|
||||||
|
CHECK(handle->get_item("key", read_uint) == ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
|
||||||
|
delete handle;
|
||||||
|
REQUIRE(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("NVSHandleSimple double type mismatch with float", "[partition_mgr]")
|
||||||
|
{
|
||||||
|
REQUIRE(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
REQUIRE(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
|
nvs::NVSHandleSimple *handle = nullptr;
|
||||||
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_3SEC_PARTITION_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
||||||
|
|
||||||
|
double test_double = 1.5;
|
||||||
|
CHECK(handle->set_item("key", test_double) == ESP_OK);
|
||||||
|
|
||||||
|
float read_float = 0.0f;
|
||||||
|
CHECK(handle->get_item("key", read_float) == ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
|
||||||
|
int64_t read_int64 = 0;
|
||||||
|
CHECK(handle->get_item("key", read_int64) == ESP_ERR_NVS_NOT_FOUND);
|
||||||
|
|
||||||
|
delete handle;
|
||||||
|
REQUIRE(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("NVSHandleSimple readonly rejects float and double writes", "[partition_mgr]")
|
||||||
|
{
|
||||||
|
REQUIRE(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
REQUIRE(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
|
nvs::NVSHandleSimple *rw_handle = nullptr;
|
||||||
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_3SEC_PARTITION_NAME, "ns_1", NVS_READWRITE, &rw_handle) == ESP_OK);
|
||||||
|
CHECK(rw_handle->set_item("fkey", 1.0f) == ESP_OK);
|
||||||
|
CHECK(rw_handle->set_item("dkey", 2.0) == ESP_OK);
|
||||||
|
delete rw_handle;
|
||||||
|
|
||||||
|
nvs::NVSHandleSimple *ro_handle = nullptr;
|
||||||
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_3SEC_PARTITION_NAME, "ns_1", NVS_READONLY, &ro_handle) == ESP_OK);
|
||||||
|
|
||||||
|
CHECK(ro_handle->set_item("fkey", 9.0f) == ESP_ERR_NVS_READ_ONLY);
|
||||||
|
CHECK(ro_handle->set_item("dkey", 9.0) == ESP_ERR_NVS_READ_ONLY);
|
||||||
|
|
||||||
|
float fval = 0.0f;
|
||||||
|
CHECK(ro_handle->get_item("fkey", fval) == ESP_OK);
|
||||||
|
CHECK(fval == 1.0f);
|
||||||
|
|
||||||
|
double dval = 0.0;
|
||||||
|
CHECK(ro_handle->get_item("dkey", dval) == ESP_OK);
|
||||||
|
CHECK(dval == 2.0);
|
||||||
|
|
||||||
|
delete ro_handle;
|
||||||
|
REQUIRE(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -921,6 +921,237 @@ void test_Page_calcEntries__invalid()
|
|||||||
TEST_ASSERT_EQUAL(0, nvsStats.namespace_count);
|
TEST_ASSERT_EQUAL(0, nvsStats.namespace_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_Page_write_read_float()
|
||||||
|
{
|
||||||
|
NVSPageFixture fix;
|
||||||
|
|
||||||
|
float val = 3.14159265f;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.writeItem(1, ItemType::FLOAT, "fval", &val, sizeof(val)));
|
||||||
|
|
||||||
|
float read_val = 0.0f;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.readItem(1, ItemType::FLOAT, "fval", &read_val, sizeof(read_val)));
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(val, read_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_Page_write_read_double()
|
||||||
|
{
|
||||||
|
NVSPageFixture fix;
|
||||||
|
|
||||||
|
double val = 2.718281828459045;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.writeItem(1, ItemType::DOUBLE, "dval", &val, sizeof(val)));
|
||||||
|
|
||||||
|
double read_val = 0.0;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.readItem(1, ItemType::DOUBLE, "dval", &read_val, sizeof(read_val)));
|
||||||
|
TEST_ASSERT_EQUAL_DOUBLE(val, read_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_Page_cmp__float_type_mismatch()
|
||||||
|
{
|
||||||
|
NVSPageFixture fix;
|
||||||
|
|
||||||
|
float val = 1.5f;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.writeItem(1, ItemType::FLOAT, "fval", &val, sizeof(val)));
|
||||||
|
|
||||||
|
int32_t int_val = 42;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_TYPE_MISMATCH, fix.page.cmpItem(1, ItemType::I32, "fval", &int_val, sizeof(int_val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_Page_cmp__double_type_mismatch()
|
||||||
|
{
|
||||||
|
NVSPageFixture fix;
|
||||||
|
|
||||||
|
double val = 1.5;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.writeItem(1, ItemType::DOUBLE, "dval", &val, sizeof(val)));
|
||||||
|
|
||||||
|
int64_t int_val = 42;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_TYPE_MISMATCH, fix.page.cmpItem(1, ItemType::I64, "dval", &int_val, sizeof(int_val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_Page_cmp__float_content_match()
|
||||||
|
{
|
||||||
|
NVSPageFixture fix;
|
||||||
|
|
||||||
|
float val = 1.5f;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.writeItem(1, ItemType::FLOAT, "fval", &val, sizeof(val)));
|
||||||
|
|
||||||
|
float cmp_val = 1.5f;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.cmpItem(1, ItemType::FLOAT, "fval", &cmp_val, sizeof(cmp_val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_Page_cmp__float_content_mismatch()
|
||||||
|
{
|
||||||
|
NVSPageFixture fix;
|
||||||
|
|
||||||
|
float val = 1.5f;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.writeItem(1, ItemType::FLOAT, "fval", &val, sizeof(val)));
|
||||||
|
|
||||||
|
float cmp_val = 2.5f;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_CONTENT_DIFFERS, fix.page.cmpItem(1, ItemType::FLOAT, "fval", &cmp_val, sizeof(cmp_val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_Page_cmp__double_content_match()
|
||||||
|
{
|
||||||
|
NVSPageFixture fix;
|
||||||
|
|
||||||
|
double val = 9.99;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.writeItem(1, ItemType::DOUBLE, "dval", &val, sizeof(val)));
|
||||||
|
|
||||||
|
double cmp_val = 9.99;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.cmpItem(1, ItemType::DOUBLE, "dval", &cmp_val, sizeof(cmp_val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_Page_find__float_wrong_type()
|
||||||
|
{
|
||||||
|
NVSPageFixture fix;
|
||||||
|
|
||||||
|
float val = 1.0f;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.writeItem(1, ItemType::FLOAT, "fval", &val, sizeof(val)));
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_TYPE_MISMATCH, fix.page.findItem(1, ItemType::I32, "fval"));
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_TYPE_MISMATCH, fix.page.findItem(1, ItemType::U32, "fval"));
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_TYPE_MISMATCH, fix.page.findItem(1, ItemType::DOUBLE, "fval"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_Page_find__double_wrong_type()
|
||||||
|
{
|
||||||
|
NVSPageFixture fix;
|
||||||
|
|
||||||
|
double val = 1.0;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.writeItem(1, ItemType::DOUBLE, "dval", &val, sizeof(val)));
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_TYPE_MISMATCH, fix.page.findItem(1, ItemType::I64, "dval"));
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_TYPE_MISMATCH, fix.page.findItem(1, ItemType::U64, "dval"));
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_TYPE_MISMATCH, fix.page.findItem(1, ItemType::FLOAT, "dval"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_Page_readItem__float_as_double_type_mismatch()
|
||||||
|
{
|
||||||
|
NVSPageFixture fix;
|
||||||
|
|
||||||
|
float val = 1.5f;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.writeItem(1, ItemType::FLOAT, "fval", &val, sizeof(val)));
|
||||||
|
|
||||||
|
double read_val = 0.0;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_TYPE_MISMATCH, fix.page.readItem(1, ItemType::DOUBLE, "fval", &read_val, sizeof(read_val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_Page_readItem__double_as_float_type_mismatch()
|
||||||
|
{
|
||||||
|
NVSPageFixture fix;
|
||||||
|
|
||||||
|
double val = 1.5;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.writeItem(1, ItemType::DOUBLE, "dval", &val, sizeof(val)));
|
||||||
|
|
||||||
|
float read_val = 0.0f;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_TYPE_MISMATCH, fix.page.readItem(1, ItemType::FLOAT, "dval", &read_val, sizeof(read_val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_Page_eraseItem__float_success()
|
||||||
|
{
|
||||||
|
NVSPageFixture fix;
|
||||||
|
|
||||||
|
float val = 1.5f;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.writeItem(1, ItemType::FLOAT, "fval", &val, sizeof(val)));
|
||||||
|
TEST_ASSERT_EQUAL(1, fix.page.getUsedEntryCount());
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.page.eraseItem(1, ItemType::FLOAT, "fval", DEFAULT_PURGE_AFTER_ERASE));
|
||||||
|
TEST_ASSERT_EQUAL(0, fix.page.getUsedEntryCount());
|
||||||
|
|
||||||
|
float read_val = 0.0f;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, fix.page.readItem(1, ItemType::FLOAT, "fval", &read_val, sizeof(read_val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backward compatibility test: verifies that a page containing entries with unknown
|
||||||
|
// data types (simulating float/double as seen by old firmware) loads successfully.
|
||||||
|
// Known-type entries must survive, unknown-type entries must be erased, and the page
|
||||||
|
// must remain ACTIVE and writable.
|
||||||
|
void test_Page_load__unknown_type_entries_erased_known_survive()
|
||||||
|
{
|
||||||
|
PartitionEmulationFixture fix;
|
||||||
|
fix.erase_all();
|
||||||
|
|
||||||
|
// Phase 1: Write a page with known-type and float/double entries via the Page API
|
||||||
|
{
|
||||||
|
Page page;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, page.load(&fix.part, 0));
|
||||||
|
TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, page.state());
|
||||||
|
|
||||||
|
uint8_t u8_val = 42;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, page.writeItem(1, ItemType::U8, "u8_key", &u8_val, sizeof(u8_val)));
|
||||||
|
|
||||||
|
int32_t i32_val = 12345;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, page.writeItem(1, ItemType::I32, "i32_key", &i32_val, sizeof(i32_val)));
|
||||||
|
|
||||||
|
float f_val = 3.14f;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, page.writeItem(1, ItemType::FLOAT, "f_key", &f_val, sizeof(f_val)));
|
||||||
|
|
||||||
|
double d_val = 2.718;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, page.writeItem(1, ItemType::DOUBLE, "d_key", &d_val, sizeof(d_val)));
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, page.state());
|
||||||
|
TEST_ASSERT_EQUAL(4, page.getUsedEntryCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 2: Patch the float and double entries to use synthetic unknown type values.
|
||||||
|
// This simulates how pre-float firmware would see these entries: valid CRC but
|
||||||
|
// unrecognized datatype, causing checkHeaderConsistency() to return false.
|
||||||
|
//
|
||||||
|
// Entry layout: page_header(32B) + entry_table(32B) + entries at 64B stride
|
||||||
|
// Entry 0 at offset 64: U8 (known)
|
||||||
|
// Entry 1 at offset 96: I32 (known)
|
||||||
|
// Entry 2 at offset 128: FLOAT -> patch to 0x34 (unknown)
|
||||||
|
// Entry 3 at offset 160: DOUBLE -> patch to 0x38 (unknown)
|
||||||
|
|
||||||
|
Item item;
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.part.read_raw(128, &item, sizeof(item)));
|
||||||
|
TEST_ASSERT_EQUAL(ItemType::FLOAT, item.datatype);
|
||||||
|
item.datatype = static_cast<ItemType>(0x34);
|
||||||
|
item.crc32 = item.calculateCrc32();
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.write_raw(128, &item, sizeof(item)));
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.part.read_raw(160, &item, sizeof(item)));
|
||||||
|
TEST_ASSERT_EQUAL(ItemType::DOUBLE, item.datatype);
|
||||||
|
item.datatype = static_cast<ItemType>(0x38);
|
||||||
|
item.crc32 = item.calculateCrc32();
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, fix.write_raw(160, &item, sizeof(item)));
|
||||||
|
|
||||||
|
// Phase 3: Reload the page from the patched partition data.
|
||||||
|
// This simulates booting old firmware that does not know about float/double.
|
||||||
|
{
|
||||||
|
Page page;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, page.load(&fix.part, 0));
|
||||||
|
|
||||||
|
// The page must remain ACTIVE — unknown entries must not corrupt it
|
||||||
|
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, page.state());
|
||||||
|
|
||||||
|
// Known-type entries must be fully readable with correct values
|
||||||
|
uint8_t read_u8 = 0;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, page.readItem(1, ItemType::U8, "u8_key", &read_u8, sizeof(read_u8)));
|
||||||
|
TEST_ASSERT_EQUAL(42, read_u8);
|
||||||
|
|
||||||
|
int32_t read_i32 = 0;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, page.readItem(1, ItemType::I32, "i32_key", &read_i32, sizeof(read_i32)));
|
||||||
|
TEST_ASSERT_EQUAL(12345, read_i32);
|
||||||
|
|
||||||
|
// Unknown-type entries must have been erased during load
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, page.findItem(1, ItemType::ANY, "f_key"));
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, page.findItem(1, ItemType::ANY, "d_key"));
|
||||||
|
|
||||||
|
// Only the 2 known-type entries should remain
|
||||||
|
TEST_ASSERT_EQUAL(2, page.getUsedEntryCount());
|
||||||
|
|
||||||
|
// The page must still be writable — verify by adding a new entry
|
||||||
|
uint8_t new_val = 99;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, page.writeItem(1, ItemType::U8, "new_key", &new_val, sizeof(new_val)));
|
||||||
|
TEST_ASSERT_EQUAL(3, page.getUsedEntryCount());
|
||||||
|
|
||||||
|
uint8_t read_new = 0;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, page.readItem(1, ItemType::U8, "new_key", &read_new, sizeof(read_new)));
|
||||||
|
TEST_ASSERT_EQUAL(99, read_new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
#define TEMPORARILY_DISABLED(x)
|
#define TEMPORARILY_DISABLED(x)
|
||||||
@@ -980,6 +1211,19 @@ int main(int argc, char **argv)
|
|||||||
RUN_TEST(test_Page_calcEntries__active_wo_blob);
|
RUN_TEST(test_Page_calcEntries__active_wo_blob);
|
||||||
RUN_TEST(test_Page_calcEntries__active_with_blob);
|
RUN_TEST(test_Page_calcEntries__active_with_blob);
|
||||||
RUN_TEST(test_Page_calcEntries__invalid);
|
RUN_TEST(test_Page_calcEntries__invalid);
|
||||||
|
RUN_TEST(test_Page_write_read_float);
|
||||||
|
RUN_TEST(test_Page_write_read_double);
|
||||||
|
RUN_TEST(test_Page_cmp__float_type_mismatch);
|
||||||
|
RUN_TEST(test_Page_cmp__double_type_mismatch);
|
||||||
|
RUN_TEST(test_Page_cmp__float_content_match);
|
||||||
|
RUN_TEST(test_Page_cmp__float_content_mismatch);
|
||||||
|
RUN_TEST(test_Page_cmp__double_content_match);
|
||||||
|
RUN_TEST(test_Page_find__float_wrong_type);
|
||||||
|
RUN_TEST(test_Page_find__double_wrong_type);
|
||||||
|
RUN_TEST(test_Page_readItem__float_as_double_type_mismatch);
|
||||||
|
RUN_TEST(test_Page_readItem__double_as_float_type_mismatch);
|
||||||
|
RUN_TEST(test_Page_eraseItem__float_success);
|
||||||
|
RUN_TEST(test_Page_load__unknown_type_entries_erased_known_survive);
|
||||||
int failures = UNITY_END();
|
int failures = UNITY_END();
|
||||||
return failures;
|
return failures;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -108,6 +108,8 @@ typedef enum {
|
|||||||
NVS_TYPE_I32 = 0x14, /*!< Type int32_t */
|
NVS_TYPE_I32 = 0x14, /*!< Type int32_t */
|
||||||
NVS_TYPE_U64 = 0x08, /*!< Type uint64_t */
|
NVS_TYPE_U64 = 0x08, /*!< Type uint64_t */
|
||||||
NVS_TYPE_I64 = 0x18, /*!< Type int64_t */
|
NVS_TYPE_I64 = 0x18, /*!< Type int64_t */
|
||||||
|
NVS_TYPE_FLOAT = 0x24, /*!< Type float (IEEE 754 single precision) */
|
||||||
|
NVS_TYPE_DOUBLE = 0x28, /*!< Type double (IEEE 754 double precision) */
|
||||||
NVS_TYPE_STR = 0x21, /*!< Type string */
|
NVS_TYPE_STR = 0x21, /*!< Type string */
|
||||||
NVS_TYPE_BLOB = 0x42, /*!< Type blob */
|
NVS_TYPE_BLOB = 0x42, /*!< Type blob */
|
||||||
NVS_TYPE_ANY = 0xff /*!< Must be last */
|
NVS_TYPE_ANY = 0xff /*!< Must be last */
|
||||||
@@ -277,6 +279,30 @@ esp_err_t nvs_set_i64 (nvs_handle_t handle, const char* key, int64_t value);
|
|||||||
*/
|
*/
|
||||||
esp_err_t nvs_set_u64 (nvs_handle_t handle, const char* key, uint64_t value);
|
esp_err_t nvs_set_u64 (nvs_handle_t handle, const char* key, uint64_t value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set float value for given key
|
||||||
|
*
|
||||||
|
* This function is the same as \c nvs_set_i8 except for the data type.
|
||||||
|
* The value must be a valid IEEE 754 float (NaN is rejected).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_ERR_INVALID_ARG if value is NaN
|
||||||
|
* - For other return values, see \c nvs_set_i8
|
||||||
|
*/
|
||||||
|
esp_err_t nvs_set_float (nvs_handle_t handle, const char* key, float value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set double value for given key
|
||||||
|
*
|
||||||
|
* This function is the same as \c nvs_set_i8 except for the data type.
|
||||||
|
* The value must be a valid IEEE 754 double (NaN is rejected).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_ERR_INVALID_ARG if value is NaN
|
||||||
|
* - For other return values, see \c nvs_set_i8
|
||||||
|
*/
|
||||||
|
esp_err_t nvs_set_double (nvs_handle_t handle, const char* key, double value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief set string for given key
|
* @brief set string for given key
|
||||||
*
|
*
|
||||||
@@ -435,6 +461,20 @@ esp_err_t nvs_get_i64 (nvs_handle_t handle, const char* key, int64_t* out_value)
|
|||||||
* This function is the same as \c nvs_get_i8 except for the data type.
|
* This function is the same as \c nvs_get_i8 except for the data type.
|
||||||
*/
|
*/
|
||||||
esp_err_t nvs_get_u64 (nvs_handle_t handle, const char* key, uint64_t* out_value);
|
esp_err_t nvs_get_u64 (nvs_handle_t handle, const char* key, uint64_t* out_value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get float value for given key
|
||||||
|
*
|
||||||
|
* This function is the same as \c nvs_get_i8 except for the data type.
|
||||||
|
*/
|
||||||
|
esp_err_t nvs_get_float (nvs_handle_t handle, const char* key, float* out_value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get double value for given key
|
||||||
|
*
|
||||||
|
* This function is the same as \c nvs_get_i8 except for the data type.
|
||||||
|
*/
|
||||||
|
esp_err_t nvs_get_double (nvs_handle_t handle, const char* key, double* out_value);
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
/**@{*/
|
/**@{*/
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -39,6 +39,8 @@ typedef union {
|
|||||||
int32_t i32_val; /**< Placeholder for signed 32 bit integer variable */
|
int32_t i32_val; /**< Placeholder for signed 32 bit integer variable */
|
||||||
uint64_t u64_val; /**< Placeholder for unsigned 64 bit integer variable */
|
uint64_t u64_val; /**< Placeholder for unsigned 64 bit integer variable */
|
||||||
int64_t i64_val; /**< Placeholder for signed 64 bit integer variable */
|
int64_t i64_val; /**< Placeholder for signed 64 bit integer variable */
|
||||||
|
float float_val; /**< Placeholder for IEEE 754 single precision float variable */
|
||||||
|
double double_val; /**< Placeholder for IEEE 754 double precision float variable */
|
||||||
nvs_bootloader_str_value_placeholder_t str_val; /**< Placeholder for string buffer information */
|
nvs_bootloader_str_value_placeholder_t str_val; /**< Placeholder for string buffer information */
|
||||||
} nvs_bootloader_value_placeholder_t;
|
} nvs_bootloader_value_placeholder_t;
|
||||||
|
|
||||||
@@ -49,14 +51,16 @@ typedef union {
|
|||||||
* Before calling the `nvs_bootloader_read` function, populate the namespace_name, key_name and value_type members.
|
* Before calling the `nvs_bootloader_read` function, populate the namespace_name, key_name and value_type members.
|
||||||
* If string value has to be read, provide also buffer and its length in the `value.str_val` member.
|
* If string value has to be read, provide also buffer and its length in the `value.str_val` member.
|
||||||
*
|
*
|
||||||
* The result_code member will be populated by the function with the result of the read operation.
|
* The result_code member will be populated after calling the `nvs_bootloader_read` function.
|
||||||
* There are 2 possible situations and interpretations of the result_code:
|
* There are 2 possible situations and interpretations depending on he result_code returned by the `nvs_bootloader_read`:
|
||||||
|
*
|
||||||
* If the return value of the `nvs_bootloader_read` was ESP_OK, the result_code will be one of the following:
|
* If the return value of the `nvs_bootloader_read` was ESP_OK, the result_code will be one of the following:
|
||||||
* - `ESP_OK`: Entry found, value member contains the data. This is the only case when the value member is populated.
|
* - `ESP_OK`: Entry found, value member contains the data. This is the only case when the value member is populated.
|
||||||
* - `ESP_ERR_NVS_TYPE_MISMATCH`: Entry was found, but requested datatype doesn't match datatype found in NVS
|
* - `ESP_ERR_NVS_TYPE_MISMATCH`: Entry was found, but requested datatype doesn't match datatype found in NVS
|
||||||
* - `ESP_ERR_NVS_NOT_FOUND`: Data was not found.
|
* - `ESP_ERR_NVS_NOT_FOUND`: Data was not found.
|
||||||
* - `ESP_ERR_INVALID_SIZE`: the value found for string is longer than the space provided in placeholder (str_val.buff_len)
|
* - `ESP_ERR_INVALID_SIZE`: the value found for string is longer than the space provided in placeholder (str_val.buff_len)
|
||||||
* If the return value of the function was ESP_ERR_INVALID_ARG, the result_code will be one of the following:
|
*
|
||||||
|
* If the return value of the `nvs_bootloader_read` was ESP_ERR_INVALID_ARG, the result_code will be one of the following:
|
||||||
* - `ESP_ERR_NVS_NOT_FOUND`: Check of this parameters was successful.
|
* - `ESP_ERR_NVS_NOT_FOUND`: Check of this parameters was successful.
|
||||||
* - `ESP_ERR_NVS_INVALID_NAME`: namespace_name is NULL or too long
|
* - `ESP_ERR_NVS_INVALID_NAME`: namespace_name is NULL or too long
|
||||||
* - `ESP_ERR_NVS_KEY_TOO_LONG`: key_name NULL or too long
|
* - `ESP_ERR_NVS_KEY_TOO_LONG`: key_name NULL or too long
|
||||||
@@ -65,12 +69,12 @@ typedef union {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char* namespace_name; /**< Namespace of the entry */
|
const char* namespace_name; /**< Input. Namespace of the entry */
|
||||||
const char* key_name; /**< Key of the entry */
|
const char* key_name; /**< Input. Key of the entry */
|
||||||
nvs_type_t value_type; /**< Expected datatype to be read, can be any of NVS_TYPE_U*, NVS_TYPE_I* or NVS_TYPE_STR */
|
nvs_type_t value_type; /**< Input. Expected datatype to be read, can be any of NVS_TYPE_U*, NVS_TYPE_I*, NVS_TYPE_FLOAT, NVS_TYPE_DOUBLE or NVS_TYPE_STR */
|
||||||
esp_err_t result_code; /**< Result code of this entry. Explanation is in general description of the struct nvs_bootloader_read_list_t*/
|
esp_err_t result_code; /**< Output. Result code of this entry. Explanation is in general description of the struct nvs_bootloader_read_list_t*/
|
||||||
nvs_bootloader_value_placeholder_t value; /**< Placeholder for value read */
|
nvs_bootloader_value_placeholder_t value; /**< Input/Output. Placeholder for value read */
|
||||||
uint8_t namespace_index; /**< Index of the namespace (internal variable, do not use) */
|
uint8_t namespace_index; /**< Output. Index of the namespace (internal variable, do not use) */
|
||||||
} nvs_bootloader_read_list_t;
|
} nvs_bootloader_read_list_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -37,6 +37,8 @@ enum class ItemType : uint8_t {
|
|||||||
I32 = NVS_TYPE_I32,
|
I32 = NVS_TYPE_I32,
|
||||||
U64 = NVS_TYPE_U64,
|
U64 = NVS_TYPE_U64,
|
||||||
I64 = NVS_TYPE_I64,
|
I64 = NVS_TYPE_I64,
|
||||||
|
FLOAT = NVS_TYPE_FLOAT,
|
||||||
|
DOUBLE = NVS_TYPE_DOUBLE,
|
||||||
SZ = NVS_TYPE_STR,
|
SZ = NVS_TYPE_STR,
|
||||||
BLOB = 0x41,
|
BLOB = 0x41,
|
||||||
BLOB_DATA = NVS_TYPE_BLOB,
|
BLOB_DATA = NVS_TYPE_BLOB,
|
||||||
@@ -298,6 +300,15 @@ constexpr ItemType itemTypeOf()
|
|||||||
return static_cast<ItemType>(((std::is_signed<T>::value)?0x10:0x00) | sizeof(T));
|
return static_cast<ItemType>(((std::is_signed<T>::value)?0x10:0x00) | sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Help to translate IEEE 754 floating-point types into ItemType.
|
||||||
|
*/
|
||||||
|
template<typename T, typename std::enable_if<std::is_floating_point<T>::value, char>::type = 0>
|
||||||
|
constexpr ItemType itemTypeOf()
|
||||||
|
{
|
||||||
|
return static_cast<ItemType>(0x20 | sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr ItemType itemTypeOf(const T&)
|
constexpr ItemType itemTypeOf(const T&)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// evaluates to true for NVS types fitting single NVS entry. At the moment all NVS_TYPE_U* or NVS_TYPE_I* */
|
// evaluates to true for NVS types fitting single NVS entry. At the moment all NVS_TYPE_U*, NVS_TYPE_I*, NVS_TYPE_FLOAT and NVS_TYPE_DOUBLE */
|
||||||
#define NVS_BOOTLOADER_TYPE_FITS_SINGLE_ENTRY(data_type) \
|
#define NVS_BOOTLOADER_TYPE_FITS_SINGLE_ENTRY(data_type) \
|
||||||
( (data_type == NVS_TYPE_U8) \
|
( (data_type == NVS_TYPE_U8) \
|
||||||
||(data_type == NVS_TYPE_I8) \
|
||(data_type == NVS_TYPE_I8) \
|
||||||
@@ -26,6 +26,8 @@ extern "C" {
|
|||||||
||(data_type == NVS_TYPE_I32) \
|
||(data_type == NVS_TYPE_I32) \
|
||||||
||(data_type == NVS_TYPE_U64) \
|
||(data_type == NVS_TYPE_U64) \
|
||||||
||(data_type == NVS_TYPE_I64) \
|
||(data_type == NVS_TYPE_I64) \
|
||||||
|
||(data_type == NVS_TYPE_FLOAT) \
|
||||||
|
||(data_type == NVS_TYPE_DOUBLE) \
|
||||||
)
|
)
|
||||||
|
|
||||||
// evaluates to true for NVS types supported by the nvs bootloader code*/
|
// evaluates to true for NVS types supported by the nvs bootloader code*/
|
||||||
@@ -43,6 +45,8 @@ extern "C" {
|
|||||||
:(data_type == NVS_TYPE_I32) ? 4 \
|
:(data_type == NVS_TYPE_I32) ? 4 \
|
||||||
:(data_type == NVS_TYPE_U64) ? 8 \
|
:(data_type == NVS_TYPE_U64) ? 8 \
|
||||||
:(data_type == NVS_TYPE_I64) ? 8 \
|
:(data_type == NVS_TYPE_I64) ? 8 \
|
||||||
|
:(data_type == NVS_TYPE_FLOAT) ? 4 \
|
||||||
|
:(data_type == NVS_TYPE_DOUBLE) ? 8 \
|
||||||
:0 \
|
:0 \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -12,6 +12,8 @@
|
|||||||
#include "nvs_partition_manager.hpp"
|
#include "nvs_partition_manager.hpp"
|
||||||
#include "esp_partition.h"
|
#include "esp_partition.h"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <cmath>
|
||||||
|
#include <limits>
|
||||||
#include "nvs_handle_simple.hpp"
|
#include "nvs_handle_simple.hpp"
|
||||||
#include "nvs_memory_management.hpp"
|
#include "nvs_memory_management.hpp"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
@@ -449,6 +451,41 @@ extern "C" esp_err_t nvs_set_u64 (nvs_handle_t handle, const char* key, uint64_t
|
|||||||
return nvs_set(handle, key, value);
|
return nvs_set(handle, key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static_assert(std::numeric_limits<float>::is_iec559, "float must conform to IEEE 754");
|
||||||
|
static_assert(sizeof(float) == 4, "float must be 4 bytes");
|
||||||
|
static_assert(std::numeric_limits<double>::is_iec559, "double must conform to IEEE 754");
|
||||||
|
static_assert(sizeof(double) == 8, "double must be 8 bytes");
|
||||||
|
|
||||||
|
extern "C" esp_err_t nvs_set_float (nvs_handle_t c_handle, const char* key, float value)
|
||||||
|
{
|
||||||
|
if (std::isnan(value)) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
Lock lock;
|
||||||
|
ESP_LOGD(TAG, "%s %s %f", __func__, key, static_cast<double>(value));
|
||||||
|
NVSHandleSimple *handle;
|
||||||
|
auto err = nvs_find_ns_handle(c_handle, &handle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return handle->set_item(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" esp_err_t nvs_set_double (nvs_handle_t c_handle, const char* key, double value)
|
||||||
|
{
|
||||||
|
if (std::isnan(value)) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
Lock lock;
|
||||||
|
ESP_LOGD(TAG, "%s %s %f", __func__, key, value);
|
||||||
|
NVSHandleSimple *handle;
|
||||||
|
auto err = nvs_find_ns_handle(c_handle, &handle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return handle->set_item(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" esp_err_t nvs_commit(nvs_handle_t c_handle)
|
extern "C" esp_err_t nvs_commit(nvs_handle_t c_handle)
|
||||||
{
|
{
|
||||||
Lock lock;
|
Lock lock;
|
||||||
@@ -539,6 +576,16 @@ extern "C" esp_err_t nvs_get_u64 (nvs_handle_t c_handle, const char* key, uint64
|
|||||||
return nvs_get(c_handle, key, out_value);
|
return nvs_get(c_handle, key, out_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" esp_err_t nvs_get_float (nvs_handle_t c_handle, const char* key, float* out_value)
|
||||||
|
{
|
||||||
|
return nvs_get(c_handle, key, out_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" esp_err_t nvs_get_double (nvs_handle_t c_handle, const char* key, double* out_value)
|
||||||
|
{
|
||||||
|
return nvs_get(c_handle, key, out_value);
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
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;
|
Lock lock;
|
||||||
|
|||||||
@@ -61,7 +61,9 @@ bool Item::checkHeaderConsistency(const uint8_t entryIndex) const
|
|||||||
case ItemType::U32:
|
case ItemType::U32:
|
||||||
case ItemType::I32:
|
case ItemType::I32:
|
||||||
case ItemType::U64:
|
case ItemType::U64:
|
||||||
case ItemType::I64: {
|
case ItemType::I64:
|
||||||
|
case ItemType::FLOAT:
|
||||||
|
case ItemType::DOUBLE: {
|
||||||
if (span != 1) {
|
if (span != 1) {
|
||||||
ESP_LOGD(TAG, "Invalid span %u for datatype %#04x", (unsigned int)span, (unsigned int)datatype);
|
ESP_LOGD(TAG, "Invalid span %u for datatype %#04x", (unsigned int)span, (unsigned int)datatype);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -763,6 +764,149 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("nvs float set and get", "[nvs]")
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
|
err = nvs_flash_init();
|
||||||
|
}
|
||||||
|
ESP_ERROR_CHECK(err);
|
||||||
|
|
||||||
|
nvs_handle_t handle;
|
||||||
|
TEST_ESP_OK(nvs_open("test_fp", NVS_READWRITE, &handle));
|
||||||
|
|
||||||
|
float val = 3.14159265f;
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "pi", val));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
float read_val = 0.0f;
|
||||||
|
TEST_ESP_OK(nvs_get_float(handle, "pi", &read_val));
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(val, read_val);
|
||||||
|
|
||||||
|
nvs_close(handle);
|
||||||
|
TEST_ESP_OK(nvs_flash_deinit());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("nvs double set and get", "[nvs]")
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
|
err = nvs_flash_init();
|
||||||
|
}
|
||||||
|
ESP_ERROR_CHECK(err);
|
||||||
|
|
||||||
|
nvs_handle_t handle;
|
||||||
|
TEST_ESP_OK(nvs_open("test_fp", NVS_READWRITE, &handle));
|
||||||
|
|
||||||
|
double val = 2.718281828459045;
|
||||||
|
TEST_ESP_OK(nvs_set_double(handle, "euler", val));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
double read_val = 0.0;
|
||||||
|
TEST_ESP_OK(nvs_get_double(handle, "euler", &read_val));
|
||||||
|
TEST_ASSERT_EQUAL_DOUBLE(val, read_val);
|
||||||
|
|
||||||
|
nvs_close(handle);
|
||||||
|
TEST_ESP_OK(nvs_flash_deinit());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("nvs float NaN rejected", "[nvs]")
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
|
err = nvs_flash_init();
|
||||||
|
}
|
||||||
|
ESP_ERROR_CHECK(err);
|
||||||
|
|
||||||
|
nvs_handle_t handle;
|
||||||
|
TEST_ESP_OK(nvs_open("test_fp", NVS_READWRITE, &handle));
|
||||||
|
|
||||||
|
float nan_val = NAN;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, nvs_set_float(handle, "nan", nan_val));
|
||||||
|
|
||||||
|
double nan_dbl = NAN;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, nvs_set_double(handle, "nan", nan_dbl));
|
||||||
|
|
||||||
|
nvs_close(handle);
|
||||||
|
TEST_ESP_OK(nvs_flash_deinit());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("nvs float and double type mismatch", "[nvs]")
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
|
err = nvs_flash_init();
|
||||||
|
}
|
||||||
|
ESP_ERROR_CHECK(err);
|
||||||
|
|
||||||
|
nvs_handle_t handle;
|
||||||
|
TEST_ESP_OK(nvs_open("test_fp", NVS_READWRITE, &handle));
|
||||||
|
TEST_ESP_OK(nvs_erase_all(handle));
|
||||||
|
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "fval", 1.5f));
|
||||||
|
TEST_ESP_OK(nvs_set_double(handle, "dval", 2.5));
|
||||||
|
TEST_ESP_OK(nvs_set_i32(handle, "ival", 42));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
double read_dbl;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, nvs_get_double(handle, "fval", &read_dbl));
|
||||||
|
|
||||||
|
float read_flt;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, nvs_get_float(handle, "dval", &read_flt));
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, nvs_get_float(handle, "ival", &read_flt));
|
||||||
|
|
||||||
|
int32_t read_int;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, nvs_get_i32(handle, "fval", &read_int));
|
||||||
|
|
||||||
|
nvs_close(handle);
|
||||||
|
TEST_ESP_OK(nvs_flash_deinit());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("nvs float and double special values", "[nvs]")
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
|
err = nvs_flash_init();
|
||||||
|
}
|
||||||
|
ESP_ERROR_CHECK(err);
|
||||||
|
|
||||||
|
nvs_handle_t handle;
|
||||||
|
TEST_ESP_OK(nvs_open("test_fp", NVS_READWRITE, &handle));
|
||||||
|
TEST_ESP_OK(nvs_erase_all(handle));
|
||||||
|
|
||||||
|
float pos_inf = INFINITY;
|
||||||
|
float neg_inf = -INFINITY;
|
||||||
|
float neg_zero = -0.0f;
|
||||||
|
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "pinf", pos_inf));
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "ninf", neg_inf));
|
||||||
|
TEST_ESP_OK(nvs_set_float(handle, "nz", neg_zero));
|
||||||
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
|
|
||||||
|
float read_pinf = 0.0f, read_ninf = 0.0f, read_nz = 1.0f;
|
||||||
|
TEST_ESP_OK(nvs_get_float(handle, "pinf", &read_pinf));
|
||||||
|
TEST_ESP_OK(nvs_get_float(handle, "ninf", &read_ninf));
|
||||||
|
TEST_ESP_OK(nvs_get_float(handle, "nz", &read_nz));
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(pos_inf, read_pinf);
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(neg_inf, read_ninf);
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(neg_zero, read_nz);
|
||||||
|
|
||||||
|
nvs_close(handle);
|
||||||
|
TEST_ESP_OK(nvs_flash_deinit());
|
||||||
|
}
|
||||||
|
|
||||||
#if CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
#if CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||||
TEST_CASE("test nvs encryption with Flash Encryption-based scheme with v2 apis", "[nvs]")
|
TEST_CASE("test nvs encryption with Flash Encryption-based scheme with v2 apis", "[nvs]")
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ NVS operates on key-value pairs. Keys are ASCII strings; the maximum key length
|
|||||||
- integer types: ``uint8_t``, ``int8_t``, ``uint16_t``, ``int16_t``, ``uint32_t``, ``int32_t``, ``uint64_t``, ``int64_t``
|
- integer types: ``uint8_t``, ``int8_t``, ``uint16_t``, ``int16_t``, ``uint32_t``, ``int32_t``, ``uint64_t``, ``int64_t``
|
||||||
- zero-terminated string
|
- zero-terminated string
|
||||||
- variable length binary data (blob)
|
- variable length binary data (blob)
|
||||||
|
- floating point types: ``float`` and ``double``
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
@@ -48,7 +49,9 @@ NVS operates on key-value pairs. Keys are ASCII strings; the maximum key length
|
|||||||
|
|
||||||
Before setting new or updating existing key-value pair, free entries in nvs pages have to be available. For integer types, at least one free entry has to be available. For the string value, at least one page capable of keeping the whole string in a contiguous row of free entries has to be available. For the blob value, the size of new data has to be available in free entries.
|
Before setting new or updating existing key-value pair, free entries in nvs pages have to be available. For integer types, at least one free entry has to be available. For the string value, at least one page capable of keeping the whole string in a contiguous row of free entries has to be available. For the blob value, the size of new data has to be available in free entries.
|
||||||
|
|
||||||
Additional data types, such as ``float`` and ``double`` might be added later.
|
.. note::
|
||||||
|
|
||||||
|
The floating point types ``float`` and ``double`` are supported regardless of the FPU presence on a particular SoC.
|
||||||
|
|
||||||
Keys are required to be unique. Assigning a new value to an existing key replaces the old value and data type with the value and data type specified by a write operation.
|
Keys are required to be unique. Assigning a new value to an existing key replaces the old value and data type with the value and data type specified by a write operation.
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ NVS 的操作对象为键值对,其中键是 ASCII 字符串,当前支持的
|
|||||||
- 整数型:``uint8_t``、``int8_t``、``uint16_t``、``int16_t``、``uint32_t``、``int32_t``、``uint64_t`` 和 ``int64_t``;
|
- 整数型:``uint8_t``、``int8_t``、``uint16_t``、``int16_t``、``uint32_t``、``int32_t``、``uint64_t`` 和 ``int64_t``;
|
||||||
- 以 0 结尾的字符串;
|
- 以 0 结尾的字符串;
|
||||||
- 可变长度的二进制数据 (BLOB)
|
- 可变长度的二进制数据 (BLOB)
|
||||||
|
- 浮点类型:``float`` 和 ``double``
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
@@ -48,7 +49,9 @@ NVS 的操作对象为键值对,其中键是 ASCII 字符串,当前支持的
|
|||||||
|
|
||||||
在设置新的键值对或更新现有键值对之前,NVS 页中必须有可用的空闲条目。对于整数类型,至少需要有一个空闲条目。对于字符串值,至少需要一个能够将整个字符串连续存储在空闲条目中的页面。对于 blob 值,空闲条目中需要有足够空间容纳新数据的大小。
|
在设置新的键值对或更新现有键值对之前,NVS 页中必须有可用的空闲条目。对于整数类型,至少需要有一个空闲条目。对于字符串值,至少需要一个能够将整个字符串连续存储在空闲条目中的页面。对于 blob 值,空闲条目中需要有足够空间容纳新数据的大小。
|
||||||
|
|
||||||
其他数据类型,例如 ``float`` 和 ``double``,可能会在以后添加。
|
.. note::
|
||||||
|
|
||||||
|
无论特定 SoC 上是否存在 FPU,均支持浮点类型 ``float`` 和 ``double``。
|
||||||
|
|
||||||
键必须唯一。为现有的键写入新值时,会将旧的值及数据类型更新为写入操作指定的值和数据类型。
|
键必须唯一。为现有的键写入新值时,会将旧的值及数据类型更新为写入操作指定的值和数据类型。
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user