cmd_nvs.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. /* Console example — NVS commands
  2. This example code is in the Public Domain (or CC0 licensed, at your option.)
  3. Unless required by applicable law or agreed to in writing, this
  4. software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  5. CONDITIONS OF ANY KIND, either express or implied.
  6. */
  7. #ifdef __cplusplus
  8. extern "C" {
  9. #endif
  10. #include "nvs_flash.h"
  11. #include <stdio.h>
  12. #include <errno.h>
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #include <inttypes.h>
  16. #include "esp_log.h"
  17. #include "esp_console.h"
  18. #include "argtable3/argtable3.h"
  19. #include "freertos/FreeRTOS.h"
  20. #include "freertos/event_groups.h"
  21. #include "esp_err.h"
  22. #include "cmd_nvs.h"
  23. #include "nvs.h"
  24. typedef struct {
  25. nvs_type_t type;
  26. const char *str;
  27. } type_str_pair_t;
  28. static const type_str_pair_t type_str_pair[] = {
  29. { NVS_TYPE_I8, "i8" },
  30. { NVS_TYPE_U8, "u8" },
  31. { NVS_TYPE_U16, "u16" },
  32. { NVS_TYPE_I16, "i16" },
  33. { NVS_TYPE_U32, "u32" },
  34. { NVS_TYPE_I32, "i32" },
  35. { NVS_TYPE_U64, "u64" },
  36. { NVS_TYPE_I64, "i64" },
  37. { NVS_TYPE_STR, "str" },
  38. { NVS_TYPE_BLOB, "blob" },
  39. { NVS_TYPE_ANY, "any" },
  40. };
  41. static const size_t TYPE_STR_PAIR_SIZE = sizeof(type_str_pair) / sizeof(type_str_pair[0]);
  42. static const char *ARG_TYPE_STR = "type can be: i8, u8, i16, u16 i32, u32 i64, u64, str, blob";
  43. char current_namespace[16] = "storage";
  44. static const char * TAG = "platform_esp32";
  45. static struct {
  46. struct arg_str *key;
  47. struct arg_str *type;
  48. struct arg_str *value;
  49. struct arg_end *end;
  50. } set_args;
  51. static struct {
  52. struct arg_str *key;
  53. struct arg_str *type;
  54. struct arg_end *end;
  55. } get_args;
  56. static struct {
  57. struct arg_str *key;
  58. struct arg_end *end;
  59. } erase_args;
  60. static struct {
  61. struct arg_str *namespace;
  62. struct arg_end *end;
  63. } erase_all_args;
  64. static struct {
  65. struct arg_str *namespace;
  66. struct arg_end *end;
  67. } namespace_args;
  68. static struct {
  69. struct arg_str *partition;
  70. struct arg_str *namespace;
  71. struct arg_str *type;
  72. struct arg_end *end;
  73. } list_args;
  74. static nvs_type_t str_to_type(const char *type)
  75. {
  76. for (int i = 0; i < TYPE_STR_PAIR_SIZE; i++) {
  77. const type_str_pair_t *p = &type_str_pair[i];
  78. if (strcmp(type, p->str) == 0) {
  79. return p->type;
  80. }
  81. }
  82. return NVS_TYPE_ANY;
  83. }
  84. static esp_err_t store_blob(nvs_handle nvs, const char *key, const char *str_values)
  85. {
  86. uint8_t value;
  87. size_t str_len = strlen(str_values);
  88. size_t blob_len = str_len / 2;
  89. if (str_len % 2) {
  90. ESP_LOGE(TAG, "Blob data must contain even number of characters");
  91. return ESP_ERR_NVS_TYPE_MISMATCH;
  92. }
  93. char *blob = (char *)malloc(blob_len);
  94. if (blob == NULL) {
  95. return ESP_ERR_NO_MEM;
  96. }
  97. for (int i = 0, j = 0; i < str_len; i++) {
  98. char ch = str_values[i];
  99. if (ch >= '0' && ch <= '9') {
  100. value = ch - '0';
  101. } else if (ch >= 'A' && ch <= 'F') {
  102. value = ch - 'A' + 10;
  103. } else if (ch >= 'a' && ch <= 'f') {
  104. value = ch - 'a' + 10;
  105. } else {
  106. ESP_LOGE(TAG, "Blob data contain invalid character");
  107. free(blob);
  108. return ESP_ERR_NVS_TYPE_MISMATCH;
  109. }
  110. if (i & 1) {
  111. blob[j++] += value;
  112. } else {
  113. blob[j] = value << 4;
  114. }
  115. }
  116. esp_err_t err = nvs_set_blob(nvs, key, blob, blob_len);
  117. free(blob);
  118. if (err == ESP_OK) {
  119. err = nvs_commit(nvs);
  120. }
  121. return err;
  122. }
  123. static void print_blob(const char *blob, size_t len)
  124. {
  125. for (int i = 0; i < len; i++) {
  126. printf("%02x", blob[i]);
  127. }
  128. printf("\n");
  129. }
  130. static esp_err_t set_value_in_nvs(const char *key, const char *str_type, const char *str_value)
  131. {
  132. esp_err_t err;
  133. nvs_handle nvs;
  134. bool range_error = false;
  135. nvs_type_t type = str_to_type(str_type);
  136. if (type == NVS_TYPE_ANY) {
  137. return ESP_ERR_NVS_TYPE_MISMATCH;
  138. }
  139. err = nvs_open(current_namespace, NVS_READWRITE, &nvs);
  140. if (err != ESP_OK) {
  141. return err;
  142. }
  143. if (type == NVS_TYPE_I8) {
  144. int32_t value = strtol(str_value, NULL, 0);
  145. if (value < INT8_MIN || value > INT8_MAX || errno == ERANGE) {
  146. range_error = true;
  147. } else {
  148. err = nvs_set_i8(nvs, key, (int8_t)value);
  149. }
  150. } else if (type == NVS_TYPE_U8) {
  151. uint32_t value = strtoul(str_value, NULL, 0);
  152. if (value > UINT8_MAX || errno == ERANGE) {
  153. range_error = true;
  154. } else {
  155. err = nvs_set_u8(nvs, key, (uint8_t)value);
  156. }
  157. } else if (type == NVS_TYPE_I16) {
  158. int32_t value = strtol(str_value, NULL, 0);
  159. if (value < INT16_MIN || value > INT16_MAX || errno == ERANGE) {
  160. range_error = true;
  161. } else {
  162. err = nvs_set_i16(nvs, key, (int16_t)value);
  163. }
  164. } else if (type == NVS_TYPE_U16) {
  165. uint32_t value = strtoul(str_value, NULL, 0);
  166. if (value > UINT16_MAX || errno == ERANGE) {
  167. range_error = true;
  168. } else {
  169. err = nvs_set_u16(nvs, key, (uint16_t)value);
  170. }
  171. } else if (type == NVS_TYPE_I32) {
  172. int32_t value = strtol(str_value, NULL, 0);
  173. if (errno != ERANGE) {
  174. err = nvs_set_i32(nvs, key, value);
  175. }
  176. } else if (type == NVS_TYPE_U32) {
  177. uint32_t value = strtoul(str_value, NULL, 0);
  178. if (errno != ERANGE) {
  179. err = nvs_set_u32(nvs, key, value);
  180. }
  181. } else if (type == NVS_TYPE_I64) {
  182. int64_t value = strtoll(str_value, NULL, 0);
  183. if (errno != ERANGE) {
  184. err = nvs_set_i64(nvs, key, value);
  185. }
  186. } else if (type == NVS_TYPE_U64) {
  187. uint64_t value = strtoull(str_value, NULL, 0);
  188. if (errno != ERANGE) {
  189. err = nvs_set_u64(nvs, key, value);
  190. }
  191. } else if (type == NVS_TYPE_STR) {
  192. err = nvs_set_str(nvs, key, str_value);
  193. } else if (type == NVS_TYPE_BLOB) {
  194. err = store_blob(nvs, key, str_value);
  195. }
  196. if (range_error || errno == ERANGE) {
  197. nvs_close(nvs);
  198. return ESP_ERR_NVS_VALUE_TOO_LONG;
  199. }
  200. if (err == ESP_OK) {
  201. ESP_LOGI(TAG, "Set value ok. Committing '%s'", key);
  202. err = nvs_commit(nvs);
  203. if (err == ESP_OK) {
  204. ESP_LOGI(TAG, "Value stored under key '%s'", key);
  205. }
  206. }
  207. nvs_close(nvs);
  208. return err;
  209. }
  210. static esp_err_t get_value_from_nvs(const char *key, const char *str_type)
  211. {
  212. nvs_handle nvs;
  213. esp_err_t err;
  214. nvs_type_t type = str_to_type(str_type);
  215. if (type == NVS_TYPE_ANY) {
  216. return ESP_ERR_NVS_TYPE_MISMATCH;
  217. }
  218. err = nvs_open(current_namespace, NVS_READONLY, &nvs);
  219. if (err != ESP_OK) {
  220. return err;
  221. }
  222. if (type == NVS_TYPE_I8) {
  223. int8_t value;
  224. err = nvs_get_i8(nvs, key, &value);
  225. if (err == ESP_OK) {
  226. printf("Value associated with key '%s' is %d \n", key, value);
  227. }
  228. } else if (type == NVS_TYPE_U8) {
  229. uint8_t value;
  230. err = nvs_get_u8(nvs, key, &value);
  231. if (err == ESP_OK) {
  232. printf("Value associated with key '%s' is %u \n", key, value);
  233. }
  234. } else if (type == NVS_TYPE_I16) {
  235. int16_t value;
  236. err = nvs_get_i16(nvs, key, &value);
  237. if (err == ESP_OK) {
  238. printf("Value associated with key '%s' is %d \n", key, value);
  239. }
  240. } else if (type == NVS_TYPE_U16) {
  241. uint16_t value;
  242. if ((err = nvs_get_u16(nvs, key, &value)) == ESP_OK) {
  243. printf("Value associated with key '%s' is %u", key, value);
  244. }
  245. } else if (type == NVS_TYPE_I32) {
  246. int32_t value;
  247. if ((err = nvs_get_i32(nvs, key, &value)) == ESP_OK) {
  248. printf("Value associated with key '%s' is %d \n", key, value);
  249. }
  250. } else if (type == NVS_TYPE_U32) {
  251. uint32_t value;
  252. if ((err = nvs_get_u32(nvs, key, &value)) == ESP_OK) {
  253. printf("Value associated with key '%s' is %u \n", key, value);
  254. }
  255. } else if (type == NVS_TYPE_I64) {
  256. int64_t value;
  257. if ((err = nvs_get_i64(nvs, key, &value)) == ESP_OK) {
  258. printf("Value associated with key '%s' is %lld \n", key, value);
  259. }
  260. } else if (type == NVS_TYPE_U64) {
  261. uint64_t value;
  262. if ( (err = nvs_get_u64(nvs, key, &value)) == ESP_OK) {
  263. printf("Value associated with key '%s' is %llu \n", key, value);
  264. }
  265. } else if (type == NVS_TYPE_STR) {
  266. size_t len=0;
  267. if ( (err = nvs_get_str(nvs, key, NULL, &len)) == ESP_OK) {
  268. char *str = (char *)malloc(len);
  269. if ( (err = nvs_get_str(nvs, key, str, &len)) == ESP_OK) {
  270. printf("String associated with key '%s' is %s \n", key, str);
  271. }
  272. free(str);
  273. }
  274. } else if (type == NVS_TYPE_BLOB) {
  275. size_t len;
  276. if ( (err = nvs_get_blob(nvs, key, NULL, &len)) == ESP_OK) {
  277. char *blob = (char *)malloc(len);
  278. if ( (err = nvs_get_blob(nvs, key, blob, &len)) == ESP_OK) {
  279. printf("Blob associated with key '%s' is %d bytes long: \n", key, len);
  280. print_blob(blob, len);
  281. }
  282. free(blob);
  283. }
  284. }
  285. nvs_close(nvs);
  286. return err;
  287. }
  288. static esp_err_t erase(const char *key)
  289. {
  290. nvs_handle nvs;
  291. esp_err_t err = nvs_open(current_namespace, NVS_READWRITE, &nvs);
  292. if (err == ESP_OK) {
  293. err = nvs_erase_key(nvs, key);
  294. if (err == ESP_OK) {
  295. err = nvs_commit(nvs);
  296. if (err == ESP_OK) {
  297. ESP_LOGI(TAG, "Value with key '%s' erased", key);
  298. }
  299. }
  300. nvs_close(nvs);
  301. }
  302. return err;
  303. }
  304. static esp_err_t erase_all(const char *name)
  305. {
  306. nvs_handle nvs;
  307. esp_err_t err = nvs_open(current_namespace, NVS_READWRITE, &nvs);
  308. if (err == ESP_OK) {
  309. err = nvs_erase_all(nvs);
  310. if (err == ESP_OK) {
  311. err = nvs_commit(nvs);
  312. }
  313. }
  314. ESP_LOGI(TAG, "Namespace '%s' was %s erased", name, (err == ESP_OK) ? "" : "not");
  315. nvs_close(nvs);
  316. return ESP_OK;
  317. }
  318. static int set_value(int argc, char **argv)
  319. {
  320. ESP_LOGD(TAG, "%s %u - Parsing keys ",__func__,__LINE__);
  321. int nerrors = arg_parse(argc, argv, (void **) &set_args);
  322. if (nerrors != 0) {
  323. ESP_LOGE(TAG, "%s %u - Error Parsing keys ",__func__,__LINE__);
  324. arg_print_errors(stderr, set_args.end, argv[0]);
  325. return 1;
  326. }
  327. const char *key = set_args.key->sval[0];
  328. const char *type = set_args.type->sval[0];
  329. const char *values = set_args.value->sval[0];
  330. ESP_LOGI(TAG, "Setting '%s' (type %s)", key,type);
  331. esp_err_t err = set_value_in_nvs(key, type, values);
  332. if (err != ESP_OK) {
  333. ESP_LOGE(TAG, "%s", esp_err_to_name(err));
  334. return 1;
  335. }
  336. return 0;
  337. }
  338. static int get_value(int argc, char **argv)
  339. {
  340. int nerrors = arg_parse(argc, argv, (void **) &get_args);
  341. if (nerrors != 0) {
  342. arg_print_errors(stderr, get_args.end, argv[0]);
  343. return 1;
  344. }
  345. const char *key = get_args.key->sval[0];
  346. const char *type = get_args.type->sval[0];
  347. esp_err_t err = get_value_from_nvs(key, type);
  348. if (err != ESP_OK) {
  349. ESP_LOGE(TAG, "%s", esp_err_to_name(err));
  350. return 1;
  351. }
  352. return 0;
  353. }
  354. static int erase_value(int argc, char **argv)
  355. {
  356. int nerrors = arg_parse(argc, argv, (void **) &erase_args);
  357. if (nerrors != 0) {
  358. arg_print_errors(stderr, erase_args.end, argv[0]);
  359. return 1;
  360. }
  361. const char *key = erase_args.key->sval[0];
  362. esp_err_t err = erase(key);
  363. if (err != ESP_OK) {
  364. ESP_LOGE(TAG, "%s", esp_err_to_name(err));
  365. return 1;
  366. }
  367. return 0;
  368. }
  369. static int erase_namespace(int argc, char **argv)
  370. {
  371. int nerrors = arg_parse(argc, argv, (void **) &erase_all_args);
  372. if (nerrors != 0) {
  373. arg_print_errors(stderr, erase_all_args.end, argv[0]);
  374. return 1;
  375. }
  376. const char *name = erase_all_args.namespace->sval[0];
  377. esp_err_t err = erase_all(name);
  378. if (err != ESP_OK) {
  379. ESP_LOGE(TAG, "%s", esp_err_to_name(err));
  380. return 1;
  381. }
  382. return 0;
  383. }
  384. static int set_namespace(int argc, char **argv)
  385. {
  386. int nerrors = arg_parse(argc, argv, (void **) &namespace_args);
  387. if (nerrors != 0) {
  388. arg_print_errors(stderr, namespace_args.end, argv[0]);
  389. return 1;
  390. }
  391. const char *namespace = namespace_args.namespace->sval[0];
  392. strlcpy(current_namespace, namespace, sizeof(current_namespace));
  393. ESP_LOGI(TAG, "Namespace set to '%s'", current_namespace);
  394. return 0;
  395. }
  396. #ifdef ESP_IDF_COMMIT_bde1c30 // this commit added support for listing nvs entries
  397. static int list(const char *part, const char *name, const char *str_type)
  398. {
  399. nvs_type_t type = str_to_type(str_type);
  400. nvs_iterator_t it = nvs_entry_find(part, NULL, type);
  401. if (it == NULL) {
  402. ESP_LOGE(TAG, "No such enty was found");
  403. return 1;
  404. }
  405. do {
  406. nvs_entry_info_t info;
  407. nvs_entry_info(it, &info);
  408. it = nvs_entry_next(it);
  409. printf("namespace '%s', key '%s', type '%s' \n",
  410. info.namespace_name, info.key, type_to_str(info.type));
  411. } while (it != NULL);
  412. return 0;
  413. }
  414. static int list_entries(int argc, char **argv)
  415. {
  416. list_args.partition->sval[0] = "";
  417. list_args.namespace->sval[0] = "";
  418. list_args.type->sval[0] = "";
  419. int nerrors = arg_parse(argc, argv, (void **) &list_args);
  420. if (nerrors != 0) {
  421. arg_print_errors(stderr, list_args.end, argv[0]);
  422. return 1;
  423. }
  424. const char *part = list_args.partition->sval[0];
  425. const char *name = list_args.namespace->sval[0];
  426. const char *type = list_args.type->sval[0];
  427. return list(part, name, type);
  428. }
  429. #endif
  430. void register_nvs()
  431. {
  432. esp_log_level_set(TAG, ESP_LOG_VERBOSE);
  433. set_args.key = arg_str1(NULL, NULL, "<key>", "key of the value to be set");
  434. set_args.type = arg_str1(NULL, NULL, "<type>", ARG_TYPE_STR);
  435. set_args.value = arg_str1("v", "value", "<value>", "value to be stored");
  436. set_args.end = arg_end(2);
  437. get_args.key = arg_str1(NULL, NULL, "<key>", "key of the value to be read");
  438. get_args.type = arg_str1(NULL, NULL, "<type>", ARG_TYPE_STR);
  439. get_args.end = arg_end(2);
  440. erase_args.key = arg_str1(NULL, NULL, "<key>", "key of the value to be erased");
  441. erase_args.end = arg_end(2);
  442. erase_all_args.namespace = arg_str1(NULL, NULL, "<namespace>", "namespace to be erased");
  443. erase_all_args.end = arg_end(2);
  444. namespace_args.namespace = arg_str1(NULL, NULL, "<namespace>", "namespace of the partition to be selected");
  445. namespace_args.end = arg_end(2);
  446. const esp_console_cmd_t set_cmd = {
  447. .command = "nvs_set",
  448. .help = "Set variable in selected namespace. Blob type must be comma separated list of hex values. \n"
  449. "Examples:\n"
  450. " nvs_set VarName i32 -v 123 \n"
  451. " nvs_set VarName srt -v YourString \n"
  452. " nvs_set VarName blob -v 0123456789abcdef \n",
  453. .hint = NULL,
  454. .func = &set_value,
  455. .argtable = &set_args
  456. };
  457. const esp_console_cmd_t get_cmd = {
  458. .command = "nvs_get",
  459. .help = "Get variable from selected namespace. \n"
  460. "Example: nvs_get VarName i32",
  461. .hint = NULL,
  462. .func = &get_value,
  463. .argtable = &get_args
  464. };
  465. const esp_console_cmd_t erase_cmd = {
  466. .command = "nvs_erase",
  467. .help = "Erase variable from current namespace",
  468. .hint = NULL,
  469. .func = &erase_value,
  470. .argtable = &erase_args
  471. };
  472. const esp_console_cmd_t erase_namespace_cmd = {
  473. .command = "nvs_erase_namespace",
  474. .help = "Erases specified namespace",
  475. .hint = NULL,
  476. .func = &erase_namespace,
  477. .argtable = &erase_all_args
  478. };
  479. const esp_console_cmd_t namespace_cmd = {
  480. .command = "nvs_namespace",
  481. .help = "Set current namespace",
  482. .hint = NULL,
  483. .func = &set_namespace,
  484. .argtable = &namespace_args
  485. };
  486. #ifdef ESP_IDF_COMMIT_bde1c30 // this commit added support for listing nvs entries
  487. const esp_console_cmd_t list_entries_cmd = {
  488. .command = "nvs_list",
  489. .help = "List stored key-value pairs stored in NVS."
  490. "Namespace and type can be specified to print only those key-value pairs.\n"
  491. "Following command list variables stored inside 'nvs' partition, under namespace 'storage' with type uint32_t"
  492. "Example: nvs_list nvs -n storage -t u32 \n",
  493. .hint = NULL,
  494. .func = &list_entries,
  495. .argtable = &list_args
  496. };
  497. ESP_ERROR_CHECK(esp_console_cmd_register(&list_entries_cmd));
  498. #endif
  499. ESP_ERROR_CHECK(esp_console_cmd_register(&set_cmd));
  500. ESP_ERROR_CHECK(esp_console_cmd_register(&get_cmd));
  501. ESP_ERROR_CHECK(esp_console_cmd_register(&erase_cmd));
  502. ESP_ERROR_CHECK(esp_console_cmd_register(&namespace_cmd));
  503. ESP_ERROR_CHECK(esp_console_cmd_register(&erase_namespace_cmd));
  504. }
  505. #ifdef __cplusplus
  506. extern }
  507. #endif