From 27e1398be3821f814aee4eaf7627b2d8fb5c4934 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Sat, 20 Feb 2016 13:51:02 +0000 Subject: Shell reorganization. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@8913 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/various/shell/shell.c | 248 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 os/various/shell/shell.c (limited to 'os/various/shell/shell.c') diff --git a/os/various/shell/shell.c b/os/various/shell/shell.c new file mode 100644 index 000000000..379b6ddf0 --- /dev/null +++ b/os/various/shell/shell.c @@ -0,0 +1,248 @@ +/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + + Licensed 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. +*/ + +/** + * @file shell.c + * @brief Simple CLI shell code. + * + * @addtogroup SHELL + * @{ + */ + +#include + +#include "ch.h" +#include "hal.h" +#include "shell.h" +#include "shell_cmd.h" +#include "chprintf.h" + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/** + * @brief Shell termination event source. + */ +event_source_t shell_terminated; + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +static char *_strtok(char *str, const char *delim, char **saveptr) { + char *token; + if (str) + *saveptr = str; + token = *saveptr; + + if (!token) + return NULL; + + token += strspn(token, delim); + *saveptr = strpbrk(token, delim); + if (*saveptr) + *(*saveptr)++ = '\0'; + + return *token ? token : NULL; +} + +static void usage(BaseSequentialStream *chp, char *p) { + + chprintf(chp, "Usage: %s\r\n", p); +} + +static void list_commands(BaseSequentialStream *chp, const ShellCommand *scp) { + + while (scp->sc_name != NULL) { + chprintf(chp, "%s ", scp->sc_name); + scp++; + } +} + +static bool cmdexec(const ShellCommand *scp, BaseSequentialStream *chp, + char *name, int argc, char *argv[]) { + + while (scp->sc_name != NULL) { + if (strcmp(scp->sc_name, name) == 0) { + scp->sc_function(chp, argc, argv); + return false; + } + scp++; + } + return true; +} + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Shell thread function. + * + * @param[in] p pointer to a @p BaseSequentialStream object + */ +THD_FUNCTION(shellThread, p) { + int n; + BaseSequentialStream *chp = ((ShellConfig *)p)->sc_channel; + const ShellCommand *scp = ((ShellConfig *)p)->sc_commands; + char *lp, *cmd, *tokp, line[SHELL_MAX_LINE_LENGTH]; + char *args[SHELL_MAX_ARGUMENTS + 1]; + + chRegSetThreadName("shell"); + chprintf(chp, "\r\nChibiOS/RT Shell\r\n"); + while (true) { + chprintf(chp, "ch> "); + if (shellGetLine(chp, line, sizeof(line))) { + chprintf(chp, "\r\nlogout"); + break; + } + lp = _strtok(line, " \t", &tokp); + cmd = lp; + n = 0; + while ((lp = _strtok(NULL, " \t", &tokp)) != NULL) { + if (n >= SHELL_MAX_ARGUMENTS) { + chprintf(chp, "too many arguments\r\n"); + cmd = NULL; + break; + } + args[n++] = lp; + } + args[n] = NULL; + if (cmd != NULL) { + if (strcmp(cmd, "exit") == 0) { + if (n > 0) { + usage(chp, "exit"); + continue; + } + break; + } + else if (strcmp(cmd, "help") == 0) { + if (n > 0) { + usage(chp, "help"); + continue; + } + chprintf(chp, "Commands: help exit "); + list_commands(chp, shell_local_commands); + if (scp != NULL) + list_commands(chp, scp); + chprintf(chp, "\r\n"); + } + else if (cmdexec(shell_local_commands, chp, cmd, n, args) && + ((scp == NULL) || cmdexec(scp, chp, cmd, n, args))) { + chprintf(chp, "%s", cmd); + chprintf(chp, " ?\r\n"); + } + } + } + shellExit(MSG_OK); +} + +/** + * @brief Shell manager initialization. + * + * @api + */ +void shellInit(void) { + + chEvtObjectInit(&shell_terminated); +} + +/** + * @brief Terminates the shell. + * @note Must be invoked from the command handlers. + * @note Does not return. + * + * @param[in] msg shell exit code + * + * @api + */ +void shellExit(msg_t msg) { + + /* Atomically broadcasting the event source and terminating the thread, + there is not a chSysUnlock() because the thread terminates upon return.*/ + chSysLock(); + chEvtBroadcastI(&shell_terminated); + chThdExitS(msg); +} + +/** + * @brief Reads a whole line from the input channel. + * @note Input chars are echoed on the same stream object with the + * following exceptions: + * - DEL and BS are echoed as BS-SPACE-BS. + * - CR is echoed as CR-LF. + * - 0x4 is echoed as "^D". + * - Other values below 0x20 are not echoed. + * . + * + * @param[in] chp pointer to a @p BaseSequentialStream object + * @param[in] line pointer to the line buffer + * @param[in] size buffer maximum length + * @return The operation status. + * @retval true the channel was reset or CTRL-D pressed. + * @retval false operation successful. + * + * @api + */ +bool shellGetLine(BaseSequentialStream *chp, char *line, unsigned size) { + char *p = line; + + while (true) { + char c; + + if (chSequentialStreamRead(chp, (uint8_t *)&c, 1) == 0) + return true; + if (c == 4) { + chprintf(chp, "^D"); + return true; + } + if ((c == 8) || (c == 127)) { + if (p != line) { + chSequentialStreamPut(chp, c); + chSequentialStreamPut(chp, 0x20); + chSequentialStreamPut(chp, c); + p--; + } + continue; + } + if (c == '\r') { + chprintf(chp, "\r\n"); + *p = 0; + return false; + } + if (c < 0x20) + continue; + if (p < line + size - 1) { + chSequentialStreamPut(chp, c); + *p++ = (char)c; + } + } +} + +/** @} */ -- cgit v1.2.3