This is an automated email from the ASF dual-hosted git repository. ccollins pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
commit e178c3d79cf526fbc146bce25f3a1e15b15a51b8 Author: Christopher Collins <ccoll...@apache.org> AuthorDate: Fri May 10 18:51:50 2019 -0700 sys/shell: Use the util/streamer interface This change allows shell commands to send the output somewhere other than the console. This is in preparation for the ability to invoke shell commands via newtmgr. --- sys/shell/include/shell/shell.h | 66 +++++++++++- sys/shell/pkg.yml | 1 + sys/shell/src/shell.c | 226 ++++++++++++++++++++++++---------------- sys/shell/src/shell_priv.h | 18 ++++ sys/shell/src/shell_prompt.c | 2 +- 5 files changed, 223 insertions(+), 90 deletions(-) diff --git a/sys/shell/include/shell/shell.h b/sys/shell/include/shell/shell.h index 859b9fa..8eecbf5 100644 --- a/sys/shell/include/shell/shell.h +++ b/sys/shell/include/shell/shell.h @@ -25,8 +25,14 @@ extern "C" { #endif #include "os/mynewt.h" +#include "streamer/streamer.h" struct os_eventq; +struct streamer; +struct shell_cmd; + +/** Command IDs in the "shell" newtmgr group. */ +#define SHELL_NMGR_OP_EXEC 0 /** @brief Callback called when command is entered. * @@ -37,6 +43,21 @@ struct os_eventq; */ typedef int (*shell_cmd_func_t)(int argc, char *argv[]); +/** + * @brief Callback for "extended" shell commands. + * + * @param cmd The shell command being executed. + * @param argc Number of arguments passed. + * @param argv Array of option strings. First option is always + * command name. + * @param streamer The streamer to write shell output to. + * + * @return 0 on success; SYS_E[...] on failure. + */ +typedef int (*shell_cmd_ext_func_t)(const struct shell_cmd *cmd, + int argc, char *argv[], + struct streamer *streamer); + struct shell_param { const char *param_name; const char *help; @@ -49,8 +70,13 @@ struct shell_cmd_help { }; struct shell_cmd { + uint8_t sc_ext : 1; /* 1 if this is an extended shell comand. */ + union { + shell_cmd_func_t sc_cmd_func; + shell_cmd_ext_func_t sc_cmd_ext_func; + }; + const char *sc_cmd; - shell_cmd_func_t sc_cmd_func; const struct shell_cmd_help *help; }; @@ -59,6 +85,32 @@ struct shell_module { const struct shell_cmd *commands; }; +#if MYNEWT_VAL(SHELL_CMD_HELP) +#define SHELL_HELP_(help_) (help_) +#else +#define SHELL_HELP_(help_) +#endif + +/** + * @brief constructs a legacy shell command. + */ +#define SHELL_CMD(cmd_, func_, help_) { \ + .sc_ext = 0, \ + .sc_cmd_func = func_, \ + .sc_cmd = cmd_, \ + .help = SHELL_HELP_(help_), \ +} + +/** + * @brief constructs an extended shell command. + */ +#define SHELL_CMD_EXT(cmd_, func_, help_) { \ + .sc_ext = 1, \ + .sc_cmd_ext_func = func_, \ + .sc_cmd = cmd_, \ + .help = SHELL_HELP_(help_), \ +} + /** @brief Register a shell_module object * * @param shell_name Module name to be entered in shell console. @@ -101,6 +153,18 @@ void shell_register_default_module(const char *name); */ void shell_evq_set(struct os_eventq *evq); +/** + * @brief Processes a set of arguments and executes their corresponding shell + * command. + * + * @param argc The argument count (including command name). + * @param argv The argument list ([0] is command name). + * @param streamer The streamer to send output to. + * + * @return 0 on success; SYS_E[...] on failure. + */ +int shell_exec(int argc, char **argv, struct streamer *streamer); + #if MYNEWT_VAL(SHELL_NEWTMGR) struct os_mbuf; typedef int (*shell_nlip_input_func_t)(struct os_mbuf *, void *arg); diff --git a/sys/shell/pkg.yml b/sys/shell/pkg.yml index 6c6f6cf..cf009a8 100644 --- a/sys/shell/pkg.yml +++ b/sys/shell/pkg.yml @@ -26,6 +26,7 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - "@apache-mynewt-core/time/datetime" + - "@apache-mynewt-core/util/streamer" pkg.deps.SHELL_NEWTMGR: - "@apache-mynewt-core/mgmt/mgmt" diff --git a/sys/shell/src/shell.c b/sys/shell/src/shell.c index 335564e..b63fe94 100644 --- a/sys/shell/src/shell.c +++ b/sys/shell/src/shell.c @@ -23,6 +23,8 @@ #include "os/mynewt.h" #include "console/console.h" +#include "streamer/streamer.h" +#include "modlog/modlog.h" #include "shell/shell.h" #include "shell_priv.h" @@ -34,7 +36,7 @@ static size_t num_of_shell_entities; static const char *prompt; static int default_module = -1; -static shell_cmd_func_t app_cmd_handler; +static struct shell_cmd app_cmd; static shell_prompt_function_t app_prompt_handler; /* Shared queue for shell events to be processed */ @@ -76,8 +78,16 @@ print_prompt(void) console_printf("%s%s", get_prompt(), MYNEWT_VAL(SHELL_PROMPT_SUFFIX)); } +static void +print_prompt_if_console(struct streamer *streamer) +{ + if (streamer == streamer_console_get()) { + print_prompt(); + } +} + static size_t -line2argv(char *str, char *argv[], size_t size) +line2argv(char *str, char *argv[], size_t size, struct streamer *streamer) { size_t argc = 0; @@ -109,7 +119,8 @@ line2argv(char *str, char *argv[], size_t size) argv[argc++] = str; if (argc == size) { - console_printf("Too many parameters (max %zu)\n", size - 1); + streamer_printf(streamer, "Too many parameters (max %zu)\n", + size - 1); return 0; } } @@ -144,24 +155,24 @@ get_destination_module(const char *module_str, int len) * If a default module was selected: argv[0] = command name */ static const char * -get_command_and_module(char *argv[], int *module) +get_command_and_module(char *argv[], int *module, struct streamer *streamer) { *module = -1; if (!argv[0]) { - console_printf("Unrecognized command\n"); + streamer_printf(streamer, "Unrecognized command\n"); return NULL; } if (default_module == -1) { if (!argv[1] || argv[1][0] == '\0') { - console_printf("Unrecognized command: %s\n", argv[0]); + streamer_printf(streamer, "Unrecognized command: %s\n", argv[0]); return NULL; } *module = get_destination_module(argv[0], -1); if (*module == -1) { - console_printf("Illegal module %s\n", argv[0]); + streamer_printf(streamer, "Illegal module %s\n", argv[0]); return NULL; } @@ -173,7 +184,8 @@ get_command_and_module(char *argv[], int *module) } static void -print_command_params(const int module, const int command) +print_command_params(const int module, const int command, + struct streamer *streamer) { const struct shell_module *shell_module = &shell_modules[module]; const struct shell_cmd *shell_cmd = &shell_module->commands[command]; @@ -184,13 +196,14 @@ print_command_params(const int module, const int command) } for (i = 0; shell_cmd->help->params[i].param_name; i++) { - console_printf("%-30s%s\n", shell_cmd->help->params[i].param_name, - shell_cmd->help->params[i].help); + streamer_printf(streamer, "%-30s%s\n", + shell_cmd->help->params[i].param_name, + shell_cmd->help->params[i].help); } } static int -show_cmd_help(char *argv[]) +show_cmd_help(char *argv[], struct streamer *streamer) { const char *command = NULL; int module = -1; @@ -198,7 +211,7 @@ show_cmd_help(char *argv[]) const struct shell_cmd *cmd; int i; - command = get_command_and_module(argv, &module); + command = get_command_and_module(argv, &module, streamer); if ((module == -1) || (command == NULL)) { return 0; } @@ -208,73 +221,75 @@ show_cmd_help(char *argv[]) cmd = &shell_module->commands[i]; if (!strcmp(command, cmd->sc_cmd)) { - if (!cmd->help || (!cmd->help->summary && !cmd->help->usage && !cmd->help->params)) { - console_printf("(no help available)\n"); + streamer_printf(streamer, "(no help available)\n"); return 0; } if (cmd->help->summary) { - console_printf("Summary:\n"); - console_printf("%s\n", cmd->help->summary); + streamer_printf(streamer, "Summary:\n"); + streamer_printf(streamer, "%s\n", cmd->help->summary); } if (cmd->help->usage) { - console_printf("Usage:\n"); - console_printf("%s\n", cmd->help->usage); + streamer_printf(streamer, "Usage:\n"); + streamer_printf(streamer, "%s\n", cmd->help->usage); } if (cmd->help->params) { - console_printf("Parameters:\n"); - print_command_params(module, i); + streamer_printf(streamer, "Parameters:\n"); + print_command_params(module, i, streamer); } return 0; } } - console_printf("Unrecognized command: %s\n", argv[0]); + streamer_printf(streamer, "Unrecognized command: %s\n", argv[0]); return 0; } static void -print_modules(void) +print_modules(struct streamer *streamer) { int module; for (module = 0; module < num_of_shell_entities; module++) { - console_printf("%s\n", shell_modules[module].name); + streamer_printf(streamer, "%s\n", shell_modules[module].name); } } static void -print_module_commands(const int module) +print_module_commands(const int module, struct streamer *streamer) { const struct shell_module *shell_module = &shell_modules[module]; int i; - console_printf("help\n"); + streamer_printf(streamer, "help\n"); for (i = 0; shell_module->commands[i].sc_cmd; i++) { - console_printf("%-30s", shell_module->commands[i].sc_cmd); + streamer_printf(streamer, "%-30s", shell_module->commands[i].sc_cmd); if (shell_module->commands[i].help && shell_module->commands[i].help->summary) { - console_printf("%s", shell_module->commands[i].help->summary); + + streamer_printf(streamer, "%s", + shell_module->commands[i].help->summary); } - console_printf("\n"); + streamer_printf(streamer, "\n"); } } static int -show_help(int argc, char *argv[]) +show_help(const struct shell_cmd *cmd, int argc, char *argv[], + struct streamer *streamer) { int module; /* help per command */ if ((argc > 2) || ((default_module != -1) && (argc == 2))) { - return show_cmd_help(&argv[1]); + return show_cmd_help(&argv[1], streamer); } /* help per module */ @@ -282,23 +297,27 @@ show_help(int argc, char *argv[]) if (default_module == -1) { module = get_destination_module(argv[1], -1); if (module == -1) { - console_printf("Illegal module %s\n", argv[1]); + streamer_printf(streamer, "Illegal module %s\n", argv[1]); return 0; } } else { module = default_module; } - print_module_commands(module); + print_module_commands(module, streamer); } else { /* help for all entities */ - console_printf("Available modules:\n"); - print_modules(); - console_printf("To select a module, enter 'select <module name>'.\n"); + streamer_printf(streamer, "Available modules:\n"); + print_modules(streamer); + streamer_printf(streamer, + "To select a module, enter 'select <module name>'.\n"); } return 0; } +static const struct shell_cmd shell_cmd_help = + SHELL_CMD_EXT("help", show_help, NULL); + static int set_default_module(const char *name) { @@ -307,7 +326,6 @@ set_default_module(const char *name) module = get_destination_module(name, -1); if (module == -1) { - console_printf("Illegal module %s, default is not changed\n", name); return -1; } @@ -317,7 +335,8 @@ set_default_module(const char *name) } static int -select_module(int argc, char *argv[]) +select_module(const struct shell_cmd *cmd, int argc, char *argv[], + struct streamer *streamer) { if (argc == 1) { default_module = -1; @@ -328,8 +347,11 @@ select_module(int argc, char *argv[]) return 0; } -static shell_cmd_func_t -get_cb(int argc, char *argv[]) +static const struct shell_cmd shell_cmd_select_module = + SHELL_CMD_EXT("select", select_module, NULL); + +static const struct shell_cmd * +shell_find_cmd(int argc, char *argv[], struct streamer *streamer) { const char *first_string = argv[0]; int module = -1; @@ -338,24 +360,24 @@ get_cb(int argc, char *argv[]) int i; if (!first_string || first_string[0] == '\0') { - console_printf("Illegal parameter\n"); + streamer_printf(streamer, "Illegal parameter\n"); return NULL; } if (!strcmp(first_string, "help")) { - return show_help; + return &shell_cmd_help; } if (!strcmp(first_string, "select")) { - return select_module; + return &shell_cmd_select_module; } if ((argc == 1) && (default_module == -1)) { - console_printf("Missing parameter\n"); + streamer_printf(streamer, "Missing parameter\n"); return NULL; } - command = get_command_and_module(argv, &module); + command = get_command_and_module(argv, &module, streamer); if ((module == -1) || (command == NULL)) { return NULL; } @@ -363,58 +385,75 @@ get_cb(int argc, char *argv[]) shell_module = &shell_modules[module]; for (i = 0; shell_module->commands[i].sc_cmd; i++) { if (!strcmp(command, shell_module->commands[i].sc_cmd)) { - return shell_module->commands[i].sc_cmd_func; + return &shell_module->commands[i]; } } return NULL; } -static void -shell_process_command(char *line) +int +shell_exec(int argc, char **argv, struct streamer *streamer) { - char *argv[MYNEWT_VAL(SHELL_CMD_ARGC_MAX) + 1]; - shell_cmd_func_t sc_cmd_func; + const struct shell_cmd *cmd; size_t argc_offset = 0; - size_t argc; + int rc; - argc = line2argv(line, argv, MYNEWT_VAL(SHELL_CMD_ARGC_MAX) + 1); - if (!argc) { - print_prompt(); - return; - } - - sc_cmd_func = get_cb(argc, argv); - if (!sc_cmd_func) { - if (app_cmd_handler != NULL) { - sc_cmd_func = app_cmd_handler; + cmd = shell_find_cmd(argc, argv, streamer); + if (!cmd) { + if (app_cmd.sc_cmd_func != NULL) { + cmd = &app_cmd; } else { - console_printf("Unrecognized command: %s\n", argv[0]); - console_printf("Type 'help' for list of available commands\n"); - print_prompt(); - return; + streamer_printf(streamer, "Unrecognized command: %s\n", argv[0]); + streamer_printf(streamer, + "Type 'help' for list of available commands\n"); + print_prompt_if_console(streamer); + return SYS_ENOENT; } } /* Allow invoking a cmd with module name as a prefix; a command should * not know how it was invoked (with or without prefix) */ - if (default_module == -1 && sc_cmd_func != select_module && - sc_cmd_func != show_help) { + if (default_module == -1 && cmd != &shell_cmd_select_module && + cmd != &shell_cmd_help) { argc_offset = 1; } /* Execute callback with arguments */ - if (sc_cmd_func(argc - argc_offset, &argv[argc_offset]) < 0) { - show_cmd_help(argv); + if (!cmd->sc_ext) { + rc = cmd->sc_cmd_func(argc - argc_offset, &argv[argc_offset]); + } else { + rc = cmd->sc_cmd_ext_func(cmd, argc - argc_offset, &argv[argc_offset], + streamer); + } + if (rc < 0) { + show_cmd_help(argv, streamer); } - print_prompt(); + print_prompt_if_console(streamer); + + return rc; +} + +static void +shell_process_command(char *line, struct streamer *streamer) +{ + char *argv[MYNEWT_VAL(SHELL_CMD_ARGC_MAX) + 1]; + size_t argc; + + argc = line2argv(line, argv, MYNEWT_VAL(SHELL_CMD_ARGC_MAX) + 1, streamer); + if (!argc) { + print_prompt_if_console(streamer); + return; + } + + shell_exec(argc, argv, streamer); } #if MYNEWT_VAL(SHELL_NEWTMGR) static void -shell_process_nlip_line(char *shell_line) +shell_process_nlip_line(char *shell_line, struct streamer *streamer) { size_t shell_line_len; @@ -428,10 +467,10 @@ shell_process_nlip_line(char *shell_line) shell_line[1] == SHELL_NLIP_DATA_START2) { shell_nlip_process(&shell_line[2], shell_line_len - 2); } else { - shell_process_command(shell_line); + shell_process_command(shell_line, streamer); } } else { - shell_process_command(shell_line); + shell_process_command(shell_line, streamer); } } #endif @@ -440,6 +479,7 @@ static void shell(struct os_event *ev) { struct console_input *cmd; + struct streamer *streamer; if (!ev) { print_prompt(); @@ -452,10 +492,12 @@ shell(struct os_event *ev) return; } + streamer = streamer_console_get(); + #if MYNEWT_VAL(SHELL_NEWTMGR) - shell_process_nlip_line(cmd->line); + shell_process_nlip_line(cmd->line, streamer); #else - shell_process_command(cmd->line); + shell_process_command(cmd->line, streamer); #endif console_line_event_put(ev); @@ -752,7 +794,7 @@ complete_select(char *line, char *cur, return; } console_printf("\n"); - print_modules(); + print_modules(streamer_console_get()); print_prompt(); console_printf("%s", line); return; @@ -788,9 +830,9 @@ completion(char *line, console_append_char_cb append_char) if (tok_len == 0) { console_printf("\n"); if (default_module == -1) { - print_modules(); + print_modules(streamer_console_get()); } else { - print_module_commands(default_module); + print_module_commands(default_module, streamer_console_get()); } print_prompt(); console_printf("%s", line); @@ -827,7 +869,7 @@ completion(char *line, console_append_char_cb append_char) if (tok_len == 0) { console_printf("\n"); - print_module_commands(module); + print_module_commands(module, streamer_console_get()); print_prompt(); console_printf("%s", line); return; @@ -849,7 +891,7 @@ completion(char *line, console_append_char_cb append_char) tok_len = get_last_token(&cur); if (tok_len == 0) { console_printf("\n"); - print_command_params(module, command); + print_command_params(module, command, streamer_console_get()); print_prompt(); console_printf("%s", line); return; @@ -863,7 +905,7 @@ completion(char *line, console_append_char_cb append_char) void shell_register_app_cmd_handler(shell_cmd_func_t handler) { - app_cmd_handler = handler; + app_cmd.sc_cmd_func = handler; } void @@ -899,7 +941,7 @@ int shell_register(const char *module_name, const struct shell_cmd *commands) { if (num_of_shell_entities >= MYNEWT_VAL(SHELL_MAX_MODULES)) { - console_printf("Max number of modules reached\n"); + MODLOG_ERROR(LOG_MODULE_DEFAULT, "Max number of modules reached\n"); assert(0); } @@ -919,22 +961,27 @@ static int module_registered; int shell_cmd_register(const struct shell_cmd *sc) { + int rc; + if (num_compat_commands >= MYNEWT_VAL(SHELL_MAX_COMPAT_COMMANDS)) { - console_printf("Max number of compat commands reached\n"); + MODLOG_ERROR(LOG_MODULE_DEFAULT, + "Max number of compat commands reached\n"); assert(0); } if (!module_registered) { shell_register(SHELL_COMPAT_MODULE_NAME, compat_commands); - set_default_module(SHELL_COMPAT_MODULE_NAME); module_registered = 1; + + rc = set_default_module(SHELL_COMPAT_MODULE_NAME); + if (rc != 0) { + MODLOG_ERROR(LOG_MODULE_DEFAULT, + "Illegal module %s, default is not changed\n", + SHELL_COMPAT_MODULE_NAME); + } } - compat_commands[num_compat_commands].sc_cmd = sc->sc_cmd; - compat_commands[num_compat_commands].sc_cmd_func = sc->sc_cmd_func; -#if MYNEWT_VAL(SHELL_CMD_HELP) - compat_commands[num_compat_commands].help = sc->help; -#endif + compat_commands[num_compat_commands] = *sc; ++num_compat_commands; return 0; } @@ -969,4 +1016,7 @@ shell_init(void) #if MYNEWT_VAL(SHELL_PROMPT_MODULE) shell_prompt_register(); #endif +#if MYNEWT_VAL(SHELL_BRIDGE) + shell_bridge_init(); +#endif } diff --git a/sys/shell/src/shell_priv.h b/sys/shell/src/shell_priv.h index 315ae1c..36a4863 100644 --- a/sys/shell/src/shell_priv.h +++ b/sys/shell/src/shell_priv.h @@ -24,7 +24,19 @@ extern "C" { #endif +#include "streamer/streamer.h" #include "shell/shell.h" +struct CborEncoder; + +#if MYNEWT_VAL(SHELL_BRIDGE) +/** + * Streams CBOR text strings to its encoder. + */ +struct shell_bridge_streamer { + struct streamer streamer; + struct CborEncoder *str_encoder; +}; +#endif #if MYNEWT_VAL(SHELL_NEWTMGR) #define SHELL_NLIP_PKT_START1 (6) @@ -40,6 +52,12 @@ void shell_nlip_clear_pkt(void); void shell_os_register(void); void shell_prompt_register(void); +#if MYNEWT_VAL(SHELL_BRIDGE) +void shell_bridge_streamer_new(struct shell_bridge_streamer *sbs, + struct CborEncoder *str_encoder); +int shell_bridge_init(void); +#endif + #ifdef __cplusplus } #endif diff --git a/sys/shell/src/shell_prompt.c b/sys/shell/src/shell_prompt.c index 0a88500..00a1c18 100644 --- a/sys/shell/src/shell_prompt.c +++ b/sys/shell/src/shell_prompt.c @@ -73,7 +73,7 @@ static const struct shell_cmd prompt_commands[] = { .help = &ticks_help, #endif }, - { NULL, NULL, NULL }, + { 0 }, };