diff --git a/components/console/commands.c b/components/console/commands.c index e5722c6655..4ac0725dc7 100644 --- a/components/console/commands.c +++ b/components/console/commands.c @@ -39,6 +39,8 @@ typedef struct cmd_item_ { SLIST_ENTRY(cmd_item_) next; //!< next command in the list } cmd_item_t; +typedef void (*const fn_print_arg_t)(cmd_item_t*); + /** linked list of command structures */ static SLIST_HEAD(cmd_list_, cmd_item_) s_cmd_list; @@ -52,6 +54,8 @@ static char *s_tmp_line_buf; static const cmd_item_t *find_command_by_name(const char *name); +static esp_console_help_verbose_level_e s_verbose_level = ESP_CONSOLE_HELP_VERBOSE_LEVEL_1; + esp_err_t esp_console_init(const esp_console_config_t *config) { if (!config) { @@ -245,6 +249,7 @@ esp_err_t esp_console_run(const char *cmdline, int *cmd_ret) static struct { struct arg_str *help_cmd; + struct arg_int *verbose_level; struct arg_end *end; } help_args; @@ -268,6 +273,17 @@ static void print_arg_help(cmd_item_t *it) printf("\n"); } +static void print_arg_command(cmd_item_t *it) +{ + const char *hint = (it->hint) ? it->hint : ""; + printf("%-s %s\n\n", it->command, hint); +} + +static fn_print_arg_t print_verbose_level_arr[ESP_CONSOLE_HELP_VERBOSE_LEVEL_MAX_NUM] = { + print_arg_command, + print_arg_help, +}; + static int help_command(int argc, char **argv) { int nerrors = arg_parse(argc, argv, (void **) &help_args); @@ -279,18 +295,33 @@ static int help_command(int argc, char **argv) cmd_item_t *it; int ret_value = 1; + esp_console_help_verbose_level_e verbose_level; if (help_args.help_cmd->count == 0) { - /* Print summary of each command */ + /* If verbose level is not provided, set it as default value */ + if (help_args.verbose_level->count == 0) { + verbose_level = s_verbose_level; + } + /* Else use the verbose level from input argument */ + else { + verbose_level = (esp_console_help_verbose_level_e)help_args.verbose_level->ival[0]; + } + /* Check if selected verbose level is valid, proceed if yes, else return */ + if (verbose_level >= ESP_CONSOLE_HELP_VERBOSE_LEVEL_MAX_NUM) { + printf("help: invalid verbose level %d", (int)verbose_level); + return 1; + } + + /* Print info of each command based on verbose level */ SLIST_FOREACH(it, &s_cmd_list, next) { if (it->help == NULL) { continue; } - print_arg_help(it); + print_verbose_level_arr[verbose_level](it); } ret_value = 0; } else { - /* Print summary of given command */ + /* Print summary of given command, verbose option will be ignored */ bool found_command = false; SLIST_FOREACH(it, &s_cmd_list, next) { if (it->help == NULL) { @@ -317,7 +348,9 @@ static int help_command(int argc, char **argv) esp_err_t esp_console_register_help_command(void) { help_args.help_cmd = arg_str0(NULL, NULL, "", "Name of command"); - help_args.end = arg_end(1); + help_args.verbose_level = arg_intn("v", "verbose", "<0|1>", 0, 1, + "If specified, list console commands with given verbose level"); + help_args.end = arg_end(2); esp_console_cmd_t command = { .command = "help", @@ -328,3 +361,12 @@ esp_err_t esp_console_register_help_command(void) }; return esp_console_cmd_register(&command); } +esp_err_t esp_console_set_help_verbose_level(esp_console_help_verbose_level_e verbose_level) +{ + /* legal verbose level sanity check */ + if (verbose_level >= ESP_CONSOLE_HELP_VERBOSE_LEVEL_MAX_NUM) { + return ESP_ERR_INVALID_ARG; + } + s_verbose_level = verbose_level; + return ESP_OK; +} diff --git a/components/console/esp_console.h b/components/console/esp_console.h index 921300f943..6fd3b81424 100644 --- a/components/console/esp_console.h +++ b/components/console/esp_console.h @@ -130,6 +130,12 @@ typedef struct { #define ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT() {} #endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG || (defined __DOXYGEN__ && SOC_USB_SERIAL_JTAG_SUPPORTED) +typedef enum { + ESP_CONSOLE_HELP_VERBOSE_LEVEL_0 = 0, + ESP_CONSOLE_HELP_VERBOSE_LEVEL_1 = 1, + ESP_CONSOLE_HELP_VERBOSE_LEVEL_MAX_NUM = 2 +} esp_console_help_verbose_level_e; + /** * @brief initialize console module * @param config console configuration @@ -314,6 +320,18 @@ const char *esp_console_get_hint(const char *buf, int *color, int *bold); */ esp_err_t esp_console_register_help_command(void); +/** + * @brief Set the verbose level for 'help' command + * + * Set the verbose level for 'help' command. Higher verbose level shows more details. + * Valid verbose_level values are described in esp_console_help_verbose_level_e and must be lower than `ESP_CONSOLE_HELP_VERBOSE_LEVEL_MAX_NUM`. + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG, if invalid verbose level is provided + */ +esp_err_t esp_console_set_help_verbose_level(esp_console_help_verbose_level_e verbose_level); + /****************************************************************************** * Console REPL ******************************************************************************/ diff --git a/components/console/test_apps/console/main/test_console.c b/components/console/test_apps/console/main/test_console.c index 4d623f3805..36e22553b8 100644 --- a/components/console/test_apps/console/main/test_console.c +++ b/components/console/test_apps/console/main/test_console.c @@ -273,3 +273,37 @@ TEST_CASE("esp console test with context", "[console]") TEST_ESP_OK(esp_console_deinit()); } + +TEST_CASE("esp console help command - set verbose level = 0", "[console][ignore]") +{ + esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); + esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); + TEST_ESP_OK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl)); + TEST_ESP_OK(esp_console_register_help_command()); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_console_set_help_verbose_level(ESP_CONSOLE_HELP_VERBOSE_LEVEL_MAX_NUM)); + TEST_ESP_OK(esp_console_set_help_verbose_level(ESP_CONSOLE_HELP_VERBOSE_LEVEL_0)); + TEST_ESP_OK(esp_console_start_repl(s_repl)); + vTaskDelay(pdMS_TO_TICKS(5000)); +} + +TEST_CASE("esp console help command - set verbose level = 1", "[console][ignore]") +{ + esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); + esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); + TEST_ESP_OK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl)); + TEST_ESP_OK(esp_console_register_help_command()); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_console_set_help_verbose_level(ESP_CONSOLE_HELP_VERBOSE_LEVEL_MAX_NUM)); + TEST_ESP_OK(esp_console_set_help_verbose_level(ESP_CONSOLE_HELP_VERBOSE_LEVEL_1)); + TEST_ESP_OK(esp_console_start_repl(s_repl)); + vTaskDelay(pdMS_TO_TICKS(5000)); +} + +TEST_CASE("esp console help command - --verbose sub command", "[console][ignore]") +{ + esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); + esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); + TEST_ESP_OK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl)); + TEST_ESP_OK(esp_console_register_help_command()); + TEST_ESP_OK(esp_console_start_repl(s_repl)); + vTaskDelay(pdMS_TO_TICKS(5000)); +} diff --git a/components/console/test_apps/console/pytest_console.py b/components/console/test_apps/console/pytest_console.py index edee3741b5..be79490c1c 100644 --- a/components/console/test_apps/console/pytest_console.py +++ b/components/console/test_apps/console/pytest_console.py @@ -183,3 +183,81 @@ def test_console_sorted_help_reverse_registration(dut: Dut, test_on: str) -> Non ) def test_console_help_quit(dut: Dut, test_on: str) -> None: do_test_help_quit(dut) + + +@pytest.mark.parametrize( + 'config', [ + pytest.param('defaults'), + ] +) +@pytest.mark.parametrize( + 'test_on', [ + pytest.param('host', marks=[pytest.mark.linux, pytest.mark.host_test]), + pytest.param('target', marks=[pytest.mark.esp32, pytest.mark.generic]), + pytest.param('target', marks=[pytest.mark.esp32c3, pytest.mark.generic]), + pytest.param('qemu', marks=[pytest.mark.esp32, pytest.mark.host_test, pytest.mark.qemu]), + ] +) +def test_console_help_verbose_level_0(dut: Dut, test_on: str) -> None: + help_verbose_info = 'Print the summary of all registered commands if no arguments are given,' + dut.expect_exact('Press ENTER to see the list of tests') + dut.write('"esp console help command - set verbose level = 0"') + + dut.expect_exact('esp>', timeout=5) + # verify help command + dut.write('help') + dut.write('help') + dut.expect_exact('help', not_matching=help_verbose_info) + + +@pytest.mark.parametrize( + 'config', [ + pytest.param('defaults'), + ] +) +@pytest.mark.parametrize( + 'test_on', [ + pytest.param('host', marks=[pytest.mark.linux, pytest.mark.host_test]), + pytest.param('target', marks=[pytest.mark.esp32, pytest.mark.generic]), + pytest.param('target', marks=[pytest.mark.esp32c3, pytest.mark.generic]), + pytest.param('qemu', marks=[pytest.mark.esp32, pytest.mark.host_test, pytest.mark.qemu]), + ] +) +def test_console_help_verbose_level_1(dut: Dut, test_on: str) -> None: + help_verbose_info = 'Print the summary of all registered commands if no arguments are given,' + dut.expect_exact('Press ENTER to see the list of tests') + dut.write('"esp console help command - set verbose level = 1"') + + dut.expect_exact('esp>', timeout=5) + # verify help command + dut.write('help') + dut.expect_exact(help_verbose_info) + + +@pytest.mark.parametrize( + 'config', [ + pytest.param('defaults'), + ] +) +@pytest.mark.parametrize( + 'test_on', [ + pytest.param('host', marks=[pytest.mark.linux, pytest.mark.host_test]), + pytest.param('target', marks=[pytest.mark.esp32, pytest.mark.generic]), + pytest.param('target', marks=[pytest.mark.esp32c3, pytest.mark.generic]), + pytest.param('qemu', marks=[pytest.mark.esp32, pytest.mark.host_test, pytest.mark.qemu]), + ] +) +def test_console_help_verbose_subcommand(dut: Dut, test_on: str) -> None: + help_verbose_info = 'Print the summary of all registered commands if no arguments are given,' + dut.expect_exact('Press ENTER to see the list of tests') + dut.write('"esp console help command - --verbose sub command"') + + dut.expect_exact('esp>', timeout=5) + # verify help --verbose=0 subcommand + dut.write('help --verbose=0') + dut.write('help --verbose=0') + dut.expect_exact('help --verbose=0',not_matching=help_verbose_info) + + # verify help --verbose=1 subcommand + dut.write('help --verbose=1') + dut.expect_exact(help_verbose_info)