From 0e5abaf3038452a105c46bdbd4694b97483e1da8 Mon Sep 17 00:00:00 2001 From: Jakob Hasse Date: Tue, 12 May 2020 12:27:31 +0800 Subject: [PATCH] Enabled enum types for nvs C++ handle Closes https://github.com/espressif/esp-idf/issues/5232 --- components/nvs_flash/include/nvs_handle.hpp | 20 ++- .../test_nvs_host/test_nvs_handle.cpp | 164 ++++++++++++++++++ 2 files changed, 182 insertions(+), 2 deletions(-) diff --git a/components/nvs_flash/include/nvs_handle.hpp b/components/nvs_flash/include/nvs_handle.hpp index 8699974a00..d87c1c280e 100644 --- a/components/nvs_flash/include/nvs_handle.hpp +++ b/components/nvs_flash/include/nvs_handle.hpp @@ -47,9 +47,11 @@ public: * @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. + * @param[in] value The value to set. Allowed types are the ones declared in ItemType as well as enums. * For strings, the maximum length (including null character) is * 4000 bytes. + * Note that enums loose their type information when stored in NVS. Ensure that the correct + * enum type is used during retrieval with \ref get_item! * * @return * - ESP_OK if value was set successfully @@ -80,7 +82,9 @@ public: * @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. + * @param value The output value. All integral types which are declared in ItemType as well as enums + * are allowed. Note however that enums lost their type information when stored in NVS. + * Ensure that the correct enum type is used during retrieval with \ref get_item! * * @return * - ESP_OK if the value was retrieved successfully @@ -233,12 +237,24 @@ std::unique_ptr open_nvs_handle(const char *ns_name, esp_err_t *err = nullptr); // Helper functions for template usage +/** + * Help to translate all integral types into ItemType. + */ template::value, void*>::type = nullptr> constexpr ItemType itemTypeOf() { return static_cast(((std::is_signed::value)?0x10:0x00) | sizeof(T)); } +/** + * Help to translate all enum types into integral ItemType. + */ +template::value, int>::type = 0> +constexpr ItemType itemTypeOf() +{ + return static_cast(((std::is_signed::value)?0x10:0x00) | sizeof(T)); +} + template constexpr ItemType itemTypeOf(const T&) { diff --git a/components/nvs_flash/test_nvs_host/test_nvs_handle.cpp b/components/nvs_flash/test_nvs_host/test_nvs_handle.cpp index bee7d823aa..3374d25192 100644 --- a/components/nvs_flash/test_nvs_host/test_nvs_handle.cpp +++ b/components/nvs_flash/test_nvs_host/test_nvs_handle.cpp @@ -20,6 +20,7 @@ #include "spi_flash_emulation.h" #include +#include using namespace std; using namespace nvs; @@ -114,3 +115,166 @@ TEST_CASE("nvshandle readonly fails", "[partition_mgr]") CHECK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK); } +TEST_CASE("NVSHandleSimple set/get char", "[partition_mgr]") +{ + enum class TestEnum : char { + FOO = -1, + BEER, + BAR + }; + + SpiFlashEmulator emu(10); + + 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); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + NVSHandleSimple *handle; + REQUIRE(NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK); + + char test_e = 'a'; + char test_e_read = 'z'; + + CHECK(handle->set_item("key", test_e) == ESP_OK); + + CHECK(handle->get_item("key", test_e_read) == ESP_OK); + CHECK(test_e == test_e_read); + + delete handle; + + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK); +} + +TEST_CASE("NVSHandleSimple correctly sets/gets int enum", "[partition_mgr]") +{ + enum class TestEnum : int { + FOO, + BAR + }; + + SpiFlashEmulator emu(10); + + 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); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + NVSHandleSimple *handle; + REQUIRE(NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK); + + TestEnum test_e = TestEnum::BAR; + TestEnum test_e_read = TestEnum::FOO; + + CHECK(handle->set_item("key", test_e) == ESP_OK); + + CHECK(handle->get_item("key", test_e_read) == ESP_OK); + CHECK(test_e == test_e_read); + + delete handle; + + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK); +} + +TEST_CASE("NVSHandleSimple correctly sets/gets int enum with negative values", "[partition_mgr]") +{ + enum class TestEnum : int { + FOO = -1, + BEER, + BAR + }; + + SpiFlashEmulator emu(10); + + 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); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + NVSHandleSimple *handle; + REQUIRE(NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK); + + TestEnum test_e = TestEnum::FOO; + TestEnum test_e_read = TestEnum::BEER; + + CHECK(handle->set_item("key", test_e) == ESP_OK); + + CHECK(handle->get_item("key", test_e_read) == ESP_OK); + CHECK(test_e == test_e_read); + + delete handle; + + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK); +} + +TEST_CASE("NVSHandleSimple correctly sets/gets uint8_t enum", "[partition_mgr]") +{ + enum class TestEnum : uint8_t { + FOO, + BAR + }; + + SpiFlashEmulator emu(10); + + 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); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + NVSHandleSimple *handle; + REQUIRE(NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK); + + TestEnum test_e = TestEnum::BAR; + TestEnum test_e_read = TestEnum::FOO; + + CHECK(handle->set_item("key", test_e) == ESP_OK); + + CHECK(handle->get_item("key", test_e_read) == ESP_OK); + CHECK(test_e == test_e_read); + + delete handle; + + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK); +} + +TEST_CASE("NVSHandleSimple correctly sets/gets char enum", "[partition_mgr]") +{ + enum class TestEnum : char { + FOO = -1, + BEER, + BAR + }; + + SpiFlashEmulator emu(10); + + 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); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + NVSHandleSimple *handle; + REQUIRE(NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK); + + TestEnum test_e = TestEnum::BAR; + TestEnum test_e_read = TestEnum::FOO; + + CHECK(handle->set_item("key", test_e) == ESP_OK); + + CHECK(handle->get_item("key", test_e_read) == ESP_OK); + CHECK(test_e == test_e_read); + + delete handle; + + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK); +} +