From 968d078c07bbdc5c1b821b57e8346c29fbdd28a6 Mon Sep 17 00:00:00 2001 From: Jakob Gegeniger Date: Wed, 1 Jan 2025 21:15:01 +0100 Subject: [PATCH] Adding NVS to project --- components/nvsUtils/CMakeLists.txt | 5 + components/nvsUtils/include/nvsFunctions.hpp | 38 +++ components/nvsUtils/src/nvsDefines.hpp | 41 +++ components/nvsUtils/src/nvsFunctions.cpp | 316 ++++++++++++++++++ components/nvsUtils/src/nvsIo.cpp | 167 +++++++++ components/nvsUtils/src/nvsIo.hpp | 149 +++++++++ components/project_bases/CMakeLists.txt | 2 +- .../project_bases/include/constraints.hpp | 43 +++ .../project_bases/include/coreExcept.hpp | 25 ++ .../include/{utils.hpp => simpleStreams.hpp} | 15 - components/project_bases/src/dummy.cpp | 9 + components/project_bases/src/utils.cpp | 9 - components/sockets/include/tcpSockets.hpp | 4 +- components/sockets/include/udpSockets.hpp | 3 +- components/tftpShell/include/cliWrapper.hpp | 2 +- components/utils/CMakeLists.txt | 4 + .../include/countDown.hpp | 0 .../include/rotatingIndex.hpp | 0 components/utils/src/dummy.cpp | 8 + 19 files changed, 812 insertions(+), 28 deletions(-) create mode 100644 components/nvsUtils/CMakeLists.txt create mode 100644 components/nvsUtils/include/nvsFunctions.hpp create mode 100644 components/nvsUtils/src/nvsDefines.hpp create mode 100644 components/nvsUtils/src/nvsFunctions.cpp create mode 100644 components/nvsUtils/src/nvsIo.cpp create mode 100644 components/nvsUtils/src/nvsIo.hpp create mode 100644 components/project_bases/include/constraints.hpp create mode 100644 components/project_bases/include/coreExcept.hpp rename components/project_bases/include/{utils.hpp => simpleStreams.hpp} (85%) create mode 100644 components/project_bases/src/dummy.cpp delete mode 100644 components/project_bases/src/utils.cpp create mode 100644 components/utils/CMakeLists.txt rename components/{project_bases => utils}/include/countDown.hpp (100%) rename components/{project_bases => utils}/include/rotatingIndex.hpp (100%) create mode 100644 components/utils/src/dummy.cpp diff --git a/components/nvsUtils/CMakeLists.txt b/components/nvsUtils/CMakeLists.txt new file mode 100644 index 0000000..03922c6 --- /dev/null +++ b/components/nvsUtils/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRC_DIRS "src" + INCLUDE_DIRS "include" + REQUIRES project_bases nvs_flash esp_common +) diff --git a/components/nvsUtils/include/nvsFunctions.hpp b/components/nvsUtils/include/nvsFunctions.hpp new file mode 100644 index 0000000..c62c7e3 --- /dev/null +++ b/components/nvsUtils/include/nvsFunctions.hpp @@ -0,0 +1,38 @@ +/** + * @file nvsFunctions.hpp + * @author Gustice + * @brief NVS-Diagnosis utility + * + * @copyright Copyright (c) 2024 + */ +#pragma once + +#include + +class NvsApi { + + public: + /// @brief Init and mount file system + /// @param mount rooted SubType of partition eg "nvs" + static void init(std::string mount = std::string{"nvs"}); + + /// @brief Get instance, ensure initialization + /// @param mount rooted SubType of partition eg "nvs" + /// @return Instance reference + static NvsApi &getInstance(std::string mount = std::string{"nvs"}); + + void setValue(const std::string &key, const std::string &value); + std::string getValue(const std::string &key); + + // Disable move and assignment + NvsApi(NvsApi &other) = delete; + void operator=(const NvsApi &) = delete; + + protected: + NvsApi(std::string mount); + ~NvsApi(); + + private: + static NvsApi *_instance; + const std::string _mountingPoint; +}; diff --git a/components/nvsUtils/src/nvsDefines.hpp b/components/nvsUtils/src/nvsDefines.hpp new file mode 100644 index 0000000..20bd40d --- /dev/null +++ b/components/nvsUtils/src/nvsDefines.hpp @@ -0,0 +1,41 @@ +/** + * @file nvsDefines.hpp + * @author Gustice + * @brief Defines and record types + * + * @copyright Copyright (c) 2024 + */ +#pragma once + +#include "nvs.h" +#include +#include +#include +#include + +static std::tuple< + std::map, + std::map> +CreateNvsDictionaries() { + std::array, 11> defines{ + {{NVS_TYPE_I8, "i8"}, + {NVS_TYPE_U8, "u8"}, + {NVS_TYPE_U16, "u16"}, + {NVS_TYPE_I16, "i16"}, + {NVS_TYPE_U32, "u32"}, + {NVS_TYPE_I32, "i32"}, + {NVS_TYPE_U64, "u64"}, + {NVS_TYPE_I64, "i64"}, + {NVS_TYPE_STR, "str"}, + {NVS_TYPE_BLOB, "blob"}, + {NVS_TYPE_ANY, "any"}}}; + + std::map k2s; + std::map s2k; + + for (auto &&e : defines) { + k2s.emplace(e.first, e.second); + s2k.emplace(e.second, e.first); + } + return {k2s, s2k}; +} diff --git a/components/nvsUtils/src/nvsFunctions.cpp b/components/nvsUtils/src/nvsFunctions.cpp new file mode 100644 index 0000000..3239325 --- /dev/null +++ b/components/nvsUtils/src/nvsFunctions.cpp @@ -0,0 +1,316 @@ +/** + * @file cmd_nvs.cpp + * @author Gustice + * @brief NVS-Diagnosis utility (derived from ESP-IDF Console-Example) + * + * @copyright Copyright (c) 2024 + */ + +#include "nvsFunctions.hpp" +#include "esp_err.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "nvs.h" +#include "nvsIo.hpp" +#include "nvs_flash.h" +#include +#include +#include +#include +#include + +#include "nvsDefines.hpp" + +static void initializeNvs() { + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + // 1.OTA app partition table has a smaller NVS partition size than the non-OTA + // partition table. This size mismatch may cause NVS initialization to fail. + // 2.NVS partition contains data in new format and cannot be recognized by this version of code. + // If this happens, we erase NVS partition and initialize NVS again. + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); +} + +NvsApi *NvsApi::_instance = nullptr; + +NvsApi::NvsApi(std::string mount) : _mountingPoint(mount) { + initializeNvs(); +} + +NvsApi::~NvsApi() { +} + +NvsApi &NvsApi::getInstance(std::string mount) { + if (_instance == nullptr) { + init(mount); + } + return *_instance; +} + +void NvsApi::init(std::string mount) { + if (_instance != nullptr) { + return; + } + _instance = new NvsApi(mount); +} + +const auto [TypeStrMap, StrTypeMap] = CreateNvsDictionaries(); + +static char activeNameSpace[16] = "storage"; +static const char *TAG = "NVS"; + +static nvs_type_t confStr2Type(const char *type) { + if (auto search = StrTypeMap.find(type); search != StrTypeMap.end()) { + return search->second; + } + ESP_LOGW(TAG, "type '%s' not found", type); + return NVS_TYPE_ANY; +} + +static const char *confType2Str(nvs_type_t type) { + if (auto search = TypeStrMap.find(type); search != TypeStrMap.end()) { + return search->second; + } + ESP_LOGW(TAG, "type %d not found", type); + return "Unknown"; +} + +struct SetArgs { + struct arg_str *key; + struct arg_str *type; + struct arg_str *value; + struct arg_end *end; +}; + +struct GetArgs { + struct arg_str *key; + struct arg_str *type; + struct arg_end *end; +}; + +struct EraseArgs { + struct arg_str *key; + struct arg_end *end; +}; + +struct EraseNameSpaceArgs { + struct arg_str *nameSpace; + struct arg_end *end; +}; + +struct NameSpaceArgs { + struct arg_str *nameSpace; + struct arg_end *end; +}; + +struct ListArgs { + struct arg_str *partition; + struct arg_str *nameSpace; + struct arg_str *type; + struct arg_end *end; +}; + +static esp_err_t setValueInNvs(const char *key, const char *strType, const char *strValue) { + nvs_type_t type = confStr2Type(strType); + if (type == NVS_TYPE_ANY) { + ESP_LOGE(TAG, "Type '%s' is undefined", strType); + return ESP_ERR_NVS_TYPE_MISMATCH; + } + + try { + NvsIo nvs(activeNameSpace, NVS_READWRITE); + + esp_err_t err = ESP_FAIL; + if (type == NVS_TYPE_I8) { + err = nvs.setValueByStr(key, strValue); + } else if (type == NVS_TYPE_U8) { + err = nvs.setValueByStr(key, strValue); + } else if (type == NVS_TYPE_I16) { + err = nvs.setValueByStr(key, strValue); + } else if (type == NVS_TYPE_U16) { + err = nvs.setValueByStr(key, strValue); + } else if (type == NVS_TYPE_I32) { + err = nvs.setValueByStr(key, strValue); + } else if (type == NVS_TYPE_U32) { + err = nvs.setValueByStr(key, strValue); + } else if (type == NVS_TYPE_I64) { + err = nvs.setValueByStr(key, strValue); + } else if (type == NVS_TYPE_U64) { + err = nvs.setValueByStr(key, strValue); + } else if (type == NVS_TYPE_STR) { + err = nvs.setString(key, strValue); + } else if (type == NVS_TYPE_BLOB) { + err = nvs.setBlob(key, strValue); + } + + if (err != ESP_OK) { + return err; + } + err = nvs.commit(); + if (err == ESP_OK) { + ESP_LOGI(TAG, "Value stored under key '%s'", key); + } + return ESP_OK; + } catch (const std::exception &e) { + ESP_LOGE(TAG, "%s", e.what()); + } + return ESP_FAIL; +} + +void NvsApi::setValue(const std::string &key, const std::string &value) { + if (setValueInNvs(key.c_str(), "str", value.c_str()) != ESP_OK) { + ESP_LOGE(TAG, "setValue failed"); + } +} + +std::string NvsApi::getValue(const std::string &key) { + try { + NvsIo nvs(activeNameSpace, NVS_READONLY); + auto opt = nvs.getString(key.c_str()); + auto value = opt.value(); + return value; + } catch (const std::bad_optional_access &e) { + ESP_LOGE(TAG, "%s", "Value not defined"); + } catch (const std::exception &e) { + ESP_LOGE(TAG, "%s", e.what()); + } + + return ""; +} + +static esp_err_t showValueFromNvs(const char *key, const char *strType) { + nvs_type_t type = confStr2Type(strType); + if (type == NVS_TYPE_ANY) { + ESP_LOGE(TAG, "Type '%s' is undefined", strType); + return ESP_ERR_NVS_TYPE_MISMATCH; + } + + try { + NvsIo nvs(activeNameSpace, NVS_READONLY); + + if (type == NVS_TYPE_I8) { + auto opt = nvs.getInt8(key); + printf("%d\n", opt.value()); + } else if (type == NVS_TYPE_U8) { + auto opt = nvs.getUint8(key); + printf("%u\n", opt.value()); + } else if (type == NVS_TYPE_I16) { + auto opt = nvs.getInt16(key); + printf("%u\n", opt.value()); + } else if (type == NVS_TYPE_U16) { + auto opt = nvs.getUint16(key); + printf("%u\n", opt.value()); + } else if (type == NVS_TYPE_I32) { + auto opt = nvs.getInt32(key); + printf("%" PRIi32 "\n", opt.value()); + } else if (type == NVS_TYPE_U32) { + auto opt = nvs.getUint32(key); + printf("%" PRIu32 "\n", opt.value()); + } else if (type == NVS_TYPE_I64) { + auto opt = nvs.getInt64(key); + printf("%lld\n", opt.value()); + } else if (type == NVS_TYPE_U64) { + auto opt = nvs.getUint64(key); + printf("%llu\n", opt.value()); + } else if (type == NVS_TYPE_STR) { + auto opt = nvs.getString(key); + printf("%s\n", opt.value().c_str()); + } else if (type == NVS_TYPE_BLOB) { + auto opt = nvs.getBlob(key); + auto value = opt.value(); + for (int i = 0; i < value.size(); i++) { + printf("%02x", value[i]); + } + printf("\n"); + } + return ESP_OK; + } catch (const std::bad_optional_access &e) { + ESP_LOGE(TAG, "%s", "Value not defined"); + } catch (const std::exception &e) { + ESP_LOGE(TAG, "%s", e.what()); + } + + return ESP_FAIL; +} + +static esp_err_t erase(const char *key) { + try { + NvsIo nvs(activeNameSpace, NVS_READWRITE); + + esp_err_t err = nvs.erase(key); + if (err != ESP_OK) { + return err; + } + err = nvs.commit(); + if (err != ESP_OK) { + return err; + } + + ESP_LOGI(TAG, "Value with key '%s' erased", key); + return ESP_OK; + } catch (const std::exception &e) { + ESP_LOGE(TAG, "%s", e.what()); + } + return ESP_FAIL; +} + +static esp_err_t eraseAllIn(const char *name) { + try { + NvsIo nvs(name, NVS_READWRITE); + + esp_err_t err = nvs.clear(); + if (err != ESP_OK) { + return err; + } + err = nvs.commit(); + if (err != ESP_OK) { + return err; + } + ESP_LOGI(TAG, "Namespace '%s' was %s erased", name, (err == ESP_OK) ? "" : "not"); + + return ESP_OK; + } catch (const std::exception &e) { + ESP_LOGE(TAG, "%s", e.what()); + } + return ESP_FAIL; +} + +static int list(const char *part, const char *name, const char *strType) { + nvs_type_t type = confStr2Type(strType); + + nvs_iterator_t it = NULL; + esp_err_t result = nvs_entry_find(part, NULL, type, &it); + if (result == ESP_ERR_NVS_NOT_FOUND) { + ESP_LOGE(TAG, "No such entry was found"); + return 1; + } + + if (result != ESP_OK) { + ESP_LOGE(TAG, "NVS error: %s", esp_err_to_name(result)); + return 1; + } + + do { + nvs_entry_info_t info; + nvs_entry_info(it, &info); + result = nvs_entry_next(&it); + + if ((strlen(name) > 0) && (strcmp(info.namespace_name, name) != 0)) { + continue; + } + + printf("namespace '%s', key '%s', type '%s' \n", + info.namespace_name, info.key, confType2Str(info.type)); + } while (result == ESP_OK); + + if (result != ESP_ERR_NVS_NOT_FOUND) { // the last iteration ran into an internal error + ESP_LOGE(TAG, "NVS error %s at current iteration, stopping.", esp_err_to_name(result)); + return 1; + } + + return 0; +} diff --git a/components/nvsUtils/src/nvsIo.cpp b/components/nvsUtils/src/nvsIo.cpp new file mode 100644 index 0000000..e204a91 --- /dev/null +++ b/components/nvsUtils/src/nvsIo.cpp @@ -0,0 +1,167 @@ +/** + * @file nvsIo.cpp + * @author Gustice + * @brief Read-Write access to specific NVS partition + * + * @copyright Copyright (c) 2024 + */ + +#include "nvsIo.hpp" +#include "esp_err.h" +#include "esp_log.h" +#include +#include + +static const char *TAG = "NVS"; + +static esp_err_t storeBlob(nvs_handle_t nvs, const char *key, const char *str_values) { + uint8_t value; + size_t str_len = strlen(str_values); + size_t blob_len = str_len / 2; + + if (str_len % 2) { + ESP_LOGE(TAG, "Blob data must contain even number of characters"); + return ESP_ERR_NVS_TYPE_MISMATCH; + } + + char *blob = (char *)malloc(blob_len); + if (blob == NULL) { + return ESP_ERR_NO_MEM; + } + + for (int i = 0, j = 0; i < str_len; i++) { + char ch = str_values[i]; + if (ch >= '0' && ch <= '9') { + value = ch - '0'; + } else if (ch >= 'A' && ch <= 'F') { + value = ch - 'A' + 10; + } else if (ch >= 'a' && ch <= 'f') { + value = ch - 'a' + 10; + } else { + ESP_LOGE(TAG, "Blob data contain invalid character"); + free(blob); + return ESP_ERR_NVS_TYPE_MISMATCH; + } + + if (i & 1) { + blob[j++] += value; + } else { + blob[j] = value << 4; + } + } + + esp_err_t err = nvs_set_blob(nvs, key, blob, blob_len); + free(blob); + + if (err == ESP_OK) { + err = nvs_commit(nvs); + } + + return err; +} + +template <> +esp_err_t NvsIo::setValueByStr(const char *key, const char *strValue) { + int32_t value = strtol(strValue, NULL, 0); + if (value < INT8_MIN || value > INT8_MAX || errno == ERANGE) { + throw CoreException(ErrMsg_TooLong); + } + return setInt8(key, (int8_t)value); +} + +template <> +esp_err_t NvsIo::setValueByStr(const char *key, const char *strValue) { + uint32_t value = strtoul(strValue, NULL, 0); + if (value > UINT8_MAX || errno == ERANGE) { + throw CoreException(ErrMsg_TooLong); + } + return setUint8(key, (uint8_t)value); +} + +template <> +esp_err_t NvsIo::setValueByStr(const char *key, const char *strValue) { + int32_t value = strtol(strValue, NULL, 0); + if (value < INT16_MIN || value > INT16_MAX || errno == ERANGE) { + throw CoreException(ErrMsg_TooLong); + } + return setInt16(key, (int16_t)value); +} + +template <> +esp_err_t NvsIo::setValueByStr(const char *key, const char *strValue) { + uint32_t value = strtoul(strValue, NULL, 0); + if (value > UINT16_MAX || errno == ERANGE) { + throw CoreException(ErrMsg_TooLong); + } + return setUint16(key, (uint16_t)value); +} + +template <> +esp_err_t NvsIo::setValueByStr(const char *key, const char *strValue) { + int32_t value = strtol(strValue, NULL, 0); + if (errno == ERANGE) { + throw CoreException(ErrMsg_TooLong); + } + return setInt32(key, value); +} + +template <> +esp_err_t NvsIo::setValueByStr(const char *key, const char *strValue) { + uint32_t value = strtoul(strValue, NULL, 0); + if (errno == ERANGE) { + throw CoreException(ErrMsg_TooLong); + } + return setUint32(key, value); +} + +template <> +esp_err_t NvsIo::setValueByStr(const char *key, const char *strValue) { + int64_t value = strtoll(strValue, NULL, 0); + if (errno == ERANGE) { + throw CoreException(ErrMsg_TooLong); + } + return setInt64(key, value); +} + +template <> +esp_err_t NvsIo::setValueByStr(const char *key, const char *strValue) { + uint64_t value = strtoull(strValue, NULL, 0); + if (errno == ERANGE) { + throw CoreException(ErrMsg_TooLong); + } + return setUint64(key, value); +} + +esp_err_t NvsIo::setString(const char *key, const char *strValue) { + return nvs_set_str(_nvs, key, strValue); +} +esp_err_t NvsIo::setBlob(const char *key, const char *strValue) { + return storeBlob(_nvs, key, strValue); +} + +std::optional NvsIo::getString(const char *key) { + size_t len; + if (nvs_get_str(_nvs, key, NULL, &len) != ESP_OK) { + return {std::nullopt}; + } + auto str = std::make_unique(len); + if ((nvs_get_str(_nvs, key, str.get(), &len)) != ESP_OK) { + return {std::nullopt}; + } + return {str.get()}; +} + +std::optional> NvsIo::getBlob(const char *key) { + size_t len; + if (nvs_get_blob(_nvs, key, NULL, &len) != ESP_OK) { + return {std::nullopt}; + } + auto blob = std::make_unique(len); + if (nvs_get_blob(_nvs, key, blob.get(), &len) != ESP_OK) { + return {std::nullopt}; + } + std::vector vec; + vec.reserve(len); + vec.insert(vec.end(), blob.get(), blob.get() + len); + return {vec}; +} diff --git a/components/nvsUtils/src/nvsIo.hpp b/components/nvsUtils/src/nvsIo.hpp new file mode 100644 index 0000000..ad1f4b7 --- /dev/null +++ b/components/nvsUtils/src/nvsIo.hpp @@ -0,0 +1,149 @@ +/** + * @file nvsIo.hpp + * @author Gustice + * @brief Read-Write access to specific NVS partition + * + * @copyright Copyright (c) 2024 + */ +#pragma once + +#include "nvs.h" +#include "coreExcept.hpp" +#include +#include +#include + +class NvsIo { + const char *ErrMsg_TooLong = "Value is too long"; + + public: + NvsIo(const char *nameSpace, nvs_open_mode_t mode) { + if (nvs_open(nameSpace, mode, &_nvs) != ESP_OK) { + throw CoreException("Unable to open NVS"); + } + } + ~NvsIo() { + nvs_close(_nvs); + } + esp_err_t commit() { + return nvs_commit(_nvs); + } + + template + esp_err_t setValueByStr(const char *key, const char *strValue); + + esp_err_t setInt8(const char *key, int8_t value) { + return nvs_set_i8(_nvs, key, value); + } + esp_err_t setUint8(const char *key, uint8_t value) { + return nvs_set_u8(_nvs, key, value); + } + esp_err_t setInt16(const char *key, int16_t value) { + return nvs_set_i16(_nvs, key, value); + } + esp_err_t setUint16(const char *key, uint16_t value) { + return nvs_set_u16(_nvs, key, value); + } + esp_err_t setInt32(const char *key, int32_t value) { + return nvs_set_i32(_nvs, key, value); + } + esp_err_t setUint32(const char *key, uint32_t value) { + return nvs_set_u32(_nvs, key, value); + } + esp_err_t setInt64(const char *key, int64_t value) { + return nvs_set_i64(_nvs, key, value); + } + esp_err_t setUint64(const char *key, uint64_t value) { + return nvs_set_u64(_nvs, key, value); + } + esp_err_t setString(const char *key, const char *strValue); + esp_err_t setBlob(const char *key, const char *strValue); + + std::optional getInt8(const char *key) { + int8_t value; + if (nvs_get_i8(_nvs, key, &value) != ESP_OK) { + return {std::nullopt}; + } + return {value}; + } + std::optional getUint8(const char *key) { + uint8_t value; + if (nvs_get_u8(_nvs, key, &value) != ESP_OK) { + return {std::nullopt}; + } + return {value}; + } + std::optional getInt16(const char *key) { + int16_t value; + if (nvs_get_i16(_nvs, key, &value) != ESP_OK) { + return {std::nullopt}; + } + return {value}; + } + std::optional getUint16(const char *key) { + uint16_t value; + if (nvs_get_u16(_nvs, key, &value) != ESP_OK) { + return {std::nullopt}; + } + return {value}; + } + std::optional getInt32(const char *key) { + int32_t value; + if (nvs_get_i32(_nvs, key, &value) != ESP_OK) { + return {std::nullopt}; + } + return {value}; + } + std::optional getUint32(const char *key) { + uint32_t value; + if (nvs_get_u32(_nvs, key, &value) != ESP_OK) { + return {std::nullopt}; + } + return {value}; + } + std::optional getInt64(const char *key) { + int64_t value; + if (nvs_get_i64(_nvs, key, &value) != ESP_OK) { + return {std::nullopt}; + } + return {value}; + } + std::optional getUint64(const char *key) { + uint64_t value; + if (nvs_get_u64(_nvs, key, &value) != ESP_OK) { + return {std::nullopt}; + } + return {value}; + } + std::optional getString(const char *key); + std::optional> getBlob(const char *key); + + esp_err_t erase(const char *key) { + return nvs_erase_key(_nvs, key); + } + + /// @brief Clear all entries in given namespace + esp_err_t clear() { + return nvs_erase_all(_nvs); + } + + private: + nvs_handle_t _nvs; +}; + +template <> +esp_err_t NvsIo::setValueByStr(const char *key, const char *strValue); +template <> +esp_err_t NvsIo::setValueByStr(const char *key, const char *strValue); +template <> +esp_err_t NvsIo::setValueByStr(const char *key, const char *strValue); +template <> +esp_err_t NvsIo::setValueByStr(const char *key, const char *strValue); +template <> +esp_err_t NvsIo::setValueByStr(const char *key, const char *strValue); +template <> +esp_err_t NvsIo::setValueByStr(const char *key, const char *strValue); +template <> +esp_err_t NvsIo::setValueByStr(const char *key, const char *strValue); +template <> +esp_err_t NvsIo::setValueByStr(const char *key, const char *strValue); \ No newline at end of file diff --git a/components/project_bases/CMakeLists.txt b/components/project_bases/CMakeLists.txt index e02288d..9889f89 100644 --- a/components/project_bases/CMakeLists.txt +++ b/components/project_bases/CMakeLists.txt @@ -1,4 +1,4 @@ idf_component_register( SRC_DIRS "src" - INCLUDE_DIRS "include" + INCLUDE_DIRS "include" "defines" ) diff --git a/components/project_bases/include/constraints.hpp b/components/project_bases/include/constraints.hpp new file mode 100644 index 0000000..23eaae8 --- /dev/null +++ b/components/project_bases/include/constraints.hpp @@ -0,0 +1,43 @@ +/** + * @file utils.hpp + * @author Gustice + * @brief Template + * + * @copyright Copyright (c) 2024 + */ +#pragma once + +#include +#include +#include + +/** + * @brief Base for constructs that allow only one concurrently active instance + * + * @tparam T + * @note needs a `T * T::SingleActive::active{};` definition in source + */ +template +class SingleActive { + static bool active; + + public: + /// @brief Constructor, memorizes if already on instance was successfully build + SingleActive() { + if (active) { + throw "Instance already active"; + } + assert(active == false && "Constructor my only be run if no instance active"); + active = true; + } + + /// @brief Destructor, clears memory of existing instance + ~SingleActive() { + assert(active == true && "Destructor my only be run on active instance"); + active = false; + } + + // Disable move and assignment + SingleActive(SingleActive &other) = delete; + void operator=(const SingleActive &) = delete; +}; diff --git a/components/project_bases/include/coreExcept.hpp b/components/project_bases/include/coreExcept.hpp new file mode 100644 index 0000000..025a1ea --- /dev/null +++ b/components/project_bases/include/coreExcept.hpp @@ -0,0 +1,25 @@ +/** + * @file coreExcept.hpp + * @author Gustice + * @brief Template + * + * @copyright Copyright (c) 2024 + */ +#pragma once + +#include + +/** + * @brief Simple exception + */ +class CoreException : public std::exception { + char const *Text; + + public: + /// @brief Constructor with simple pointer to text + CoreException(char const *text) : Text(text) { + } + + /// @brief error message getter + char const *what() const throw() override { return Text; } +}; diff --git a/components/project_bases/include/utils.hpp b/components/project_bases/include/simpleStreams.hpp similarity index 85% rename from components/project_bases/include/utils.hpp rename to components/project_bases/include/simpleStreams.hpp index 8ed23d4..903b6b3 100644 --- a/components/project_bases/include/utils.hpp +++ b/components/project_bases/include/simpleStreams.hpp @@ -13,21 +13,6 @@ #include #include -/** - * @brief Simple exception - */ -class CoreException : public std::exception { - char const *Text; - - public: - /// @brief Constructor with simple pointer to text - CoreException(char const *text) : Text(text) { - } - - /// @brief error message getter - char const *what() const throw() override { return Text; } -}; - /** * @brief Common interface for character streams */ diff --git a/components/project_bases/src/dummy.cpp b/components/project_bases/src/dummy.cpp new file mode 100644 index 0000000..dc28298 --- /dev/null +++ b/components/project_bases/src/dummy.cpp @@ -0,0 +1,9 @@ +/** + * @file dummy.cpp + * @author Gustice + * @brief Silence toolchain + * + * @copyright Copyright (c) 2024 + */ + +#include "portBase.hpp" diff --git a/components/project_bases/src/utils.cpp b/components/project_bases/src/utils.cpp deleted file mode 100644 index c31d1f5..0000000 --- a/components/project_bases/src/utils.cpp +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @file utils.cpp - * @author Gustice - * @brief Implementation of utilities - * - * @copyright Copyright (c) 2024 - */ - -#include "utils.hpp" diff --git a/components/sockets/include/tcpSockets.hpp b/components/sockets/include/tcpSockets.hpp index 93444f9..f6935f0 100644 --- a/components/sockets/include/tcpSockets.hpp +++ b/components/sockets/include/tcpSockets.hpp @@ -10,9 +10,11 @@ #include "esp_log.h" #include "etherCommon.hpp" -#include "utils.hpp" +#include "coreExcept.hpp" #include #include +#include +#include "simpleStreams.hpp" /** * @brief TCP-Socket wrapper for ESP-IDF socket implementation diff --git a/components/sockets/include/udpSockets.hpp b/components/sockets/include/udpSockets.hpp index 3f6682c..e03499a 100644 --- a/components/sockets/include/udpSockets.hpp +++ b/components/sockets/include/udpSockets.hpp @@ -10,10 +10,11 @@ #include "Task.hpp" #include "esp_log.h" #include "etherCommon.hpp" -#include "utils.hpp" +#include "coreExcept.hpp" #include #include #include +#include "simpleStreams.hpp" constexpr bool UDP_WITH_TIMEOUT = false; diff --git a/components/tftpShell/include/cliWrapper.hpp b/components/tftpShell/include/cliWrapper.hpp index 088dc4d..d1eb9b0 100644 --- a/components/tftpShell/include/cliWrapper.hpp +++ b/components/tftpShell/include/cliWrapper.hpp @@ -14,7 +14,7 @@ #include #include #include -#include "utils.hpp" +#include "simpleStreams.hpp" /* Module configuration */ static constexpr int CLI_RX_BUFFER_SIZE = 64; diff --git a/components/utils/CMakeLists.txt b/components/utils/CMakeLists.txt new file mode 100644 index 0000000..e02288d --- /dev/null +++ b/components/utils/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register( + SRC_DIRS "src" + INCLUDE_DIRS "include" +) diff --git a/components/project_bases/include/countDown.hpp b/components/utils/include/countDown.hpp similarity index 100% rename from components/project_bases/include/countDown.hpp rename to components/utils/include/countDown.hpp diff --git a/components/project_bases/include/rotatingIndex.hpp b/components/utils/include/rotatingIndex.hpp similarity index 100% rename from components/project_bases/include/rotatingIndex.hpp rename to components/utils/include/rotatingIndex.hpp diff --git a/components/utils/src/dummy.cpp b/components/utils/src/dummy.cpp new file mode 100644 index 0000000..9969bbe --- /dev/null +++ b/components/utils/src/dummy.cpp @@ -0,0 +1,8 @@ +/** + * @file dummy.cpp + * @author Gustice + * @brief Silence toolchain + * + * @copyright Copyright (c) 2024 + */ +