vars.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. /**
  2. * Copyright (c) 2018 - 2019, 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 <stddef.h>
  41. #include <stdint.h>
  42. #include <stdbool.h>
  43. #include <string.h>
  44. #include "sdk_config.h"
  45. #include "nrf_cli.h"
  46. #include "cli_utils.h"
  47. #include "raw.h"
  48. #include "vars.h"
  49. /* =============================================================================================
  50. * Configuration and definitions
  51. * =============================================================================================
  52. */
  53. #ifndef APP_VAR_MEMORY_SIZE
  54. #define APP_VAR_MEMORY_SIZE (16 * 1024) ///< @brief Define default size of the variable memory space.
  55. #endif
  56. #define TEMP_PREFIX "$_TMP@" ///< @brief Variable name prefix for temporary variables.
  57. #define TEMP_PREFIX_LEN 6 ///< @brief Length of @ref TEMP_PREFIX.
  58. /* =============================================================================================
  59. * Variable memory buffer definition
  60. * =============================================================================================
  61. */
  62. #define VAR_MEMORY_BEGIN ((uint8_t *)var_memory) ///< @brief Returns pointer to the first byte of the variable memory space.
  63. #define VAR_MEMORY_END ((uint8_t *)var_memory + APP_VAR_MEMORY_SIZE) ///< @brief Returns pointer to the next byte after the last byte of the variable memory space.
  64. static uint32_t var_memory[(APP_VAR_MEMORY_SIZE + 3) / 4]; ///< @brief Array holding variable memory space. It is uint32_t to force correct alignment.
  65. /* =============================================================================================
  66. * Dynamically allocated memory block type definition
  67. * =============================================================================================
  68. */
  69. /** @brief Callback function to prevent user from deleting a dynamically allocated block. @see var_free_fn_t.
  70. */
  71. static bool alloc_user_free_prevent(var_t * p_var)
  72. {
  73. nrf_cli_fprintf(cli_get(), NRF_CLI_WARNING, "Cannot delete dynamically allocated memory.\n");
  74. return false;
  75. }
  76. /** @brief Variable type that contains the dynamically allocated block.
  77. */
  78. static var_type_t var_alloc =
  79. {
  80. .p_description = "Dynamically allocated memory buffer",
  81. .free_fn = alloc_user_free_prevent,
  82. .print_fn = NULL,
  83. .p_tag = NULL,
  84. };
  85. /* =============================================================================================
  86. * Block access functions
  87. * =============================================================================================
  88. */
  89. /** @brief Returns the first block of the variable memory space, including free and dynamically allocated blocks.
  90. */
  91. static var_header_t * block_begin()
  92. {
  93. return (var_header_t *)VAR_MEMORY_BEGIN;
  94. }
  95. /** @brief Returns the next block after the one provided.
  96. */
  97. static var_header_t * block_next(var_header_t * current)
  98. {
  99. uint8_t * p_this = (uint8_t *)current;
  100. uint8_t * p_next = p_this + current->total_size;
  101. if (p_next < VAR_MEMORY_END)
  102. {
  103. return (var_header_t *)p_next;
  104. }
  105. else
  106. {
  107. return NULL;
  108. }
  109. }
  110. /** @brief Returns true if block is a variable, meaning it is not free and it is not a dynamically allocated block.
  111. */
  112. static bool block_is_var(var_header_t * p_block)
  113. {
  114. return (p_block->p_type != NULL) && (p_block->p_type != &var_alloc);
  115. }
  116. /** @brief Combines all neighboring free blocks, starting with the block provided in the parameter.
  117. */
  118. static void block_free_space_consolidate(var_header_t * p_block)
  119. {
  120. var_header_t * p_next_block;
  121. if ((p_block == NULL) || (p_block->p_type != NULL))
  122. {
  123. return;
  124. }
  125. p_next_block = block_next(p_block);
  126. while ((p_next_block != NULL) && (p_next_block->p_type == NULL))
  127. {
  128. p_block->total_size += p_next_block->total_size;
  129. p_next_block = block_next(p_block);
  130. }
  131. }
  132. /** @brief Allocates a block inside the variable memory space.
  133. *
  134. * Only total size of the block is set after this call. The rest of data (including content) is zeroed.
  135. * @param size Requested total size of a block, including header.
  136. * @param verbose Prints messages in case of problems if true.
  137. * @return Pointer to the newly allocated block, or NULL if there is no space available.
  138. */
  139. static var_header_t * block_allocate(size_t size, bool verbose)
  140. {
  141. var_header_t * p_block;
  142. var_header_t * p_next_block;
  143. uint32_t allocate_size = (size + 3) & ~3;
  144. // Iterate over all blocks
  145. for (p_block = block_begin(); p_block != NULL; p_block = block_next(p_block))
  146. {
  147. // Skip used blocks
  148. if (p_block->p_type != NULL)
  149. {
  150. continue;
  151. }
  152. // If after this unused block there are also unused blocks, merge them all.
  153. block_free_space_consolidate(p_block);
  154. // If this unused block is big enough to hold requested size, use it.
  155. if (p_block->total_size >= allocate_size)
  156. {
  157. size_t old_size = p_block->total_size;
  158. memset(p_block, 0x00, p_block->total_size);
  159. if (old_size - allocate_size > sizeof(var_header_t))
  160. {
  161. // This block is bigger than requested, so divide it into two blocks.
  162. p_block->total_size = allocate_size;
  163. p_next_block = block_next(p_block);
  164. p_next_block->p_type = NULL;
  165. p_next_block->total_size = old_size - allocate_size;
  166. }
  167. else
  168. {
  169. p_block->total_size = old_size;
  170. }
  171. return p_block;
  172. }
  173. }
  174. if (verbose)
  175. {
  176. nrf_cli_fprintf(cli_get(), NRF_CLI_WARNING, "No more space in variable memory\n");
  177. }
  178. return NULL;
  179. }
  180. /* =============================================================================================
  181. * Variable access functions
  182. * =============================================================================================
  183. */
  184. void var_init(void)
  185. {
  186. var_header_t * initial_block = block_begin();
  187. initial_block->total_size = APP_VAR_MEMORY_SIZE;
  188. initial_block->p_type = NULL;
  189. }
  190. var_t * var_begin(void)
  191. {
  192. var_header_t * p_start = block_begin();
  193. if (block_is_var(p_start))
  194. {
  195. return (var_t *)p_start;
  196. }
  197. else
  198. {
  199. return var_next((var_t *)p_start);
  200. }
  201. }
  202. var_t * var_next(var_t * current_var)
  203. {
  204. var_header_t * p_next = block_next((var_header_t *)current_var);
  205. while ((p_next != NULL) && !block_is_var(p_next))
  206. {
  207. p_next = block_next(p_next);
  208. }
  209. return (var_t *)p_next;
  210. }
  211. var_t * var_get(const char * p_name, bool verbose)
  212. {
  213. var_t * p_var;
  214. // Iterate over all objects
  215. for (p_var = var_begin(); p_var != NULL; p_var = var_next(p_var))
  216. {
  217. if (strcmp(p_var->name, p_name) == 0)
  218. {
  219. return p_var;
  220. }
  221. }
  222. if (verbose)
  223. {
  224. nrf_cli_fprintf(cli_get(), NRF_CLI_WARNING, "Variable '%s' not found\n", p_name);
  225. }
  226. return NULL;
  227. }
  228. /** @brief Checks whether name of the variable is valid.
  229. * @param p_name Name to check.
  230. * @param verbose Print messages if name is invalid.
  231. * @return true is name is valid.
  232. */
  233. static bool var_name_validate(const char * p_name, bool verbose)
  234. {
  235. size_t i;
  236. size_t len = strlen(p_name);
  237. if (p_name[0] != '$')
  238. {
  239. if (verbose)
  240. {
  241. nrf_cli_fprintf(cli_get(), NRF_CLI_WARNING, "Variable name must start with '$' sign\n");
  242. }
  243. return false;
  244. }
  245. else if (len <= 1)
  246. {
  247. if (verbose)
  248. {
  249. nrf_cli_fprintf(cli_get(), NRF_CLI_WARNING, "Variable name empty\n");
  250. }
  251. return false;
  252. }
  253. else if (len > VAR_NAME_LENGTH_MAX)
  254. {
  255. if (verbose)
  256. {
  257. nrf_cli_fprintf(cli_get(),
  258. NRF_CLI_WARNING,
  259. "Variable name too long, maximum %d, actual %d\n",
  260. VAR_NAME_LENGTH_MAX,
  261. len);
  262. }
  263. return false;
  264. }
  265. for (i = 0; i < len; i++)
  266. {
  267. if ((p_name[i] <= ' ') || (p_name[i] >= '\x7F'))
  268. {
  269. if (verbose)
  270. {
  271. nrf_cli_fprintf(cli_get(),
  272. NRF_CLI_WARNING,
  273. "Invalid character in variable name\n");
  274. }
  275. return false;
  276. }
  277. }
  278. return true;
  279. }
  280. var_t * var_create(const char * p_name, var_type_t const * p_type, size_t size, bool verbose)
  281. {
  282. var_t * p_var;
  283. if (!var_name_validate(p_name, verbose))
  284. {
  285. return NULL;
  286. }
  287. p_var = var_get(p_name, false);
  288. if (p_var != NULL)
  289. {
  290. if (verbose)
  291. {
  292. nrf_cli_fprintf(cli_get(),
  293. NRF_CLI_INFO,
  294. "Variable '%s' already exists, overriding.\n",
  295. p_name);
  296. }
  297. if (!var_delete(p_var->name, verbose))
  298. {
  299. return NULL;
  300. }
  301. }
  302. p_var = (var_t *)block_allocate(sizeof(var_t) + size, verbose);
  303. if (p_var == NULL)
  304. {
  305. return NULL;
  306. }
  307. p_var->data_size = size;
  308. strcpy(p_var->name, p_name);
  309. p_var->header.p_type = p_type;
  310. return p_var;
  311. }
  312. /** @brief Deletes variable by using pointer to the variable.
  313. * @param p_var Pointer to variable to delete.
  314. * @return false if variable free function prevents from its deletion.
  315. */
  316. static bool var_delete_by_ptr(var_t * p_var)
  317. {
  318. if (p_var->header.p_type->free_fn != NULL)
  319. {
  320. if (!p_var->header.p_type->free_fn(p_var))
  321. {
  322. return false;
  323. }
  324. }
  325. // Mark matching object as unused block
  326. p_var->header.p_type = NULL;
  327. return true;
  328. }
  329. bool var_delete(const char * p_name, bool verbose)
  330. {
  331. var_t * p_var = var_get(p_name, verbose);
  332. if (p_var != NULL)
  333. {
  334. if (!var_delete_by_ptr(p_var))
  335. {
  336. if (verbose)
  337. {
  338. nrf_cli_fprintf(cli_get(), NRF_CLI_WARNING, "Cannot delete '%s'\n", p_name);
  339. }
  340. return false;
  341. }
  342. return true;
  343. }
  344. return false;
  345. }
  346. bool var_rename(const char * p_name, const char * p_new_name, bool verbose)
  347. {
  348. var_t * p_dest_var;
  349. var_t * p_var = var_get(p_name, verbose);
  350. if (p_var == NULL)
  351. {
  352. return false;
  353. }
  354. if (!var_name_validate(p_new_name, verbose))
  355. {
  356. return false;
  357. }
  358. p_dest_var = var_get(p_new_name, false);
  359. if (p_dest_var != NULL)
  360. {
  361. if (verbose)
  362. {
  363. nrf_cli_fprintf(cli_get(),
  364. NRF_CLI_WARNING,
  365. "Variable '%s' already exists, overriding.\n",
  366. p_new_name);
  367. }
  368. if (!var_delete(p_dest_var->name, verbose))
  369. {
  370. return false;
  371. }
  372. }
  373. strcpy(p_var->name, p_new_name);
  374. return true;
  375. }
  376. void var_show(var_t * p_var)
  377. {
  378. nrf_cli_fprintf(cli_get(), NRF_CLI_NORMAL, "Name: %s\n", p_var->name);
  379. nrf_cli_fprintf(cli_get(), NRF_CLI_NORMAL, "Description: %s", p_var->header.p_type->p_description);
  380. if (p_var->header.p_type->print_fn)
  381. {
  382. nrf_cli_fprintf(cli_get(), NRF_CLI_NORMAL, ". ");
  383. p_var->header.p_type->print_fn(p_var, true);
  384. }
  385. nrf_cli_fprintf(cli_get(), NRF_CLI_NORMAL, "\n");
  386. nrf_cli_fprintf(cli_get(), NRF_CLI_NORMAL, "Allocated bytes: %d\n", p_var->header.total_size);
  387. nrf_cli_fprintf(cli_get(), NRF_CLI_NORMAL, "Used bytes: %d\n", p_var->data_size);
  388. if (p_var->header.p_type->print_fn != NULL)
  389. {
  390. p_var->header.p_type->print_fn(p_var, false);
  391. }
  392. }
  393. void var_dynamic_cmd(nrf_cli_cmd_entry_t const * p_subcmd, size_t idx, nrf_cli_static_entry_t * p_static)
  394. {
  395. var_t * p_var;
  396. // Iterate over all objects
  397. for (p_var = var_begin(); p_var != NULL; p_var = var_next(p_var))
  398. {
  399. if (idx == 0)
  400. {
  401. p_static->p_syntax = p_var->name;
  402. p_static->handler = NULL;
  403. p_static->p_subcmd = p_subcmd;
  404. p_static->p_help = NULL;
  405. return;
  406. }
  407. idx--;
  408. }
  409. p_static->p_syntax = NULL;
  410. }
  411. /* =============================================================================================
  412. * Temporary variable handling functions
  413. * =============================================================================================
  414. */
  415. /** @brief Generates new name for the temporary variable.
  416. * @return Pointer to the static buffer that contains the new name. It is valid until the next
  417. * var_temp_name_generate call.
  418. */
  419. static char * var_temp_name_generate()
  420. {
  421. int i;
  422. static char name[] = TEMP_PREFIX "AAAAAAAAA";
  423. for (i = TEMP_PREFIX_LEN + 8; i > 0; i--)
  424. {
  425. if (name[i] == 'Z')
  426. {
  427. name[i] = 'A';
  428. }
  429. else
  430. {
  431. name[i]++;
  432. break;
  433. }
  434. }
  435. return name;
  436. }
  437. var_t * var_temp_create(var_type_t const * p_type, size_t size, bool verbose)
  438. {
  439. return var_create(var_temp_name_generate(), p_type, size, verbose);
  440. }
  441. bool var_is_temp(var_t const * p_var)
  442. {
  443. return strncmp(p_var->name, TEMP_PREFIX, TEMP_PREFIX_LEN) == 0;
  444. }
  445. void var_all_temp_delete(void)
  446. {
  447. var_t * p_var;
  448. for (p_var = var_begin(); p_var != NULL; p_var = var_next(p_var))
  449. {
  450. if (strncmp(p_var->name, TEMP_PREFIX, TEMP_PREFIX_LEN) == 0)
  451. {
  452. UNUSED_RETURN_VALUE(var_delete(p_var->name, false));
  453. }
  454. }
  455. }
  456. /* =============================================================================================
  457. * Memory allocation inside variables memory
  458. * =============================================================================================
  459. */
  460. void * var_malloc(size_t size)
  461. {
  462. var_header_t * p_block = block_allocate(sizeof(var_header_t) + size, true);
  463. if (p_block != NULL)
  464. {
  465. p_block->p_type = &var_alloc;
  466. }
  467. return (void*)(&p_block[1]);
  468. }
  469. void * var_calloc(size_t count, size_t size)
  470. {
  471. return var_malloc(count * size);
  472. }
  473. void var_free(void* p_data)
  474. {
  475. var_header_t * p_block = &((var_header_t *)p_data)[-1];
  476. if (p_data != NULL)
  477. {
  478. p_block->p_type = NULL;
  479. }
  480. }
  481. void * var_realloc(void * p_old, size_t new_size)
  482. {
  483. void * p_dest = var_malloc(new_size);
  484. var_free(p_old);
  485. if ((p_old != NULL) && (p_dest != NULL))
  486. {
  487. var_header_t * p_src_block = &((var_header_t *)p_old)[-1];
  488. size_t copy_bytes = p_src_block->total_size - sizeof(var_header_t);
  489. if (copy_bytes < new_size)
  490. {
  491. copy_bytes = new_size;
  492. }
  493. memcpy(p_dest, p_old, copy_bytes);
  494. }
  495. return p_dest;
  496. }
  497. void * var_temp_alloc(size_t size)
  498. {
  499. var_t * p_temp_var;
  500. p_temp_var = var_temp_create(&g_raw_type, size, true);
  501. if (p_temp_var == NULL)
  502. {
  503. return NULL;
  504. }
  505. return VAR_DATA(p_temp_var);
  506. }
  507. /* =============================================================================================
  508. * Variable handling commands
  509. * =============================================================================================
  510. */
  511. VAR_REGISTER_SUB_COMMANDS(m_subcmd_var, NULL);
  512. /** @brief Command to list all variables. See command help for details.
  513. */
  514. static bool cmd_ls(nrf_cli_t const * p_cli, size_t argc, char ** argv)
  515. {
  516. var_t * p_var;
  517. UNUSED_PARAMETER(argv);
  518. CLI_ARGS_CHECK(argc == 1);
  519. nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "%-16s %6s %s\n", "Name", "Size", "Description");
  520. nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "%-16s %6s %s\n", "----", "----", "-----------");
  521. // Iterate over all variables
  522. for (p_var = var_begin(); p_var != NULL; p_var = var_next(p_var))
  523. {
  524. nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "%-16s %6d %s. ", p_var->name,
  525. p_var->data_size, p_var->header.p_type->p_description);
  526. if (p_var->header.p_type->print_fn)
  527. {
  528. p_var->header.p_type->print_fn(p_var, true);
  529. }
  530. nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\n");
  531. }
  532. return true;
  533. }
  534. CLI_CMD_REGISTER(ls, NULL, cmd_ls,
  535. "List all defined variables.\n"
  536. "Usage:\n"
  537. " ls\n"
  538. );
  539. /** @brief Command to remove a variable. See command help for details.
  540. */
  541. static bool cmd_rm(nrf_cli_t const * p_cli, size_t argc, char ** argv)
  542. {
  543. UNUSED_PARAMETER(p_cli);
  544. CLI_ARGS_CHECK(argc == 2);
  545. if (strcmp(argv[1], "*") == 0)
  546. {
  547. var_t * p_next_var;
  548. var_t * p_var = var_begin();
  549. bool ok = true;
  550. while (p_var != NULL)
  551. {
  552. p_next_var = var_next(p_var);
  553. ok = var_delete(p_var->name, true) && ok;
  554. p_var = p_next_var;
  555. }
  556. return ok;
  557. }
  558. else
  559. {
  560. return var_delete(argv[1], true);
  561. }
  562. }
  563. CLI_CMD_REGISTER(rm, &m_subcmd_var, cmd_rm,
  564. "Remove a variable.\n"
  565. "Usage:\n"
  566. " rm variable_name\n"
  567. "Arguments:\n"
  568. " IN variable_name Name of the variable to remove or \"*\" to delete all.\n"
  569. );
  570. /** @brief Command to rename a variable. See command help for details.
  571. */
  572. static bool cmd_mv(nrf_cli_t const * p_cli, size_t argc, char ** argv)
  573. {
  574. var_t * p_var;
  575. UNUSED_PARAMETER(p_cli);
  576. CLI_ARGS_CHECK(argc == 3);
  577. p_var = cli_input_arg_get(1, NULL);
  578. CLI_CHECK(p_var != NULL);
  579. return var_rename(p_var->name, argv[2], true);
  580. }
  581. CLI_CMD_REGISTER(mv, &m_subcmd_var, cmd_mv,
  582. "Rename a variable.\n"
  583. "Usage:\n"
  584. " mv old_name new_name\n"
  585. "Arguments:\n"
  586. " IN old_name Name of the variable to rename.\n"
  587. " IN new_name New name of the variable.\n"
  588. );
  589. /** @brief Command to show a variable. See command help for details.
  590. */
  591. static bool cmd_show(nrf_cli_t const * p_cli, size_t argc, char ** argv)
  592. {
  593. var_t * p_var;
  594. UNUSED_PARAMETER(p_cli);
  595. UNUSED_PARAMETER(argv);
  596. CLI_ARGS_CHECK(argc == 2);
  597. p_var = cli_input_arg_get(1, NULL);
  598. CLI_CHECK(p_var != NULL);
  599. var_show(p_var);
  600. return true;
  601. }
  602. CLI_CMD_REGISTER(show, &m_subcmd_var, cmd_show,
  603. "Show a content of a variable.\n"
  604. "Usage:\n"
  605. " show variable_name\n"
  606. "Arguments:\n"
  607. " IN variable_name Name of the variable to show.\n"
  608. );
  609. /** @brief Command to show full content of variable memory space. See command help for details.
  610. */
  611. static bool cmd_varmap(nrf_cli_t const * p_cli, size_t argc, char ** argv)
  612. {
  613. var_header_t * p_block;
  614. UNUSED_PARAMETER(p_cli);
  615. CLI_ARGS_CHECK(argc == 1);
  616. UNUSED_RETURN_VALUE(block_allocate(APP_VAR_MEMORY_SIZE + 1, false)); // Force free block consolidation
  617. nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "%6s %6s %-16s %s\n", "Size", "Used", "Name",
  618. "Description");
  619. nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "%6s %6s %-16s %s\n", "----", "----", "----",
  620. "-----------");
  621. // Iterate over all blocks
  622. for (p_block = block_begin(); p_block != NULL; p_block = block_next(p_block))
  623. {
  624. if (p_block->p_type != NULL)
  625. {
  626. char const * name;
  627. size_t data_size;
  628. if (p_block->p_type == &var_alloc)
  629. {
  630. name = "[dynamic]";
  631. data_size = p_block->total_size - sizeof(var_header_t);
  632. }
  633. else
  634. {
  635. name = ((var_t *)p_block)->name;
  636. data_size = ((var_t *)p_block)->data_size;
  637. }
  638. nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "%6d %6d %-16s %s. ", p_block->total_size,
  639. data_size, name, p_block->p_type->p_description);
  640. if (p_block->p_type->print_fn)
  641. {
  642. p_block->p_type->print_fn((var_t *)p_block, true);
  643. }
  644. nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\n");
  645. }
  646. else
  647. {
  648. nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "%6d %6s %-16s %s\n", p_block->total_size,
  649. "", "[FREE]", "Unused memory block");
  650. }
  651. }
  652. return true;
  653. }
  654. CLI_CMD_REGISTER(varmap, NULL, cmd_varmap,
  655. "Print full content of the variable memory.\n"
  656. "Usage:\n"
  657. " varmap\n"
  658. );