From 48026bb824fd2d9cfb00ecd040db6ef3a416bae9 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Fri, 22 Jan 2021 21:43:36 -0500 Subject: upload initial port --- ChibiOS_20.3.2/os/various/shell/shell.c | 604 ++++++++++++++++++++++++++++ ChibiOS_20.3.2/os/various/shell/shell.h | 235 +++++++++++ ChibiOS_20.3.2/os/various/shell/shell.mk | 9 + ChibiOS_20.3.2/os/various/shell/shell_cmd.c | 247 ++++++++++++ ChibiOS_20.3.2/os/various/shell/shell_cmd.h | 114 ++++++ 5 files changed, 1209 insertions(+) create mode 100644 ChibiOS_20.3.2/os/various/shell/shell.c create mode 100644 ChibiOS_20.3.2/os/various/shell/shell.h create mode 100644 ChibiOS_20.3.2/os/various/shell/shell.mk create mode 100644 ChibiOS_20.3.2/os/various/shell/shell_cmd.c create mode 100644 ChibiOS_20.3.2/os/various/shell/shell_cmd.h (limited to 'ChibiOS_20.3.2/os/various/shell') diff --git a/ChibiOS_20.3.2/os/various/shell/shell.c b/ChibiOS_20.3.2/os/various/shell/shell.c new file mode 100644 index 0000000..19db9aa --- /dev/null +++ b/ChibiOS_20.3.2/os/various/shell/shell.c @@ -0,0 +1,604 @@ +/* + ChibiOS - Copyright (C) 2006..2018 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. */ +/*===========================================================================*/ + +#if !defined(_CHIBIOS_NIL_) || defined(__DOXYGEN__) +/** + * @brief Shell termination event source. + */ +event_source_t shell_terminated; +#endif + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +static char *parse_arguments(char *str, char **saveptr) { + char *p; + + if (str != NULL) + *saveptr = str; + + p = *saveptr; + if (!p) { + return NULL; + } + + /* Skipping white space.*/ + p += strspn(p, " \t"); + + if (*p == '"') { + /* If an argument starts with a double quote then its delimiter is another + quote.*/ + p++; + *saveptr = strpbrk(p, "\""); + } + else { + /* The delimiter is white space.*/ + *saveptr = strpbrk(p, " \t"); + } + + /* Replacing the delimiter with a zero.*/ + if (*saveptr != NULL) { + *(*saveptr)++ = '\0'; + } + + return *p != '\0' ? p : NULL; +} + +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; +} + +#if (SHELL_USE_HISTORY == TRUE) || defined(__DOXYGEN__) +static void del_histbuff_entry(ShellHistory *shp) { + int pos = shp->sh_beg + *(shp->sh_buffer + shp->sh_beg) + 1; + + if (pos >= shp->sh_size) + pos -= shp->sh_size; + + shp->sh_beg = pos; +} + +static bool is_histbuff_space(ShellHistory *shp, int length) { + + if (shp->sh_end >= shp->sh_beg) { + if (length < (shp->sh_size - (shp->sh_end - shp->sh_beg + 1))) + return true; + } + else { + if (length < (shp->sh_beg - shp->sh_end - 1)) + return true; + } + + return false; +} + +static void save_history(ShellHistory *shp, char *line, int length) { + + if (shp == NULL) + return; + + if (length > shp->sh_size - 2) + return; + + while ((*(line + length -1) == ' ') && (length > 0)) + length--; + + if (length <= 0) + return; + + while (!is_histbuff_space(shp, length)) + del_histbuff_entry(shp); + + if (length < shp->sh_size - shp->sh_end - 1) + memcpy(shp->sh_buffer + shp->sh_end + 1, line, length); + else { + /* + * Since there isn't enough room left at the end of the buffer, + * split the line to save up to the end of the buffer and then + * wrap back to the beginning of the buffer. + */ + int part_len = shp->sh_size - shp->sh_end - 1; + memcpy(shp->sh_buffer + shp->sh_end + 1, line, part_len); + memcpy(shp->sh_buffer, line + part_len, length - part_len); + } + + /* Save the length of the current line and move the buffer end pointer */ + *(shp->sh_buffer + shp->sh_end) = (char)length; + shp->sh_end += length + 1; + if (shp->sh_end >= shp->sh_size) + shp->sh_end -= shp->sh_size; + *(shp->sh_buffer + shp->sh_end) = 0; + shp->sh_cur = 0; +} + +static int get_history(ShellHistory *shp, char *line, int dir) { + int count=0; + + if (shp == NULL) + return -1; + + /* Count the number of lines saved in the buffer */ + int idx = shp->sh_beg; + while (idx != shp->sh_end) { + idx += *(shp->sh_buffer + idx) + 1; + if (idx >= shp->sh_size) + idx -= shp->sh_size; + count++; + } + + if (dir == SHELL_HIST_DIR_FW) { + if (shp->sh_cur > 0) + shp->sh_cur -= 2; + else + return 0; + } + + if (count >= shp->sh_cur) { + idx = shp->sh_beg; + int i = 0; + while (idx != shp->sh_end && shp->sh_cur != (count - i - 1)) { + idx += *(shp->sh_buffer + idx) + 1; + if (idx >= shp->sh_size) + idx -= shp->sh_size; + i++; + } + + int length = *(shp->sh_buffer + idx); + + if (length > 0) { + shp->sh_cur++; + + memset(line, 0, SHELL_MAX_LINE_LENGTH); + if ((idx + length) < shp->sh_size) { + memcpy(line, (shp->sh_buffer + idx + 1), length); + } + else { + /* + * Since the saved line was split at the end of the buffer, + * get the line in two parts. + */ + int part_len = shp->sh_size - idx - 1; + memcpy(line, shp->sh_buffer + idx + 1, part_len); + memcpy(line + part_len, shp->sh_buffer, length - part_len); + } + return length; + } + else if (dir == SHELL_HIST_DIR_FW) { + shp->sh_cur++; + return 0; + } + } + return -1; +} +#endif + +#if (SHELL_USE_COMPLETION == TRUE) || defined(__DOXYGEN__) +static void get_completions(ShellConfig *scfg, char *line) { + const ShellCommand *lcp = shell_local_commands; + const ShellCommand *scp = scfg->sc_commands; + char **scmp = scfg->sc_completion; + char help_cmp[] = "help"; + + if (strstr(help_cmp, line) == help_cmp) { + *scmp++ = help_cmp; + } + while (lcp->sc_name != NULL) { + if (strstr(lcp->sc_name, line) == lcp->sc_name) { + *scmp++ = (char *)lcp->sc_name; + } + lcp++; + } + if (scp != NULL) { + while (scp->sc_name != NULL) { + if (strstr(scp->sc_name, line) == scp->sc_name) { + *scmp++ = (char *)scp->sc_name; + } + scp++; + } + } + + *scmp = NULL; +} + +static int process_completions(ShellConfig *scfg, char *line, int length, unsigned size) { + char **scmp = scfg->sc_completion; + char **cmp = scmp + 1; + char *c = line + length; + int clen = 0; + + if (*scmp != NULL) { + if (*cmp == NULL) { + clen = strlen(*scmp); + int i = length; + while ((c < line + clen) && (c < line + size - 1)) + *c++ = *(*scmp + i++); + if (c < line + size -1) { + *c = ' '; + clen++; + } + } + else { + while (*(*scmp + clen) != 0) { + while ((*(*scmp + clen) == *(*cmp + clen)) && + (*(*cmp + clen) != 0) && (*cmp != NULL)) { + cmp++; + } + if (*cmp == NULL) { + if ((c < line + size - 1) && (clen >= length)) + *c++ = *(*scmp + clen); + cmp = scmp + 1; + clen++; + } + else { + break; + } + } + } + + *(line + clen) = 0; + } + + return clen; +} + +static void write_completions(ShellConfig *scfg, char *line, int pos) { + BaseSequentialStream *chp = scfg->sc_channel; + char **scmp = scfg->sc_completion; + + if (*(scmp + 1) != NULL) { + chprintf(chp, SHELL_NEWLINE_STR); + while (*scmp != NULL) + chprintf(chp, " %s", *scmp++); + chprintf(chp, SHELL_NEWLINE_STR); + + chprintf(chp, SHELL_PROMPT_STR); + chprintf(chp, "%s", line); + } + else { + chprintf(chp, "%s", line + pos); + } +} +#endif + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Shell thread function. + * + * @param[in] p pointer to a @p BaseSequentialStream object + */ +THD_FUNCTION(shellThread, p) { + int n; + ShellConfig *scfg = p; + BaseSequentialStream *chp = scfg->sc_channel; + const ShellCommand *scp = scfg->sc_commands; + char *lp, *cmd, *tokp, line[SHELL_MAX_LINE_LENGTH]; + char *args[SHELL_MAX_ARGUMENTS + 1]; + +#if !defined(_CHIBIOS_NIL_) + chRegSetThreadName(SHELL_THREAD_NAME); +#endif + +#if SHELL_USE_HISTORY == TRUE + *(scfg->sc_histbuf) = 0; + ShellHistory hist = { + scfg->sc_histbuf, + scfg->sc_histsize, + 0, + 0, + 0 + }; + ShellHistory *shp = &hist; +#else + ShellHistory *shp = NULL; +#endif + + chprintf(chp, SHELL_NEWLINE_STR); + chprintf(chp, "ChibiOS/RT Shell" SHELL_NEWLINE_STR); +#if !defined(_CHIBIOS_NIL_) + while (!chThdShouldTerminateX()) { +#else + while (true) { +#endif + chprintf(chp, SHELL_PROMPT_STR); + if (shellGetLine(scfg, line, sizeof(line), shp)) { +#if (SHELL_CMD_EXIT_ENABLED == TRUE) && !defined(_CHIBIOS_NIL_) + chprintf(chp, SHELL_NEWLINE_STR); + chprintf(chp, "logout"); + break; +#else + /* Putting a delay in order to avoid an endless loop trying to read + an unavailable stream.*/ + osalThreadSleepMilliseconds(100); +#endif + } + lp = parse_arguments(line, &tokp); + cmd = lp; + n = 0; + while ((lp = parse_arguments(NULL, &tokp)) != NULL) { + if (n >= SHELL_MAX_ARGUMENTS) { + chprintf(chp, "too many arguments" SHELL_NEWLINE_STR); + cmd = NULL; + break; + } + args[n++] = lp; + } + args[n] = NULL; + if (cmd != NULL) { + if (strcmp(cmd, "help") == 0) { + if (n > 0) { + shellUsage(chp, "help"); + continue; + } + chprintf(chp, "Commands: help "); + list_commands(chp, shell_local_commands); + if (scp != NULL) + list_commands(chp, scp); + chprintf(chp, SHELL_NEWLINE_STR); + } + else if (cmdexec(shell_local_commands, chp, cmd, n, args) && + ((scp == NULL) || cmdexec(scp, chp, cmd, n, args))) { + chprintf(chp, "%s", cmd); + chprintf(chp, " ?" SHELL_NEWLINE_STR); + } + } + } +#if !defined(_CHIBIOS_NIL_) + shellExit(MSG_OK); +#endif +} + +/** + * @brief Shell manager initialization. + * + * @api + */ +void shellInit(void) { + +#if !defined(_CHIBIOS_NIL_) + chEvtObjectInit(&shell_terminated); +#endif +} + +#if !defined(_CHIBIOS_NIL_) || defined(__DOXYGEN__) +/** + * @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); +} +#endif + +/** + * @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] scfg pointer to a @p ShellConfig object + * @param[in] line pointer to the line buffer + * @param[in] size buffer maximum length + * @param[in] shp pointer to a @p ShellHistory object or NULL + * @return The operation status. + * @retval true the channel was reset or CTRL-D pressed. + * @retval false operation successful. + * + * @api + */ +bool shellGetLine(ShellConfig *scfg, char *line, unsigned size, ShellHistory *shp) { + char *p = line; + BaseSequentialStream *chp = scfg->sc_channel; +#if SHELL_USE_ESC_SEQ == TRUE + bool escape = false; + bool bracket = false; +#endif + +#if SHELL_USE_HISTORY != TRUE + (void) shp; +#endif + + while (true) { + char c; + + if (streamRead(chp, (uint8_t *)&c, 1) == 0) + return true; +#if SHELL_USE_ESC_SEQ == TRUE + if (c == 27) { + escape = true; + continue; + } + if (escape) { + escape = false; + if (c == '[') { + escape = true; + bracket = true; + continue; + } + if (bracket) { + bracket = false; +#if SHELL_USE_HISTORY == TRUE + if (c == 'A') { + int len = get_history(shp, line, SHELL_HIST_DIR_BK); + + if (len > 0) { + _shell_reset_cur(chp); + _shell_clr_line(chp); + chprintf(chp, "%s", line); + p = line + len; + } + continue; + } + if (c == 'B') { + int len = get_history(shp, line, SHELL_HIST_DIR_FW); + + if (len == 0) + *line = 0; + + if (len >= 0) { + _shell_reset_cur(chp); + _shell_clr_line(chp); + chprintf(chp, "%s", line); + p = line + len; + } + continue; + } +#endif + } + continue; + } +#endif +#if (SHELL_CMD_EXIT_ENABLED == TRUE) && !defined(_CHIBIOS_NIL_) + if (c == 4) { + chprintf(chp, "^D"); + return true; + } +#endif + if ((c == 8) || (c == 127)) { + if (p != line) { + streamPut(chp, 0x08); + streamPut(chp, 0x20); + streamPut(chp, 0x08); + p--; + } + continue; + } + if (c == '\r') { + chprintf(chp, SHELL_NEWLINE_STR); +#if SHELL_USE_HISTORY == TRUE + save_history(shp, line, p - line); +#endif + *p = 0; + return false; + } +#if SHELL_USE_COMPLETION == TRUE + if (c == '\t') { + if (p < line + size - 1) { + *p = 0; + + get_completions(scfg, line); + int len = process_completions(scfg, line, p - line, size); + if (len > 0) { + write_completions(scfg, line, p - line); + p = line + len; + } + } + continue; + } +#endif +#if SHELL_USE_HISTORY == TRUE + if (c == 14) { + int len = get_history(shp, line, SHELL_HIST_DIR_FW); + + if (len == 0) + *line = 0; + + if (len >= 0) { + _shell_reset_cur(chp); + _shell_clr_line(chp); + chprintf(chp, "%s", line); + p = line + len; + } + continue; + } + if (c == 16) { + int len = get_history(shp, line, SHELL_HIST_DIR_BK); + + if (len > 0) { + _shell_reset_cur(chp); + _shell_clr_line(chp); + chprintf(chp, "%s", line); + p = line + len; + } + continue; + } +#endif + if (c < 0x20) + continue; + if (p < line + size - 1) { + streamPut(chp, c); + *p++ = (char)c; + } + } +} + +/** @} */ diff --git a/ChibiOS_20.3.2/os/various/shell/shell.h b/ChibiOS_20.3.2/os/various/shell/shell.h new file mode 100644 index 0000000..d11adc0 --- /dev/null +++ b/ChibiOS_20.3.2/os/various/shell/shell.h @@ -0,0 +1,235 @@ +/* + ChibiOS - Copyright (C) 2006..2018 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.h + * @brief Simple CLI shell header. + * + * @addtogroup SHELL + * @{ + */ + +#ifndef SHELL_H +#define SHELL_H + +#if defined(SHELL_CONFIG_FILE) +#include "shellconf.h" +#endif + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/** + * @brief Shell History Constants + */ +#define SHELL_HIST_DIR_BK 0 +#define SHELL_HIST_DIR_FW 1 + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @brief Shell maximum input line length. + */ +#if !defined(SHELL_MAX_LINE_LENGTH) || defined(__DOXYGEN__) +#define SHELL_MAX_LINE_LENGTH 64 +#endif + +/** + * @brief Shell maximum arguments per command. + */ +#if !defined(SHELL_MAX_ARGUMENTS) || defined(__DOXYGEN__) +#define SHELL_MAX_ARGUMENTS 4 +#endif + +/** + * @brief Shell maximum command history. + */ +#if !defined(SHELL_MAX_HIST_BUFF) || defined(__DOXYGEN__) +#define SHELL_MAX_HIST_BUFF 8 * SHELL_MAX_LINE_LENGTH +#endif + +/** + * @brief Enable shell command history + */ +#if !defined(SHELL_USE_HISTORY) || defined(__DOXYGEN__) +#define SHELL_USE_HISTORY FALSE +#endif + +/** + * @brief Enable shell command completion + */ +#if !defined(SHELL_USE_COMPLETION) || defined(__DOXYGEN__) +#define SHELL_USE_COMPLETION FALSE +#endif + +/** + * @brief Shell Maximum Completions (Set to max commands with common prefix) + */ +#if !defined(SHELL_MAX_COMPLETIONS) || defined(__DOXYGEN__) +#define SHELL_MAX_COMPLETIONS 8 +#endif + +/** + * @brief Enable shell escape sequence processing + */ +#if !defined(SHELL_USE_ESC_SEQ) || defined(__DOXYGEN__) +#define SHELL_USE_ESC_SEQ FALSE +#endif + +/** + * @brief Prompt string + */ +#if !defined(SHELL_PROMPT_STR) || defined(__DOXYGEN__) +#define SHELL_PROMPT_STR "ch> " +#endif + +/** + * @brief Newline string + */ +#if !defined(SHELL_NEWLINE_STR) || defined(__DOXYGEN__) +#define SHELL_NEWLINE_STR "\r\n" +#endif + +/** + * @brief Default shell thread name. + */ +#if !defined(SHELL_THREAD_NAME) || defined(__DOXYGEN__) +#define SHELL_THREAD_NAME "shell" +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Command handler function type. + */ +typedef void (*shellcmd_t)(BaseSequentialStream *chp, int argc, char *argv[]); + +/** + * @brief Custom command entry type. + */ +typedef struct { + const char *sc_name; /**< @brief Command name. */ + shellcmd_t sc_function; /**< @brief Command function. */ +} ShellCommand; + +/** + * @brief Shell history type. + */ +typedef struct { + char *sh_buffer; /**< @brief Buffer to store command + history. */ + const int sh_size; /**< @brief Shell history buffer + size. */ + int sh_beg; /**< @brief Beginning command index + in buffer. */ + int sh_end; /**< @brief Ending command index + in buffer. */ + int sh_cur; /**< @brief Currently selected + command in buffer. */ +} ShellHistory; + +/** + * @brief Shell descriptor type. + */ +typedef struct { + BaseSequentialStream *sc_channel; /**< @brief I/O channel associated + to the shell. */ + const ShellCommand *sc_commands; /**< @brief Shell extra commands + table. */ +#if (SHELL_USE_HISTORY == TRUE) || defined(__DOXYGEN__) + char *sc_histbuf; /**< @brief Shell command history + buffer. */ + const int sc_histsize; /**< @brief Shell history buffer + size. */ +#endif +#if (SHELL_USE_COMPLETION == TRUE) || defined(__DOXYGEN__) + char **sc_completion; /**< @brief Shell command completion + buffer. */ +#endif +} ShellConfig; + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/** + * @brief Send escape codes to move cursor to the beginning of the line + * + * @param[in] stream pointer to a @p BaseSequentialStream object + * + * @notapi + */ +#define _shell_reset_cur(stream) chprintf(stream, "\033[%dD\033[%dC", \ + SHELL_MAX_LINE_LENGTH + \ + strlen(SHELL_PROMPT_STR) + 2, \ + strlen(SHELL_PROMPT_STR)) + +/** + * @brief Send escape codes to clear the rest of the line + * + * @param[in] stream pointer to a @p BaseSequentialStream object + * + * @notapi + */ +#define _shell_clr_line(stream) chprintf(stream, "\033[K") + +/** + * @brief Prints out usage message + * + * @param[in] stream pointer to a @p BaseSequentialStream object + * @param[in] message pointer to message string + * + * @api + */ +#define shellUsage(stream, message) \ + chprintf(stream, "Usage: %s" SHELL_NEWLINE_STR, message) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern event_source_t shell_terminated; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void shellInit(void); + THD_FUNCTION(shellThread, p); + void shellExit(msg_t msg); + bool shellGetLine(ShellConfig *scfg, char *line, + unsigned size, ShellHistory *shp); +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +#endif /* SHELL_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/various/shell/shell.mk b/ChibiOS_20.3.2/os/various/shell/shell.mk new file mode 100644 index 0000000..dfe901a --- /dev/null +++ b/ChibiOS_20.3.2/os/various/shell/shell.mk @@ -0,0 +1,9 @@ +# RT Shell files. +SHELLSRC = $(CHIBIOS)/os/various/shell/shell.c \ + $(CHIBIOS)/os/various/shell/shell_cmd.c + +SHELLINC = $(CHIBIOS)/os/various/shell + +# Shared variables +ALLCSRC += $(SHELLSRC) +ALLINC += $(SHELLINC) diff --git a/ChibiOS_20.3.2/os/various/shell/shell_cmd.c b/ChibiOS_20.3.2/os/various/shell/shell_cmd.c new file mode 100644 index 0000000..525f269 --- /dev/null +++ b/ChibiOS_20.3.2/os/various/shell/shell_cmd.c @@ -0,0 +1,247 @@ +/* + ChibiOS - Copyright (C) 2006..2018 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_cmd.c + * @brief Simple CLI shell common commands code. + * + * @addtogroup SHELL + * @{ + */ + +#include + +#include "ch.h" +#include "hal.h" +#include "shell.h" +#include "shell_cmd.h" +#include "chprintf.h" + +#if (SHELL_CMD_TEST_ENABLED == TRUE) || defined(__DOXYGEN__) +#include "rt_test_root.h" +#include "oslib_test_root.h" +#endif + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +#if ((SHELL_CMD_EXIT_ENABLED == TRUE) && !defined(_CHIBIOS_NIL_)) || \ + defined(__DOXYGEN__) +static void cmd_exit(BaseSequentialStream *chp, int argc, char *argv[]) { + + (void)argv; + if (argc > 0) { + shellUsage(chp, "exit"); + return; + } + + shellExit(MSG_OK); +} +#endif + +#if (SHELL_CMD_INFO_ENABLED == TRUE) || defined(__DOXYGEN__) +static void cmd_info(BaseSequentialStream *chp, int argc, char *argv[]) { + + (void)argv; + if (argc > 0) { + shellUsage(chp, "info"); + return; + } + + chprintf(chp, "Kernel: %s" SHELL_NEWLINE_STR, CH_KERNEL_VERSION); +#ifdef PORT_COMPILER_NAME + chprintf(chp, "Compiler: %s" SHELL_NEWLINE_STR, PORT_COMPILER_NAME); +#endif + chprintf(chp, "Architecture: %s" SHELL_NEWLINE_STR, PORT_ARCHITECTURE_NAME); +#ifdef PORT_CORE_VARIANT_NAME + chprintf(chp, "Core Variant: %s" SHELL_NEWLINE_STR, PORT_CORE_VARIANT_NAME); +#endif +#ifdef PORT_INFO + chprintf(chp, "Port Info: %s" SHELL_NEWLINE_STR, PORT_INFO); +#endif +#ifdef PLATFORM_NAME + chprintf(chp, "Platform: %s" SHELL_NEWLINE_STR, PLATFORM_NAME); +#endif +#ifdef BOARD_NAME + chprintf(chp, "Board: %s" SHELL_NEWLINE_STR, BOARD_NAME); +#endif +#ifdef __DATE__ +#ifdef __TIME__ + chprintf(chp, "Build time: %s%s%s" SHELL_NEWLINE_STR, __DATE__, " - ", __TIME__); +#endif +#endif +} +#endif + +#if (SHELL_CMD_ECHO_ENABLED == TRUE) || defined(__DOXYGEN__) +static void cmd_echo(BaseSequentialStream *chp, int argc, char *argv[]) { + + (void)argv; + if (argc != 1) { + shellUsage(chp, "echo \"message\""); + return; + } + chprintf(chp, "%s" SHELL_NEWLINE_STR, argv[0]); +} +#endif + +#if (SHELL_CMD_SYSTIME_ENABLED == TRUE) || defined(__DOXYGEN__) +static void cmd_systime(BaseSequentialStream *chp, int argc, char *argv[]) { + + (void)argv; + if (argc > 0) { + shellUsage(chp, "systime"); + return; + } + chprintf(chp, "%lu" SHELL_NEWLINE_STR, (unsigned long)chVTGetSystemTime()); +} +#endif + +#if (SHELL_CMD_MEM_ENABLED == TRUE) || defined(__DOXYGEN__) +static void cmd_mem(BaseSequentialStream *chp, int argc, char *argv[]) { + size_t n, total, largest; + + (void)argv; + if (argc > 0) { + shellUsage(chp, "mem"); + return; + } + n = chHeapStatus(NULL, &total, &largest); + chprintf(chp, "core free memory : %u bytes" SHELL_NEWLINE_STR, chCoreGetStatusX()); + chprintf(chp, "heap fragments : %u" SHELL_NEWLINE_STR, n); + chprintf(chp, "heap free total : %u bytes" SHELL_NEWLINE_STR, total); + chprintf(chp, "heap free largest: %u bytes" SHELL_NEWLINE_STR, largest); +} +#endif + +#if (SHELL_CMD_THREADS_ENABLED == TRUE) || defined(__DOXYGEN__) +static void cmd_threads(BaseSequentialStream *chp, int argc, char *argv[]) { + static const char *states[] = {CH_STATE_NAMES}; + thread_t *tp; + + (void)argv; + if (argc > 0) { + shellUsage(chp, "threads"); + return; + } + chprintf(chp, "stklimit stack addr refs prio state name\r\n" SHELL_NEWLINE_STR); + tp = chRegFirstThread(); + do { +#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE) + uint32_t stklimit = (uint32_t)tp->wabase; +#else + uint32_t stklimit = 0U; +#endif + chprintf(chp, "%08lx %08lx %08lx %4lu %4lu %9s %12s" SHELL_NEWLINE_STR, + stklimit, (uint32_t)tp->ctx.sp, (uint32_t)tp, + (uint32_t)tp->refs - 1, (uint32_t)tp->prio, states[tp->state], + tp->name == NULL ? "" : tp->name); + tp = chRegNextThread(tp); + } while (tp != NULL); +} +#endif + +#if (SHELL_CMD_TEST_ENABLED == TRUE) || defined(__DOXYGEN__) +static THD_FUNCTION(test_rt, arg) { + BaseSequentialStream *chp = (BaseSequentialStream *)arg; + test_execute(chp, &rt_test_suite); +} + +static THD_FUNCTION(test_oslib, arg) { + BaseSequentialStream *chp = (BaseSequentialStream *)arg; + test_execute(chp, &oslib_test_suite); +} + +static void cmd_test(BaseSequentialStream *chp, int argc, char *argv[]) { + thread_t *tp; + tfunc_t tfp; + + (void)argv; + if (argc != 1) { + shellUsage(chp, "test rt|oslib"); + return; + } + if (!strcmp(argv[0], "rt")) { + tfp = test_rt; + } + else if (!strcmp(argv[0], "oslib")) { + tfp = test_oslib; + } + else { + shellUsage(chp, "test rt|oslib"); + return; + } + tp = chThdCreateFromHeap(NULL, SHELL_CMD_TEST_WA_SIZE, + "test", chThdGetPriorityX(), + tfp, chp); + if (tp == NULL) { + chprintf(chp, "out of memory" SHELL_NEWLINE_STR); + return; + } + chThdWait(tp); +} +#endif + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Array of the default commands. + */ +const ShellCommand shell_local_commands[] = { +#if (SHELL_CMD_EXIT_ENABLED == TRUE) && !defined(_CHIBIOS_NIL_) + {"exit", cmd_exit}, +#endif +#if SHELL_CMD_INFO_ENABLED == TRUE + {"info", cmd_info}, +#endif +#if SHELL_CMD_ECHO_ENABLED == TRUE + {"echo", cmd_echo}, +#endif +#if SHELL_CMD_SYSTIME_ENABLED == TRUE + {"systime", cmd_systime}, +#endif +#if SHELL_CMD_MEM_ENABLED == TRUE + {"mem", cmd_mem}, +#endif +#if SHELL_CMD_THREADS_ENABLED == TRUE + {"threads", cmd_threads}, +#endif +#if SHELL_CMD_TEST_ENABLED == TRUE + {"test", cmd_test}, +#endif + {NULL, NULL} +}; + +/** @} */ diff --git a/ChibiOS_20.3.2/os/various/shell/shell_cmd.h b/ChibiOS_20.3.2/os/various/shell/shell_cmd.h new file mode 100644 index 0000000..f913822 --- /dev/null +++ b/ChibiOS_20.3.2/os/various/shell/shell_cmd.h @@ -0,0 +1,114 @@ +/* + ChibiOS - Copyright (C) 2006..2018 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_cmd.h + * @brief Simple CLI shell common commands header. + * + * @addtogroup SHELL + * @{ + */ + +#ifndef SHELLCMD_H +#define SHELLCMD_H + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +#if !defined(SHELL_CMD_EXIT_ENABLED) || defined(__DOXYGEN__) +#define SHELL_CMD_EXIT_ENABLED TRUE +#endif + +#if !defined(SHELL_CMD_INFO_ENABLED) || defined(__DOXYGEN__) +#define SHELL_CMD_INFO_ENABLED TRUE +#endif + +#if !defined(SHELL_CMD_ECHO_ENABLED) || defined(__DOXYGEN__) +#define SHELL_CMD_ECHO_ENABLED TRUE +#endif + +#if !defined(SHELL_CMD_SYSTIME_ENABLED) || defined(__DOXYGEN__) +#define SHELL_CMD_SYSTIME_ENABLED TRUE +#endif + +#if !defined(SHELL_CMD_MEM_ENABLED) || defined(__DOXYGEN__) +#define SHELL_CMD_MEM_ENABLED TRUE +#endif + +#if !defined(SHELL_CMD_THREADS_ENABLED) || defined(__DOXYGEN__) +#define SHELL_CMD_THREADS_ENABLED TRUE +#endif + +#if !defined(SHELL_CMD_TEST_ENABLED) || defined(__DOXYGEN__) +#define SHELL_CMD_TEST_ENABLED TRUE +#endif + +#if !defined(SHELL_CMD_TEST_WA_SIZE) || defined(__DOXYGEN__) +#define SHELL_CMD_TEST_WA_SIZE THD_WORKING_AREA_SIZE(256) +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if (SHELL_CMD_MEM_ENABLED == TRUE) && (CH_CFG_USE_MEMCORE == FALSE) +#error "SHELL_CMD_MEM_ENABLED requires CH_CFG_USE_MEMCORE" +#endif + +#if (SHELL_CMD_MEM_ENABLED == TRUE) && (CH_CFG_USE_HEAP == FALSE) +#error "SHELL_CMD_MEM_ENABLED requires CH_CFG_USE_HEAP" +#endif + +#if (SHELL_CMD_THREADS_ENABLED == TRUE) && (CH_CFG_USE_REGISTRY == FALSE) +#error "SHELL_CMD_THREADS_ENABLED requires CH_CFG_USE_REGISTRY" +#endif + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern const ShellCommand shell_local_commands[]; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +#endif /* SHELLCMD_H */ + +/** @} */ -- cgit v1.2.3