317 lines
8.9 KiB
C++
317 lines
8.9 KiB
C++
/**
|
|
* @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 <errno.h>
|
|
#include <inttypes.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#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<int8_t>(key, strValue);
|
|
} else if (type == NVS_TYPE_U8) {
|
|
err = nvs.setValueByStr<uint8_t>(key, strValue);
|
|
} else if (type == NVS_TYPE_I16) {
|
|
err = nvs.setValueByStr<int16_t>(key, strValue);
|
|
} else if (type == NVS_TYPE_U16) {
|
|
err = nvs.setValueByStr<uint16_t>(key, strValue);
|
|
} else if (type == NVS_TYPE_I32) {
|
|
err = nvs.setValueByStr<int32_t>(key, strValue);
|
|
} else if (type == NVS_TYPE_U32) {
|
|
err = nvs.setValueByStr<uint32_t>(key, strValue);
|
|
} else if (type == NVS_TYPE_I64) {
|
|
err = nvs.setValueByStr<int64_t>(key, strValue);
|
|
} else if (type == NVS_TYPE_U64) {
|
|
err = nvs.setValueByStr<uint64_t>(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, "Value '%s' not defined", key.c_str());
|
|
} 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;
|
|
}
|