From d7777d3bd54c8b0a16b21cd462efb3f67cce84f5 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 15 Jan 2018 11:15:47 -0500 Subject: [PATCH] shell: support standalone commands This will allow us to register commands directly without a need for a module. Signed-off-by: Anas Nashif --- include/linker/linker-defs.h | 5 ++- include/shell/shell.h | 25 +++++++++++++ subsys/shell/shell.c | 69 +++++++++++++++++++++++++++++------- 3 files changed, 85 insertions(+), 14 deletions(-) diff --git a/include/linker/linker-defs.h b/include/linker/linker-defs.h index 03477a8e05e..a3448762e0a 100644 --- a/include/linker/linker-defs.h +++ b/include/linker/linker-defs.h @@ -102,7 +102,10 @@ #define SHELL_INIT_SECTIONS() \ __shell_module_start = .; \ KEEP(*(".shell_module_*")); \ - __shell_module_end = .; + __shell_module_end = .; \ + __shell_cmd_start = .; \ + KEEP(*(".shell_cmd_*")); \ + __shell_cmd_end = .; \ #ifdef CONFIG_APPLICATION_MEMORY diff --git a/include/shell/shell.h b/include/shell/shell.h index 045d97789ed..88fe797abd5 100644 --- a/include/shell/shell.h +++ b/include/shell/shell.h @@ -79,6 +79,21 @@ struct shell_module { * Shell array entries must be packed to calculate array size correctly. * @param _prompt Optional prompt handler to be set when module is selected. */ + + +/** + * @def SHELL_REGISTER_COMMAND + * + * @brief Create a standalone command and set it up for boot time + * initialization. + * + * @details This macro define a shell_cmd object hat is automatically + * configured by the kernel during system initialization. + * + * The command will be available in he default module, so it will be available + * immediatly when. + * + */ #ifdef CONFIG_CONSOLE_SHELL #define SHELL_REGISTER(_name, _commands) \ SHELL_REGISTER_WITH_PROMPT(_name, _commands, NULL) @@ -91,9 +106,19 @@ struct shell_module { .commands = _commands, \ .prompt = _prompt \ } + +#define SHELL_REGISTER_COMMAND(name, callback, _help) \ + \ + const struct shell_cmd (__shell__##name) __used \ + __attribute__((__section__(".shell_cmd_"))) = { \ + .cmd_name = name, \ + .cb = callback, \ + .help = _help \ + } #else #define SHELL_REGISTER(_name, _commands) #define SHELL_REGISTER_WITH_PROMPT(_name, _commands, _prompt) +#define SHELL_REGISTER_COMMAND(_name, _callback, _help) #endif /** @brief Initialize shell with optional prompt, NULL in case no prompt is diff --git a/subsys/shell/shell.c b/subsys/shell/shell.c index 5733e3e9957..ac88e171058 100644 --- a/subsys/shell/shell.c +++ b/subsys/shell/shell.c @@ -38,7 +38,12 @@ /* command table is located in the dedicated memory segment (.shell_) */ extern struct shell_module __shell_module_start[]; extern struct shell_module __shell_module_end[]; + +extern struct shell_cmd __shell_cmd_start[]; +extern struct shell_cmd __shell_cmd_end[]; + #define NUM_OF_SHELL_ENTITIES (__shell_module_end - __shell_module_start) +#define NUM_OF_SHELL_CMDS (__shell_cmd_end - __shell_cmd_start) static const char *prompt; static char default_module_prompt[PROMPT_MAX_LEN]; @@ -196,6 +201,22 @@ static const struct shell_cmd *get_mod_cmd(struct shell_module *module, return get_cmd(module->commands, cmd_str); } +static const struct shell_cmd *get_standalone(const char *command) +{ + int i; + + for (i = 0; i < NUM_OF_SHELL_CMDS; i++) { + if (!strcmp(command, __shell_cmd_start[i].cmd_name)) { + return &__shell_cmd_start[i]; + } + } + + return NULL; +} + +/** + * Handle internal 'help' command + */ static int cmd_help(int argc, char *argv[]) { struct shell_module *module = default_module; @@ -218,16 +239,21 @@ static int cmd_help(int argc, char *argv[]) } if (!module) { - printk("No help found for '%s'\n", cmd_str); - return -EINVAL; - } - - cmd = get_mod_cmd(module, cmd_str); - if (cmd) { - return show_cmd_help(cmd, true); + cmd = get_standalone(cmd_str); + if (cmd) { + return show_cmd_help(cmd, true); + } else { + printk("No help found for '%s'\n", cmd_str); + return -EINVAL; + } } else { - printk("Unknown command '%s'\n", cmd_str); - return -EINVAL; + cmd = get_mod_cmd(module, cmd_str); + if (cmd) { + return show_cmd_help(cmd, true); + } else { + printk("Unknown command '%s'\n", cmd_str); + return -EINVAL; + } } } @@ -239,15 +265,26 @@ module_help: } else { /* help for all entities */ int i; + printk("[Modules]\n"); + if (NUM_OF_SHELL_ENTITIES == 0) { printk("No registered modules.\n"); - } else { - printk("Available modules:\n"); } + for (i = 0; i < NUM_OF_SHELL_ENTITIES; i++) { printk("%s\n", __shell_module_start[i].module_name); } + printk("\n[Commands]\n"); + + if (NUM_OF_SHELL_CMDS == 0) { + printk("No registered commands.\n"); + } + + for (i = 0; i < NUM_OF_SHELL_CMDS; i++) { + printk("%s\n", __shell_cmd_start[i].cmd_name); + } + printk("\nTo select a module, enter 'select '.\n"); } @@ -260,7 +297,7 @@ static int set_default_module(const char *name) if (strlen(name) > MODULE_NAME_MAX_LEN) { printk("Module name %s is too long, default is not changed\n", - name); + name); return -EINVAL; } @@ -310,6 +347,7 @@ static const struct shell_cmd *get_internal(const char *command) return get_cmd(internal_commands, command); } + int shell_exec(char *line) { char *argv[ARGC_MAX + 1], **argv_start = argv; @@ -326,7 +364,12 @@ int shell_exec(char *line) goto done; } - if (argc == 1 && !default_module) { + cmd = get_standalone(argv[0]); + if (cmd) { + goto done; + } + + if (argc == 1 && !default_module && NUM_OF_SHELL_CMDS == 0) { printk("No module selected. Use 'select' or 'help'.\n"); return -EINVAL; }