nvs_utilities.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. #include "nvs_utilities.h"
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include "esp_system.h"
  5. #include "esp_log.h"
  6. #include "esp_console.h"
  7. #include "esp_vfs_dev.h"
  8. #include "driver/uart.h"
  9. #include "linenoise/linenoise.h"
  10. #include "argtable3/argtable3.h"
  11. #include "nvs.h"
  12. #include "nvs_flash.h"
  13. #include "nvs_utilities.h"
  14. #include "platform_config.h"
  15. #include "tools.h"
  16. const char current_namespace[] = "config";
  17. const char settings_partition[] = "settings";
  18. static const char * TAG = "nvs_utilities";
  19. typedef struct {
  20. nvs_type_t type;
  21. const char *str;
  22. } type_str_pair_t;
  23. static const type_str_pair_t type_str_pair[] = {
  24. { NVS_TYPE_I8, "i8" },
  25. { NVS_TYPE_U8, "u8" },
  26. { NVS_TYPE_U16, "u16" },
  27. { NVS_TYPE_I16, "i16" },
  28. { NVS_TYPE_U32, "u32" },
  29. { NVS_TYPE_I32, "i32" },
  30. { NVS_TYPE_U64, "u64" },
  31. { NVS_TYPE_I64, "i64" },
  32. { NVS_TYPE_STR, "str" },
  33. { NVS_TYPE_BLOB, "blob" },
  34. { NVS_TYPE_ANY, "any" },
  35. };
  36. static const size_t TYPE_STR_PAIR_SIZE = sizeof(type_str_pair) / sizeof(type_str_pair[0]);
  37. void print_blob(const char *blob, size_t len)
  38. {
  39. for (int i = 0; i < len; i++) {
  40. printf("%02x", blob[i]);
  41. }
  42. printf("\n");
  43. }
  44. nvs_type_t str_to_type(const char *type)
  45. {
  46. for (int i = 0; i < TYPE_STR_PAIR_SIZE; i++) {
  47. const type_str_pair_t *p = &type_str_pair[i];
  48. if (strcmp(type, p->str) == 0) {
  49. return p->type;
  50. }
  51. }
  52. return NVS_TYPE_ANY;
  53. }
  54. const char *type_to_str(nvs_type_t type)
  55. {
  56. for (int i = 0; i < TYPE_STR_PAIR_SIZE; i++) {
  57. const type_str_pair_t *p = &type_str_pair[i];
  58. if (p->type == type) {
  59. return p->str;
  60. }
  61. }
  62. return "Unknown";
  63. }
  64. void erase_settings_partition(){
  65. ESP_LOGW(TAG, "Erasing nvs on partition %s",settings_partition);
  66. ESP_ERROR_CHECK(nvs_flash_erase_partition(settings_partition));
  67. nvs_flash_init_partition(settings_partition);
  68. }
  69. void initialize_nvs() {
  70. ESP_LOGI(TAG, "Initializing flash nvs ");
  71. esp_err_t err = nvs_flash_init();
  72. if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
  73. ESP_LOGW(TAG, "%s. Erasing nvs flash", esp_err_to_name(err));
  74. ESP_ERROR_CHECK(nvs_flash_erase());
  75. err = nvs_flash_init();
  76. }
  77. if(err != ESP_OK){
  78. ESP_LOGE(TAG, "nvs_flash_init failed. %s.", esp_err_to_name(err));
  79. }
  80. ESP_ERROR_CHECK(err);
  81. ESP_LOGI(TAG, "Initializing nvs partition %s",settings_partition);
  82. err = nvs_flash_init_partition(settings_partition);
  83. if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
  84. ESP_LOGW(TAG, "%s. Erasing nvs on partition %s",esp_err_to_name(err),settings_partition);
  85. ESP_ERROR_CHECK(nvs_flash_erase_partition(settings_partition));
  86. err = nvs_flash_init_partition(settings_partition);
  87. }
  88. if(err!=ESP_OK){
  89. ESP_LOGE(TAG, "nvs_flash_init_partition failed. %s",esp_err_to_name(err));
  90. }
  91. ESP_ERROR_CHECK(err);
  92. ESP_LOGD(TAG, "nvs init completed");
  93. }
  94. esp_err_t nvs_load_config() {
  95. nvs_entry_info_t info;
  96. esp_err_t err = ESP_OK;
  97. size_t malloc_int = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
  98. size_t malloc_spiram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
  99. nvs_iterator_t it = nvs_entry_find(settings_partition, NULL, NVS_TYPE_ANY);
  100. if (it == NULL) {
  101. ESP_LOGW(TAG, "empty nvs partition %s, namespace %s", settings_partition, current_namespace);
  102. }
  103. while (it != NULL) {
  104. nvs_entry_info(it, &info);
  105. if (strstr(info.namespace_name, current_namespace)) {
  106. if (strlen(info.key) == 0) {
  107. ESP_LOGW(TAG, "empty key name in namespace %s. Removing it.", current_namespace);
  108. nvs_handle_t nvs_handle;
  109. err = nvs_open(settings_partition, NVS_READWRITE, &nvs_handle);
  110. if (err != ESP_OK) {
  111. ESP_LOGE(TAG, "nvs_open failed. %s", esp_err_to_name(err));
  112. } else {
  113. if ((err = nvs_erase_key(nvs_handle, info.key)) != ESP_OK) {
  114. ESP_LOGE(TAG, "nvs_erase_key failed. %s", esp_err_to_name(err));
  115. } else {
  116. nvs_commit(nvs_handle);
  117. }
  118. nvs_close(nvs_handle);
  119. if (err == ESP_OK) {
  120. ESP_LOGW(TAG, "nvs_erase_key completed on empty key. Restarting system to apply changes.");
  121. esp_restart();
  122. }
  123. }
  124. if (err != ESP_OK) {
  125. ESP_LOGW(TAG, "nvs_erase_key failed on empty key. Configuration partition should be erased. %s", esp_err_to_name(err));
  126. err = ESP_OK;
  127. }
  128. }
  129. else {
  130. void* value = get_nvs_value_alloc(info.type, info.key);
  131. if (value == NULL) {
  132. ESP_LOGE(TAG, "nvs read failed.");
  133. return ESP_FAIL;
  134. }
  135. config_set_value(info.type, info.key, value);
  136. free(value);
  137. }
  138. }
  139. it = nvs_entry_next(it);
  140. }
  141. char* json_string = config_alloc_get_json(false);
  142. if (json_string != NULL) {
  143. ESP_LOGD(TAG, "config json : %s\n", json_string);
  144. free(json_string);
  145. }
  146. ESP_LOGW(TAG, "Configuration memory usage. Heap internal:%zu (min:%zu) (used:%zu) external:%zu (min:%zu) (used:%zd)",
  147. heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
  148. heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
  149. malloc_int - heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
  150. heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
  151. heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
  152. malloc_spiram - heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
  153. return err;
  154. }
  155. esp_err_t store_nvs_value(nvs_type_t type, const char *key, void * data) {
  156. if (type == NVS_TYPE_BLOB)
  157. return ESP_ERR_NVS_TYPE_MISMATCH;
  158. return store_nvs_value_len(type, key, data,0);
  159. }
  160. esp_err_t store_nvs_value_len_for_partition(const char * partition,const char * namespace,nvs_type_t type, const char *key, const void * data,size_t data_len) {
  161. esp_err_t err;
  162. nvs_handle nvs;
  163. if(!key || key[0]=='\0'){
  164. ESP_LOGE(TAG, "Cannot store value to nvs: key is empty");
  165. return ESP_ERR_INVALID_ARG;
  166. }
  167. if (type == NVS_TYPE_ANY) {
  168. return ESP_ERR_NVS_TYPE_MISMATCH;
  169. }
  170. err = nvs_open_from_partition(partition, namespace, NVS_READWRITE, &nvs);
  171. if (err != ESP_OK) {
  172. return err;
  173. }
  174. if (type == NVS_TYPE_I8) {
  175. err = nvs_set_i8(nvs, key, *(int8_t *) data);
  176. } else if (type == NVS_TYPE_U8) {
  177. err = nvs_set_u8(nvs, key, *(uint8_t *) data);
  178. } else if (type == NVS_TYPE_I16) {
  179. err = nvs_set_i16(nvs, key, *(int16_t *) data);
  180. } else if (type == NVS_TYPE_U16) {
  181. err = nvs_set_u16(nvs, key, *(uint16_t *) data);
  182. } else if (type == NVS_TYPE_I32) {
  183. err = nvs_set_i32(nvs, key, *(int32_t *) data);
  184. } else if (type == NVS_TYPE_U32) {
  185. err = nvs_set_u32(nvs, key, *(uint32_t *) data);
  186. } else if (type == NVS_TYPE_I64) {
  187. err = nvs_set_i64(nvs, key, *(int64_t *) data);
  188. } else if (type == NVS_TYPE_U64) {
  189. err = nvs_set_u64(nvs, key, *(uint64_t *) data);
  190. } else if (type == NVS_TYPE_STR) {
  191. err = nvs_set_str(nvs, key, data);
  192. } else if (type == NVS_TYPE_BLOB) {
  193. err = nvs_set_blob(nvs, key, (void *) data, data_len);
  194. }
  195. if (err == ESP_OK) {
  196. err = nvs_commit(nvs);
  197. if (err == ESP_OK) {
  198. ESP_LOGI(TAG, "Value stored under key '%s'", key);
  199. }
  200. }
  201. nvs_close(nvs);
  202. return err;
  203. }
  204. esp_err_t store_nvs_value_len(nvs_type_t type, const char *key, void * data,
  205. size_t data_len) {
  206. return store_nvs_value_len_for_partition(settings_partition,current_namespace,type,key,data,data_len);
  207. }
  208. void * get_nvs_value_alloc_for_partition(const char * partition,const char * namespace,nvs_type_t type, const char *key, size_t * size){
  209. nvs_handle nvs;
  210. esp_err_t err;
  211. void * value=NULL;
  212. if(size){
  213. *size=0;
  214. }
  215. err = nvs_open_from_partition(partition, namespace, NVS_READONLY, &nvs);
  216. if (err != ESP_OK) {
  217. ESP_LOGE(TAG, "Could not open the nvs storage.");
  218. return NULL;
  219. }
  220. if (type == NVS_TYPE_I8) {
  221. value=malloc_init_external(sizeof(int8_t));
  222. err = nvs_get_i8(nvs, key, (int8_t *) value);
  223. } else if (type == NVS_TYPE_U8) {
  224. value=malloc_init_external(sizeof(uint8_t));
  225. err = nvs_get_u8(nvs, key, (uint8_t *) value);
  226. } else if (type == NVS_TYPE_I16) {
  227. value=malloc_init_external(sizeof(int16_t));
  228. err = nvs_get_i16(nvs, key, (int16_t *) value);
  229. } else if (type == NVS_TYPE_U16) {
  230. value=malloc_init_external(sizeof(uint16_t));
  231. err = nvs_get_u16(nvs, key, (uint16_t *) value);
  232. } else if (type == NVS_TYPE_I32) {
  233. value=malloc_init_external(sizeof(int32_t));
  234. err = nvs_get_i32(nvs, key, (int32_t *) value);
  235. } else if (type == NVS_TYPE_U32) {
  236. value=malloc_init_external(sizeof(uint32_t));
  237. err = nvs_get_u32(nvs, key, (uint32_t *) value);
  238. } else if (type == NVS_TYPE_I64) {
  239. value=malloc_init_external(sizeof(int64_t));
  240. err = nvs_get_i64(nvs, key, (int64_t *) value);
  241. } else if (type == NVS_TYPE_U64) {
  242. value=malloc_init_external(sizeof(uint64_t));
  243. err = nvs_get_u64(nvs, key, (uint64_t *) value);
  244. } else if (type == NVS_TYPE_STR) {
  245. size_t len=0;
  246. err = nvs_get_str(nvs, key, NULL, &len);
  247. if (err == ESP_OK) {
  248. value=malloc_init_external(len+1);
  249. err = nvs_get_str(nvs, key, value, &len);
  250. if(size){
  251. *size=len;
  252. }
  253. }
  254. } else if (type == NVS_TYPE_BLOB) {
  255. size_t len;
  256. err = nvs_get_blob(nvs, key, NULL, &len);
  257. if (err == ESP_OK) {
  258. value=malloc_init_external(len+1);
  259. if(size){
  260. *size=len;
  261. }
  262. err = nvs_get_blob(nvs, key, value, &len);
  263. }
  264. }
  265. if(err!=ESP_OK){
  266. ESP_LOGD(TAG, "Value not found for key %s",key);
  267. if(value!=NULL)
  268. free(value);
  269. value=NULL;
  270. }
  271. nvs_close(nvs);
  272. return value;
  273. }
  274. void * get_nvs_value_alloc(nvs_type_t type, const char *key) {
  275. return get_nvs_value_alloc_for_partition(settings_partition, current_namespace,type,key,NULL);
  276. }
  277. esp_err_t get_nvs_value(nvs_type_t type, const char *key, void*value, const uint8_t buf_size) {
  278. nvs_handle nvs;
  279. esp_err_t err;
  280. err = nvs_open_from_partition(settings_partition, current_namespace, NVS_READONLY, &nvs);
  281. if (err != ESP_OK) {
  282. return err;
  283. }
  284. if (type == NVS_TYPE_I8) {
  285. err = nvs_get_i8(nvs, key, (int8_t *) value);
  286. } else if (type == NVS_TYPE_U8) {
  287. err = nvs_get_u8(nvs, key, (uint8_t *) value);
  288. } else if (type == NVS_TYPE_I16) {
  289. err = nvs_get_i16(nvs, key, (int16_t *) value);
  290. } else if (type == NVS_TYPE_U16) {
  291. err = nvs_get_u16(nvs, key, (uint16_t *) value);
  292. } else if (type == NVS_TYPE_I32) {
  293. err = nvs_get_i32(nvs, key, (int32_t *) value);
  294. } else if (type == NVS_TYPE_U32) {
  295. err = nvs_get_u32(nvs, key, (uint32_t *) value);
  296. } else if (type == NVS_TYPE_I64) {
  297. err = nvs_get_i64(nvs, key, (int64_t *) value);
  298. } else if (type == NVS_TYPE_U64) {
  299. err = nvs_get_u64(nvs, key, (uint64_t *) value);
  300. } else if (type == NVS_TYPE_STR) {
  301. size_t len;
  302. if ((err = nvs_get_str(nvs, key, NULL, &len)) == ESP_OK) {
  303. if (len > buf_size) {
  304. //ESP_LOGE("Error reading value for %s. Buffer size: %d, Value Length: %d", key, buf_size, len);
  305. err = ESP_FAIL;
  306. } else {
  307. err = nvs_get_str(nvs, key, value, &len);
  308. }
  309. }
  310. } else if (type == NVS_TYPE_BLOB) {
  311. size_t len;
  312. if ((err = nvs_get_blob(nvs, key, NULL, &len)) == ESP_OK) {
  313. if (len > buf_size) {
  314. //ESP_LOGE("Error reading value for %s. Buffer size: %d, Value Length: %d",
  315. // key, buf_size, len);
  316. err = ESP_FAIL;
  317. } else {
  318. err = nvs_get_blob(nvs, key, value, &len);
  319. }
  320. }
  321. }
  322. nvs_close(nvs);
  323. return err;
  324. }
  325. esp_err_t erase_nvs_for_partition(const char * partition, const char * namespace,const char *key)
  326. {
  327. nvs_handle nvs;
  328. esp_err_t err = nvs_open_from_partition(partition,namespace, NVS_READWRITE, &nvs);
  329. if (err == ESP_OK) {
  330. err = nvs_erase_key(nvs, key);
  331. if (err == ESP_OK) {
  332. err = nvs_commit(nvs);
  333. if (err == ESP_OK) {
  334. ESP_LOGI(TAG, "Value with key '%s' erased", key);
  335. }
  336. }
  337. nvs_close(nvs);
  338. }
  339. else {
  340. ESP_LOGE(TAG,"Could not erase key %s from partition %s namespace %s : %s", key,partition,namespace, esp_err_to_name(err));
  341. }
  342. return err;
  343. }
  344. esp_err_t erase_nvs(const char *key)
  345. {
  346. return erase_nvs_for_partition(NVS_DEFAULT_PART_NAME, current_namespace,key);
  347. }
  348. esp_err_t erase_nvs_partition(const char * partition, const char * namespace){
  349. nvs_handle nvs;
  350. const char * step = "Opening";
  351. ESP_LOGD(TAG,"%s partition %s, namespace %s ",step,partition,namespace);
  352. esp_err_t err = nvs_open_from_partition(partition,namespace, NVS_READWRITE, &nvs);
  353. if (err == ESP_OK) {
  354. step = "Erasing";
  355. ESP_LOGD(TAG,"%s namespace %s ",step,partition);
  356. err = nvs_erase_all(nvs);
  357. if (err == ESP_OK) {
  358. step = "Committing";
  359. ESP_LOGD(TAG,"%s",step);
  360. err = nvs_commit(nvs);
  361. }
  362. }
  363. if(err !=ESP_OK){
  364. ESP_LOGE(TAG,"%s partition %s, name space %s : %s",step,partition,namespace,esp_err_to_name(err));
  365. }
  366. ESP_LOGD(TAG,"Closing %s ",namespace);
  367. nvs_close(nvs);
  368. return err;
  369. }