cli.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. /**
  2. * Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Nordic
  13. * Semiconductor ASA integrated circuit in a product or a software update for
  14. * such product, must reproduce the above copyright notice, this list of
  15. * conditions and the following disclaimer in the documentation and/or other
  16. * materials provided with the distribution.
  17. *
  18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * 4. This software, with or without modification, must only be used with a
  23. * Nordic Semiconductor ASA integrated circuit.
  24. *
  25. * 5. Any software provided in binary form under this license must not be reverse
  26. * engineered, decompiled, modified and/or disassembled.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. */
  40. #include <string.h>
  41. #include "app_error.h"
  42. #include "boards.h"
  43. #include "nrf_cli.h"
  44. #include "nrf_cli_uart.h"
  45. #include "nrf_drv_uart.h"
  46. #include "fds.h"
  47. #include "nrf_soc.h"
  48. #include "sdk_config.h"
  49. #include "fds_example.h"
  50. #define PRINT_HELP "print records\n" \
  51. "usage: print all|config"
  52. #define PRINT_ALL_HELP "print all records\n" \
  53. "usage: print all"
  54. #define PRINT_CFG_HELP "print configuration\n" \
  55. "usage: print config"
  56. #define WRITE_HELP "write a record\n" \
  57. "usage: write file_id key \"data\"\n" \
  58. "- file_id:\tfile ID, in HEX\n" \
  59. "- key:\trecord key, in HEX\n" \
  60. "- data:\trecord contents"
  61. #define DELETE_HELP "delete a record\n" \
  62. "usage: delete file_id key\n" \
  63. "- file_id:\tfile ID, in HEX\n" \
  64. "- key:\trecord key, in HEX\n" \
  65. #define DELETE_ALL_HELP "delete all records\n" \
  66. "usage: delete_all" \
  67. #define UPDATE_HELP "update configuration\n" \
  68. "usage: update on|off on|off boot_count device_name" \
  69. #define STAT_HELP "print statistics\n" \
  70. "usage: stat"
  71. #define GC_HELP "run garbage collection\n" \
  72. "usage: gc"
  73. NRF_CLI_UART_DEF(cli_uart, 0, 64, 16);
  74. NRF_CLI_DEF(m_cli_uart, "fds example:~$ ", &cli_uart.transport, '\r', 4);
  75. /* Defined in main.c */
  76. extern char const * fds_err_str(ret_code_t ret);
  77. void cli_init(void)
  78. {
  79. nrf_drv_uart_config_t uart_config = NRF_DRV_UART_DEFAULT_CONFIG;
  80. uart_config.pseltxd = TX_PIN_NUMBER;
  81. uart_config.pselrxd = RX_PIN_NUMBER;
  82. uart_config.hwfc = NRF_UART_HWFC_DISABLED;
  83. ret_code_t rc = nrf_cli_init(&m_cli_uart, &uart_config, true, true, NRF_LOG_SEVERITY_INFO);
  84. APP_ERROR_CHECK(rc);
  85. }
  86. void cli_start(void)
  87. {
  88. ret_code_t rc = nrf_cli_start(&m_cli_uart);
  89. APP_ERROR_CHECK(rc);
  90. }
  91. void cli_process(void)
  92. {
  93. nrf_cli_process(&m_cli_uart);
  94. }
  95. static void cli_unknown_param_help(nrf_cli_t const * p_cli,
  96. char const * p_param,
  97. char const * p_cmd)
  98. {
  99. nrf_cli_fprintf(p_cli,
  100. NRF_CLI_ERROR,
  101. "%s: unknown parameter '%s'\n"
  102. "Try '%s -h' for help.\n",
  103. p_cmd,
  104. p_param,
  105. p_cmd);
  106. }
  107. static void cli_wrong_param_count_help(nrf_cli_t const * p_cli, char const * p_cmd)
  108. {
  109. nrf_cli_fprintf(p_cli,
  110. NRF_CLI_ERROR,
  111. "%s: wrong parameter count.\n"
  112. "Try '%s -h' for help.\n",
  113. p_cmd,
  114. p_cmd);
  115. }
  116. static void record_write(nrf_cli_t const * p_cli,
  117. uint32_t fid,
  118. uint32_t key,
  119. void const * p_data,
  120. uint32_t len)
  121. {
  122. fds_record_t const rec =
  123. {
  124. .file_id = fid,
  125. .key = key,
  126. .data.p_data = p_data,
  127. .data.length_words = (len + 3) / sizeof(uint32_t)
  128. };
  129. nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
  130. "writing record to flash...\n"
  131. "file: 0x%x, key: 0x%x, \"%s\", len: %u bytes\n",
  132. fid, key, p_data, len);
  133. ret_code_t rc = fds_record_write(NULL, &rec);
  134. if (rc != NRF_SUCCESS)
  135. {
  136. nrf_cli_fprintf(p_cli, NRF_CLI_ERROR,
  137. "error: fds_record_write() returned %s.\n",
  138. fds_err_str(rc));
  139. }
  140. }
  141. static void record_update(nrf_cli_t const * p_cli, configuration_t const * p_cfg)
  142. {
  143. fds_record_desc_t desc = {0};
  144. fds_find_token_t ftok = {0};
  145. if (fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &ftok) == NRF_SUCCESS)
  146. {
  147. fds_record_t const rec =
  148. {
  149. .file_id = CONFIG_FILE,
  150. .key = CONFIG_REC_KEY,
  151. .data.p_data = p_cfg,
  152. .data.length_words = (sizeof(configuration_t) + 3) / sizeof(uint32_t)
  153. };
  154. ret_code_t rc = fds_record_update(&desc, &rec);
  155. if (rc != NRF_SUCCESS)
  156. {
  157. nrf_cli_fprintf(p_cli, NRF_CLI_ERROR,
  158. "error: fds_record_update() returned %s.\n",
  159. fds_err_str(rc));
  160. }
  161. }
  162. else
  163. {
  164. nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "error: could not find config file.\n");
  165. }
  166. }
  167. static void record_delete(nrf_cli_t const * p_cli, uint32_t fid, uint32_t key)
  168. {
  169. fds_find_token_t tok = {0};
  170. fds_record_desc_t desc = {0};
  171. nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
  172. "deleting record...\n"
  173. "file: 0x%x, key: 0x%x\n",
  174. fid,
  175. key);
  176. if (fds_record_find(fid, key, &desc, &tok) == NRF_SUCCESS)
  177. {
  178. ret_code_t rc = fds_record_delete(&desc);
  179. if (rc != NRF_SUCCESS)
  180. {
  181. nrf_cli_fprintf(p_cli, NRF_CLI_ERROR,
  182. "error: fds_record_delete() returned %s.\n", fds_err_str(rc));
  183. return;
  184. }
  185. nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT, "record id: 0x%x\n", desc.record_id);
  186. }
  187. else
  188. {
  189. nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "error: record not found!\n");
  190. }
  191. }
  192. bool record_delete_next(void)
  193. {
  194. fds_find_token_t tok = {0};
  195. fds_record_desc_t desc = {0};
  196. if (fds_record_iterate(&desc, &tok) == NRF_SUCCESS)
  197. {
  198. ret_code_t rc = fds_record_delete(&desc);
  199. if (rc != NRF_SUCCESS)
  200. {
  201. return false;
  202. }
  203. return true;
  204. }
  205. else
  206. {
  207. /* No records left to delete. */
  208. return false;
  209. }
  210. }
  211. static void print_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
  212. {
  213. if (nrf_cli_help_requested(p_cli))
  214. {
  215. nrf_cli_help_print(p_cli, NULL, 0);
  216. }
  217. else if (argc != 2)
  218. {
  219. cli_wrong_param_count_help(p_cli, "print");
  220. }
  221. else
  222. {
  223. cli_unknown_param_help(p_cli, argv[1], "print");
  224. }
  225. }
  226. static void print_cfg_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
  227. {
  228. fds_record_desc_t desc = {0};
  229. fds_find_token_t tok = {0};
  230. while (fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok) == NRF_SUCCESS)
  231. {
  232. ret_code_t rc;
  233. fds_flash_record_t frec = {0};
  234. rc = fds_record_open(&desc, &frec);
  235. switch (rc)
  236. {
  237. case NRF_SUCCESS:
  238. break;
  239. case FDS_ERR_CRC_CHECK_FAILED:
  240. nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "error: CRC check failed!\n");
  241. continue;
  242. case FDS_ERR_NOT_FOUND:
  243. nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "error: record not found!\n");
  244. continue;
  245. default:
  246. {
  247. nrf_cli_fprintf(p_cli, NRF_CLI_ERROR,
  248. "error: unexpecte error %s.\n",
  249. fds_err_str(rc));
  250. continue;
  251. }
  252. }
  253. configuration_t * p_cfg = (configuration_t *)(frec.p_data);
  254. nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
  255. "config1:\t%s\n"
  256. "config2:\t%s\n"
  257. "boot count:\t%u\n"
  258. "device name:\t%s\n",
  259. p_cfg->config1_on ? "on" : "off",
  260. p_cfg->config2_on ? "on" : "off",
  261. p_cfg->boot_count,
  262. p_cfg->device_name);
  263. rc = fds_record_close(&desc);
  264. APP_ERROR_CHECK(rc);
  265. }
  266. }
  267. static void print_all_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
  268. {
  269. fds_find_token_t tok = {0};
  270. fds_record_desc_t desc = {0};
  271. nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
  272. "rec. id\t"
  273. "\tfile id\t"
  274. "\trec. key"
  275. "\tlength\n");
  276. while (fds_record_iterate(&desc, &tok) != FDS_ERR_NOT_FOUND)
  277. {
  278. ret_code_t rc;
  279. fds_flash_record_t frec = {0};
  280. rc = fds_record_open(&desc, &frec);
  281. switch (rc)
  282. {
  283. case NRF_SUCCESS:
  284. break;
  285. case FDS_ERR_CRC_CHECK_FAILED:
  286. nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "error: CRC check failed!\n");
  287. continue;
  288. case FDS_ERR_NOT_FOUND:
  289. nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "error: record not found!\n");
  290. continue;
  291. default:
  292. {
  293. nrf_cli_fprintf(p_cli, NRF_CLI_ERROR,
  294. "error: unexpecte error %s.\n",
  295. fds_err_str(rc));
  296. continue;
  297. }
  298. }
  299. uint32_t const len = frec.p_header->length_words * sizeof(uint32_t);
  300. nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
  301. " 0x%04x\t"
  302. "\t 0x%04x\t"
  303. "\t 0x%04x\t"
  304. "\t %4u bytes\n",
  305. frec.p_header->record_id,
  306. frec.p_header->file_id,
  307. frec.p_header->record_key,
  308. len);
  309. rc = fds_record_close(&desc);
  310. APP_ERROR_CHECK(rc);
  311. }
  312. }
  313. static void write_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
  314. {
  315. if (nrf_cli_help_requested(p_cli))
  316. {
  317. nrf_cli_help_print(p_cli, NULL, 0);
  318. }
  319. else if (argc != 4)
  320. {
  321. cli_wrong_param_count_help(p_cli, "write");
  322. }
  323. else
  324. {
  325. /* Must be statically allocated, because it is going to be written in flash. */
  326. static uint8_t m_data[256];
  327. uint16_t const fid = strtol(argv[1], NULL, 16);
  328. uint16_t const key = strtol(argv[2], NULL, 16);
  329. uint32_t const len = strlen(argv[3]) < sizeof(m_data) ?
  330. strlen(argv[3]) : sizeof(m_data);
  331. /* Copy data to static variable. */
  332. memset(m_data, 0x00, sizeof(m_data));
  333. memcpy(m_data, argv[3], len);
  334. record_write(p_cli, fid, key, m_data, len);
  335. }
  336. }
  337. static void update_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
  338. {
  339. if (nrf_cli_help_requested(p_cli))
  340. {
  341. nrf_cli_help_print(p_cli, NULL, 0);
  342. }
  343. else if (argc != 5)
  344. {
  345. cli_wrong_param_count_help(p_cli, "update");
  346. }
  347. else
  348. {
  349. /* Must be statically allocated, because it is going to be written in flash. */
  350. static configuration_t cfg = {0};
  351. memset(&cfg, 0x00, sizeof(configuration_t));
  352. cfg.config1_on = !strcmp(argv[1], "on");
  353. cfg.config2_on = !strcmp(argv[2], "on");
  354. cfg.boot_count = strtol(argv[3], NULL, 10);
  355. uint16_t const len = strlen(argv[4]) < sizeof(cfg.device_name) ?
  356. strlen(argv[4]) : sizeof(cfg.device_name);
  357. memcpy(cfg.device_name, argv[4], len);
  358. nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
  359. "updating configuration: %s, %s, boot_count=%u, device_name=\"%s\"\n",
  360. cfg.config1_on ? "on" : "off",
  361. cfg.config2_on ? "on" : "off",
  362. cfg.boot_count,
  363. cfg.device_name);
  364. record_update(p_cli, &cfg);
  365. }
  366. }
  367. static void delete_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
  368. {
  369. if (nrf_cli_help_requested(p_cli))
  370. {
  371. nrf_cli_help_print(p_cli, NULL, 0);
  372. }
  373. else if (argc < 3)
  374. {
  375. cli_wrong_param_count_help(p_cli, "delete");
  376. }
  377. else
  378. {
  379. uint32_t const fid = strtol(argv[1], NULL, 16);
  380. uint32_t const key = strtol(argv[2], NULL, 16);
  381. record_delete(p_cli, fid, key);
  382. }
  383. }
  384. static void delete_all_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
  385. {
  386. if (nrf_cli_help_requested(p_cli))
  387. {
  388. nrf_cli_help_print(p_cli, NULL, 0);
  389. }
  390. else if (argc != 1)
  391. {
  392. cli_wrong_param_count_help(p_cli, "delete_all");
  393. }
  394. else
  395. {
  396. delete_all_begin();
  397. }
  398. }
  399. static void stat_cmd(nrf_cli_t const * p_cli, size_t argc, char **argv)
  400. {
  401. if (nrf_cli_help_requested(p_cli))
  402. {
  403. nrf_cli_help_print(p_cli, NULL, 0);
  404. }
  405. else
  406. {
  407. /* Print fds_stat(). */
  408. fds_stat_t stat = {0};
  409. ret_code_t rc = fds_stat(&stat);
  410. APP_ERROR_CHECK(rc);
  411. nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
  412. "total pages:\t%u\n"
  413. "total records:\t%u\n"
  414. "valid records:\t%u\n"
  415. "dirty records:\t%u\n"
  416. "largest contig:\t%u\n"
  417. "freeable words:\t%u (%u bytes)\n",
  418. stat.pages_available,
  419. stat.valid_records + stat.dirty_records,
  420. stat.valid_records,
  421. stat.dirty_records,
  422. stat.largest_contig,
  423. stat.freeable_words,
  424. stat.freeable_words * sizeof(uint32_t));
  425. }
  426. }
  427. static void gc_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
  428. {
  429. ret_code_t rc = fds_gc();
  430. switch (rc)
  431. {
  432. case NRF_SUCCESS:
  433. break;
  434. default:
  435. nrf_cli_fprintf(p_cli, NRF_CLI_ERROR,
  436. "error: garbage collection returned %s\n", fds_err_str(rc));
  437. break;
  438. }
  439. }
  440. NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_print)
  441. {
  442. NRF_CLI_CMD(all, NULL, PRINT_ALL_HELP, print_all_cmd),
  443. NRF_CLI_CMD(config, NULL, PRINT_CFG_HELP, print_cfg_cmd),
  444. NRF_CLI_SUBCMD_SET_END
  445. };
  446. NRF_CLI_CMD_REGISTER(print, &m_print, PRINT_HELP, print_cmd);
  447. NRF_CLI_CMD_REGISTER(write, NULL, WRITE_HELP, write_cmd);
  448. NRF_CLI_CMD_REGISTER(update, NULL, UPDATE_HELP, update_cmd);
  449. NRF_CLI_CMD_REGISTER(delete, NULL, DELETE_HELP, delete_cmd);
  450. NRF_CLI_CMD_REGISTER(delete_all, NULL, DELETE_ALL_HELP, delete_all_cmd);
  451. NRF_CLI_CMD_REGISTER(gc, NULL, GC_HELP, gc_cmd);
  452. NRF_CLI_CMD_REGISTER(stat, NULL, STAT_HELP, stat_cmd);