| 
									
										
										
										
											2021-05-17 03:41:32 +02:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2024-01-11 10:53:29 +08:00
										 |  |  |  * SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD | 
					
						
							| 
									
										
										
										
											2021-05-17 03:41:32 +02:00
										 |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: Apache-2.0 | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <sys/param.h>
 | 
					
						
							| 
									
										
										
										
											2023-08-01 23:24:27 -07:00
										 |  |  | #include "esp_heap_caps.h"
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | #include "esp_log.h"
 | 
					
						
							|  |  |  | #include "esp_console.h"
 | 
					
						
							| 
									
										
										
										
											2020-02-03 18:01:04 +08:00
										 |  |  | #include "esp_system.h"
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | #include "linenoise/linenoise.h"
 | 
					
						
							|  |  |  | #include "argtable3/argtable3.h"
 | 
					
						
							| 
									
										
										
										
											2019-03-14 17:29:32 +08:00
										 |  |  | #include "sys/queue.h"
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define ANSI_COLOR_DEFAULT      39      /** Default foreground color */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct cmd_item_ { | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Command name (statically allocated by application) | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  |     const char *command; | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     /**
 | 
					
						
							|  |  |  |      * Help text (statically allocated by application), may be NULL. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  |     const char *help; | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     /**
 | 
					
						
							|  |  |  |      * Hint text, usually lists possible arguments, dynamically allocated. | 
					
						
							|  |  |  |      * May be NULL. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  |     char *hint; | 
					
						
							| 
									
										
										
										
											2023-10-20 20:48:52 +03:00
										 |  |  |     esp_console_cmd_func_t func;                        //!< pointer to the command handler (without user context)
 | 
					
						
							|  |  |  |     esp_console_cmd_func_with_context_t func_w_context; //!< pointer to the command handler (with user context)
 | 
					
						
							|  |  |  |     void *argtable;                                     //!< optional pointer to arg table
 | 
					
						
							|  |  |  |     void *context;                                      //!< optional pointer to user context
 | 
					
						
							|  |  |  |     SLIST_ENTRY(cmd_item_) next;                        //!< next command in the list
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | } cmd_item_t; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-17 18:09:32 +08:00
										 |  |  | typedef void (*const fn_print_arg_t)(cmd_item_t*); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | /** linked list of command structures */ | 
					
						
							|  |  |  | static SLIST_HEAD(cmd_list_, cmd_item_) s_cmd_list; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** run-time configuration options */ | 
					
						
							| 
									
										
										
										
											2023-08-02 16:17:34 +08:00
										 |  |  | static esp_console_config_t s_config = { | 
					
						
							|  |  |  |     .heap_alloc_caps = MALLOC_CAP_DEFAULT | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** temporary buffer used for command line parsing */ | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  | static char *s_tmp_line_buf; | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  | static const cmd_item_t *find_command_by_name(const char *name); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-17 18:09:32 +08:00
										 |  |  | static esp_console_help_verbose_level_e s_verbose_level = ESP_CONSOLE_HELP_VERBOSE_LEVEL_1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  | esp_err_t esp_console_init(const esp_console_config_t *config) | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-02-03 18:01:04 +08:00
										 |  |  |     if (!config) { | 
					
						
							|  |  |  |         return ESP_ERR_INVALID_ARG; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     if (s_tmp_line_buf) { | 
					
						
							|  |  |  |         return ESP_ERR_INVALID_STATE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     memcpy(&s_config, config, sizeof(s_config)); | 
					
						
							|  |  |  |     if (s_config.hint_color == 0) { | 
					
						
							|  |  |  |         s_config.hint_color = ANSI_COLOR_DEFAULT; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-08-10 10:35:32 +08:00
										 |  |  |     if (s_config.heap_alloc_caps == 0) { | 
					
						
							|  |  |  |         s_config.heap_alloc_caps = MALLOC_CAP_DEFAULT; | 
					
						
							| 
									
										
										
										
											2023-08-01 23:24:27 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-08-02 16:17:34 +08:00
										 |  |  |     s_tmp_line_buf = heap_caps_calloc(1, config->max_cmdline_length, s_config.heap_alloc_caps); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     if (s_tmp_line_buf == NULL) { | 
					
						
							|  |  |  |         return ESP_ERR_NO_MEM; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-16 16:33:30 +07:00
										 |  |  | esp_err_t esp_console_deinit(void) | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!s_tmp_line_buf) { | 
					
						
							|  |  |  |         return ESP_ERR_INVALID_STATE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     free(s_tmp_line_buf); | 
					
						
							| 
									
										
										
										
											2020-02-03 18:01:04 +08:00
										 |  |  |     s_tmp_line_buf = NULL; | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     cmd_item_t *it, *tmp; | 
					
						
							|  |  |  |     SLIST_FOREACH_SAFE(it, &s_cmd_list, next, tmp) { | 
					
						
							| 
									
										
										
										
											2020-02-03 18:01:04 +08:00
										 |  |  |         SLIST_REMOVE(&s_cmd_list, it, cmd_item_, next); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |         free(it->hint); | 
					
						
							|  |  |  |         free(it); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-21 16:37:27 +08:00
										 |  |  | void esp_console_rm_item_free_hint(cmd_item_t *item) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     SLIST_REMOVE(&s_cmd_list, item, cmd_item_, next); | 
					
						
							|  |  |  |     free(item->hint); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | esp_err_t esp_console_cmd_deregister(const char *cmd_name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     cmd_item_t *item = (cmd_item_t *)find_command_by_name(cmd_name); | 
					
						
							|  |  |  |     if (item == NULL) { | 
					
						
							|  |  |  |         return ESP_ERR_INVALID_ARG; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     esp_console_rm_item_free_hint(item); | 
					
						
							|  |  |  |     heap_caps_free(item); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | esp_err_t esp_console_cmd_register(const esp_console_cmd_t *cmd) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-02-03 18:01:04 +08:00
										 |  |  |     cmd_item_t *item = NULL; | 
					
						
							|  |  |  |     if (!cmd || cmd->command == NULL) { | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |         return ESP_ERR_INVALID_ARG; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (strchr(cmd->command, ' ') != NULL) { | 
					
						
							|  |  |  |         return ESP_ERR_INVALID_ARG; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-10-20 20:48:52 +03:00
										 |  |  |     if ((cmd->func == NULL && cmd->func_w_context == NULL) | 
					
						
							|  |  |  |             || (cmd->func != NULL && cmd->func_w_context != NULL)) { | 
					
						
							|  |  |  |         return ESP_ERR_INVALID_ARG; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-02-03 18:01:04 +08:00
										 |  |  |     item = (cmd_item_t *)find_command_by_name(cmd->command); | 
					
						
							|  |  |  |     if (!item) { | 
					
						
							|  |  |  |         // not registered before
 | 
					
						
							| 
									
										
										
										
											2023-08-02 16:17:34 +08:00
										 |  |  |         item = heap_caps_calloc(1, sizeof(*item), s_config.heap_alloc_caps); | 
					
						
							| 
									
										
										
										
											2020-02-03 18:01:04 +08:00
										 |  |  |         if (item == NULL) { | 
					
						
							|  |  |  |             return ESP_ERR_NO_MEM; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         // remove from list and free the old hint, because we will alloc new hint for the command
 | 
					
						
							| 
									
										
										
										
											2024-05-21 16:37:27 +08:00
										 |  |  |         esp_console_rm_item_free_hint(item); | 
					
						
							| 
									
										
										
										
											2020-02-03 18:01:04 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     item->command = cmd->command; | 
					
						
							|  |  |  |     item->help = cmd->help; | 
					
						
							|  |  |  |     if (cmd->hint) { | 
					
						
							|  |  |  |         /* Prepend a space before the hint. It separates command name and
 | 
					
						
							|  |  |  |          * the hint. arg_print_syntax below adds this space as well. | 
					
						
							|  |  |  |          */ | 
					
						
							| 
									
										
										
										
											2018-07-20 13:25:45 +08:00
										 |  |  |         int unused __attribute__((unused)); | 
					
						
							|  |  |  |         unused = asprintf(&item->hint, " %s", cmd->hint); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     } else if (cmd->argtable) { | 
					
						
							|  |  |  |         /* Generate hint based on cmd->argtable */ | 
					
						
							| 
									
										
										
										
											2023-11-01 21:05:25 +02:00
										 |  |  |         arg_dstr_t ds = arg_dstr_create(); | 
					
						
							|  |  |  |         arg_print_syntax_ds(ds, cmd->argtable, NULL); | 
					
						
							|  |  |  |         item->hint = strdup(arg_dstr_cstr(ds)); | 
					
						
							|  |  |  |         arg_dstr_destroy(ds); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     item->argtable = cmd->argtable; | 
					
						
							| 
									
										
										
										
											2024-01-11 10:53:29 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (cmd->func) { | 
					
						
							|  |  |  |         item->func = cmd->func; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         // cmd->func_w_context is valid here according to check above
 | 
					
						
							|  |  |  |         item->func_w_context = cmd->func_w_context; | 
					
						
							|  |  |  |         item->context = cmd->context; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-13 10:53:05 +08:00
										 |  |  |     cmd_item_t *last; | 
					
						
							| 
									
										
										
										
											2023-11-04 21:06:45 +02:00
										 |  |  |     cmd_item_t *it; | 
					
						
							| 
									
										
										
										
											2024-03-13 10:53:05 +08:00
										 |  |  | #if CONFIG_CONSOLE_SORTED_HELP
 | 
					
						
							|  |  |  |     last = NULL; | 
					
						
							| 
									
										
										
										
											2023-11-04 21:06:45 +02:00
										 |  |  |     SLIST_FOREACH(it, &s_cmd_list, next) { | 
					
						
							|  |  |  |         if (strcmp(it->command, item->command) > 0) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         last = it; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-03-13 10:53:05 +08:00
										 |  |  | #else
 | 
					
						
							|  |  |  |     last = SLIST_FIRST(&s_cmd_list); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     if (last == NULL) { | 
					
						
							|  |  |  |         SLIST_INSERT_HEAD(&s_cmd_list, item, next); | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2024-03-13 10:53:05 +08:00
										 |  |  | #if !CONFIG_CONSOLE_SORTED_HELP
 | 
					
						
							|  |  |  |         while ((it = SLIST_NEXT(last, next)) != NULL) { | 
					
						
							|  |  |  |             last = it; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |         SLIST_INSERT_AFTER(last, item, next); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void esp_console_get_completion(const char *buf, linenoiseCompletions *lc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     size_t len = strlen(buf); | 
					
						
							|  |  |  |     if (len == 0) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  |     cmd_item_t *it; | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     SLIST_FOREACH(it, &s_cmd_list, next) { | 
					
						
							|  |  |  |         /* Check if command starts with buf */ | 
					
						
							|  |  |  |         if (strncmp(buf, it->command, len) == 0) { | 
					
						
							|  |  |  |             linenoiseAddCompletion(lc, it->command); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  | const char *esp_console_get_hint(const char *buf, int *color, int *bold) | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-11-17 12:48:35 +08:00
										 |  |  |     size_t len = strlen(buf); | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  |     cmd_item_t *it; | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     SLIST_FOREACH(it, &s_cmd_list, next) { | 
					
						
							|  |  |  |         if (strlen(it->command) == len && | 
					
						
							|  |  |  |                 strncmp(buf, it->command, len) == 0) { | 
					
						
							|  |  |  |             *color = s_config.hint_color; | 
					
						
							|  |  |  |             *bold = s_config.hint_bold; | 
					
						
							|  |  |  |             return it->hint; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  | static const cmd_item_t *find_command_by_name(const char *name) | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  |     const cmd_item_t *cmd = NULL; | 
					
						
							|  |  |  |     cmd_item_t *it; | 
					
						
							| 
									
										
										
										
											2020-11-17 12:48:35 +08:00
										 |  |  |     size_t len = strlen(name); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     SLIST_FOREACH(it, &s_cmd_list, next) { | 
					
						
							| 
									
										
										
										
											2020-02-03 18:01:04 +08:00
										 |  |  |         if (strlen(it->command) == len && | 
					
						
							|  |  |  |                 strcmp(name, it->command) == 0) { | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |             cmd = it; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return cmd; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  | esp_err_t esp_console_run(const char *cmdline, int *cmd_ret) | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     if (s_tmp_line_buf == NULL) { | 
					
						
							|  |  |  |         return ESP_ERR_INVALID_STATE; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-08-02 16:17:34 +08:00
										 |  |  |     char **argv = (char **) heap_caps_calloc(s_config.max_cmdline_args, sizeof(char *), s_config.heap_alloc_caps); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     if (argv == NULL) { | 
					
						
							|  |  |  |         return ESP_ERR_NO_MEM; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     strlcpy(s_tmp_line_buf, cmdline, s_config.max_cmdline_length); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     size_t argc = esp_console_split_argv(s_tmp_line_buf, argv, | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  |                                          s_config.max_cmdline_args); | 
					
						
							| 
									
										
										
										
											2017-10-13 07:12:08 +08:00
										 |  |  |     if (argc == 0) { | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  |         free(argv); | 
					
						
							| 
									
										
										
										
											2017-10-13 07:12:08 +08:00
										 |  |  |         return ESP_ERR_INVALID_ARG; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  |     const cmd_item_t *cmd = find_command_by_name(argv[0]); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     if (cmd == NULL) { | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  |         free(argv); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |         return ESP_ERR_NOT_FOUND; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-10-20 20:48:52 +03:00
										 |  |  |     if (cmd->func) { | 
					
						
							|  |  |  |         *cmd_ret = (*cmd->func)(argc, argv); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (cmd->func_w_context) { | 
					
						
							|  |  |  |         *cmd_ret = (*cmd->func_w_context)(cmd->context, argc, argv); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     free(argv); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-24 15:29:10 -07:00
										 |  |  | static struct { | 
					
						
							|  |  |  |     struct arg_str *help_cmd; | 
					
						
							| 
									
										
										
										
											2024-05-17 18:09:32 +08:00
										 |  |  |     struct arg_int *verbose_level; | 
					
						
							| 
									
										
										
										
											2023-07-24 15:29:10 -07:00
										 |  |  |     struct arg_end *end; | 
					
						
							|  |  |  | } help_args; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-14 11:03:13 +08:00
										 |  |  | static void print_arg_help(cmd_item_t *it) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-29 16:12:51 +02:00
										 |  |  |     /* First line: command name and hint
 | 
					
						
							|  |  |  |      * Pad all the hints to the same column | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     const char *hint = (it->hint) ? it->hint : ""; | 
					
						
							|  |  |  |     printf("%-s %s\n", it->command, hint); | 
					
						
							|  |  |  |     /* Second line: print help.
 | 
					
						
							|  |  |  |      * Argtable has a nice helper function for this which does line | 
					
						
							|  |  |  |      * wrapping. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     printf("  "); // arg_print_formatted does not indent the first line
 | 
					
						
							|  |  |  |     arg_print_formatted(stdout, 2, 78, it->help); | 
					
						
							|  |  |  |     /* Finally, print the list of arguments */ | 
					
						
							|  |  |  |     if (it->argtable) { | 
					
						
							|  |  |  |         arg_print_glossary(stdout, (void **) it->argtable, "  %12s  %s\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     printf("\n"); | 
					
						
							| 
									
										
										
										
											2023-08-14 11:03:13 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-17 18:09:32 +08:00
										 |  |  | 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, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  | static int help_command(int argc, char **argv) | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-07-24 15:29:10 -07:00
										 |  |  |     int nerrors = arg_parse(argc, argv, (void **) &help_args); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (nerrors != 0) { | 
					
						
							|  |  |  |         arg_print_errors(stderr, help_args.end, argv[0]); | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  |     cmd_item_t *it; | 
					
						
							| 
									
										
										
										
											2023-08-14 11:03:13 +08:00
										 |  |  |     int ret_value = 1; | 
					
						
							| 
									
										
										
										
											2024-05-17 18:09:32 +08:00
										 |  |  |     esp_console_help_verbose_level_e verbose_level; | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-14 11:03:13 +08:00
										 |  |  |     if (help_args.help_cmd->count == 0) { | 
					
						
							| 
									
										
										
										
											2024-05-17 18:09:32 +08:00
										 |  |  |         /* 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 */ | 
					
						
							| 
									
										
										
										
											2023-08-14 11:03:13 +08:00
										 |  |  |         SLIST_FOREACH(it, &s_cmd_list, next) { | 
					
						
							|  |  |  |             if (it->help == NULL) { | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2024-05-17 18:09:32 +08:00
										 |  |  |             print_verbose_level_arr[verbose_level](it); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-08-14 11:03:13 +08:00
										 |  |  |         ret_value = 0; | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2024-05-17 18:09:32 +08:00
										 |  |  |         /* Print summary of given command, verbose option will be ignored */ | 
					
						
							| 
									
										
										
										
											2023-08-14 11:03:13 +08:00
										 |  |  |         bool found_command = false; | 
					
						
							|  |  |  |         SLIST_FOREACH(it, &s_cmd_list, next) { | 
					
						
							|  |  |  |             if (it->help == NULL) { | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (strcmp(help_args.help_cmd->sval[0], it->command) == 0) { | 
					
						
							|  |  |  |                 print_arg_help(it); | 
					
						
							|  |  |  |                 found_command = true; | 
					
						
							|  |  |  |                 ret_value = 0; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-07-24 15:29:10 -07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-08-14 11:03:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /* If given command has not been found, print error message*/ | 
					
						
							|  |  |  |         if (!found_command) { | 
					
						
							|  |  |  |             printf("help: Unrecognized option '%s'. Please use correct command as argument " | 
					
						
							|  |  |  |                    "or type 'help' only to print help for all commands\n", help_args.help_cmd->sval[0]); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-08-14 11:03:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return ret_value; | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-16 16:33:30 +07:00
										 |  |  | esp_err_t esp_console_register_help_command(void) | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-07-24 15:29:10 -07:00
										 |  |  |     help_args.help_cmd = arg_str0(NULL, NULL, "<string>", "Name of command"); | 
					
						
							| 
									
										
										
										
											2024-05-17 18:09:32 +08:00
										 |  |  |     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); | 
					
						
							| 
									
										
										
										
											2023-07-24 15:29:10 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     esp_console_cmd_t command = { | 
					
						
							| 
									
										
										
										
											2018-04-30 14:22:45 +05:30
										 |  |  |         .command = "help", | 
					
						
							| 
									
										
										
										
											2023-08-14 11:03:13 +08:00
										 |  |  |         .help = "Print the summary of all registered commands if no arguments " | 
					
						
							| 
									
										
										
										
											2024-04-29 16:12:51 +02:00
										 |  |  |         "are given, otherwise print summary of given command.", | 
					
						
							| 
									
										
										
										
											2023-07-24 15:29:10 -07:00
										 |  |  |         .func = &help_command, | 
					
						
							|  |  |  |         .argtable = &help_args | 
					
						
							| 
									
										
										
										
											2017-08-15 16:11:19 +08:00
										 |  |  |     }; | 
					
						
							|  |  |  |     return esp_console_cmd_register(&command); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-05-17 18:09:32 +08:00
										 |  |  | 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; | 
					
						
							|  |  |  | } |