diff --git a/sys/include/shell.h b/sys/include/shell.h index ee2cc882f6..9854a82184 100644 --- a/sys/include/shell.h +++ b/sys/include/shell.h @@ -24,6 +24,7 @@ #include "periph/pm.h" #include "kernel_defines.h" +#include "xfa.h" #ifdef __cplusplus extern "C" { @@ -196,6 +197,37 @@ static inline void shell_run(const shell_command_t *commands, shell_run_forever(commands, line_buf, len); } +/** + * @brief Define shell command + * + * This macro is a helper for defining a shell command and adding it to the + * shell commands XFA (cross file array). + * + * Shell commands added using this macros will be sorted *after* builtins and + * commands passed via parameter to `shell_run_once()`. If a command with the + * same name exists in any of those, they will make a command added via this + * macro inaccassible. + * + * Commands added with this macro will be sorted alphanumerically by `name`. + * + * @experimental This should be considered experimental API, subject to change + * without notice! + * + * Example: + * + * ```.c + * #include "shell.h" + * static int _my_command(int argc, char **argv) { + * // ... + * } + * SHELL_COMMAND(my_command, "my command help text", _my_command); + * ``` + */ +#define SHELL_COMMAND(name, help, func) \ + XFA_USE_CONST(shell_command_t*, shell_commands_xfa); \ + static const shell_command_t _xfa_ ## name ## _cmd = { #name, help, &func }; \ + XFA_ADD_PTR(shell_commands_xfa, name, name, &_xfa_ ## name ## _cmd) + #ifdef __cplusplus } #endif diff --git a/sys/shell/shell.c b/sys/shell/shell.c index bae4cda24f..45bbcc2784 100644 --- a/sys/shell/shell.c +++ b/sys/shell/shell.c @@ -36,9 +36,13 @@ #include #include "kernel_defines.h" +#include "xfa.h" #include "shell.h" #include "shell_commands.h" +/* define shell command cross file array */ +XFA_INIT_CONST(shell_command_t*, shell_commands_xfa); + #define ETX '\x03' /** ASCII "End-of-Text", or Ctrl-C */ #define EOT '\x04' /** ASCII "End-of-Transmission", or Ctrl-D */ #define BS '\x08' /** ASCII "Backspace" */ @@ -92,6 +96,19 @@ static shell_command_handler_t search_commands(const shell_command_t *entry, return NULL; } +static shell_command_handler_t search_commands_xfa(char *command) +{ + unsigned n = XFA_LEN(shell_command_t*, shell_commands_xfa); + + for (unsigned i = 0; i < n; i++) { + const volatile shell_command_t *entry = shell_commands_xfa[i]; + if (strcmp(entry->name, command) == 0) { + return entry->handler; + } + } + return NULL; +} + static shell_command_handler_t find_handler( const shell_command_t *command_list, char *command) { @@ -104,6 +121,10 @@ static shell_command_handler_t find_handler( handler = search_commands(_builtin_cmds, command); } + if (handler == NULL) { + handler = search_commands_xfa(command); + } + return handler; } @@ -114,6 +135,15 @@ static void print_commands(const shell_command_t *entry) } } +static void print_commands_xfa(void) +{ + unsigned n = XFA_LEN(shell_command_t*, shell_commands_xfa); + for (unsigned i = 0; i < n; i++) { + const volatile shell_command_t *entry = shell_commands_xfa[i]; + printf("%-20s %s\n", entry->name, entry->desc); + } +} + static void print_help(const shell_command_t *command_list) { puts("Command Description" @@ -125,6 +155,8 @@ static void print_help(const shell_command_t *command_list) if (_builtin_cmds != NULL) { print_commands(_builtin_cmds); } + + print_commands_xfa(); } /**