You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2019/05/31 19:48:22 UTC
[mynewt-core] 05/10: sys/shell: Use the util/streamer interface
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 <cc...@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 },
};