sys/shell: shell improvements This patch brings improved shell functionality.
* Modules that group shell commands into subshells. A default module can be selected to avoid typing the module prefix with each command. * Per command help messages, per command parameter lists and per parameter help messages. The help messages can be conditionally compiled out to save flash. Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/1151ca8a Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/1151ca8a Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/1151ca8a Branch: refs/heads/master Commit: 1151ca8a9a76d63e880dc78e8af42f8b29027ce8 Parents: a819c9b Author: MichaÅ Narajowski <michal.narajow...@codecoup.pl> Authored: Wed May 3 11:05:27 2017 +0200 Committer: MichaÅ Narajowski <michal.narajow...@codecoup.pl> Committed: Wed May 3 11:37:52 2017 +0200 ---------------------------------------------------------------------- sys/shell/include/shell/shell.h | 86 +++- sys/shell/include/shell/shell_prompt.h | 33 -- sys/shell/include/shell/shell_tick.h | 33 -- sys/shell/pkg.yml | 2 - sys/shell/src/shell.c | 761 +++++++++++----------------- sys/shell/src/shell_os.c | 159 ------ sys/shell/src/shell_priv.h | 35 -- sys/shell/src/shell_prompt.c | 75 --- sys/shell/src/shell_tick.c | 62 --- sys/shell/syscfg.yml | 19 +- 10 files changed, 389 insertions(+), 876 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/1151ca8a/sys/shell/include/shell/shell.h ---------------------------------------------------------------------- diff --git a/sys/shell/include/shell/shell.h b/sys/shell/include/shell/shell.h index d5473c2..d056e65 100644 --- a/sys/shell/include/shell/shell.h +++ b/sys/shell/include/shell/shell.h @@ -16,40 +16,90 @@ * specific language governing permissions and limitations * under the License. */ + #ifndef __SHELL_H__ #define __SHELL_H__ -#include <os/os.h> - #ifdef __cplusplus extern "C" { #endif -struct os_eventq; +/** @brief Callback called when command is entered. + * + * @param argc Number of parameters passed. + * @param argv Array of option strings. First option is always command name. + * + * @return 0 in case of success or negative value in case of error. + */ +typedef int (*shell_cmd_func_t)(int argc, char *argv[]); + +struct shell_param { + const char *param_name; + const char *help; +}; + +struct shell_cmd_help { + const char *summary; + const char *usage; + const struct shell_param *params; +}; -typedef int (*shell_cmd_func_t)(int argc, char **argv); struct shell_cmd { - char *sc_cmd; + const char *sc_cmd; shell_cmd_func_t sc_cmd_func; - STAILQ_ENTRY(shell_cmd) sc_next; + const struct shell_cmd_help *help; +}; + +struct shell_module { + const char *module_name; + const struct shell_cmd *commands; }; -int shell_cmd_register(struct shell_cmd *sc); +/** @brief Callback called when registering module + * + * @param module_name Name of the module + * @param commands Array of shell_cmd structs + * + * @return 0 in case of success or negative value in case of error. + */ +typedef int (*shell_register_function_t)(const char *module_name, + const struct shell_cmd *commands); + +/** @brief Register a shell_module object + * + * @param shell_name Module name to be entered in shell console. + * + * @param shell_commands Array of commands to register. + * The array should be terminated with an empty element. + */ +int shell_register(const char *shell_name, + const struct shell_cmd *shell_commands); -#define SHELL_NLIP_PKT_START1 (6) -#define SHELL_NLIP_PKT_START2 (9) -#define SHELL_NLIP_DATA_START1 (4) -#define SHELL_NLIP_DATA_START2 (20) +/** @brief Optionally register an app default cmd handler. + * + * @param handler To be called if no cmd found in cmds registered with + * shell_init. + */ +void shell_register_app_cmd_handler(shell_cmd_func_t handler); -typedef int (*shell_nlip_input_func_t)(struct os_mbuf *, void *arg); -int shell_nlip_input_register(shell_nlip_input_func_t nf, void *arg); -int shell_nlip_output(struct os_mbuf *m); +/** @brief Callback to get the current prompt. + * + * @returns Current prompt string. + */ +typedef const char *(*shell_prompt_function_t)(void); -void shell_evq_set(struct os_eventq *evq); -void shell_init(void); +/** @brief Optionally register a custom prompt callback. + * + * @param handler To be called to get the current prompt. + */ +void shell_register_prompt_handler(shell_prompt_function_t handler); -int shell_cmd_list_lock(void); -int shell_cmd_list_unlock(void); +/** @brief Optionally register a default module, to avoid typing it in + * shell console. + * + * @param name Module name. + */ +void shell_register_default_module(const char *name); #ifdef __cplusplus } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/1151ca8a/sys/shell/include/shell/shell_prompt.h ---------------------------------------------------------------------- diff --git a/sys/shell/include/shell/shell_prompt.h b/sys/shell/include/shell/shell_prompt.h deleted file mode 100644 index 9f42b54..0000000 --- a/sys/shell/include/shell/shell_prompt.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_SHELL_PROMPT_ -#define H_SHELL_PROMPT_ - -#ifdef __cplusplus -extern "C" { -#endif - -int shell_prompt_cmd(int argc, char **argv); - -#ifdef __cplusplus -} -#endif - -#endif http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/1151ca8a/sys/shell/include/shell/shell_tick.h ---------------------------------------------------------------------- diff --git a/sys/shell/include/shell/shell_tick.h b/sys/shell/include/shell/shell_tick.h deleted file mode 100644 index 0d0b2e6..0000000 --- a/sys/shell/include/shell/shell_tick.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_SHELL_TICKS_ -#define H_SHELL_TICKS_ - -#ifdef __cplusplus -extern "C" { -#endif - -int shell_ticks_cmd(int argc, char **argv); - -#ifdef __cplusplus -} -#endif - -#endif http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/1151ca8a/sys/shell/pkg.yml ---------------------------------------------------------------------- diff --git a/sys/shell/pkg.yml b/sys/shell/pkg.yml index 39d46b1..1f38a8d 100644 --- a/sys/shell/pkg.yml +++ b/sys/shell/pkg.yml @@ -25,9 +25,7 @@ pkg.keywords: pkg.deps: - kernel/os - - encoding/base64 - time/datetime - - util/crc pkg.req_apis: - console http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/1151ca8a/sys/shell/src/shell.c ---------------------------------------------------------------------- diff --git a/sys/shell/src/shell.c b/sys/shell/src/shell.c index 02cb3a1..c91dd42 100644 --- a/sys/shell/src/shell.c +++ b/sys/shell/src/shell.c @@ -21,543 +21,432 @@ #include <string.h> #include <assert.h> -#include "sysinit/sysinit.h" #include "syscfg/syscfg.h" -#include "defs/error.h" -#include "console/console.h" -#include "console/prompt.h" -#include "console/ticks.h" #include "os/os.h" -#include "os/endian.h" -#include "base64/base64.h" -#include "crc/crc16.h" +#include "console/console.h" +#include "sysinit/sysinit.h" #include "shell/shell.h" -#include "shell_priv.h" - -static shell_nlip_input_func_t g_shell_nlip_in_func; -static void *g_shell_nlip_in_arg; - -static struct os_mqueue g_shell_nlip_mq; - -#define SHELL_HELP_PER_LINE 6 -#define SHELL_MAX_ARGS 20 - -static int shell_echo_cmd(int argc, char **argv); -static int shell_help_cmd(int argc, char **argv); -int shell_prompt_cmd(int argc, char **argv); -int shell_ticks_cmd(int argc, char **argv); - - -static void shell_event_console_rdy(struct os_event *ev); - -/* Shared queue that the shell uses for work items. */ -static struct os_eventq *shell_evq; - -static struct shell_cmd g_shell_echo_cmd = { - .sc_cmd = "echo", - .sc_cmd_func = shell_echo_cmd -}; -static struct shell_cmd g_shell_help_cmd = { - .sc_cmd = "?", - .sc_cmd_func = shell_help_cmd -}; -static struct shell_cmd g_shell_prompt_cmd = { - .sc_cmd = "prompt", - .sc_cmd_func = shell_prompt_cmd -}; -static struct shell_cmd g_shell_ticks_cmd = { - .sc_cmd = "ticks", - .sc_cmd_func = shell_ticks_cmd -}; -static struct shell_cmd g_shell_os_tasks_display_cmd = { - .sc_cmd = "tasks", - .sc_cmd_func = shell_os_tasks_display_cmd -}; -static struct shell_cmd g_shell_os_mpool_display_cmd = { - .sc_cmd = "mempools", - .sc_cmd_func = shell_os_mpool_display_cmd -}; -static struct shell_cmd g_shell_os_date_cmd = { - .sc_cmd = "date", - .sc_cmd_func = shell_os_date_cmd -}; - -static struct os_event shell_console_rdy_ev = { - .ev_cb = shell_event_console_rdy, -}; - -static struct os_mutex g_shell_cmd_list_lock; - -static char *shell_line; -static int shell_line_len; -static char *argv[SHELL_MAX_ARGS]; - -static STAILQ_HEAD(, shell_cmd) g_shell_cmd_list = - STAILQ_HEAD_INITIALIZER(g_shell_cmd_list); - -static struct os_mbuf *g_nlip_mbuf; -static uint16_t g_nlip_expected_len; - -static struct os_eventq * -shell_evq_get(void) -{ - return shell_evq; -} -void -shell_evq_set(struct os_eventq *evq) -{ - os_eventq_designate(&shell_evq, evq, NULL); -} +#define SHELL_PROMPT "shell> " -int -shell_cmd_list_lock(void) +#define MODULE_NAME_MAX_LEN 20 + +/* additional chars are "> " (include '\0' )*/ +#define PROMPT_SUFFIX 3 +#define PROMPT_MAX_LEN (MODULE_NAME_MAX_LEN + PROMPT_SUFFIX) + +static struct shell_module shell_modules[MYNEWT_VAL(SHELL_MAX_MODULES)]; +static size_t num_of_shell_entities; + +static const char *prompt; +static char default_module_prompt[PROMPT_MAX_LEN]; +static int default_module = -1; + +static shell_cmd_func_t app_cmd_handler; +static shell_prompt_function_t app_prompt_handler; + +static struct console_input buf[MYNEWT_VAL(SHELL_MAX_CMD_QUEUED)]; + +static struct os_eventq avail_queue; +static struct os_event shell_console_ev[MYNEWT_VAL(SHELL_MAX_CMD_QUEUED)]; + +static const char * +get_prompt(void) { - int rc; + if (app_prompt_handler) { + const char *str; - if (!os_started()) { - return (0); + str = app_prompt_handler(); + if (str) { + return str; + } } - rc = os_mutex_pend(&g_shell_cmd_list_lock, OS_WAIT_FOREVER); - if (rc != 0) { - goto err; + if (default_module != -1) { + return default_module_prompt; } - return (0); -err: - return (rc); + + return prompt; } -int -shell_cmd_list_unlock(void) +static size_t +line2argv(char *str, char *argv[], size_t size) { - int rc; + size_t argc = 0; + + if (!strlen(str)) { + return 0; + } - if (!os_started()) { - return (0); + while (*str && *str == ' ') { + str++; } - rc = os_mutex_release(&g_shell_cmd_list_lock); - if (rc != 0) { - goto err; + if (!*str) { + return 0; } - return (0); -err: - return (rc); -} -static int -shell_cmd_find(char *cmd_name, struct shell_cmd **out_cmd) -{ - struct shell_cmd *sc; - int rc; + argv[argc++] = str; - rc = shell_cmd_list_lock(); - if (rc != 0) { - return rc; - } + while ((str = strchr(str, ' '))) { + *str++ = '\0'; + + while (*str && *str == ' ') { + str++; + } - STAILQ_FOREACH(sc, &g_shell_cmd_list, sc_next) { - if (!strcmp(sc->sc_cmd, cmd_name)) { + if (!*str) { break; } - } - rc = shell_cmd_list_unlock(); - if (rc != 0) { - return rc; - } + argv[argc++] = str; - if (out_cmd != NULL) { - *out_cmd = sc; + if (argc == size) { + console_printf("Too many parameters (max %zu)\n", size - 1); + return 0; + } } - if (sc == NULL) { - return SYS_ENOENT; - } + /* keep it POSIX style where argv[argc] is required to be NULL */ + argv[argc] = NULL; - return 0; + return argc; } -int -shell_cmd_register(struct shell_cmd *sc) +static int +get_destination_module(const char *module_str, uint8_t len) { - int rc; + int i; -#if MYNEWT_VAL(SHELL_DEBUG) - /* Ensure command not already registered. */ - assert(shell_cmd_find(sc->sc_cmd, NULL) == SYS_ENOENT); -#endif + for (i = 0; i < num_of_shell_entities; i++) { + if (!strncmp(module_str, + shell_modules[i].module_name, len)) { + return i; + } + } - /* Add the command that is being registered. */ - rc = shell_cmd_list_lock(); - if (rc != 0) { - goto err; + return -1; +} + +/* For a specific command: argv[0] = module name, argv[1] = command name + * If a default module was selected: argv[0] = command name + */ +static const char * +get_command_and_module(char *argv[], int *module) +{ + *module = -1; + + if (!argv[0]) { + console_printf("Unrecognized command\n"); + return NULL; } - STAILQ_INSERT_TAIL(&g_shell_cmd_list, sc, sc_next); + if (default_module == -1) { + if (!argv[1] || argv[1][0] == '\0') { + console_printf("Unrecognized command: %s\n", argv[0]); + return NULL; + } - rc = shell_cmd_list_unlock(); - if (rc != 0) { - goto err; + *module = get_destination_module(argv[0], MODULE_NAME_MAX_LEN); + if (*module == -1) { + console_printf("Illegal module %s\n", argv[0]); + return NULL; + } + + return argv[1]; } - return (0); -err: - return (rc); + *module = default_module; + return argv[0]; } static int -shell_cmd(char *cmd, char **argv, int argc) +show_cmd_help(char *argv[]) { - struct shell_cmd *sc = NULL; - int rc; + const char *command = NULL; + int module = -1; + const struct shell_module *shell_module = NULL; + int i; - rc = shell_cmd_find(cmd, &sc); - switch (rc) { - case 0: - sc->sc_cmd_func(argc, argv); + command = get_command_and_module(argv, &module); + if ((module == -1) || (command == NULL)) { return 0; + } - case SYS_ENOENT: - console_printf("Unknown command %s\n", cmd); - return 0; + shell_module = &shell_modules[module]; + for (i = 0; shell_module->commands[i].sc_cmd; i++) { + if (!strcmp(command, shell_module->commands[i].sc_cmd)) { + console_printf("%s:\n", shell_module->commands[i].sc_cmd); - default: - return rc; + if (!shell_module->commands[i].help) { + console_printf("\n"); + return 0; + } + if (shell_module->commands[i].help->usage) { + console_printf("%s\n", shell_module->commands[i].help->usage); + } else if (shell_module->commands[i].help->summary) { + console_printf("%s\n", shell_module->commands[i].help->summary); + } else { + console_printf("\n"); + } + + return 0; + } } + + console_printf("Unrecognized command: %s\n", argv[0]); + return 0; } -static int -shell_process_command(char *line, int len) +static void +print_modules(void) { - char *tok; - char *tok_ptr; - int argc; - - tok_ptr = NULL; - tok = strtok_r(line, " ", &tok_ptr); - argc = 0; - while (argc < SHELL_MAX_ARGS - 1 && tok != NULL) { - argv[argc++] = tok; + int module; - tok = strtok_r(NULL, " ", &tok_ptr); + for (module = 0; module < num_of_shell_entities; module++) { + console_printf("%s\n", shell_modules[module].module_name); } +} - /* Terminate the argument list with a null pointer. */ - argv[argc] = NULL; +static void +print_module_commands(const int module) +{ + const struct shell_module *shell_module = &shell_modules[module]; + int i; - if (argc) { - (void) shell_cmd(argv[0], argv, argc); - } - else { + console_printf("help\n"); + + for (i = 0; shell_module->commands[i].sc_cmd; i++) { + console_printf("%-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); + } console_printf("\n"); } - console_print_prompt(); - return (0); } static int -shell_nlip_process(char *data, int len) +show_help(int argc, char *argv[]) { - uint16_t copy_len; - int rc; - struct os_mbuf *m; - uint16_t crc; + int module; - rc = base64_decode(data, data); - if (rc < 0) { - goto err; + /* help per command */ + if ((argc > 2) || ((default_module != -1) && (argc == 2))) { + return show_cmd_help(&argv[1]); } - len = rc; - - if (g_nlip_mbuf == NULL) { - if (len < 2) { - rc = -1; - goto err; - } - g_nlip_expected_len = ntohs(*(uint16_t *) data); - g_nlip_mbuf = os_msys_get_pkthdr(g_nlip_expected_len, 0); - if (!g_nlip_mbuf) { - rc = -1; - goto err; + /* help per module */ + if ((argc == 2) || ((default_module != -1) && (argc == 1))) { + if (default_module == -1) { + module = get_destination_module(argv[1], MODULE_NAME_MAX_LEN); + if (module == -1) { + console_printf("Illegal module %s\n", argv[1]); + return 0; + } + } else { + module = default_module; } - data += sizeof(uint16_t); - len -= sizeof(uint16_t); + print_module_commands(module); + } else { /* help for all entities */ + console_printf("Available modules:\n"); + print_modules(); + console_printf("To select a module, enter 'select <module name>'.\n"); } - copy_len = min(g_nlip_expected_len - OS_MBUF_PKTHDR(g_nlip_mbuf)->omp_len, - len); + return 0; +} + +static int +set_default_module(const char *name) +{ + int module; - rc = os_mbuf_copyinto(g_nlip_mbuf, OS_MBUF_PKTHDR(g_nlip_mbuf)->omp_len, - data, copy_len); - if (rc != 0) { - goto err; + if (strlen(name) > MODULE_NAME_MAX_LEN) { + console_printf("Module name %s is too long, default is not changed\n", + name); + return -1; } - if (OS_MBUF_PKTHDR(g_nlip_mbuf)->omp_len == g_nlip_expected_len) { - if (g_shell_nlip_in_func) { - crc = CRC16_INITIAL_CRC; - for (m = g_nlip_mbuf; m; m = SLIST_NEXT(m, om_next)) { - crc = crc16_ccitt(crc, m->om_data, m->om_len); - } - if (crc == 0 && g_nlip_expected_len >= sizeof(crc)) { - os_mbuf_adj(g_nlip_mbuf, -sizeof(crc)); - g_shell_nlip_in_func(g_nlip_mbuf, g_shell_nlip_in_arg); - } else { - os_mbuf_free_chain(g_nlip_mbuf); - } - } else { - os_mbuf_free_chain(g_nlip_mbuf); - } - g_nlip_mbuf = NULL; - g_nlip_expected_len = 0; + module = get_destination_module(name, MODULE_NAME_MAX_LEN); + + if (module == -1) { + console_printf("Illegal module %s, default is not changed\n", name); + return -1; } - return (0); -err: - return (rc); + default_module = module; + + strncpy(default_module_prompt, name, MODULE_NAME_MAX_LEN); + strcat(default_module_prompt, "> "); + + return 0; } static int -shell_nlip_mtx(struct os_mbuf *m) +select_module(int argc, char *argv[]) { -#define SHELL_NLIP_MTX_BUF_SIZE (12) - uint8_t readbuf[SHELL_NLIP_MTX_BUF_SIZE]; - char encodebuf[BASE64_ENCODE_SIZE(SHELL_NLIP_MTX_BUF_SIZE)]; - char pkt_seq[3] = { '\n', SHELL_NLIP_PKT_START1, SHELL_NLIP_PKT_START2 }; - char esc_seq[2] = { SHELL_NLIP_DATA_START1, SHELL_NLIP_DATA_START2 }; - uint16_t totlen; - uint16_t dlen; - uint16_t off; - uint16_t crc; - int rb_off; - int elen; - uint16_t nwritten; - uint16_t linelen; - int rc; - struct os_mbuf *tmp; - void *ptr; - - /* Convert the mbuf into a packet. - * - * starts with 06 09 - * base64 encode: - * - total packet length (uint16_t) - * - data - * - crc - * base64 encoded data must be less than 122 bytes per line to - * avoid overflows and adhere to convention. - * - * continuation packets are preceded by 04 20 until the entire - * buffer has been sent. - */ - crc = CRC16_INITIAL_CRC; - for (tmp = m; tmp; tmp = SLIST_NEXT(tmp, om_next)) { - crc = crc16_ccitt(crc, tmp->om_data, tmp->om_len); + if (argc == 1) { + default_module = -1; + } else { + set_default_module(argv[1]); } - crc = htons(crc); - ptr = os_mbuf_extend(m, sizeof(crc)); - if (!ptr) { - rc = -1; - goto err; - } - memcpy(ptr, &crc, sizeof(crc)); - - totlen = OS_MBUF_PKTHDR(m)->omp_len; - nwritten = 0; - off = 0; - /* Start a packet */ - console_write(pkt_seq, sizeof(pkt_seq)); - - linelen = 0; + return 0; +} - rb_off = 2; - dlen = htons(totlen); - memcpy(readbuf, &dlen, sizeof(dlen)); +static shell_cmd_func_t +get_cb(int argc, char *argv[]) +{ + const char *first_string = argv[0]; + int module = -1; + const struct shell_module *shell_module; + const char *command; + int i; - while (totlen > 0) { - dlen = min(SHELL_NLIP_MTX_BUF_SIZE - rb_off, totlen); + if (!first_string || first_string[0] == '\0') { + console_printf("Illegal parameter\n"); + return NULL; + } - rc = os_mbuf_copydata(m, off, dlen, readbuf + rb_off); - if (rc != 0) { - goto err; - } - off += dlen; - - /* If the next packet will overwhelm the line length, truncate - * this line. - */ - if (linelen + - BASE64_ENCODE_SIZE(min(SHELL_NLIP_MTX_BUF_SIZE - rb_off, - totlen - dlen)) >= 120) { - elen = base64_encode(readbuf, dlen + rb_off, encodebuf, 1); - console_write(encodebuf, elen); - console_write("\n", 1); - console_write(esc_seq, sizeof(esc_seq)); - linelen = 0; - } else { - elen = base64_encode(readbuf, dlen + rb_off, encodebuf, 0); - console_write(encodebuf, elen); - linelen += elen; - } + if (!strcmp(first_string, "help")) { + return show_help; + } - rb_off = 0; + if (!strcmp(first_string, "select")) { + return select_module; + } - nwritten += elen; - totlen -= dlen; + if ((argc == 1) && (default_module == -1)) { + console_printf("Missing parameter\n"); + return NULL; } - elen = base64_pad(encodebuf, linelen); - console_write(encodebuf, elen); + command = get_command_and_module(argv, &module); + if ((module == -1) || (command == NULL)) { + return NULL; + } - console_write("\n", 1); + shell_module = &shell_modules[module]; + console_printf("module: %d, command: %s\n", module, command); + 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 (0); -err: - return (rc); + return NULL; } -int -shell_nlip_input_register(shell_nlip_input_func_t nf, void *arg) +static void +shell_process_command(char *line) { - g_shell_nlip_in_func = nf; - g_shell_nlip_in_arg = arg; + char *argv[MYNEWT_VAL(SHELL_CMD_ARGC_MAX) + 1]; + shell_cmd_func_t sc_cmd_func; + size_t argc_offset = 0; + size_t argc; + + argc = line2argv(line, argv, MYNEWT_VAL(SHELL_CMD_ARGC_MAX) + 1); + if (!argc) { + console_printf("%s", get_prompt()); + return; + } - return (0); -} + sc_cmd_func = get_cb(argc, argv); + if (!sc_cmd_func) { + if (app_cmd_handler != NULL) { + sc_cmd_func = app_cmd_handler; + } else { + console_printf("Unrecognized command: %s\n", argv[0]); + console_printf("Type 'help' for list of available commands\n"); + console_printf("%s", get_prompt()); + return; + } + } -int -shell_nlip_output(struct os_mbuf *m) -{ - int rc; + /* 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) { + argc_offset = 1; + } - rc = os_mqueue_put(&g_shell_nlip_mq, shell_evq_get(), m); - if (rc != 0) { - goto err; + /* Execute callback with arguments */ + if (sc_cmd_func(argc - argc_offset, &argv[argc_offset]) < 0) { + show_cmd_help(argv); } - return (0); -err: - return (rc); + console_printf("%s", get_prompt()); } static void -shell_read_console(void) +shell(struct os_event *ev) { - int rc; - int full_line; + struct console_input *cmd; - while (1) { - rc = console_read(shell_line + shell_line_len, - MYNEWT_VAL(SHELL_MAX_INPUT_LEN) - shell_line_len, &full_line); - if (rc <= 0 && !full_line) { - break; - } - shell_line_len += rc; - if (full_line) { - if (shell_line_len > 2) { - if (shell_line[0] == SHELL_NLIP_PKT_START1 && - shell_line[1] == SHELL_NLIP_PKT_START2) { - if (g_nlip_mbuf) { - os_mbuf_free_chain(g_nlip_mbuf); - g_nlip_mbuf = NULL; - } - g_nlip_expected_len = 0; - - rc = shell_nlip_process(&shell_line[2], shell_line_len - 2); - } else if (shell_line[0] == SHELL_NLIP_DATA_START1 && - shell_line[1] == SHELL_NLIP_DATA_START2) { - rc = shell_nlip_process(&shell_line[2], shell_line_len - 2); - } else { - shell_process_command(shell_line, shell_line_len); - } - } else { - shell_process_command(shell_line, shell_line_len); - } - shell_line_len = 0; - } + if (!ev) { + console_printf("%s", get_prompt()); + return; } + + cmd = ev->ev_arg; + if (!cmd) { + console_printf("%s", get_prompt()); + return; + } + + shell_process_command(cmd->line); + os_eventq_put(&avail_queue, ev); } -static void -shell_event_console_rdy(struct os_event *ev) +void +shell_register_app_cmd_handler(shell_cmd_func_t handler) { - shell_read_console(); + app_cmd_handler = handler; } -static void -shell_event_data_in(struct os_event *ev) +void +shell_register_prompt_handler(shell_prompt_function_t handler) { - struct os_mbuf *m; - - /* Copy data out of the mbuf 12 bytes at a time and write it to - * the console. - */ - while (1) { - m = os_mqueue_get(&g_shell_nlip_mq); - if (!m) { - break; - } + app_prompt_handler = handler; +} - (void) shell_nlip_mtx(m); +void +shell_register_default_module(const char *name) +{ + int result = set_default_module(name); - os_mbuf_free_chain(m); + if (result != -1) { + console_printf("\n"); + console_printf("%s", default_module_prompt); } } -/** - * This function is called from the console APIs when data is available - * to be read. This is either a full line, or when the - * console buffer (default = 128) is full. - */ static void -shell_console_rx_cb(void) -{ - os_eventq_put(shell_evq_get(), &shell_console_rdy_ev); -} - -static int -shell_echo_cmd(int argc, char **argv) +line_queue_init(void) { int i; - for (i = 1; i < argc; i++) { - console_write(argv[i], strlen(argv[i])); - console_write(" ", sizeof(" ")-1); + for (i = 0; i < MYNEWT_VAL(SHELL_MAX_CMD_QUEUED); i++) { + shell_console_ev[i].ev_cb = shell; + shell_console_ev[i].ev_arg = &buf[i]; + os_eventq_put(&avail_queue, &shell_console_ev[i]); } - console_write("\n", sizeof("\n")-1); - - return (0); } -static int -shell_help_cmd(int argc, char **argv) +int +shell_register(const char *module_name, const struct shell_cmd *commands) { - int rc; - int i = 0; - struct shell_cmd *sc; - - rc = shell_cmd_list_lock(); - if (rc != 0) { + if (num_of_shell_entities >= MYNEWT_VAL(SHELL_MAX_MODULES)) { return -1; } - console_printf("Commands:\n"); - STAILQ_FOREACH(sc, &g_shell_cmd_list, sc_next) { - console_printf("%9s ", sc->sc_cmd); - if (i++ % SHELL_HELP_PER_LINE == SHELL_HELP_PER_LINE - 1) { - console_printf("\n"); - } - } - if (i % SHELL_HELP_PER_LINE) { - console_printf("\n"); - } - shell_cmd_list_unlock(); - return (0); + shell_modules[num_of_shell_entities].module_name = module_name; + shell_modules[num_of_shell_entities].commands = commands; + ++num_of_shell_entities; + + return 0; } void @@ -570,42 +459,8 @@ shell_init(void) return; #endif - int rc; - - free(shell_line); - shell_line = NULL; - -#if MYNEWT_VAL(SHELL_MAX_INPUT_LEN) > 0 - shell_line = malloc(MYNEWT_VAL(SHELL_MAX_INPUT_LEN)); - SYSINIT_PANIC_ASSERT(shell_line != NULL); -#endif - - rc = os_mutex_init(&g_shell_cmd_list_lock); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = shell_cmd_register(&g_shell_echo_cmd); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = shell_cmd_register(&g_shell_help_cmd); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = shell_cmd_register(&g_shell_prompt_cmd); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = shell_cmd_register(&g_shell_ticks_cmd); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = shell_cmd_register(&g_shell_os_tasks_display_cmd); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = shell_cmd_register(&g_shell_os_mpool_display_cmd); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = shell_cmd_register(&g_shell_os_date_cmd); - SYSINIT_PANIC_ASSERT(rc == 0); - - os_mqueue_init(&g_shell_nlip_mq, shell_event_data_in, NULL); - console_init(shell_console_rx_cb); - - shell_evq_set(os_eventq_dflt_get()); + os_eventq_init(&avail_queue); + line_queue_init(); + prompt = SHELL_PROMPT; + console_set_queues(&avail_queue, os_eventq_dflt_get()); } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/1151ca8a/sys/shell/src/shell_os.c ---------------------------------------------------------------------- diff --git a/sys/shell/src/shell_os.c b/sys/shell/src/shell_os.c deleted file mode 100644 index 48a3b3d..0000000 --- a/sys/shell/src/shell_os.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "os/os.h" - -#include "os/queue.h" -#include "os/os_time.h" - -#include "console/console.h" -#include "shell/shell.h" -#include "shell_priv.h" - -#include <assert.h> -#include <string.h> -#include <datetime/datetime.h> - -int -shell_os_tasks_display_cmd(int argc, char **argv) -{ - struct os_task *prev_task; - struct os_task_info oti; - char *name; - int found; - - name = NULL; - found = 0; - - if (argc > 1 && strcmp(argv[1], "")) { - name = argv[1]; - } - - console_printf("Tasks: \n"); - prev_task = NULL; - console_printf("%8s %3s %3s %8s %8s %8s %8s %8s %8s %3s\n", - "task", "pri", "tid", "runtime", "csw", "stksz", "stkuse", - "lcheck", "ncheck", "flg"); - while (1) { - prev_task = os_task_info_get_next(prev_task, &oti); - if (prev_task == NULL) { - break; - } - - if (name) { - if (strcmp(name, oti.oti_name)) { - continue; - } else { - found = 1; - } - } - - console_printf("%8s %3u %3u %8lu %8lu %8u %8u %8lu %8lu %3x\n", - oti.oti_name, oti.oti_prio, oti.oti_taskid, - (unsigned long)oti.oti_runtime, (unsigned long)oti.oti_cswcnt, - oti.oti_stksize, oti.oti_stkusage, - (unsigned long)oti.oti_last_checkin, - (unsigned long)oti.oti_next_checkin, oti.oti_flags); - - } - - if (name && !found) { - console_printf("Couldn't find task with name %s\n", name); - } - - return (0); -} - -int -shell_os_mpool_display_cmd(int argc, char **argv) -{ - struct os_mempool *mp; - struct os_mempool_info omi; - char *name; - int found; - - name = NULL; - found = 0; - - if (argc > 1 && strcmp(argv[1], "")) { - name = argv[1]; - } - - console_printf("Mempools: \n"); - mp = NULL; - console_printf("%32s %5s %4s %4s %4s\n", "name", "blksz", "cnt", "free", - "min"); - while (1) { - mp = os_mempool_info_get_next(mp, &omi); - if (mp == NULL) { - break; - } - - if (name) { - if (strcmp(name, omi.omi_name)) { - continue; - } else { - found = 1; - } - } - - console_printf("%32s %5d %4d %4d %4d\n", omi.omi_name, - omi.omi_block_size, omi.omi_num_blocks, - omi.omi_num_free, omi.omi_min_free); - } - - if (name && !found) { - console_printf("Couldn't find a memory pool with name %s\n", - name); - } - - return (0); -} - -int -shell_os_date_cmd(int argc, char **argv) -{ - struct os_timeval tv; - struct os_timezone tz; - char buf[DATETIME_BUFSIZE]; - int rc; - - argc--; argv++; /* skip command name */ - - if (argc == 0) { - /* Display the current datetime */ - rc = os_gettimeofday(&tv, &tz); - assert(rc == 0); - rc = datetime_format(&tv, &tz, buf, sizeof(buf)); - assert(rc == 0); - console_printf("%s\n", buf); - } else if (argc == 1) { - /* Set the current datetime */ - rc = datetime_parse(*argv, &tv, &tz); - if (rc == 0) { - rc = os_settimeofday(&tv, &tz); - } else { - console_printf("Invalid datetime\n"); - } - } else { - rc = -1; - } - - return (rc); -} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/1151ca8a/sys/shell/src/shell_priv.h ---------------------------------------------------------------------- diff --git a/sys/shell/src/shell_priv.h b/sys/shell/src/shell_priv.h deleted file mode 100644 index e79d56e..0000000 --- a/sys/shell/src/shell_priv.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef __SHELL_PRIV_H_ -#define __SHELL_PRIV_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -int shell_os_tasks_display_cmd(int argc, char **argv); -int shell_os_mpool_display_cmd(int argc, char **argv); -int shell_os_date_cmd(int argc, char **argv); - -#ifdef __cplusplus -} -#endif - -#endif /* __SHELL_PRIV_H_ */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/1151ca8a/sys/shell/src/shell_prompt.c ---------------------------------------------------------------------- diff --git a/sys/shell/src/shell_prompt.c b/sys/shell/src/shell_prompt.c deleted file mode 100644 index 801d7ca..0000000 --- a/sys/shell/src/shell_prompt.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include <string.h> -#include "shell/shell.h" -#include <console/console.h> -#include <console/prompt.h> -static char shell_prompt = '>'; - -void console_set_prompt(char p); - -/** - * Handles the 'prompt' command - * with set argument, sets the prompt to the provided char - * with the show argument, echos the current prompt - * otherwise echos the prompt and the usage message - */ -int -shell_prompt_cmd(int argc, char **argv) -{ - int rc; - - rc = shell_cmd_list_lock(); - if (rc != 0) { - return -1; - } - if (argc > 1) { - if (!strcmp(argv[1], "show")) { - console_printf(" Prompt character: %c\n", shell_prompt); - } - else if (!strcmp(argv[1],"set")) { - shell_prompt = argv[2][0]; - console_printf(" Prompt set to: %c\n", argv[2][0]); - console_set_prompt(argv[2][0]); - } - else if (!strcmp(argv[1], "on")) { - console_yes_prompt(); - console_printf(" Prompt now on.\n"); - } - else if (!strcmp(argv[1], "off")) { - console_no_prompt(); - console_printf(" Prompt now off.\n"); - } - else { - goto usage; - } - } - else { - goto usage; - } - shell_cmd_list_unlock(); - return 0; -usage: - console_printf("Usage: prompt [on|off]|[set|show] [prompt_char]\n"); - shell_cmd_list_unlock(); - return 0; - -} - \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/1151ca8a/sys/shell/src/shell_tick.c ---------------------------------------------------------------------- diff --git a/sys/shell/src/shell_tick.c b/sys/shell/src/shell_tick.c deleted file mode 100644 index ec2fdff..0000000 --- a/sys/shell/src/shell_tick.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include <string.h> -#include "shell/shell.h" -#include <console/console.h> -#include <console/ticks.h> -#include "syscfg/syscfg.h" - -/** - * Handles the 'ticks' command - */ -int -shell_ticks_cmd(int argc, char **argv) -{ - int rc; - - rc = shell_cmd_list_lock(); - if (rc != 0) { - return -1; - } - if (argc > 1) { - if (!strcmp(argv[1], "on")) { - console_yes_ticks(); - console_printf(" Console Ticks on\n"); - } - else if (!strcmp(argv[1],"off")) { - console_printf(" Console Ticks off\n"); - console_no_ticks(); - } - else { - goto usage; - } - } - else { - goto usage; - } - shell_cmd_list_unlock(); - return 0; -usage: - console_printf(" Usage: ticks [on|off]\n"); - shell_cmd_list_unlock(); - return 0; - -} - \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/1151ca8a/sys/shell/syscfg.yml ---------------------------------------------------------------------- diff --git a/sys/shell/syscfg.yml b/sys/shell/syscfg.yml index af7ad77..8a53bff 100644 --- a/sys/shell/syscfg.yml +++ b/sys/shell/syscfg.yml @@ -22,9 +22,16 @@ syscfg.defs: SHELL_TASK: description: 'Controls whether shell is enabled or not.' value: 0 - SHELL_MAX_INPUT_LEN: - description: 'Maximum input line length' - value: 256 - SHELL_DEBUG: - description: Enables additional error checking in the shell package. - value: 0 + + SHELL_CMD_ARGC_MAX: + description: 'Max number of command line arguments' + value: 12 + SHELL_CMD_HELP: + description: 'Include help information for shell commands' + value: 1 + SHELL_MAX_MODULES: + description: 'Max number of modules' + value: 3 + SHELL_MAX_CMD_QUEUED: + description: 'Max number of command lines queued' + value: 1