ChibiOS/RT Architecture - Reference Manual - Guides |
00001 /* 00002 ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio. 00003 00004 This file is part of ChibiOS/RT. 00005 00006 ChibiOS/RT is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation; either version 3 of the License, or 00009 (at your option) any later version. 00010 00011 ChibiOS/RT is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 00019 --- 00020 00021 A special exception to the GPL can be applied should you wish to distribute 00022 a combined work that includes ChibiOS/RT, without being obliged to provide 00023 the source code for any proprietary components. See the file exception.txt 00024 for full details of how and when the exception can be applied. 00025 */ 00026 00027 /** 00028 * @file shell.c 00029 * @brief Simple CLI shell code. 00030 * @addtogroup SHELL 00031 * @{ 00032 */ 00033 00034 #include <stdio.h> 00035 #include <string.h> 00036 00037 #include "ch.h" 00038 #include "hal.h" 00039 #include "shell.h" 00040 00041 #if SHELL_USE_IPRINTF 00042 #define sprintf siprintf 00043 #endif 00044 00045 /** 00046 * @brief Shell termination event source. 00047 */ 00048 EventSource shell_terminated; 00049 00050 #if defined(WIN32) 00051 /* 00052 * MinGW does not seem to have this function... 00053 */ 00054 static char *strtok_r(char *str, const char *delim, char **saveptr) { 00055 char *token; 00056 if (str) 00057 *saveptr = str; 00058 token = *saveptr; 00059 00060 if (!token) 00061 return NULL; 00062 00063 token += strspn(token, delim); 00064 *saveptr = strpbrk(token, delim); 00065 if (*saveptr) 00066 *(*saveptr)++ = '\0'; 00067 00068 return *token ? token : NULL; 00069 } 00070 #endif 00071 00072 static void usage(BaseChannel *chp, char *p) { 00073 00074 shellPrint(chp, "Usage: "); 00075 shellPrintLine(chp, p); 00076 } 00077 00078 static void list_commands(BaseChannel *chp, const ShellCommand *scp) { 00079 00080 while (scp->sc_name != NULL) { 00081 shellPrint(chp, scp->sc_name); 00082 shellPrint(chp, " "); 00083 scp++; 00084 } 00085 } 00086 00087 static void cmd_info(BaseChannel *chp, int argc, char *argv[]) { 00088 00089 (void)argv; 00090 if (argc > 0) { 00091 usage(chp, "info"); 00092 return; 00093 } 00094 00095 shellPrint(chp, "Kernel version: "); 00096 shellPrintLine(chp, CH_KERNEL_VERSION); 00097 #ifdef __GNUC__ 00098 shellPrint(chp, "GCC Version: "); 00099 shellPrintLine(chp, __VERSION__); 00100 #endif 00101 shellPrint(chp, "Architecture: "); 00102 shellPrintLine(chp, CH_ARCHITECTURE_NAME); 00103 #ifdef CH_CORE_VARIANT_NAME 00104 shellPrint(chp, "Core Variant: "); 00105 shellPrintLine(chp, CH_CORE_VARIANT_NAME); 00106 #endif 00107 #ifdef PLATFORM_NAME 00108 shellPrint(chp, "Platform: "); 00109 shellPrintLine(chp, PLATFORM_NAME); 00110 #endif 00111 #ifdef BOARD_NAME 00112 shellPrint(chp, "Board: "); 00113 shellPrintLine(chp, BOARD_NAME); 00114 #endif 00115 } 00116 00117 static void cmd_systime(BaseChannel *chp, int argc, char *argv[]) { 00118 char buf[12]; 00119 00120 (void)argv; 00121 if (argc > 0) { 00122 usage(chp, "systime"); 00123 return; 00124 } 00125 sprintf(buf, "%lu", (unsigned long)chTimeNow()); 00126 shellPrintLine(chp, buf); 00127 } 00128 00129 /** 00130 * @brief Array of the default commands. 00131 */ 00132 static ShellCommand local_commands[] = { 00133 {"info", cmd_info}, 00134 {"systime", cmd_systime}, 00135 {NULL, NULL} 00136 }; 00137 00138 static bool_t cmdexec(const ShellCommand *scp, BaseChannel *chp, 00139 char *name, int argc, char *argv[]) { 00140 00141 while (scp->sc_name != NULL) { 00142 if (strcasecmp(scp->sc_name, name) == 0) { 00143 scp->sc_function(chp, argc, argv); 00144 return FALSE; 00145 } 00146 scp++; 00147 } 00148 return TRUE; 00149 } 00150 00151 /** 00152 * @brief Shell thread function. 00153 * 00154 * @param[in] p pointer to a @p BaseChannel object 00155 * @return Termination reason. 00156 * @retval RDY_OK terminated by command. 00157 * @retval RDY_RESET terminated by reset condition on the I/O channel. 00158 */ 00159 static msg_t shell_thread(void *p) { 00160 int n; 00161 msg_t msg = RDY_OK; 00162 BaseChannel *chp = ((ShellConfig *)p)->sc_channel; 00163 const ShellCommand *scp = ((ShellConfig *)p)->sc_commands; 00164 char *lp, *cmd, *tokp, line[SHELL_MAX_LINE_LENGTH]; 00165 char *args[SHELL_MAX_ARGUMENTS + 1]; 00166 00167 shellPrintLine(chp, ""); 00168 shellPrintLine(chp, "ChibiOS/RT Shell"); 00169 while (TRUE) { 00170 shellPrint(chp, "ch> "); 00171 if (shellGetLine(chp, line, sizeof(line))) { 00172 shellPrint(chp, "\nlogout"); 00173 break; 00174 } 00175 lp = strtok_r(line, " \009", &tokp); 00176 cmd = lp; 00177 n = 0; 00178 while ((lp = strtok_r(NULL, " \009", &tokp)) != NULL) { 00179 if (n >= SHELL_MAX_ARGUMENTS) { 00180 shellPrintLine(chp, "too many arguments"); 00181 cmd = NULL; 00182 break; 00183 } 00184 args[n++] = lp; 00185 } 00186 args[n] = NULL; 00187 if (cmd != NULL) { 00188 if (strcasecmp(cmd, "exit") == 0) { 00189 if (n > 0) 00190 usage(chp, "exit"); 00191 break; 00192 } 00193 else if (strcasecmp(cmd, "help") == 0) { 00194 if (n > 0) 00195 usage(chp, "help"); 00196 shellPrint(chp, "Commands: help exit "); 00197 list_commands(chp, local_commands); 00198 if (scp != NULL) 00199 list_commands(chp, scp); 00200 shellPrintLine(chp, ""); 00201 } 00202 else if (cmdexec(local_commands, chp, cmd, n, args) && 00203 ((scp == NULL) || cmdexec(scp, chp, cmd, n, args))) { 00204 shellPrint(chp, cmd); 00205 shellPrintLine(chp, " ?"); 00206 } 00207 } 00208 } 00209 chSysLock(); 00210 chEvtBroadcastI(&shell_terminated); 00211 return msg; 00212 } 00213 00214 /** 00215 * @brief Shell manager initialization. 00216 */ 00217 void shellInit(void) { 00218 00219 chEvtInit(&shell_terminated); 00220 } 00221 00222 /** 00223 * @brief Spawns a new shell. 00224 * 00225 * @param[in] scp pointer to a @p ShellConfig object 00226 * @param[in] size size of the shell working area to be allocated 00227 * @param[in] prio the priority level for the new shell 00228 * 00229 * @return A pointer to the shell thread. 00230 * @retval NULL thread creation failed because memory allocation. 00231 */ 00232 Thread *shellCreate(const ShellConfig *scp, size_t size, tprio_t prio) { 00233 00234 return chThdCreateFromHeap(NULL, size, prio, shell_thread, (void *)scp); 00235 } 00236 00237 /** 00238 * @brief Prints a string. 00239 * 00240 * @param[in] chp pointer to a @p BaseChannel object 00241 * @param[in] msg pointer to the string 00242 */ 00243 void shellPrint(BaseChannel *chp, const char *msg) { 00244 00245 while (*msg) 00246 chIOPut(chp, *msg++); 00247 } 00248 00249 /** 00250 * @brief Prints a string with a final newline. 00251 * 00252 * @param[in] chp pointer to a @p BaseChannel object 00253 * @param[in] msg pointer to the string 00254 */ 00255 void shellPrintLine(BaseChannel *chp, const char *msg) { 00256 00257 shellPrint(chp, msg); 00258 shellPrint(chp, "\r\n"); 00259 } 00260 00261 /** 00262 * @brief Reads a whole line from the input channel. 00263 * 00264 * @param[in] chp pointer to a @p BaseChannel object 00265 * @param[in] line pointer to the line buffer 00266 * @param[in] size buffer maximum length 00267 * 00268 * @return The operation status. 00269 * @retval TRUE the channel was reset or CTRL-D pressed. 00270 * @retval FALSE operation successful. 00271 */ 00272 bool_t shellGetLine(BaseChannel *chp, char *line, unsigned size) { 00273 char *p = line; 00274 00275 while (TRUE) { 00276 short c = (short)chIOGet(chp); 00277 if (c < 0) 00278 return TRUE; 00279 if (c == 4) { 00280 shellPrintLine(chp, "^D"); 00281 return TRUE; 00282 } 00283 if (c == 8) { 00284 if (p != line) { 00285 chIOPut(chp, (uint8_t)c); 00286 chIOPut(chp, 0x20); 00287 chIOPut(chp, (uint8_t)c); 00288 p--; 00289 } 00290 continue; 00291 } 00292 if (c == '\r') { 00293 shellPrintLine(chp, ""); 00294 *p = 0; 00295 return FALSE; 00296 } 00297 if (c < 0x20) 00298 continue; 00299 if (p < line + size - 1) { 00300 chIOPut(chp, (uint8_t)c); 00301 *p++ = (char)c; 00302 } 00303 } 00304 } 00305 00306 /** @} */