diff --git a/drivers/flash/flash_shell.c b/drivers/flash/flash_shell.c index d0270e8965b..bd550e7a0cd 100644 --- a/drivers/flash/flash_shell.c +++ b/drivers/flash/flash_shell.c @@ -216,8 +216,6 @@ static int cmd_test(const struct shell *shell, size_t argc, char *argv[]) return 0; } -#define HELP_NONE "[none]" - SHELL_CREATE_STATIC_SUBCMD_SET(flash_cmds) { SHELL_CMD(erase, NULL, " ", cmd_erase), SHELL_CMD(read, NULL, "
", cmd_read), @@ -228,22 +226,9 @@ SHELL_CREATE_STATIC_SUBCMD_SET(flash_cmds) { static int cmd_flash(const struct shell *shell, size_t argc, char **argv) { - int err; - - if (argc == 1) { - shell_help_print(shell); - /* shell_cmd_precheck returns 1 when help is printed */ - return 1; - } - - err = shell_cmd_precheck(shell, argc == 2); - if (err) { - return err; - } - - error(shell, "%s:%s%s", argv[0], "unknown parameter: ", argv[1]); + error(shell, "%s:unknown parameter: %s", argv[0], argv[1]); return -EINVAL; } -SHELL_CMD_REGISTER(flash, &flash_cmds, "Flash shell commands", - cmd_flash); +SHELL_CMD_ARG_REGISTER(flash, &flash_cmds, "Flash shell commands", + cmd_flash, 2, 0); diff --git a/include/shell/shell.h b/include/shell/shell.h index e09caf554b4..e5c728f7309 100644 --- a/include/shell/shell.h +++ b/include/shell/shell.h @@ -119,14 +119,14 @@ struct shell_static_entry { */ #define SHELL_CMD_ARG_REGISTER(syntax, subcmd, help, handler, \ mandatory, optional) \ - static const struct shell_static_entry UTIL_CAT(shell_, syntax) = \ + static const struct shell_static_entry UTIL_CAT(_shell_, syntax) = \ SHELL_CMD_ARG(syntax, subcmd, help, handler, mandatory, optional); \ static const struct shell_cmd_entry UTIL_CAT(shell_cmd_, syntax) \ __attribute__ ((section("." \ STRINGIFY(UTIL_CAT(shell_root_cmd_, syntax))))) \ __attribute__((used)) = { \ .is_dynamic = false, \ - .u.entry = &UTIL_CAT(shell_, syntax) \ + .u.entry = &UTIL_CAT(_shell_, syntax) \ } /** @@ -141,14 +141,14 @@ struct shell_static_entry { * @param[in] handler Pointer to a function handler. */ #define SHELL_CMD_REGISTER(syntax, subcmd, help, handler) \ - static const struct shell_static_entry UTIL_CAT(shell_, syntax) = \ + static const struct shell_static_entry UTIL_CAT(_shell_, syntax) = \ SHELL_CMD(syntax, subcmd, help, handler); \ static const struct shell_cmd_entry UTIL_CAT(shell_cmd_, syntax) \ __attribute__ ((section("." \ STRINGIFY(UTIL_CAT(shell_root_cmd_, syntax))))) \ __attribute__((used)) = { \ .is_dynamic = false, \ - .u.entry = &UTIL_CAT(shell_, syntax) \ + .u.entry = &UTIL_CAT(_shell_, syntax) \ } /** @@ -440,6 +440,8 @@ struct shell { k_thread_stack_t *stack; }; +extern void shell_print_stream(const void *user_ctx, const char *data, + size_t data_len); /** * @brief Macro for defining a shell instance. * @@ -614,16 +616,6 @@ void shell_fprintf(const struct shell *shell, enum shell_vt100_color color, */ void shell_process(const struct shell *shell); -/** - * @brief Prints the current command help. - * - * Function will print a help string with the currently entered command and - * its subcommands (if exist). - * - * @param[in] shell Pointer to the shell instance. - */ -void shell_help_print(const struct shell *shell); - /** * @brief Change displayed shell prompt. * @@ -636,30 +628,14 @@ void shell_help_print(const struct shell *shell); int shell_prompt_change(const struct shell *shell, char *prompt); /** - * @brief Prints help if requested and prints error message on wrong argument - * count. - * Optionally, printing help on wrong argument count can be enabled. + * @brief Prints the current command help. * - * @param[in] shell Pointer to the shell instance. - * @param[in] arg_cnt_ok Flag indicating valid number of arguments. + * Function will print a help string with: the currently entered command + * and subcommands (if they exist). * - * @return 0 if check passed - * @return 1 if help was requested - * @return -EINVAL if wrong argument count + * @param[in] shell Pointer to the shell instance. */ -int shell_cmd_precheck(const struct shell *shell, - bool arg_cnt_ok); - -/** - * @internal @brief This function shall not be used directly, it is required by - * the fprintf module. - * - * @param[in] p_user_ctx Pointer to the context for the shell instance. - * @param[in] p_data Pointer to the data buffer. - * @param[in] data_len Data buffer size. - */ -void shell_print_stream(const void *user_ctx, const char *data, - size_t data_len); +void shell_help_print(const struct shell *shell); /** @brief Execute command. * diff --git a/include/shell/shell_fprintf.h b/include/shell/shell_fprintf.h index 7ae81ab5801..6fbe337f216 100644 --- a/include/shell/shell_fprintf.h +++ b/include/shell/shell_fprintf.h @@ -76,7 +76,6 @@ void shell_fprintf_fmt(const struct shell_fprintf *sh_fprintf, */ void shell_fprintf_buffer_flush(const struct shell_fprintf *sh_fprintf); - #ifdef __cplusplus } #endif diff --git a/samples/drivers/flash_shell/src/main.c b/samples/drivers/flash_shell/src/main.c index 0f261bdb1c2..eb3857d0a9a 100644 --- a/samples/drivers/flash_shell/src/main.c +++ b/samples/drivers/flash_shell/src/main.c @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ - #include #include @@ -241,15 +240,11 @@ static int cmd_flash(const struct shell *shell, size_t argc, char **argv) static int cmd_write_block_size(const struct shell *shell, size_t argc, char **argv) { + ARG_UNUSED(argc); ARG_UNUSED(argv); - int err = shell_cmd_precheck(shell, argc == 1); + int err = check_flash_device(shell); - if (err) { - return err; - } - - err = check_flash_device(shell); if (!err) { PR_SHELL(shell, "%d\n", flash_get_write_block_size(flash_device)); @@ -260,19 +255,13 @@ static int cmd_write_block_size(const struct shell *shell, size_t argc, static int cmd_read(const struct shell *shell, size_t argc, char **argv) { - - int err = shell_cmd_precheck(shell, argc == 3); + int err = check_flash_device(shell); unsigned long int offset, len; if (err) { goto exit; } - err = check_flash_device(shell); - if (err) { - goto exit; - } - if (parse_ul(argv[1], &offset) || parse_ul(argv[2], &len)) { PR_ERROR(shell, "Invalid arguments.\n"); err = -EINVAL; @@ -287,18 +276,14 @@ exit: static int cmd_erase(const struct shell *shell, size_t argc, char **argv) { - int err = shell_cmd_precheck(shell, argc == 3); - unsigned long int offset, size; + int err = check_flash_device(shell); + unsigned long int offset; + unsigned long int size; if (err) { goto exit; } - err = check_flash_device(shell); - if (err) { - goto exit; - } - if (parse_ul(argv[1], &offset) || parse_ul(argv[2], &size)) { PR_ERROR(shell, "Invalid arguments.\n"); err = -EINVAL; @@ -312,15 +297,11 @@ exit: static int cmd_write(const struct shell *shell, size_t argc, char **argv) { - int err = shell_cmd_precheck(shell, argc > 2); unsigned long int i, offset; u8_t buf[ARGC_MAX]; - if (err) { - goto exit; - } + int err = check_flash_device(shell); - err = check_flash_device(shell); if (err) { goto exit; } @@ -365,15 +346,11 @@ exit: static int cmd_page_count(const struct shell *shell, size_t argc, char **argv) { ARG_UNUSED(argv); + ARG_UNUSED(argc); - int err = shell_cmd_precheck(shell, argc == 1); + int err = check_flash_device(shell); size_t page_count; - if (err) { - return err; - } - - err = check_flash_device(shell); if (!err) { page_count = flash_get_page_count(flash_device); PR_SHELL(shell, "Flash device contains %lu pages.\n", @@ -409,15 +386,11 @@ static bool page_layout_cb(const struct flash_pages_info *info, void *datav) static int cmd_page_layout(const struct shell *shell, size_t argc, char **argv) { - int err = shell_cmd_precheck(shell, argc <= 3); unsigned long int start_page, end_page; struct page_layout_data data; - if (err) { - return err; - } + int err = check_flash_device(shell); - err = check_flash_device(shell); if (err) { goto bail; } @@ -463,12 +436,6 @@ static int cmd_page_read(const struct shell *shell, size_t argc, char **argv) struct flash_pages_info info; int ret; - - ret = shell_cmd_precheck(shell, argc == 3 || argc == 4); - if (ret) { - return ret; - } - ret = check_flash_device(shell); if (ret) { return ret; @@ -512,11 +479,6 @@ static int cmd_page_erase(const struct shell *shell, size_t argc, char **argv) return ret; } - ret = shell_cmd_precheck(shell, argc == 2 || argc == 3); - if (ret) { - return ret; - } - if (parse_ul(argv[1], &page)) { ret = -EINVAL; goto bail; @@ -563,15 +525,11 @@ static int cmd_page_write(const struct shell *shell, size_t argc, char **argv) return ret; } - ret = shell_cmd_precheck(shell, argc > 2); - if (ret) { - return ret; - } - - if (argc < 2 || parse_ul(argv[1], &page) || parse_ul(argv[2], &off)) { + if (parse_ul(argv[1], &page) || parse_ul(argv[2], &off)) { ret = -EINVAL; goto bail; } + argc -= 3; argv += 3; for (i = 0; i < argc; i++) { @@ -601,12 +559,6 @@ static int cmd_set_dev(const struct shell *shell, size_t argc, char **argv) { struct device *dev; const char *name; - int ret; - - ret = shell_cmd_precheck(shell, argc == 2); - if (ret) { - return ret; - } name = argv[1]; @@ -642,19 +594,21 @@ void main(void) SHELL_CREATE_STATIC_SUBCMD_SET(sub_flash) { /* Alphabetically sorted to ensure correct Tab autocompletion. */ - SHELL_CMD(erase, NULL, ERASE_HELP, cmd_erase), + SHELL_CMD_ARG(erase, NULL, ERASE_HELP, cmd_erase, 3, 0), #ifdef CONFIG_FLASH_PAGE_LAYOUT - SHELL_CMD(page_count, NULL, PAGE_COUNT_HELP, cmd_page_count), - SHELL_CMD(page_errase, NULL, PAGE_ERASE_HELP, cmd_page_erase), - SHELL_CMD(page_layout, NULL, PAGE_LAYOUT_HELP, cmd_page_layout), - SHELL_CMD(page_read, NULL, PAGE_READ_HELP, cmd_page_read), - SHELL_CMD(page_write, NULL, PAGE_WRITE_HELP, cmd_page_write), + SHELL_CMD_ARG(page_count, NULL, PAGE_COUNT_HELP, cmd_page_count, 1, 0), + SHELL_CMD_ARG(page_erase, NULL, PAGE_ERASE_HELP, cmd_page_erase, 2, 1), + SHELL_CMD_ARG(page_layout, NULL, PAGE_LAYOUT_HELP, + cmd_page_layout, 1, 2), + SHELL_CMD_ARG(page_read, NULL, PAGE_READ_HELP, cmd_page_read, 3, 1), + SHELL_CMD_ARG(page_write, NULL, PAGE_WRITE_HELP, + cmd_page_write, 3, 255), #endif - SHELL_CMD(read, NULL, READ_HELP, cmd_read), - SHELL_CMD(set_device, NULL, SET_DEV_HELP, cmd_set_dev), - SHELL_CMD(write, NULL, WRITE_HELP, cmd_write), - SHELL_CMD(write_block_size, NULL, WRITE_BLOCK_SIZE_HELP, - cmd_write_block_size), + SHELL_CMD_ARG(read, NULL, READ_HELP, cmd_read, 3, 0), + SHELL_CMD_ARG(set_device, NULL, SET_DEV_HELP, cmd_set_dev, 2, 0), + SHELL_CMD_ARG(write, NULL, WRITE_HELP, cmd_write, 3, 255), + SHELL_CMD_ARG(write_block_size, NULL, WRITE_BLOCK_SIZE_HELP, + cmd_write_block_size, 1, 0), SHELL_SUBCMD_SET_END /* Array terminated. */ }; diff --git a/samples/mpu/mpu_test/src/main.c b/samples/mpu/mpu_test/src/main.c index c3c47278752..29f9e0fa90a 100644 --- a/samples/mpu/mpu_test/src/main.c +++ b/samples/mpu/mpu_test/src/main.c @@ -134,18 +134,6 @@ static int cmd_mtest(const struct shell *shell, size_t argc, char *argv[]) { u32_t *mem; u32_t val; - int err; - - if (argc > 3) { - PR_ERROR(shell, "mtest accepts 1 (Read) or 2 (Write)" - "parameters\n"); - return -EINVAL; - } - - err = shell_cmd_precheck(shell, (argc >= 2) && (argc <= 3)); - if (err) { - return err; - } val = (u32_t)strtol(argv[1], NULL, 16); mem = (u32_t *) val; @@ -166,7 +154,7 @@ void main(void) SHELL_CREATE_STATIC_SUBCMD_SET(sub_mpu) { - SHELL_CMD(mtest, NULL, MTEST_CMD_HELP, cmd_mtest), + SHELL_CMD_ARG(mtest, NULL, MTEST_CMD_HELP, cmd_mtest, 2, 1), SHELL_CMD(read, NULL, READ_CMD_HELP, cmd_read), SHELL_CMD(run, NULL, RUN_CMD_HELP, cmd_run), #if defined(CONFIG_SOC_FLASH_MCUX) diff --git a/samples/subsys/shell/shell_module/src/dynamic_cmd.c b/samples/subsys/shell/shell_module/src/dynamic_cmd.c index b560c84d0a7..a1305e465c5 100644 --- a/samples/subsys/shell/shell_module/src/dynamic_cmd.c +++ b/samples/subsys/shell/shell_module/src/dynamic_cmd.c @@ -19,24 +19,6 @@ static u8_t dynamic_cmd_cnt; typedef int cmp_t(const void *, const void *); extern void qsort(void *a, size_t n, size_t es, cmp_t *cmp); -static int cmd_dynamic(const struct shell *shell, size_t argc, char **argv) -{ - if ((argc == 1)) { - shell_help_print(shell); - return 0; - } - - if (argc > 2) { - shell_fprintf(shell, SHELL_ERROR, - "%s: bad parameter count\r\n", argv[0]); - } else { - shell_fprintf(shell, SHELL_ERROR, - "%s: please specify subcommand\r\n", argv[0]); - } - - return -ENOEXEC; -} - /* function required by qsort */ static int string_cmp(const void *p_a, const void *p_b) { @@ -46,40 +28,35 @@ static int string_cmp(const void *p_a, const void *p_b) static int cmd_dynamic_add(const struct shell *shell, size_t argc, char **argv) { - u8_t idx; u16_t cmd_len; + u8_t idx; - if (argc != 2) { - shell_fprintf(shell, SHELL_ERROR, - "%s: bad parameter count\r\n", argv[0]); - return -ENOEXEC; - } + ARG_UNUSED(argc); if (dynamic_cmd_cnt >= MAX_CMD_CNT) { - shell_fprintf(shell, SHELL_ERROR, "command limit reached\r\n"); + shell_error(shell, "command limit reached"); return -ENOEXEC; } cmd_len = strlen(argv[1]); if (cmd_len >= MAX_CMD_LEN) { - shell_fprintf(shell, SHELL_ERROR, "too long command\r\n"); + shell_error(shell, "too long command"); return -ENOEXEC; } for (idx = 0U; idx < cmd_len; idx++) { if (!isalnum((int)(argv[1][idx]))) { - shell_fprintf(shell, SHELL_ERROR, - "bad command name - please use only" - " alphanumerical characters\r\n"); + shell_error(shell, + "bad command name - please use only" + " alphanumerical characters"); return -ENOEXEC; } } for (idx = 0U; idx < MAX_CMD_CNT; idx++) { if (!strcmp(dynamic_cmd_buffer[idx], argv[1])) { - shell_fprintf(shell, SHELL_ERROR, - "duplicated command\r\n"); + shell_error(shell, "duplicated command"); return -ENOEXEC; } } @@ -89,32 +66,7 @@ static int cmd_dynamic_add(const struct shell *shell, qsort(dynamic_cmd_buffer, dynamic_cmd_cnt, sizeof(dynamic_cmd_buffer[0]), string_cmp); - shell_fprintf(shell, SHELL_NORMAL, "command added successfully\r\n"); - - return 0; -} - -static int cmd_dynamic_show(const struct shell *shell, - size_t argc, char **argv) -{ - if (argc != 1) { - shell_fprintf(shell, SHELL_ERROR, - "%s: bad parameter count\r\n", argv[0]); - return -ENOEXEC; - } - - if (dynamic_cmd_cnt == 0) { - shell_fprintf(shell, SHELL_WARNING, - "Please add some commands first.\r\n"); - return -ENOEXEC; - } - - shell_fprintf(shell, SHELL_NORMAL, "Dynamic command list:\r\n"); - - for (u8_t i = 0; i < dynamic_cmd_cnt; i++) { - shell_fprintf(shell, SHELL_NORMAL, - "[%3d] %s\r\n", i, dynamic_cmd_buffer[i]); - } + shell_print(shell, "command added successfully"); return 0; } @@ -122,22 +74,17 @@ static int cmd_dynamic_show(const struct shell *shell, static int cmd_dynamic_execute(const struct shell *shell, size_t argc, char **argv) { - if (argc != 2) { - shell_fprintf(shell, SHELL_ERROR, - "%s: bad parameter count\r\n", argv[0]); - return -ENOEXEC; - } + ARG_UNUSED(argc); + ARG_UNUSED(argv); for (u8_t idx = 0; idx < dynamic_cmd_cnt; idx++) { if (!strcmp(dynamic_cmd_buffer[idx], argv[1])) { - shell_fprintf(shell, SHELL_NORMAL, - "dynamic command: %s\r\n", argv[1]); + shell_print(shell, "dynamic command: %s", argv[1]); return 0; } } - shell_fprintf(shell, SHELL_ERROR, - "%s: uknown parameter: %s\r\n", argv[0], argv[1]); + shell_error(shell, "%s: uknown parameter: %s", argv[0], argv[1]); return -ENOEXEC; } @@ -145,16 +92,8 @@ static int cmd_dynamic_execute(const struct shell *shell, static int cmd_dynamic_remove(const struct shell *shell, size_t argc, char **argv) { - if (argc == 1) { - shell_help_print(shell); - return 0; - } - - if (argc != 2) { - shell_fprintf(shell, SHELL_ERROR, - "%s: bad parameter count\r\n", argv[0]); - return -ENOEXEC; - } + ARG_UNUSED(argc); + ARG_UNUSED(argv); for (u8_t idx = 0; idx < dynamic_cmd_cnt; idx++) { if (!strcmp(dynamic_cmd_buffer[idx], argv[1])) { @@ -168,17 +107,35 @@ static int cmd_dynamic_remove(const struct shell *shell, size_t argc, } --dynamic_cmd_cnt; - shell_fprintf(shell, SHELL_NORMAL, - "command removed successfully\r\n"); + shell_print(shell, "command removed successfully"); return 0; } } - shell_fprintf(shell, SHELL_ERROR, - "did not find command: %s\r\n", argv[1]); + shell_error(shell, "did not find command: %s", argv[1]); return -ENOEXEC; } +static int cmd_dynamic_show(const struct shell *shell, + size_t argc, char **argv) +{ + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + if (dynamic_cmd_cnt == 0) { + shell_warn(shell, "Please add some commands first."); + return -ENOEXEC; + } + + shell_print(shell, "Dynamic command list:"); + + for (u8_t i = 0; i < dynamic_cmd_cnt; i++) { + shell_print(shell, "[%3d] %s", i, dynamic_cmd_buffer[i]); + } + + return 0; +} + /* dynamic command creation */ static void dynamic_cmd_get(size_t idx, struct shell_static_entry *entry) { @@ -201,21 +158,21 @@ static void dynamic_cmd_get(size_t idx, struct shell_static_entry *entry) SHELL_CREATE_DYNAMIC_CMD(m_sub_dynamic_set, dynamic_cmd_get); SHELL_CREATE_STATIC_SUBCMD_SET(m_sub_dynamic) { - SHELL_CMD(add, NULL, + SHELL_CMD_ARG(add, NULL, "Add a new dynamic command.\nExample usage: [ dynamic add test " "] will add a dynamic command 'test'.\nIn this example, command" " name length is limited to 32 chars. You can add up to 20" " commands. Commands are automatically sorted to ensure correct" " shell completion.", - cmd_dynamic_add), - SHELL_CMD(execute, &m_sub_dynamic_set, - "Execute a command.", cmd_dynamic_execute), - SHELL_CMD(remove, &m_sub_dynamic_set, - "Remove a command.", cmd_dynamic_remove), - SHELL_CMD(show, NULL, - "Show all added dynamic commands.", cmd_dynamic_show), + cmd_dynamic_add, 2, 0), + SHELL_CMD_ARG(execute, &m_sub_dynamic_set, + "Execute a command.", cmd_dynamic_execute, 2, 0), + SHELL_CMD_ARG(remove, &m_sub_dynamic_set, + "Remove a command.", cmd_dynamic_remove, 2, 0), + SHELL_CMD_ARG(show, NULL, + "Show all added dynamic commands.", cmd_dynamic_show, 1, 0), SHELL_SUBCMD_SET_END }; SHELL_CMD_REGISTER(dynamic, &m_sub_dynamic, - "Demonstrate dynamic command usage.", cmd_dynamic); + "Demonstrate dynamic command usage.", NULL); diff --git a/samples/subsys/shell/shell_module/src/main.c b/samples/subsys/shell/shell_module/src/main.c index cf12565f1ab..fc33ddd987b 100644 --- a/samples/subsys/shell/shell_module/src/main.c +++ b/samples/subsys/shell/shell_module/src/main.c @@ -31,29 +31,22 @@ static int cmd_log_test_start(const struct shell *shell, size_t argc, { ARG_UNUSED(argv); - int err = shell_cmd_precheck(shell, argc == 1); - - if (err) { - return err; - } - k_timer_start(&log_timer, period, period); - shell_fprintf(shell, SHELL_NORMAL, "Log test started\n"); + shell_print(shell, "Log test started\n"); + return 0; } static int cmd_log_test_start_demo(const struct shell *shell, size_t argc, char **argv) { - cmd_log_test_start(shell, argc, argv, 200); - return 0; + return cmd_log_test_start(shell, argc, argv, 200); } static int cmd_log_test_start_flood(const struct shell *shell, size_t argc, char **argv) { - cmd_log_test_start(shell, argc, argv, 10); - return 0; + return cmd_log_test_start(shell, argc, argv, 10); } static int cmd_log_test_stop(const struct shell *shell, size_t argc, @@ -62,33 +55,28 @@ static int cmd_log_test_stop(const struct shell *shell, size_t argc, ARG_UNUSED(argc); ARG_UNUSED(argv); - int err = shell_cmd_precheck(shell, argc == 1); - - if (err) { - return err; - } - k_timer_stop(&log_timer); - shell_fprintf(shell, SHELL_NORMAL, "Log test stopped\n"); + shell_print(shell, "Log test stopped"); return 0; } + SHELL_CREATE_STATIC_SUBCMD_SET(sub_log_test_start) { /* Alphabetically sorted. */ - SHELL_CMD(demo, NULL, + SHELL_CMD_ARG(demo, NULL, "Start log timer which generates log message every 200ms.", - cmd_log_test_start_demo), - SHELL_CMD(flood, NULL, + cmd_log_test_start_demo, 1, 0), + SHELL_CMD_ARG(flood, NULL, "Start log timer which generates log message every 10ms.", - cmd_log_test_start_flood), + cmd_log_test_start_flood, 1, 0), SHELL_SUBCMD_SET_END /* Array terminated. */ }; SHELL_CREATE_STATIC_SUBCMD_SET(sub_log_test) { /* Alphabetically sorted. */ - SHELL_CMD(start, &sub_log_test_start, "Start log test", NULL), - SHELL_CMD(stop, NULL, "Stop log test.", cmd_log_test_stop), + SHELL_CMD_ARG(start, &sub_log_test_start, "Start log test", NULL, 2, 0), + SHELL_CMD_ARG(stop, NULL, "Stop log test.", cmd_log_test_stop, 1, 0), SHELL_SUBCMD_SET_END /* Array terminated. */ }; @@ -99,20 +87,18 @@ static int cmd_demo_ping(const struct shell *shell, size_t argc, char **argv) ARG_UNUSED(argc); ARG_UNUSED(argv); - shell_fprintf(shell, SHELL_NORMAL, "pong\n"); + shell_print(shell, "pong"); return 0; } static int cmd_demo_params(const struct shell *shell, size_t argc, char **argv) { - int cnt; - - shell_fprintf(shell, SHELL_NORMAL, "argc = %d\n", argc); - for (cnt = 0; cnt < argc; cnt++) { - shell_fprintf(shell, SHELL_NORMAL, - " argv[%d] = %s\n", cnt, argv[cnt]); + shell_print(shell, "argc = %d", argc); + for (size_t cnt = 0; cnt < argc; cnt++) { + shell_print(shell, " argv[%d] = %s", cnt, argv[cnt]); } + return 0; } @@ -121,8 +107,8 @@ static int cmd_version(const struct shell *shell, size_t argc, char **argv) ARG_UNUSED(argc); ARG_UNUSED(argv); - shell_fprintf(shell, SHELL_NORMAL, - "Zephyr version %s\n", KERNEL_VERSION_STRING); + shell_print(shell, "Zephyr version %s", KERNEL_VERSION_STRING); + return 0; } @@ -135,8 +121,7 @@ SHELL_CREATE_STATIC_SUBCMD_SET(sub_demo) }; SHELL_CMD_REGISTER(demo, &sub_demo, "Demo commands", NULL); -SHELL_CMD_REGISTER(version, NULL, "Show kernel version", cmd_version); - +SHELL_CMD_ARG_REGISTER(version, NULL, "Show kernel version", cmd_version, 1, 0); void main(void) { diff --git a/subsys/bluetooth/host/mesh/shell.c b/subsys/bluetooth/host/mesh/shell.c index 30f43d0674f..71153549ed5 100644 --- a/subsys/bluetooth/host/mesh/shell.c +++ b/subsys/bluetooth/host/mesh/shell.c @@ -1574,12 +1574,6 @@ static int cmd_provision(const struct shell *shell, size_t argc, char *argv[]) int cmd_timeout(const struct shell *shell, size_t argc, char *argv[]) { s32_t timeout; - int err; - - err = shell_cmd_precheck(shell, (argc >= 1)); - if (err) { - return err; - } if (argc < 2) { timeout = bt_mesh_cfg_cli_timeout_get(); @@ -1619,11 +1613,6 @@ static int cmd_fault_get(const struct shell *shell, size_t argc, char *argv[]) u16_t cid; int err; - err = shell_cmd_precheck(shell, (argc == 1)); - if (err) { - return err; - } - cid = strtoul(argv[1], NULL, 0); fault_count = sizeof(faults); @@ -2043,7 +2032,7 @@ static int cmd_mesh(const struct shell *shell, size_t argc, char **argv) { if (argc == 1) { shell_help_print(shell); - /* shell_cmd_precheck returns 1 when help is printed */ + /* shell returns 1 when help is printed */ return 1; } diff --git a/subsys/bluetooth/shell/bredr.c b/subsys/bluetooth/shell/bredr.c index 3517382d758..aa62a71d196 100644 --- a/subsys/bluetooth/shell/bredr.c +++ b/subsys/bluetooth/shell/bredr.c @@ -552,7 +552,7 @@ static int cmd_br(const struct shell *shell, size_t argc, char **argv) { if (argc == 1) { shell_help_print(shell); - /* shell_cmd_precheck returns 1 when help is printed */ + /* shell returns 1 when help is printed */ return 1; } diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index 93cf88148c8..fc669f1cdd9 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -614,7 +614,7 @@ static int cmd_scan(const struct shell *shell, size_t argc, char *argv[]) dups = BT_HCI_LE_SCAN_FILTER_DUP_ENABLE; } else { shell_help_print(shell); - /* shell_cmd_precheck returns 1 when help is printed */ + /* shell returns 1 when help is printed */ return 1; } } @@ -628,7 +628,7 @@ static int cmd_scan(const struct shell *shell, size_t argc, char *argv[]) return cmd_passive_scan_on(shell, dups); } else { shell_help_print(shell); - /* shell_cmd_precheck returns 1 when help is printed */ + /* shell returns 1 when help is printed */ return 1; } @@ -747,7 +747,7 @@ static int cmd_disconnect(const struct shell *shell, size_t argc, char *argv[]) if (argc < 3) { shell_help_print(shell); - /* shell_cmd_precheck returns 1 when help is printed */ + /* shell returns 1 when help is printed */ return 1; } @@ -796,7 +796,7 @@ static int cmd_auto_conn(const struct shell *shell, size_t argc, char *argv[]) return bt_le_set_auto_conn(&addr, NULL); } else { shell_help_print(shell); - /* shell_cmd_precheck returns 1 when help is printed */ + /* shell returns 1 when help is printed */ return 1; } @@ -823,7 +823,7 @@ static int cmd_directed_adv(const struct shell *shell, if (strcmp(argv[3], "low")) { shell_help_print(shell); - /* shell_cmd_precheck returns 1 when help is printed */ + /* shell returns 1 when help is printed */ return 1; } @@ -1015,7 +1015,7 @@ static int cmd_bondable(const struct shell *shell, size_t argc, char *argv[]) bt_set_bondable(false); } else { shell_help_print(shell); - /* shell_cmd_precheck returns 1 when help is printed */ + /* shell returns 1 when help is printed */ return 1; } @@ -1209,7 +1209,7 @@ static int cmd_auth(const struct shell *shell, size_t argc, char *argv[]) bt_conn_auth_cb_register(NULL); } else { shell_help_print(shell); - /* shell_cmd_precheck returns 1 when help is printed */ + /* shell returns 1 when help is printed */ return 1; } @@ -1390,7 +1390,7 @@ static int cmd_bt(const struct shell *shell, size_t argc, char **argv) { if (argc == 1) { shell_help_print(shell); - /* shell_cmd_precheck returns 1 when help is printed */ + /* shell returns 1 when help is printed */ return 1; } diff --git a/subsys/bluetooth/shell/gatt.c b/subsys/bluetooth/shell/gatt.c index 1cb153cf2b0..7cb4a66afc7 100644 --- a/subsys/bluetooth/shell/gatt.c +++ b/subsys/bluetooth/shell/gatt.c @@ -797,7 +797,7 @@ static int cmd_gatt(const struct shell *shell, size_t argc, char **argv) { if (argc == 1) { shell_help_print(shell); - /* shell_cmd_precheck returns 1 when help is printed */ + /* shell returns 1 when help is printed */ return 1; } diff --git a/subsys/bluetooth/shell/l2cap.c b/subsys/bluetooth/shell/l2cap.c index 4715ff3c364..ed44862de6b 100644 --- a/subsys/bluetooth/shell/l2cap.c +++ b/subsys/bluetooth/shell/l2cap.c @@ -417,7 +417,7 @@ static int cmd_l2cap(const struct shell *shell, size_t argc, char **argv) { if (argc == 1) { shell_help_print(shell); - /* shell_cmd_precheck returns 1 when help is printed */ + /* shell returns 1 when help is printed */ return 1; } diff --git a/subsys/bluetooth/shell/rfcomm.c b/subsys/bluetooth/shell/rfcomm.c index a3f26c9e514..a1ddeb3c9fe 100644 --- a/subsys/bluetooth/shell/rfcomm.c +++ b/subsys/bluetooth/shell/rfcomm.c @@ -245,7 +245,7 @@ static int cmd_rfcomm(const struct shell *shell, size_t argc, char **argv) { if (argc == 1) { shell_help_print(shell); - /* shell_cmd_precheck returns 1 when help is printed */ + /* shell returns 1 when help is printed */ return 1; } diff --git a/subsys/bluetooth/shell/ticker.c b/subsys/bluetooth/shell/ticker.c index 2b923b7dc90..cd72b41370a 100644 --- a/subsys/bluetooth/shell/ticker.c +++ b/subsys/bluetooth/shell/ticker.c @@ -136,7 +136,7 @@ static int cmd_ticker(const struct shell *shell, size_t argc, char **argv) { if (argc == 1) { shell_help_print(shell); - /* shell_cmd_precheck returns 1 when help is printed */ + /* shell returns 1 when help is printed */ return 1; } diff --git a/subsys/fs/shell.c b/subsys/fs/shell.c index 28b9ee9524b..3d9495b2767 100644 --- a/subsys/fs/shell.c +++ b/subsys/fs/shell.c @@ -166,11 +166,6 @@ static int cmd_trunc(const struct shell *shell, size_t argc, char **argv) int length; int err; - err = shell_cmd_precheck(shell, (argc >= 2)); - if (err) { - return err; - } - if (argv[1][0] == '/') { strncpy(path, argv[1], sizeof(path) - 1); path[MAX_PATH_LEN - 1] = '\0'; @@ -212,11 +207,6 @@ static int cmd_mkdir(const struct shell *shell, size_t argc, char **argv) int err; char path[MAX_PATH_LEN]; - err = shell_cmd_precheck(shell, (argc == 2)); - if (err) { - return err; - } - create_abs_path(argv[1], path, sizeof(path)); err = fs_mkdir(path); @@ -234,11 +224,6 @@ static int cmd_rm(const struct shell *shell, size_t argc, char **argv) int err; char path[MAX_PATH_LEN]; - err = shell_cmd_precheck(shell, (argc == 2)); - if (err) { - return err; - } - create_abs_path(argv[1], path, sizeof(path)); err = fs_unlink(path); @@ -260,11 +245,6 @@ static int cmd_read(const struct shell *shell, size_t argc, char **argv) off_t offset; int err; - err = shell_cmd_precheck(shell, (argc >= 2)); - if (err) { - return err; - } - create_abs_path(argv[1], path, sizeof(path)); if (argc > 2) { @@ -356,11 +336,6 @@ static int cmd_write(const struct shell *shell, size_t argc, char **argv) off_t offset = -1; int err; - err = shell_cmd_precheck(shell, (argc >= 3)); - if (err) { - return err; - } - create_abs_path(argv[1], path, sizeof(path)); if (!strcmp(argv[2], "-o")) { @@ -439,11 +414,6 @@ static int cmd_mount_fat(const struct shell *shell, size_t argc, char **argv) char *mntpt; int res; - res = shell_cmd_precheck(shell, (argc == 2)); - if (res) { - return res; - } - mntpt = mntpt_prepare(argv[1]); if (!mntpt) { shell_fprintf(shell, SHELL_ERROR, @@ -473,11 +443,6 @@ static int cmd_mount_nffs(const struct shell *shell, size_t argc, char **argv) char *mntpt; int res; - res = shell_cmd_precheck(shell, (argc == 2)); - if (res) { - return res; - } - mntpt = mntpt_prepare(argv[1]); if (!mntpt) { shell_fprintf(shell, SHELL_ERROR, @@ -512,13 +477,15 @@ SHELL_CREATE_STATIC_SUBCMD_SET(sub_fs_mount) { #if defined(CONFIG_FAT_FILESYSTEM_ELM) - SHELL_CMD(fat, NULL, - "Mount fatfs. fs mount fat ", cmd_mount_fat), + SHELL_CMD_ARG(fat, NULL, + "Mount fatfs. fs mount fat ", + cmd_mount_fat, 2, 0), #endif #if defined(CONFIG_FILE_SYSTEM_NFFS) - SHELL_CMD(nffs, NULL, - "Mount nffs. fs mount nffs ", cmd_mount_nffs), + SHELL_CMD_ARG(nffs, NULL, + "Mount nffs. fs mount nffs ", + cmd_mount_nffs, 2, 0), #endif SHELL_SUBCMD_SET_END @@ -530,16 +497,16 @@ SHELL_CREATE_STATIC_SUBCMD_SET(sub_fs) SHELL_CMD(cd, NULL, "Change working directory", cmd_cd), SHELL_CMD(ls, NULL, "List files in current directory", cmd_ls), - SHELL_CMD(mkdir, NULL, "Create directory", cmd_mkdir), + SHELL_CMD_ARG(mkdir, NULL, "Create directory", cmd_mkdir, 2, 0), #if defined(CONFIG_FILE_SYSTEM_NFFS) || defined(CONFIG_FAT_FILESYSTEM_ELM) SHELL_CMD(mount, &sub_fs_mount, " ", NULL), #endif SHELL_CMD(pwd, NULL, "Print current working directory", cmd_pwd), - SHELL_CMD(read, NULL, "Read from file", cmd_read), - SHELL_CMD(rm, NULL, "Remove file", cmd_rm), - SHELL_CMD(trunc, NULL, "Truncate file", cmd_trunc), - SHELL_CMD(write, NULL, "Write file", cmd_write), + SHELL_CMD_ARG(read, NULL, "Read from file", cmd_read, 2, 255), + SHELL_CMD_ARG(rm, NULL, "Remove file", cmd_rm, 2, 0), + SHELL_CMD_ARG(trunc, NULL, "Truncate file", cmd_trunc, 2, 255), + SHELL_CMD_ARG(write, NULL, "Write file", cmd_write, 3, 255), SHELL_SUBCMD_SET_END }; diff --git a/subsys/logging/log_cmds.c b/subsys/logging/log_cmds.c index 5f7fc7b795a..c1f7017f6fb 100644 --- a/subsys/logging/log_cmds.c +++ b/subsys/logging/log_cmds.c @@ -57,8 +57,7 @@ static bool shell_state_precheck(const struct shell *shell) { if (shell->log_backend->control_block->state == SHELL_LOG_BACKEND_UNINIT) { - shell_fprintf(shell, SHELL_ERROR, - "Shell log backend not initialized.\r\n"); + shell_error(shell, "Shell log backend not initialized."); return false; } @@ -82,8 +81,7 @@ static int shell_backend_cmd_execute(const struct shell *shell, if (backend) { func(shell, backend, argc, argv); } else { - shell_fprintf(shell, SHELL_ERROR, - "Invalid backend: %s\r\n", name); + shell_error(shell, "Invalid backend: %s", name); return -ENOEXEC; } return 0; @@ -101,7 +99,7 @@ static int log_status(const struct shell *shell, if (!log_backend_is_active(backend)) { - shell_fprintf(shell, SHELL_ERROR, "Logs are halted!\r\n"); + shell_warn(shell, "Logs are halted!"); } shell_fprintf(shell, SHELL_NORMAL, "%-40s | current | built-in \r\n", @@ -168,7 +166,7 @@ static void filters_set(const struct shell *shell, int cnt = all ? log_sources_count() : argc; if (!backend->cb->active) { - shell_fprintf(shell, SHELL_WARNING, "Backend not active.\r\n"); + shell_warn(shell, "Backend not active."); } for (i = 0; i < cnt; i++) { @@ -185,13 +183,11 @@ static void filters_set(const struct shell *shell, log_source_name_get( CONFIG_LOG_DOMAIN_ID, i) : argv[i]; - shell_fprintf(shell, SHELL_WARNING, - "%s: level set to %s.\r\n", - name, severity_lvls[set_lvl]); + shell_warn(shell, "%s: level set to %s.", + name, severity_lvls[set_lvl]); } } else { - shell_fprintf(shell, SHELL_ERROR, - "%s: unknown source name.\r\n", argv[i]); + shell_error(shell, "%s: unknown source name.", argv[i]); } } } @@ -214,17 +210,11 @@ static int log_enable(const struct shell *shell, char **argv) { int severity_level; - int err = shell_cmd_precheck(shell, (argc > 1)); - - if (err) { - return err; - } severity_level = severity_level_get(argv[1]); if (severity_level < 0) { - shell_fprintf(shell, SHELL_ERROR, "Invalid severity: %s\r\n", - argv[1]); + shell_error(shell, "Invalid severity: %s", argv[1]); return -ENOEXEC; } @@ -254,12 +244,6 @@ static int log_disable(const struct shell *shell, size_t argc, char **argv) { - int err = shell_cmd_precheck(shell, (argc > 1)); - - if (err) { - return err; - } - filters_set(shell, backend, argc - 1, &argv[1], LOG_LEVEL_NONE); return 0; } @@ -361,11 +345,6 @@ static int cmd_log_backends_list(const struct shell *shell, size_t argc, char **argv) { int backend_count; - int err = shell_cmd_precheck(shell, (argc == 1)); - - if (err) { - return err; - } backend_count = log_backend_count_get(); @@ -387,15 +366,15 @@ static int cmd_log_backends_list(const struct shell *shell, SHELL_CREATE_STATIC_SUBCMD_SET(sub_log_backend) { - SHELL_CMD(disable, &dsub_module_name, + SHELL_CMD_ARG(disable, &dsub_module_name, "'log disable .. ' disables logs in " "specified modules (all if no modules specified).", - cmd_log_backend_disable), - SHELL_CMD(enable, &dsub_severity_lvl, + cmd_log_backend_disable, 2, 255), + SHELL_CMD_ARG(enable, &dsub_severity_lvl, "'log enable ... ' enables logs" " up to given level in specified modules (all if no modules " "specified).", - cmd_log_backend_enable), + cmd_log_backend_enable, 2, 255), SHELL_CMD(go, NULL, "Resume logging", cmd_log_backend_go), SHELL_CMD(halt, NULL, "Halt logging", cmd_log_backend_halt), SHELL_CMD(status, NULL, "Logger status", cmd_log_backend_status), @@ -423,33 +402,21 @@ SHELL_CREATE_STATIC_SUBCMD_SET(sub_log_stat) { SHELL_CMD(backend, &dsub_backend_name_dynamic, "Logger backends commands.", NULL), - SHELL_CMD(disable, &dsub_module_name, + SHELL_CMD_ARG(disable, &dsub_module_name, "'log disable .. ' disables logs in specified " "modules (all if no modules specified).", - cmd_log_self_disable), - SHELL_CMD(enable, &dsub_severity_lvl, + cmd_log_self_disable, 2, 255), + SHELL_CMD_ARG(enable, &dsub_severity_lvl, "'log enable ... ' enables logs up to" " given level in specified modules (all if no modules specified).", - cmd_log_self_enable), + cmd_log_self_enable, 2, 255), SHELL_CMD(go, NULL, "Resume logging", cmd_log_self_go), SHELL_CMD(halt, NULL, "Halt logging", cmd_log_self_halt), - SHELL_CMD(list_backends, NULL, "Lists logger backends.", - cmd_log_backends_list), + SHELL_CMD_ARG(list_backends, NULL, "Lists logger backends.", + cmd_log_backends_list, 1, 0), SHELL_CMD(status, NULL, "Logger status", cmd_log_self_status), SHELL_SUBCMD_SET_END }; -static int cmd_log(const struct shell *shell, size_t argc, char **argv) -{ - if (argc == 1) { - shell_help_print(shell); - return 0; - } - - shell_fprintf(shell, SHELL_ERROR, "%s:%s%s\r\n", - argv[0], " unknown parameter: ", argv[1]); - return -ENOEXEC; -} - SHELL_CMD_REGISTER(log, &sub_log_stat, "Commands for controlling logger", - cmd_log); + NULL); diff --git a/subsys/shell/CMakeLists.txt b/subsys/shell/CMakeLists.txt index 415c496a63f..9007fd7ea32 100644 --- a/subsys/shell/CMakeLists.txt +++ b/subsys/shell/CMakeLists.txt @@ -33,6 +33,11 @@ zephyr_sources_ifdef( shell_rtt.c ) +zephyr_sources_ifdef( + CONFIG_SHELL_HELP + shell_help.c + ) + zephyr_sources_ifdef( CONFIG_SHELL_CMDS shell_cmds.c diff --git a/subsys/shell/shell.c b/subsys/shell/shell.c index 64ce48ef709..6a4221490bc 100644 --- a/subsys/shell/shell.c +++ b/subsys/shell/shell.c @@ -9,6 +9,7 @@ #include #include #include +#include "shell_help.h" #include "shell_utils.h" #include "shell_ops.h" #include "shell_wildcard.h" @@ -42,26 +43,6 @@ static int shell_execute(const struct shell *shell); -extern const struct shell_cmd_entry __shell_root_cmds_start[0]; -extern const struct shell_cmd_entry __shell_root_cmds_end[0]; - -static inline const struct shell_cmd_entry *shell_root_cmd_get(u32_t id) -{ - return &__shell_root_cmds_start[id]; -} - -static inline u32_t shell_root_cmd_count(void) -{ - return ((u8_t *)__shell_root_cmds_end - - (u8_t *)__shell_root_cmds_start)/ - sizeof(struct shell_cmd_entry); -} - -static inline void transport_buffer_flush(const struct shell *shell) -{ - shell_fprintf_buffer_flush(shell->fprintf_ctx); -} - /* Function returns true if delete escape code shall be interpreted as * backspace. */ @@ -88,93 +69,33 @@ static void shell_cmd_buffer_clear(const struct shell *shell) shell->ctx->cmd_buff_len = 0; } -static void shell_pend_on_txdone(const struct shell *shell) -{ - if (IS_ENABLED(CONFIG_MULTITHREADING)) { - k_poll(&shell->ctx->events[SHELL_SIGNAL_TXDONE], 1, K_FOREVER); - k_poll_signal_reset(&shell->ctx->signals[SHELL_SIGNAL_TXDONE]); - } else { - /* Blocking wait in case of bare metal. */ - while (!shell->ctx->internal.flags.tx_rdy) { - } - shell->ctx->internal.flags.tx_rdy = 0; - } -} - -/* Function sends data stream to the shell instance. Each time before the - * shell_write function is called, it must be ensured that IO buffer of fprintf - * is flushed to avoid synchronization issues. - * For that purpose, use function transport_buffer_flush(shell) - */ -static void shell_write(const struct shell *shell, const void *data, - size_t length) -{ - __ASSERT_NO_MSG(shell && data); - - size_t offset = 0; - size_t tmp_cnt; - - while (length) { - int err = shell->iface->api->write(shell->iface, - &((const u8_t *) data)[offset], length, - &tmp_cnt); - (void)err; - __ASSERT_NO_MSG(err == 0); - __ASSERT_NO_MSG(length >= tmp_cnt); - offset += tmp_cnt; - length -= tmp_cnt; - if (tmp_cnt == 0 && - (shell->ctx->state != SHELL_STATE_PANIC_MODE_ACTIVE)) { - shell_pend_on_txdone(shell); - } - } -} - -/* @brief Function shall be used to search commands. +/** + * @brief Prints error message on wrong argument count. + * Optionally, printing help on wrong argument count. * - * It moves the pointer entry to command of static command structure. If the - * command cannot be found, the function will set entry to NULL. + * @param[in] shell Pointer to the shell instance. + * @param[in] arg_cnt_ok Flag indicating valid number of arguments. * - * @param command Pointer to command which will be processed (no matter - * the root command). - * @param lvl Level of the requested command. - * @param idx Index of the requested command. - * @param entry Pointer which points to subcommand[idx] after function - * execution. - * @param st_entry Pointer to the structure where dynamic entry data can be - * stored. + * @return 0 if check passed + * @return 1 if help was requested + * @return -EINVAL if wrong argument count */ -static void cmd_get(const struct shell_cmd_entry *command, size_t lvl, - size_t idx, const struct shell_static_entry **entry, - struct shell_static_entry *d_entry) +static int shell_cmd_precheck(const struct shell *shell, + bool arg_cnt_ok) { - __ASSERT_NO_MSG(entry != NULL); - __ASSERT_NO_MSG(d_entry != NULL); + if (!arg_cnt_ok) { + shell_fprintf(shell, SHELL_ERROR, + "%s: wrong parameter count\n", + shell->ctx->active_cmd.syntax); - if (lvl == SHELL_CMD_ROOT_LVL) { - if (idx < shell_root_cmd_count()) { - const struct shell_cmd_entry *cmd; - - cmd = shell_root_cmd_get(idx); - *entry = cmd->u.entry; - } else { - *entry = NULL; + if (IS_ENABLED(CONFIG_SHELL_HELP_ON_WRONG_ARGUMENT_COUNT)) { + shell_help_print(shell); } - return; + + return -EINVAL; } - if (command == NULL) { - *entry = NULL; - return; - } - - if (command->is_dynamic) { - command->u.dynamic_get(idx, d_entry); - *entry = (d_entry->syntax != NULL) ? d_entry : NULL; - } else { - *entry = (command->u.entry[idx].syntax != NULL) ? - &command->u.entry[idx] : NULL; - } + return 0; } static void vt100_color_set(const struct shell *shell, @@ -364,7 +285,7 @@ static const struct shell_static_entry *find_cmd( size_t idx = 0; do { - cmd_get(cmd, lvl, idx++, &entry, d_entry); + shell_cmd_get(cmd, lvl, idx++, &entry, d_entry); if (entry && (strcmp(cmd_str, entry->syntax) == 0)) { return entry; } @@ -490,8 +411,8 @@ static void find_completion_candidates(const struct shell_static_entry *cmd, *cnt = 0; while (true) { - cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, - idx, &candidate, &dynamic_entry); + shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, + idx, &candidate, &dynamic_entry); if (!candidate) { break; @@ -526,8 +447,8 @@ static void autocomplete(const struct shell *shell, /* shell->ctx->active_cmd can be safely used outside of command context * to save stack */ - cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, - subcmd_idx, &match, &shell->ctx->active_cmd); + shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, + subcmd_idx, &match, &shell->ctx->active_cmd); cmd_len = shell_strlen(match->syntax); /* no exact match found */ @@ -589,8 +510,8 @@ static void tab_options_print(const struct shell *shell, /* shell->ctx->active_cmd can be safely used outside of command * context to save stack */ - cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, - idx, &match, &shell->ctx->active_cmd); + shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, + idx, &match, &shell->ctx->active_cmd); idx++; if (str && match->syntax && @@ -617,8 +538,9 @@ static u16_t common_beginning_find(const struct shell_static_entry *cmd, u16_t common = UINT16_MAX; size_t idx = first + 1; - cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, - first, &match, &dynamic_entry); + + shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, + first, &match, &dynamic_entry); *str = match->syntax; @@ -627,8 +549,8 @@ static u16_t common_beginning_find(const struct shell_static_entry *cmd, const struct shell_static_entry *match2; int curr_common; - cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, - idx++, &match2, &dynamic_entry2); + shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, + idx++, &match2, &dynamic_entry2); if (match2 == NULL) { break; @@ -675,6 +597,7 @@ static void shell_tab_handle(const struct shell *shell) size_t argc; size_t cnt; + bool tab_possible = shell_tab_prepare(shell, &cmd, argv, &argc, &arg_idx, &d_entry); @@ -949,22 +872,6 @@ static void cmd_trim(const struct shell *shell) shell->ctx->cmd_buff_pos = shell->ctx->cmd_buff_len; } -/* Function returning pointer to root command matching requested syntax. */ -static const struct shell_cmd_entry *root_cmd_find(const char *syntax) -{ - const size_t cmd_count = shell_root_cmd_count(); - const struct shell_cmd_entry *cmd; - - for (size_t cmd_idx = 0; cmd_idx < cmd_count; ++cmd_idx) { - cmd = shell_root_cmd_get(cmd_idx); - if (strcmp(syntax, cmd->u.entry->syntax) == 0) { - return cmd; - } - } - - return NULL; -} - static int exec_cmd(const struct shell *shell, size_t argc, char **argv, struct shell_static_entry help_entry) { @@ -976,12 +883,14 @@ static int exec_cmd(const struct shell *shell, size_t argc, char **argv, shell->ctx->active_cmd = help_entry; } shell_help_print(shell); + /* 1 is return value when shell prints help */ + ret_val = 1; } else { shell_fprintf(shell, SHELL_ERROR, SHELL_MSG_SPECIFY_SUBCOMMAND); + ret_val = -ENOEXEC; } - ret_val = -ENOEXEC; goto clear; } @@ -1123,7 +1032,8 @@ static int shell_execute(const struct shell *shell) } } - cmd_get(p_cmd, cmd_lvl, cmd_idx++, &p_static_entry, &d_entry); + shell_cmd_get(p_cmd, cmd_lvl, cmd_idx++, &p_static_entry, + &d_entry); if ((cmd_idx == 0) || (p_static_entry == NULL)) { break; @@ -1482,13 +1392,6 @@ void shell_process(const struct shell *shell) internal.value); } -/* Function shall be only used by the fprintf module. */ -void shell_print_stream(const void *user_ctx, const char *data, - size_t data_len) -{ - shell_write((const struct shell *) user_ctx, data, data_len); -} - void shell_fprintf(const struct shell *shell, enum shell_vt100_color color, const char *p_fmt, ...) { @@ -1516,216 +1419,6 @@ void shell_fprintf(const struct shell *shell, enum shell_vt100_color color, va_end(args); } -/* Function prints a string on terminal screen with requested margin. - * It takes care to not divide words. - * shell Pointer to shell instance. - * p_str Pointer to string to be printed. - * terminal_offset Requested left margin. - * offset_first_line Add margin to the first printed line. - */ -static void formatted_text_print(const struct shell *shell, const char *str, - size_t terminal_offset, bool offset_first_line) -{ - size_t offset = 0; - size_t length; - - if (str == NULL) { - return; - } - - if (offset_first_line) { - shell_op_cursor_horiz_move(shell, terminal_offset); - } - - - /* Skipping whitespace. */ - while (isspace((int) *(str + offset))) { - ++offset; - } - - while (true) { - size_t idx = 0; - - length = shell_strlen(str) - offset; - - if (length <= - shell->ctx->vt100_ctx.cons.terminal_wid - terminal_offset) { - for (idx = 0; idx < length; idx++) { - if (*(str + offset + idx) == '\n') { - transport_buffer_flush(shell); - shell_write(shell, str + offset, idx); - offset += idx + 1; - cursor_next_line_move(shell); - shell_op_cursor_horiz_move(shell, - terminal_offset); - break; - } - } - - /* String will fit in one line. */ - shell_raw_fprintf(shell->fprintf_ctx, str + offset); - - break; - } - - /* String is longer than terminal line so text needs to - * divide in the way to not divide words. - */ - length = shell->ctx->vt100_ctx.cons.terminal_wid - - terminal_offset; - - while (true) { - /* Determining line break. */ - if (isspace((int) (*(str + offset + idx)))) { - length = idx; - if (*(str + offset + idx) == '\n') { - break; - } - } - - if ((idx + terminal_offset) >= - shell->ctx->vt100_ctx.cons.terminal_wid) { - /* End of line reached. */ - break; - } - - ++idx; - } - - /* Writing one line, fprintf IO buffer must be flushed - * before calling shell_write. - */ - transport_buffer_flush(shell); - shell_write(shell, str + offset, length); - offset += length; - - /* Calculating text offset to ensure that next line will - * not begin with a space. - */ - while (isspace((int) (*(str + offset)))) { - ++offset; - } - - cursor_next_line_move(shell); - shell_op_cursor_horiz_move(shell, terminal_offset); - - } - cursor_next_line_move(shell); -} - -static void help_cmd_print(const struct shell *shell) -{ - static const char cmd_sep[] = " - "; /* commands separator */ - - u16_t field_width = shell_strlen(shell->ctx->active_cmd.syntax) + - shell_strlen(cmd_sep); - - shell_fprintf(shell, SHELL_NORMAL, "%s%s", - shell->ctx->active_cmd.syntax, cmd_sep); - - formatted_text_print(shell, shell->ctx->active_cmd.help, - field_width, false); -} - -static void help_item_print(const struct shell *shell, const char *item_name, - u16_t item_name_width, const char *item_help) -{ - static const u8_t tabulator[] = " "; - const u16_t offset = 2 * strlen(tabulator) + item_name_width + 1; - - if (item_name == NULL) { - return; - } - - if (!IS_ENABLED(CONFIG_NEWLIB_LIBC) && !IS_ENABLED(CONFIG_ARCH_POSIX)) { - /* print option name */ - shell_fprintf(shell, SHELL_NORMAL, "%s%-*s%s:", - tabulator, - item_name_width, item_name, - tabulator); - } else { - u16_t tmp = item_name_width - strlen(item_name); - char space = ' '; - - shell_fprintf(shell, SHELL_NORMAL, "%s%s", tabulator, - item_name); - for (u16_t i = 0; i < tmp; i++) { - shell_write(shell, &space, 1); - } - shell_fprintf(shell, SHELL_NORMAL, "%s:", tabulator); - } - - if (item_help == NULL) { - cursor_next_line_move(shell); - return; - } - /* print option help */ - formatted_text_print(shell, item_help, offset, false); -} - -/* Function is printing command help, its subcommands name and subcommands - * help string. - */ -static void help_subcmd_print(const struct shell *shell) -{ - const struct shell_static_entry *entry = NULL; - struct shell_static_entry static_entry; - u16_t longest_syntax = 0U; - size_t cmd_idx = 0; - - /* Checking if there are any subcommands available. */ - if (!shell->ctx->active_cmd.subcmd) { - return; - } - - /* Searching for the longest subcommand to print. */ - do { - cmd_get(shell->ctx->active_cmd.subcmd, !SHELL_CMD_ROOT_LVL, - cmd_idx++, &entry, &static_entry); - - if (!entry) { - break; - } - - u16_t len = shell_strlen(entry->syntax); - - longest_syntax = longest_syntax > len ? longest_syntax : len; - } while (cmd_idx != 0); /* too many commands */ - - if (cmd_idx == 1) { - return; - } - - shell_fprintf(shell, SHELL_NORMAL, "Subcommands:\r\n"); - - /* Printing subcommands and help string (if exists). */ - cmd_idx = 0; - - while (true) { - cmd_get(shell->ctx->active_cmd.subcmd, !SHELL_CMD_ROOT_LVL, - cmd_idx++, &entry, &static_entry); - - if (entry == NULL) { - break; - } - - help_item_print(shell, entry->syntax, longest_syntax, - entry->help); - } -} - -void shell_help_print(const struct shell *shell) -{ - __ASSERT_NO_MSG(shell); - - if (!IS_ENABLED(CONFIG_SHELL_HELP)) { - return; - } - - help_cmd_print(shell); - help_subcmd_print(shell); -} - int shell_prompt_change(const struct shell *shell, char *prompt) { @@ -1741,22 +1434,16 @@ int shell_prompt_change(const struct shell *shell, char *prompt) return -1; } -int shell_cmd_precheck(const struct shell *shell, - bool arg_cnt_ok) +void shell_help_print(const struct shell *shell) { - if (!arg_cnt_ok) { - shell_fprintf(shell, SHELL_ERROR, - "%s: wrong parameter count\n", - shell->ctx->active_cmd.syntax); + __ASSERT_NO_MSG(shell); - if (IS_ENABLED(CONFIG_SHELL_HELP_ON_WRONG_ARGUMENT_COUNT)) { - shell_help_print(shell); - } - - return -EINVAL; + if (!IS_ENABLED(CONFIG_SHELL_HELP)) { + return; } - return 0; + shell_help_cmd_print(shell); + shell_help_subcmd_print(shell); } int shell_execute_cmd(const struct shell *shell, const char *cmd) diff --git a/subsys/shell/shell_cmds.c b/subsys/shell/shell_cmds.c index 99cc565d495..48716bee974 100644 --- a/subsys/shell/shell_cmds.c +++ b/subsys/shell/shell_cmds.c @@ -41,6 +41,7 @@ "Disable shell echo. Editing keys and meta-keys are not handled" #define SHELL_HELP_SHELL "Useful, not Unix-like shell commands." +#define SHELL_HELP_HELP "Prints help message." #define SHELL_MSG_UNKNOWN_PARAMETER " unknown parameter: " @@ -96,7 +97,7 @@ static int cursor_position_get(const struct shell *shell, u16_t *x, u16_t *y) /* Index start position in the buffer where 'y' * is stored. */ - buff_idx = 2U; + buff_idx = 2; while (shell->ctx->temp_buff[buff_idx] != ';') { *y = *y * 10 + @@ -184,157 +185,84 @@ static int cmd_clear(const struct shell *shell, size_t argc, char **argv) { ARG_UNUSED(argv); - int ret = shell_cmd_precheck(shell, (argc == 1)); - - if (ret) { - return ret; - } - SHELL_VT100_CMD(shell, SHELL_VT100_CURSORHOME); SHELL_VT100_CMD(shell, SHELL_VT100_CLEARSCREEN); return 0; } -static int cmd_shell(const struct shell *shell, size_t argc, char **argv) -{ - int ret = shell_cmd_precheck(shell, (argc == 2)); - - if (ret) { - return ret; - } - - shell_fprintf(shell, SHELL_ERROR, "%s:%s%s\n", argv[0], - SHELL_MSG_UNKNOWN_PARAMETER, argv[1]); - - return -EINVAL; -} - static int cmd_bacskpace_mode_backspace(const struct shell *shell, size_t argc, char **argv) { + ARG_UNUSED(argc); ARG_UNUSED(argv); - int ret = shell_cmd_precheck(shell, (argc == 1)); + shell->ctx->internal.flags.mode_delete = 0; - if (ret == 0) { - shell->ctx->internal.flags.mode_delete = 0; - } - - return ret; + return 0; } static int cmd_bacskpace_mode_delete(const struct shell *shell, size_t argc, char **argv) { + ARG_UNUSED(argc); ARG_UNUSED(argv); - int ret = shell_cmd_precheck(shell, (argc == 1)); + shell->ctx->internal.flags.mode_delete = 1; - if (ret == 0) { - shell->ctx->internal.flags.mode_delete = 1; - } - - return ret; -} - -static int cmd_bacskpace_mode(const struct shell *shell, size_t argc, - char **argv) -{ - int ret = shell_cmd_precheck(shell, (argc == 2)); - - if (ret) { - return ret; - } - - shell_fprintf(shell, SHELL_ERROR, "%s:%s%s\n", argv[0], - SHELL_MSG_UNKNOWN_PARAMETER, argv[1]); - - return -EINVAL; + return 0; } static int cmd_colors_off(const struct shell *shell, size_t argc, char **argv) { + ARG_UNUSED(argc); ARG_UNUSED(argv); - int ret = shell_cmd_precheck(shell, (argc == 1)); + shell->ctx->internal.flags.use_colors = 0; - if (ret == 0) { - shell->ctx->internal.flags.use_colors = 0; - } - - return ret; + return 0; } static int cmd_colors_on(const struct shell *shell, size_t argc, char **argv) { ARG_UNUSED(argv); + ARG_UNUSED(argv); - int ret = shell_cmd_precheck(shell, (argc == 1)); + shell->ctx->internal.flags.use_colors = 1; - if (ret == 0) { - shell->ctx->internal.flags.use_colors = 1; - } - - return ret; -} - -static int cmd_colors(const struct shell *shell, size_t argc, char **argv) -{ - int ret = shell_cmd_precheck(shell, (argc == 2)); - - if (ret) { - return ret; - } - - shell_fprintf(shell, SHELL_ERROR, "%s:%s%s\n", argv[0], - SHELL_MSG_UNKNOWN_PARAMETER, argv[1]); - - return -EINVAL; + return 0; } static int cmd_echo_off(const struct shell *shell, size_t argc, char **argv) { + ARG_UNUSED(argc); ARG_UNUSED(argv); - int ret = shell_cmd_precheck(shell, (argc == 1)); + shell->ctx->internal.flags.echo = 0; - if (ret == 0) { - shell->ctx->internal.flags.echo = 0; - } - - return ret; + return 0; } static int cmd_echo_on(const struct shell *shell, size_t argc, char **argv) { + ARG_UNUSED(argc); ARG_UNUSED(argv); - int ret = shell_cmd_precheck(shell, (argc == 1)); + shell->ctx->internal.flags.echo = 1; - if (ret == 0) { - shell->ctx->internal.flags.echo = 1; - } - - return ret; + return 0; } static int cmd_echo(const struct shell *shell, size_t argc, char **argv) { - int ret = shell_cmd_precheck(shell, (argc <= 2)); - - if (ret) { - return ret; - } - if (argc == 2) { - shell_fprintf(shell, SHELL_ERROR, "%s:%s%s\n", argv[0], - SHELL_MSG_UNKNOWN_PARAMETER, argv[1]); + shell_error(shell, "%s:%s%s", argv[0], + SHELL_MSG_UNKNOWN_PARAMETER, argv[1]); return -EINVAL; } - shell_fprintf(shell, SHELL_NORMAL, "Echo status: %s\n", - flag_echo_is_set(shell) ? "on" : "off"); + shell_print(shell, "Echo status: %s", + flag_echo_is_set(shell) ? "on" : "off"); return 0; } @@ -344,42 +272,36 @@ static int cmd_help(const struct shell *shell, size_t argc, char **argv) ARG_UNUSED(argc); ARG_UNUSED(argv); - shell_fprintf(shell, SHELL_NORMAL, + shell_print(shell, "Please press the button to see all available commands.\n" "You can also use the button to prompt or auto-complete" " all commands or its subcommands.\n" "You can try to call commands with <-h> or <--help> parameter" - " for more information.\n"); + " for more information."); return 0; } static int cmd_history(const struct shell *shell, size_t argc, char **argv) { + ARG_UNUSED(argc); ARG_UNUSED(argv); size_t i = 0; size_t len; - int ret; if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) { - shell_fprintf(shell, SHELL_ERROR, SHELL_MSG_CMD_NOT_SUPPORTED); + shell_error(shell, "Command not supported."); return -ENOEXEC; } - ret = shell_cmd_precheck(shell, (argc == 1)); - - if (ret) { - return ret; - } - while (1) { shell_history_get(shell->history, true, shell->ctx->temp_buff, &len); if (len) { - shell_fprintf(shell, SHELL_NORMAL, "[%3d] %s\n", - i++, shell->ctx->temp_buff); + shell_print(shell, "[%3d] %s", + i++, shell->ctx->temp_buff); } else { break; @@ -394,72 +316,46 @@ static int cmd_history(const struct shell *shell, size_t argc, char **argv) static int cmd_shell_stats_show(const struct shell *shell, size_t argc, char **argv) { + ARG_UNUSED(argc); ARG_UNUSED(argv); if (!IS_ENABLED(CONFIG_SHELL_STATS)) { - shell_fprintf(shell, SHELL_ERROR, SHELL_MSG_CMD_NOT_SUPPORTED); + shell_error(shell, "Command not supported."); return -ENOEXEC; } - int ret = shell_cmd_precheck(shell, (argc == 1)); + shell_print(shell, "Lost logs: %u", shell->stats->log_lost_cnt); - if (ret == 0) { - shell_fprintf(shell, SHELL_NORMAL, "Lost logs: %u\n", - shell->stats->log_lost_cnt); - } - - return ret; + return 0; } static int cmd_shell_stats_reset(const struct shell *shell, size_t argc, char **argv) { + ARG_UNUSED(argc); ARG_UNUSED(argv); if (!IS_ENABLED(CONFIG_SHELL_STATS)) { - shell_fprintf(shell, SHELL_ERROR, SHELL_MSG_CMD_NOT_SUPPORTED); + shell_error(shell, "Command not supported."); return -ENOEXEC; } - int ret = shell_cmd_precheck(shell, (argc == 1)); + shell->stats->log_lost_cnt = 0; - if (ret == 0) { - shell->stats->log_lost_cnt = 0; - } - - return ret; -} - -static int cmd_shell_stats(const struct shell *shell, size_t argc, char **argv) -{ - ARG_UNUSED(argc); - - if (argc == 1) { - shell_help_print(shell); - } else { - shell_fprintf(shell, SHELL_ERROR, "%s:%s%s\n", argv[0], - SHELL_MSG_UNKNOWN_PARAMETER, argv[1]); - } - - return -EINVAL; + return 0; } static int cmd_resize_default(const struct shell *shell, size_t argc, char **argv) { + ARG_UNUSED(argc); ARG_UNUSED(argv); - int ret = shell_cmd_precheck(shell, (argc == 1)); + SHELL_VT100_CMD(shell, SHELL_VT100_SETCOL_80); + shell->ctx->vt100_ctx.cons.terminal_wid = SHELL_DEFAULT_TERMINAL_WIDTH; + shell->ctx->vt100_ctx.cons.terminal_hei = SHELL_DEFAULT_TERMINAL_HEIGHT; - if (ret == 0) { - SHELL_VT100_CMD(shell, SHELL_VT100_SETCOL_80); - shell->ctx->vt100_ctx.cons.terminal_wid = - SHELL_DEFAULT_TERMINAL_WIDTH; - shell->ctx->vt100_ctx.cons.terminal_hei = - SHELL_DEFAULT_TERMINAL_HEIGHT; - } - - return ret; + return 0; } static int cmd_resize(const struct shell *shell, size_t argc, char **argv) @@ -467,18 +363,13 @@ static int cmd_resize(const struct shell *shell, size_t argc, char **argv) int err; if (!IS_ENABLED(CONFIG_SHELL_CMDS_RESIZE)) { - shell_fprintf(shell, SHELL_ERROR, SHELL_MSG_CMD_NOT_SUPPORTED); + shell_error(shell, "Command not supported."); return -ENOEXEC; } - err = shell_cmd_precheck(shell, (argc <= 2)); - if (err) { - return err; - } - if (argc != 1) { - shell_fprintf(shell, SHELL_ERROR, "%s:%s%s\n", argv[0], - SHELL_MSG_UNKNOWN_PARAMETER, argv[1]); + shell_error(shell, "%s:%s%s", argv[0], + SHELL_MSG_UNKNOWN_PARAMETER, argv[1]); return -EINVAL; } @@ -488,9 +379,8 @@ static int cmd_resize(const struct shell *shell, size_t argc, char **argv) SHELL_DEFAULT_TERMINAL_WIDTH; shell->ctx->vt100_ctx.cons.terminal_hei = SHELL_DEFAULT_TERMINAL_HEIGHT; - shell_fprintf(shell, SHELL_WARNING, - "No response from the terminal, assumed 80x24 " - "screen size\n"); + shell_warn(shell, "No response from the terminal, assumed 80x24" + " screen size"); return -ENOEXEC; } @@ -499,54 +389,56 @@ static int cmd_resize(const struct shell *shell, size_t argc, char **argv) SHELL_CREATE_STATIC_SUBCMD_SET(m_sub_colors) { - SHELL_CMD(off, NULL, SHELL_HELP_COLORS_OFF, cmd_colors_off), - SHELL_CMD(on, NULL, SHELL_HELP_COLORS_ON, cmd_colors_on), + SHELL_CMD_ARG(off, NULL, SHELL_HELP_COLORS_OFF, cmd_colors_off, 1, 0), + SHELL_CMD_ARG(on, NULL, SHELL_HELP_COLORS_ON, cmd_colors_on, 1, 0), SHELL_SUBCMD_SET_END }; SHELL_CREATE_STATIC_SUBCMD_SET(m_sub_echo) { - SHELL_CMD(off, NULL, SHELL_HELP_ECHO_OFF, cmd_echo_off), - SHELL_CMD(on, NULL, SHELL_HELP_ECHO_ON, cmd_echo_on), + SHELL_CMD_ARG(off, NULL, SHELL_HELP_ECHO_OFF, cmd_echo_off, 1, 0), + SHELL_CMD_ARG(on, NULL, SHELL_HELP_ECHO_ON, cmd_echo_on, 1, 0), SHELL_SUBCMD_SET_END }; SHELL_CREATE_STATIC_SUBCMD_SET(m_sub_shell_stats) { - SHELL_CMD(reset, NULL, SHELL_HELP_STATISTICS_RESET, - cmd_shell_stats_reset), - SHELL_CMD(show, NULL, SHELL_HELP_STATISTICS_SHOW, cmd_shell_stats_show), + SHELL_CMD_ARG(reset, NULL, SHELL_HELP_STATISTICS_RESET, + cmd_shell_stats_reset, 1, 0), + SHELL_CMD_ARG(show, NULL, SHELL_HELP_STATISTICS_SHOW, + cmd_shell_stats_show, 1, 0), SHELL_SUBCMD_SET_END }; SHELL_CREATE_STATIC_SUBCMD_SET(m_sub_backspace_mode) { - SHELL_CMD(backspace, NULL, SHELL_HELP_BACKSPACE_MODE_BACKSPACE, - cmd_bacskpace_mode_backspace), - SHELL_CMD(delete, NULL, SHELL_HELP_BACKSPACE_MODE_DELETE, - cmd_bacskpace_mode_delete), + SHELL_CMD_ARG(backspace, NULL, SHELL_HELP_BACKSPACE_MODE_BACKSPACE, + cmd_bacskpace_mode_backspace, 1, 0), + SHELL_CMD_ARG(delete, NULL, SHELL_HELP_BACKSPACE_MODE_DELETE, + cmd_bacskpace_mode_delete, 1, 0), SHELL_SUBCMD_SET_END }; SHELL_CREATE_STATIC_SUBCMD_SET(m_sub_shell) { SHELL_CMD(backspace_mode, &m_sub_backspace_mode, - SHELL_HELP_BACKSPACE_MODE, cmd_bacskpace_mode), - SHELL_CMD(colors, &m_sub_colors, SHELL_HELP_COLORS, cmd_colors), - SHELL_CMD(echo, &m_sub_echo, SHELL_HELP_ECHO, cmd_echo), - SHELL_CMD(stats, &m_sub_shell_stats, SHELL_HELP_STATISTICS, - cmd_shell_stats), + SHELL_HELP_BACKSPACE_MODE, NULL), + SHELL_CMD(colors, &m_sub_colors, SHELL_HELP_COLORS, NULL), + SHELL_CMD_ARG(echo, &m_sub_echo, SHELL_HELP_ECHO, cmd_echo, 1, 1), + SHELL_CMD(stats, &m_sub_shell_stats, SHELL_HELP_STATISTICS, NULL), SHELL_SUBCMD_SET_END }; SHELL_CREATE_STATIC_SUBCMD_SET(m_sub_resize) { - SHELL_CMD(default, NULL, SHELL_HELP_RESIZE_DEFAULT, cmd_resize_default), + SHELL_CMD_ARG(default, NULL, SHELL_HELP_RESIZE_DEFAULT, + cmd_resize_default, 1, 0), SHELL_SUBCMD_SET_END }; -SHELL_CMD_REGISTER(clear, NULL, SHELL_HELP_CLEAR, cmd_clear); -SHELL_CMD_REGISTER(shell, &m_sub_shell, SHELL_HELP_SHELL, cmd_shell); -SHELL_CMD_REGISTER(help, NULL, NULL, cmd_help); -SHELL_CMD_REGISTER(history, NULL, SHELL_HELP_HISTORY, cmd_history); -SHELL_CMD_REGISTER(resize, &m_sub_resize, SHELL_HELP_RESIZE, cmd_resize); +SHELL_CMD_ARG_REGISTER(clear, NULL, SHELL_HELP_CLEAR, cmd_clear, 1, 0); +SHELL_CMD_REGISTER(shell, &m_sub_shell, SHELL_HELP_SHELL, NULL); +SHELL_CMD_ARG_REGISTER(help, NULL, SHELL_HELP_HELP, cmd_help, 1, 255); +SHELL_CMD_ARG_REGISTER(history, NULL, SHELL_HELP_HISTORY, cmd_history, 1, 0); +SHELL_CMD_ARG_REGISTER(resize, &m_sub_resize, SHELL_HELP_RESIZE, cmd_resize, + 1, 1); diff --git a/subsys/shell/shell_help.c b/subsys/shell/shell_help.c new file mode 100644 index 00000000000..825b92a16e4 --- /dev/null +++ b/subsys/shell/shell_help.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "shell_ops.h" +#include "shell_help.h" +#include "shell_utils.h" + +/* Function prints a string on terminal screen with requested margin. + * It takes care to not divide words. + * shell Pointer to shell instance. + * p_str Pointer to string to be printed. + * terminal_offset Requested left margin. + * offset_first_line Add margin to the first printed line. + */ +static void formatted_text_print(const struct shell *shell, const char *str, + size_t terminal_offset, bool offset_first_line) +{ + size_t offset = 0; + size_t length; + + if (str == NULL) { + return; + } + + if (offset_first_line) { + shell_op_cursor_horiz_move(shell, terminal_offset); + } + + + /* Skipping whitespace. */ + while (isspace((int) *(str + offset))) { + ++offset; + } + + while (true) { + size_t idx = 0; + + length = shell_strlen(str) - offset; + + if (length <= + shell->ctx->vt100_ctx.cons.terminal_wid - terminal_offset) { + for (idx = 0; idx < length; idx++) { + if (*(str + offset + idx) == '\n') { + transport_buffer_flush(shell); + shell_write(shell, str + offset, idx); + offset += idx + 1; + cursor_next_line_move(shell); + shell_op_cursor_horiz_move(shell, + terminal_offset); + break; + } + } + + /* String will fit in one line. */ + shell_raw_fprintf(shell->fprintf_ctx, str + offset); + + break; + } + + /* String is longer than terminal line so text needs to + * divide in the way to not divide words. + */ + length = shell->ctx->vt100_ctx.cons.terminal_wid + - terminal_offset; + + while (true) { + /* Determining line break. */ + if (isspace((int) (*(str + offset + idx)))) { + length = idx; + if (*(str + offset + idx) == '\n') { + break; + } + } + + if ((idx + terminal_offset) >= + shell->ctx->vt100_ctx.cons.terminal_wid) { + /* End of line reached. */ + break; + } + + ++idx; + } + + /* Writing one line, fprintf IO buffer must be flushed + * before calling shell_write. + */ + transport_buffer_flush(shell); + shell_write(shell, str + offset, length); + offset += length; + + /* Calculating text offset to ensure that next line will + * not begin with a space. + */ + while (isspace((int) (*(str + offset)))) { + ++offset; + } + + cursor_next_line_move(shell); + shell_op_cursor_horiz_move(shell, terminal_offset); + + } + cursor_next_line_move(shell); +} + +static void help_item_print(const struct shell *shell, const char *item_name, + u16_t item_name_width, const char *item_help) +{ + static const u8_t tabulator[] = " "; + const u16_t offset = 2 * strlen(tabulator) + item_name_width + 1; + + if (item_name == NULL) { + return; + } + + if (!IS_ENABLED(CONFIG_NEWLIB_LIBC) && !IS_ENABLED(CONFIG_ARCH_POSIX)) { + /* print option name */ + shell_fprintf(shell, SHELL_NORMAL, "%s%-*s%s:", + tabulator, + item_name_width, item_name, + tabulator); + } else { + u16_t tmp = item_name_width - strlen(item_name); + char space = ' '; + + shell_fprintf(shell, SHELL_NORMAL, "%s%s", tabulator, + item_name); + for (u16_t i = 0; i < tmp; i++) { + shell_write(shell, &space, 1); + } + shell_fprintf(shell, SHELL_NORMAL, "%s:", tabulator); + } + + if (item_help == NULL) { + cursor_next_line_move(shell); + return; + } + /* print option help */ + formatted_text_print(shell, item_help, offset, false); +} + +/* Function is printing command help, its subcommands name and subcommands + * help string. + */ +void shell_help_subcmd_print(const struct shell *shell) +{ + const struct shell_static_entry *entry = NULL; + struct shell_static_entry static_entry; + u16_t longest_syntax = 0; + size_t cmd_idx = 0; + + /* Checking if there are any subcommands available. */ + if (!shell->ctx->active_cmd.subcmd) { + return; + } + + /* Searching for the longest subcommand to print. */ + do { + shell_cmd_get(shell->ctx->active_cmd.subcmd, + !SHELL_CMD_ROOT_LVL, + cmd_idx++, &entry, &static_entry); + + if (!entry) { + break; + } + + u16_t len = shell_strlen(entry->syntax); + + longest_syntax = longest_syntax > len ? longest_syntax : len; + } while (cmd_idx != 0); /* too many commands */ + + if (cmd_idx == 1) { + return; + } + + shell_fprintf(shell, SHELL_NORMAL, "Subcommands:\r\n"); + + /* Printing subcommands and help string (if exists). */ + cmd_idx = 0; + + while (true) { + shell_cmd_get(shell->ctx->active_cmd.subcmd, + !SHELL_CMD_ROOT_LVL, + cmd_idx++, &entry, &static_entry); + + if (entry == NULL) { + break; + } + + help_item_print(shell, entry->syntax, longest_syntax, + entry->help); + } +} + +void shell_help_cmd_print(const struct shell *shell) +{ + static const char cmd_sep[] = " - "; /* commands separator */ + + u16_t field_width = shell_strlen(shell->ctx->active_cmd.syntax) + + shell_strlen(cmd_sep); + + shell_fprintf(shell, SHELL_NORMAL, "%s%s", + shell->ctx->active_cmd.syntax, cmd_sep); + + formatted_text_print(shell, shell->ctx->active_cmd.help, + field_width, false); +} + diff --git a/subsys/shell/shell_help.h b/subsys/shell/shell_help.h new file mode 100644 index 00000000000..7f7ecf8fa28 --- /dev/null +++ b/subsys/shell/shell_help.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SHELL_HELP_H__ +#define SHELL_HELP_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Function is printing command help string. */ +void shell_help_cmd_print(const struct shell *shell); + +/* Function is printing subcommands help string. */ +void shell_help_subcmd_print(const struct shell *shell); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* SHELL_HELP__ */ diff --git a/subsys/shell/shell_ops.c b/subsys/shell/shell_ops.c index 0cfb892e193..8eae498f3e3 100644 --- a/subsys/shell/shell_ops.c +++ b/subsys/shell/shell_ops.c @@ -262,3 +262,47 @@ void shell_op_completion_insert(const struct shell *shell, { data_insert(shell, compl, compl_len); } + +static void shell_pend_on_txdone(const struct shell *shell) +{ + if (IS_ENABLED(CONFIG_MULTITHREADING)) { + k_poll(&shell->ctx->events[SHELL_SIGNAL_TXDONE], 1, K_FOREVER); + k_poll_signal_reset(&shell->ctx->signals[SHELL_SIGNAL_TXDONE]); + } else { + /* Blocking wait in case of bare metal. */ + while (!shell->ctx->internal.flags.tx_rdy) { + } + shell->ctx->internal.flags.tx_rdy = 0; + } +} + +void shell_write(const struct shell *shell, const void *data, + size_t length) +{ + __ASSERT_NO_MSG(shell && data); + + size_t offset = 0; + size_t tmp_cnt; + + while (length) { + int err = shell->iface->api->write(shell->iface, + &((const u8_t *) data)[offset], length, + &tmp_cnt); + (void)err; + __ASSERT_NO_MSG(err == 0); + __ASSERT_NO_MSG(length >= tmp_cnt); + offset += tmp_cnt; + length -= tmp_cnt; + if (tmp_cnt == 0 && + (shell->ctx->state != SHELL_STATE_PANIC_MODE_ACTIVE)) { + shell_pend_on_txdone(shell); + } + } +} + +/* Function shall be only used by the fprintf module. */ +void shell_print_stream(const void *user_ctx, const char *data, + size_t data_len) +{ + shell_write((const struct shell *) user_ctx, data, data_len); +} diff --git a/subsys/shell/shell_ops.h b/subsys/shell/shell_ops.h index c87db7ab8fa..5549191aa0b 100644 --- a/subsys/shell/shell_ops.h +++ b/subsys/shell/shell_ops.h @@ -6,7 +6,6 @@ #ifndef SHELL_OPS_H__ #define SHELL_OPS_H__ -#include #include #include "shell_vt100.h" #include "shell_utils.h" @@ -121,6 +120,29 @@ void shell_op_completion_insert(const struct shell *shell, u16_t compl_len); bool shell_cursor_in_empty_line(const struct shell *shell); + +/* Function sends data stream to the shell instance. Each time before the + * shell_write function is called, it must be ensured that IO buffer of fprintf + * is flushed to avoid synchronization issues. + * For that purpose, use function transport_buffer_flush(shell) + * + * This function can be only used by shell module, it shall not be called + * directly. + */ +void shell_write(const struct shell *shell, const void *data, + size_t length); + +/** + * @internal @brief This function shall not be used directly, it is required by + * the fprintf module. + * + * @param[in] p_user_ctx Pointer to the context for the shell instance. + * @param[in] p_data Pointer to the data buffer. + * @param[in] data_len Data buffer size. + */ +void shell_print_stream(const void *user_ctx, const char *data, + size_t data_len); + #ifdef __cplusplus } #endif diff --git a/subsys/shell/shell_utils.c b/subsys/shell/shell_utils.c index db55ddeb308..f3ee1a37ce1 100644 --- a/subsys/shell/shell_utils.c +++ b/subsys/shell/shell_utils.c @@ -6,6 +6,14 @@ #include "shell_utils.h" #include +extern const struct shell_cmd_entry __shell_root_cmds_start[0]; +extern const struct shell_cmd_entry __shell_root_cmds_end[0]; + +static inline const struct shell_cmd_entry *shell_root_cmd_get(u32_t id) +{ + return &__shell_root_cmds_start[id]; +} + /* Calculates relative line number of given position in buffer */ static u32_t line_num_with_buffer_offset_get(struct shell_multiline_cons *cons, u16_t buffer_pos) @@ -209,6 +217,62 @@ void shell_pattern_remove(char *buff, u16_t *buff_len, const char *pattern) memmove(pattern_addr, pattern_addr + pattern_len, shift); } +static inline u32_t shell_root_cmd_count(void) +{ + return ((u8_t *)__shell_root_cmds_end - + (u8_t *)__shell_root_cmds_start)/ + sizeof(struct shell_cmd_entry); +} + +/* Function returning pointer to root command matching requested syntax. */ +const struct shell_cmd_entry *root_cmd_find(const char *syntax) +{ + const size_t cmd_count = shell_root_cmd_count(); + const struct shell_cmd_entry *cmd; + + for (size_t cmd_idx = 0; cmd_idx < cmd_count; ++cmd_idx) { + cmd = shell_root_cmd_get(cmd_idx); + if (strcmp(syntax, cmd->u.entry->syntax) == 0) { + return cmd; + } + } + + return NULL; +} + +void shell_cmd_get(const struct shell_cmd_entry *command, size_t lvl, + size_t idx, const struct shell_static_entry **entry, + struct shell_static_entry *d_entry) +{ + __ASSERT_NO_MSG(entry != NULL); + __ASSERT_NO_MSG(d_entry != NULL); + + if (lvl == SHELL_CMD_ROOT_LVL) { + if (idx < shell_root_cmd_count()) { + const struct shell_cmd_entry *cmd; + + cmd = shell_root_cmd_get(idx); + *entry = cmd->u.entry; + } else { + *entry = NULL; + } + return; + } + + if (command == NULL) { + *entry = NULL; + return; + } + + if (command->is_dynamic) { + command->u.dynamic_get(idx, d_entry); + *entry = (d_entry->syntax != NULL) ? d_entry : NULL; + } else { + *entry = (command->u.entry[idx].syntax != NULL) ? + &command->u.entry[idx] : NULL; + } +} + int shell_command_add(char *buff, u16_t *buff_len, const char *new_cmd, const char *pattern) { diff --git a/subsys/shell/shell_utils.h b/subsys/shell/shell_utils.h index f4913310078..3d9b4724f2b 100644 --- a/subsys/shell/shell_utils.h +++ b/subsys/shell/shell_utils.h @@ -8,6 +8,7 @@ #include #include + #ifdef __cplusplus extern "C" { #endif @@ -42,9 +43,29 @@ char shell_make_argv(size_t *argc, char **argv, char *cmd, uint8_t max_argc); */ void shell_pattern_remove(char *buff, u16_t *buff_len, const char *pattern); +/* @brief Function shall be used to search commands. + * + * It moves the pointer entry to command of static command structure. If the + * command cannot be found, the function will set entry to NULL. + * + * @param command Pointer to command which will be processed (no matter + * the root command). + * @param lvl Level of the requested command. + * @param idx Index of the requested command. + * @param entry Pointer which points to subcommand[idx] after function + * execution. + * @param st_entry Pointer to the structure where dynamic entry data can be + * stored. + */ +void shell_cmd_get(const struct shell_cmd_entry *command, size_t lvl, + size_t idx, const struct shell_static_entry **entry, + struct shell_static_entry *d_entry); + int shell_command_add(char *buff, u16_t *buff_len, const char *new_cmd, const char *pattern); +const struct shell_cmd_entry *root_cmd_find(const char *syntax); + void shell_spaces_trim(char *str); /** @brief Remove white chars from beginning and end of command buffer. @@ -52,6 +73,11 @@ void shell_spaces_trim(char *str); */ void shell_buffer_trim(char *buff, u16_t *buff_len); +static inline void transport_buffer_flush(const struct shell *shell) +{ + shell_fprintf_buffer_flush(shell->fprintf_ctx); +} + #ifdef __cplusplus } #endif diff --git a/tests/bluetooth/shell/src/main.c b/tests/bluetooth/shell/src/main.c index ddb47b42150..35823bbdd9c 100644 --- a/tests/bluetooth/shell/src/main.c +++ b/tests/bluetooth/shell/src/main.c @@ -33,12 +33,6 @@ static bool hrs_simulate; static int cmd_hrs_simulate(const struct shell *shell, size_t argc, char *argv[]) { - int err = shell_cmd_precheck(shell, (argc == 2)); - - if (err) { - return err; - } - if (!strcmp(argv[1], "on")) { static bool hrs_registered; @@ -68,34 +62,22 @@ static int cmd_hrs_simulate(const struct shell *shell, SHELL_CREATE_STATIC_SUBCMD_SET(hrs_cmds) { #if defined(CONFIG_BT_CONN) - SHELL_CMD(hrs-simulate, NULL, - "register and simulate Heart Rate Service ", - cmd_hrs_simulate), + SHELL_CMD_ARG(hrs-simulate, NULL, + "register and simulate Heart Rate Service ", + cmd_hrs_simulate, 2, 0), #endif /* CONFIG_BT_CONN */ SHELL_SUBCMD_SET_END }; static int cmd_hrs(const struct shell *shell, size_t argc, char **argv) { - int err = shell_cmd_precheck(shell, (argc == 2)); - - if (argc == 1) { - shell_help_print(shell); - /* shell_cmd_precheck returns 1 when help is printed */ - return 1; - } - - if (err) { - return err; - } - shell_error(shell, "%s unknown parameter: %s", argv[0], argv[1]); return -ENOEXEC; } -SHELL_CMD_REGISTER(hrs, &hrs_cmds, "Heart Rate Service shell commands", - cmd_hrs); +SHELL_CMD_ARG_REGISTER(hrs, &hrs_cmds, "Heart Rate Service shell commands", + cmd_hrs, 2, 0); void main(void) { diff --git a/tests/shell/src/main.c b/tests/shell/src/main.c index 51a667ce8d3..2a00e596b23 100644 --- a/tests/shell/src/main.c +++ b/tests/shell/src/main.c @@ -34,8 +34,8 @@ static void test_shell_execute_cmd(const char *cmd, int result) static void test_cmd_help(void) { test_shell_execute_cmd("help", 0); - test_shell_execute_cmd("help -h", 0); - test_shell_execute_cmd("help --help", 0); + test_shell_execute_cmd("help -h", 1); + test_shell_execute_cmd("help --help", 1); test_shell_execute_cmd("help dummy", 0); test_shell_execute_cmd("help dummy dummy", 0); } @@ -53,13 +53,13 @@ static void test_cmd_shell(void) { test_shell_execute_cmd("shell -h", 1); test_shell_execute_cmd("shell --help", 1); - test_shell_execute_cmd("shell dummy", -EINVAL); - test_shell_execute_cmd("shell dummy dummy", -EINVAL); + test_shell_execute_cmd("shell dummy", 1); + test_shell_execute_cmd("shell dummy dummy", 1); /* subcommand: backspace_mode */ test_shell_execute_cmd("shell backspace_mode -h", 1); test_shell_execute_cmd("shell backspace_mode --help", 1); - test_shell_execute_cmd("shell backspace_mode dummy", -EINVAL); + test_shell_execute_cmd("shell backspace_mode dummy", 1); test_shell_execute_cmd("shell backspace_mode backspace", 0); test_shell_execute_cmd("shell backspace_mode backspace -h", 1); @@ -78,8 +78,8 @@ static void test_cmd_shell(void) /* subcommand: colors */ test_shell_execute_cmd("shell colors -h", 1); test_shell_execute_cmd("shell colors --help", 1); - test_shell_execute_cmd("shell colors dummy", -EINVAL); - test_shell_execute_cmd("shell colors dummy dummy", -EINVAL); + test_shell_execute_cmd("shell colors dummy", 1); + test_shell_execute_cmd("shell colors dummy dummy", 1); test_shell_execute_cmd("shell colors off", 0); test_shell_execute_cmd("shell colors off -h", 1); @@ -113,11 +113,11 @@ static void test_cmd_shell(void) test_shell_execute_cmd("shell echo on dummy dummy", -EINVAL); /* subcommand: stats */ - test_shell_execute_cmd("shell stats", -EINVAL); + test_shell_execute_cmd("shell stats", 1); test_shell_execute_cmd("shell stats -h", 1); test_shell_execute_cmd("shell stats --help", 1); - test_shell_execute_cmd("shell stats dummy", -EINVAL); - test_shell_execute_cmd("shell stats dummy dummy", -EINVAL); + test_shell_execute_cmd("shell stats dummy", 1); + test_shell_execute_cmd("shell stats dummy dummy", 1); test_shell_execute_cmd("shell stats reset", 0); test_shell_execute_cmd("shell stats reset -h", 1); @@ -195,10 +195,11 @@ static void test_shell_wildcards_dynamic(void) static int cmd_test_module(const struct shell *shell, size_t argc, char **argv) { ARG_UNUSED(argv); + ARG_UNUSED(argc); - return shell_cmd_precheck(shell, (argc == 1)); + return 0; } -SHELL_CMD_REGISTER(test_shell_cmd, NULL, NULL, cmd_test_module); +SHELL_CMD_ARG_REGISTER(test_shell_cmd, NULL, "help", cmd_test_module, 1, 0); static int cmd_wildcard(const struct shell *shell, size_t argc, char **argv)