aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios/os/various/shell
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chibios/os/various/shell')
-rw-r--r--lib/chibios/os/various/shell/shell.c604
-rw-r--r--lib/chibios/os/various/shell/shell.h235
-rw-r--r--lib/chibios/os/various/shell/shell.mk9
-rw-r--r--lib/chibios/os/various/shell/shell_cmd.c248
-rw-r--r--lib/chibios/os/various/shell/shell_cmd.h114
5 files changed, 1210 insertions, 0 deletions
diff --git a/lib/chibios/os/various/shell/shell.c b/lib/chibios/os/various/shell/shell.c
new file mode 100644
index 000000000..7e9b98f9d
--- /dev/null
+++ b/lib/chibios/os/various/shell/shell.c
@@ -0,0 +1,604 @@
1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/**
18 * @file shell.c
19 * @brief Simple CLI shell code.
20 *
21 * @addtogroup SHELL
22 * @{
23 */
24
25#include <string.h>
26
27#include "ch.h"
28#include "hal.h"
29#include "shell.h"
30#include "shell_cmd.h"
31#include "chprintf.h"
32
33/*===========================================================================*/
34/* Module local definitions. */
35/*===========================================================================*/
36
37/*===========================================================================*/
38/* Module exported variables. */
39/*===========================================================================*/
40
41#if !defined(_CHIBIOS_NIL_) || defined(__DOXYGEN__)
42/**
43 * @brief Shell termination event source.
44 */
45event_source_t shell_terminated;
46#endif
47
48/*===========================================================================*/
49/* Module local types. */
50/*===========================================================================*/
51
52/*===========================================================================*/
53/* Module local variables. */
54/*===========================================================================*/
55
56/*===========================================================================*/
57/* Module local functions. */
58/*===========================================================================*/
59
60static char *parse_arguments(char *str, char **saveptr) {
61 char *p;
62
63 if (str != NULL)
64 *saveptr = str;
65
66 p = *saveptr;
67 if (!p) {
68 return NULL;
69 }
70
71 /* Skipping white space.*/
72 p += strspn(p, " \t");
73
74 if (*p == '"') {
75 /* If an argument starts with a double quote then its delimiter is another
76 quote.*/
77 p++;
78 *saveptr = strpbrk(p, "\"");
79 }
80 else {
81 /* The delimiter is white space.*/
82 *saveptr = strpbrk(p, " \t");
83 }
84
85 /* Replacing the delimiter with a zero.*/
86 if (*saveptr != NULL) {
87 *(*saveptr)++ = '\0';
88 }
89
90 return *p != '\0' ? p : NULL;
91}
92
93static void list_commands(BaseSequentialStream *chp, const ShellCommand *scp) {
94
95 while (scp->sc_name != NULL) {
96 chprintf(chp, "%s ", scp->sc_name);
97 scp++;
98 }
99}
100
101static bool cmdexec(const ShellCommand *scp, BaseSequentialStream *chp,
102 char *name, int argc, char *argv[]) {
103
104 while (scp->sc_name != NULL) {
105 if (strcmp(scp->sc_name, name) == 0) {
106 scp->sc_function(chp, argc, argv);
107 return false;
108 }
109 scp++;
110 }
111 return true;
112}
113
114#if (SHELL_USE_HISTORY == TRUE) || defined(__DOXYGEN__)
115static void del_histbuff_entry(ShellHistory *shp) {
116 int pos = shp->sh_beg + *(shp->sh_buffer + shp->sh_beg) + 1;
117
118 if (pos >= shp->sh_size)
119 pos -= shp->sh_size;
120
121 shp->sh_beg = pos;
122}
123
124static bool is_histbuff_space(ShellHistory *shp, int length) {
125
126 if (shp->sh_end >= shp->sh_beg) {
127 if (length < (shp->sh_size - (shp->sh_end - shp->sh_beg + 1)))
128 return true;
129 }
130 else {
131 if (length < (shp->sh_beg - shp->sh_end - 1))
132 return true;
133 }
134
135 return false;
136}
137
138static void save_history(ShellHistory *shp, char *line, int length) {
139
140 if (shp == NULL)
141 return;
142
143 if (length > shp->sh_size - 2)
144 return;
145
146 while ((*(line + length -1) == ' ') && (length > 0))
147 length--;
148
149 if (length <= 0)
150 return;
151
152 while (!is_histbuff_space(shp, length))
153 del_histbuff_entry(shp);
154
155 if (length < shp->sh_size - shp->sh_end - 1)
156 memcpy(shp->sh_buffer + shp->sh_end + 1, line, length);
157 else {
158 /*
159 * Since there isn't enough room left at the end of the buffer,
160 * split the line to save up to the end of the buffer and then
161 * wrap back to the beginning of the buffer.
162 */
163 int part_len = shp->sh_size - shp->sh_end - 1;
164 memcpy(shp->sh_buffer + shp->sh_end + 1, line, part_len);
165 memcpy(shp->sh_buffer, line + part_len, length - part_len);
166 }
167
168 /* Save the length of the current line and move the buffer end pointer */
169 *(shp->sh_buffer + shp->sh_end) = (char)length;
170 shp->sh_end += length + 1;
171 if (shp->sh_end >= shp->sh_size)
172 shp->sh_end -= shp->sh_size;
173 *(shp->sh_buffer + shp->sh_end) = 0;
174 shp->sh_cur = 0;
175}
176
177static int get_history(ShellHistory *shp, char *line, int dir) {
178 int count=0;
179
180 if (shp == NULL)
181 return -1;
182
183 /* Count the number of lines saved in the buffer */
184 int idx = shp->sh_beg;
185 while (idx != shp->sh_end) {
186 idx += *(shp->sh_buffer + idx) + 1;
187 if (idx >= shp->sh_size)
188 idx -= shp->sh_size;
189 count++;
190 }
191
192 if (dir == SHELL_HIST_DIR_FW) {
193 if (shp->sh_cur > 0)
194 shp->sh_cur -= 2;
195 else
196 return 0;
197 }
198
199 if (count >= shp->sh_cur) {
200 idx = shp->sh_beg;
201 int i = 0;
202 while (idx != shp->sh_end && shp->sh_cur != (count - i - 1)) {
203 idx += *(shp->sh_buffer + idx) + 1;
204 if (idx >= shp->sh_size)
205 idx -= shp->sh_size;
206 i++;
207 }
208
209 int length = *(shp->sh_buffer + idx);
210
211 if (length > 0) {
212 shp->sh_cur++;
213
214 memset(line, 0, SHELL_MAX_LINE_LENGTH);
215 if ((idx + length) < shp->sh_size) {
216 memcpy(line, (shp->sh_buffer + idx + 1), length);
217 }
218 else {
219 /*
220 * Since the saved line was split at the end of the buffer,
221 * get the line in two parts.
222 */
223 int part_len = shp->sh_size - idx - 1;
224 memcpy(line, shp->sh_buffer + idx + 1, part_len);
225 memcpy(line + part_len, shp->sh_buffer, length - part_len);
226 }
227 return length;
228 }
229 else if (dir == SHELL_HIST_DIR_FW) {
230 shp->sh_cur++;
231 return 0;
232 }
233 }
234 return -1;
235}
236#endif
237
238#if (SHELL_USE_COMPLETION == TRUE) || defined(__DOXYGEN__)
239static void get_completions(ShellConfig *scfg, char *line) {
240 const ShellCommand *lcp = shell_local_commands;
241 const ShellCommand *scp = scfg->sc_commands;
242 char **scmp = scfg->sc_completion;
243 char help_cmp[] = "help";
244
245 if (strstr(help_cmp, line) == help_cmp) {
246 *scmp++ = help_cmp;
247 }
248 while (lcp->sc_name != NULL) {
249 if (strstr(lcp->sc_name, line) == lcp->sc_name) {
250 *scmp++ = (char *)lcp->sc_name;
251 }
252 lcp++;
253 }
254 if (scp != NULL) {
255 while (scp->sc_name != NULL) {
256 if (strstr(scp->sc_name, line) == scp->sc_name) {
257 *scmp++ = (char *)scp->sc_name;
258 }
259 scp++;
260 }
261 }
262
263 *scmp = NULL;
264}
265
266static int process_completions(ShellConfig *scfg, char *line, int length, unsigned size) {
267 char **scmp = scfg->sc_completion;
268 char **cmp = scmp + 1;
269 char *c = line + length;
270 int clen = 0;
271
272 if (*scmp != NULL) {
273 if (*cmp == NULL) {
274 clen = strlen(*scmp);
275 int i = length;
276 while ((c < line + clen) && (c < line + size - 1))
277 *c++ = *(*scmp + i++);
278 if (c < line + size -1) {
279 *c = ' ';
280 clen++;
281 }
282 }
283 else {
284 while (*(*scmp + clen) != 0) {
285 while ((*(*scmp + clen) == *(*cmp + clen)) &&
286 (*(*cmp + clen) != 0) && (*cmp != NULL)) {
287 cmp++;
288 }
289 if (*cmp == NULL) {
290 if ((c < line + size - 1) && (clen >= length))
291 *c++ = *(*scmp + clen);
292 cmp = scmp + 1;
293 clen++;
294 }
295 else {
296 break;
297 }
298 }
299 }
300
301 *(line + clen) = 0;
302 }
303
304 return clen;
305}
306
307static void write_completions(ShellConfig *scfg, char *line, int pos) {
308 BaseSequentialStream *chp = scfg->sc_channel;
309 char **scmp = scfg->sc_completion;
310
311 if (*(scmp + 1) != NULL) {
312 chprintf(chp, SHELL_NEWLINE_STR);
313 while (*scmp != NULL)
314 chprintf(chp, " %s", *scmp++);
315 chprintf(chp, SHELL_NEWLINE_STR);
316
317 chprintf(chp, SHELL_PROMPT_STR);
318 chprintf(chp, "%s", line);
319 }
320 else {
321 chprintf(chp, "%s", line + pos);
322 }
323}
324#endif
325
326/*===========================================================================*/
327/* Module exported functions. */
328/*===========================================================================*/
329
330/**
331 * @brief Shell thread function.
332 *
333 * @param[in] p pointer to a @p BaseSequentialStream object
334 */
335THD_FUNCTION(shellThread, p) {
336 int n;
337 ShellConfig *scfg = p;
338 BaseSequentialStream *chp = scfg->sc_channel;
339 const ShellCommand *scp = scfg->sc_commands;
340 char *lp, *cmd, *tokp, line[SHELL_MAX_LINE_LENGTH];
341 char *args[SHELL_MAX_ARGUMENTS + 1];
342
343#if !defined(_CHIBIOS_NIL_)
344 chRegSetThreadName(SHELL_THREAD_NAME);
345#endif
346
347#if SHELL_USE_HISTORY == TRUE
348 *(scfg->sc_histbuf) = 0;
349 ShellHistory hist = {
350 scfg->sc_histbuf,
351 scfg->sc_histsize,
352 0,
353 0,
354 0
355 };
356 ShellHistory *shp = &hist;
357#else
358 ShellHistory *shp = NULL;
359#endif
360
361 chprintf(chp, SHELL_NEWLINE_STR);
362 chprintf(chp, "ChibiOS/RT Shell" SHELL_NEWLINE_STR);
363#if !defined(_CHIBIOS_NIL_)
364 while (!chThdShouldTerminateX()) {
365#else
366 while (true) {
367#endif
368 chprintf(chp, SHELL_PROMPT_STR);
369 if (shellGetLine(scfg, line, sizeof(line), shp)) {
370#if (SHELL_CMD_EXIT_ENABLED == TRUE) && !defined(_CHIBIOS_NIL_)
371 chprintf(chp, SHELL_NEWLINE_STR);
372 chprintf(chp, "logout");
373 break;
374#else
375 /* Putting a delay in order to avoid an endless loop trying to read
376 an unavailable stream.*/
377 osalThreadSleepMilliseconds(100);
378#endif
379 }
380 lp = parse_arguments(line, &tokp);
381 cmd = lp;
382 n = 0;
383 while ((lp = parse_arguments(NULL, &tokp)) != NULL) {
384 if (n >= SHELL_MAX_ARGUMENTS) {
385 chprintf(chp, "too many arguments" SHELL_NEWLINE_STR);
386 cmd = NULL;
387 break;
388 }
389 args[n++] = lp;
390 }
391 args[n] = NULL;
392 if (cmd != NULL) {
393 if (strcmp(cmd, "help") == 0) {
394 if (n > 0) {
395 shellUsage(chp, "help");
396 continue;
397 }
398 chprintf(chp, "Commands: help ");
399 list_commands(chp, shell_local_commands);
400 if (scp != NULL)
401 list_commands(chp, scp);
402 chprintf(chp, SHELL_NEWLINE_STR);
403 }
404 else if (cmdexec(shell_local_commands, chp, cmd, n, args) &&
405 ((scp == NULL) || cmdexec(scp, chp, cmd, n, args))) {
406 chprintf(chp, "%s", cmd);
407 chprintf(chp, " ?" SHELL_NEWLINE_STR);
408 }
409 }
410 }
411#if !defined(_CHIBIOS_NIL_)
412 shellExit(MSG_OK);
413#endif
414}
415
416/**
417 * @brief Shell manager initialization.
418 *
419 * @api
420 */
421void shellInit(void) {
422
423#if !defined(_CHIBIOS_NIL_)
424 chEvtObjectInit(&shell_terminated);
425#endif
426}
427
428#if !defined(_CHIBIOS_NIL_) || defined(__DOXYGEN__)
429/**
430 * @brief Terminates the shell.
431 * @note Must be invoked from the command handlers.
432 * @note Does not return.
433 *
434 * @param[in] msg shell exit code
435 *
436 * @api
437 */
438void shellExit(msg_t msg) {
439
440 /* Atomically broadcasting the event source and terminating the thread,
441 there is not a chSysUnlock() because the thread terminates upon return.*/
442 chSysLock();
443 chEvtBroadcastI(&shell_terminated);
444 chThdExitS(msg);
445}
446#endif
447
448/**
449 * @brief Reads a whole line from the input channel.
450 * @note Input chars are echoed on the same stream object with the
451 * following exceptions:
452 * - DEL and BS are echoed as BS-SPACE-BS.
453 * - CR is echoed as CR-LF.
454 * - 0x4 is echoed as "^D".
455 * - Other values below 0x20 are not echoed.
456 * .
457 *
458 * @param[in] scfg pointer to a @p ShellConfig object
459 * @param[in] line pointer to the line buffer
460 * @param[in] size buffer maximum length
461 * @param[in] shp pointer to a @p ShellHistory object or NULL
462 * @return The operation status.
463 * @retval true the channel was reset or CTRL-D pressed.
464 * @retval false operation successful.
465 *
466 * @api
467 */
468bool shellGetLine(ShellConfig *scfg, char *line, unsigned size, ShellHistory *shp) {
469 char *p = line;
470 BaseSequentialStream *chp = scfg->sc_channel;
471#if SHELL_USE_ESC_SEQ == TRUE
472 bool escape = false;
473 bool bracket = false;
474#endif
475
476#if SHELL_USE_HISTORY != TRUE
477 (void) shp;
478#endif
479
480 while (true) {
481 char c;
482
483 if (streamRead(chp, (uint8_t *)&c, 1) == 0)
484 return true;
485#if SHELL_USE_ESC_SEQ == TRUE
486 if (c == 27) {
487 escape = true;
488 continue;
489 }
490 if (escape) {
491 escape = false;
492 if (c == '[') {
493 escape = true;
494 bracket = true;
495 continue;
496 }
497 if (bracket) {
498 bracket = false;
499#if SHELL_USE_HISTORY == TRUE
500 if (c == 'A') {
501 int len = get_history(shp, line, SHELL_HIST_DIR_BK);
502
503 if (len > 0) {
504 _shell_reset_cur(chp);
505 _shell_clr_line(chp);
506 chprintf(chp, "%s", line);
507 p = line + len;
508 }
509 continue;
510 }
511 if (c == 'B') {
512 int len = get_history(shp, line, SHELL_HIST_DIR_FW);
513
514 if (len == 0)
515 *line = 0;
516
517 if (len >= 0) {
518 _shell_reset_cur(chp);
519 _shell_clr_line(chp);
520 chprintf(chp, "%s", line);
521 p = line + len;
522 }
523 continue;
524 }
525#endif
526 }
527 continue;
528 }
529#endif
530#if (SHELL_CMD_EXIT_ENABLED == TRUE) && !defined(_CHIBIOS_NIL_)
531 if (c == 4) {
532 chprintf(chp, "^D");
533 return true;
534 }
535#endif
536 if ((c == 8) || (c == 127)) {
537 if (p != line) {
538 streamPut(chp, 0x08);
539 streamPut(chp, 0x20);
540 streamPut(chp, 0x08);
541 p--;
542 }
543 continue;
544 }
545 if (c == '\r') {
546 chprintf(chp, SHELL_NEWLINE_STR);
547#if SHELL_USE_HISTORY == TRUE
548 save_history(shp, line, p - line);
549#endif
550 *p = 0;
551 return false;
552 }
553#if SHELL_USE_COMPLETION == TRUE
554 if (c == '\t') {
555 if (p < line + size - 1) {
556 *p = 0;
557
558 get_completions(scfg, line);
559 int len = process_completions(scfg, line, p - line, size);
560 if (len > 0) {
561 write_completions(scfg, line, p - line);
562 p = line + len;
563 }
564 }
565 continue;
566 }
567#endif
568#if SHELL_USE_HISTORY == TRUE
569 if (c == 14) {
570 int len = get_history(shp, line, SHELL_HIST_DIR_FW);
571
572 if (len == 0)
573 *line = 0;
574
575 if (len >= 0) {
576 _shell_reset_cur(chp);
577 _shell_clr_line(chp);
578 chprintf(chp, "%s", line);
579 p = line + len;
580 }
581 continue;
582 }
583 if (c == 16) {
584 int len = get_history(shp, line, SHELL_HIST_DIR_BK);
585
586 if (len > 0) {
587 _shell_reset_cur(chp);
588 _shell_clr_line(chp);
589 chprintf(chp, "%s", line);
590 p = line + len;
591 }
592 continue;
593 }
594#endif
595 if (c < 0x20)
596 continue;
597 if (p < line + size - 1) {
598 streamPut(chp, c);
599 *p++ = (char)c;
600 }
601 }
602}
603
604/** @} */
diff --git a/lib/chibios/os/various/shell/shell.h b/lib/chibios/os/various/shell/shell.h
new file mode 100644
index 000000000..6ea555a1d
--- /dev/null
+++ b/lib/chibios/os/various/shell/shell.h
@@ -0,0 +1,235 @@
1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/**
18 * @file shell.h
19 * @brief Simple CLI shell header.
20 *
21 * @addtogroup SHELL
22 * @{
23 */
24
25#ifndef SHELL_H
26#define SHELL_H
27
28#if defined(SHELL_CONFIG_FILE)
29#include "shellconf.h"
30#endif
31
32/*===========================================================================*/
33/* Module constants. */
34/*===========================================================================*/
35
36/**
37 * @brief Shell History Constants
38 */
39#define SHELL_HIST_DIR_BK 0
40#define SHELL_HIST_DIR_FW 1
41
42/*===========================================================================*/
43/* Module pre-compile time settings. */
44/*===========================================================================*/
45
46/**
47 * @brief Shell maximum input line length.
48 */
49#if !defined(SHELL_MAX_LINE_LENGTH) || defined(__DOXYGEN__)
50#define SHELL_MAX_LINE_LENGTH 64
51#endif
52
53/**
54 * @brief Shell maximum arguments per command.
55 */
56#if !defined(SHELL_MAX_ARGUMENTS) || defined(__DOXYGEN__)
57#define SHELL_MAX_ARGUMENTS 4
58#endif
59
60/**
61 * @brief Shell maximum command history.
62 */
63#if !defined(SHELL_MAX_HIST_BUFF) || defined(__DOXYGEN__)
64#define SHELL_MAX_HIST_BUFF 8 * SHELL_MAX_LINE_LENGTH
65#endif
66
67/**
68 * @brief Enable shell command history
69 */
70#if !defined(SHELL_USE_HISTORY) || defined(__DOXYGEN__)
71#define SHELL_USE_HISTORY FALSE
72#endif
73
74/**
75 * @brief Enable shell command completion
76 */
77#if !defined(SHELL_USE_COMPLETION) || defined(__DOXYGEN__)
78#define SHELL_USE_COMPLETION FALSE
79#endif
80
81/**
82 * @brief Shell Maximum Completions (Set to max commands with common prefix)
83 */
84#if !defined(SHELL_MAX_COMPLETIONS) || defined(__DOXYGEN__)
85#define SHELL_MAX_COMPLETIONS 8
86#endif
87
88/**
89 * @brief Enable shell escape sequence processing
90 */
91#if !defined(SHELL_USE_ESC_SEQ) || defined(__DOXYGEN__)
92#define SHELL_USE_ESC_SEQ FALSE
93#endif
94
95/**
96 * @brief Prompt string
97 */
98#if !defined(SHELL_PROMPT_STR) || defined(__DOXYGEN__)
99#define SHELL_PROMPT_STR "ch> "
100#endif
101
102/**
103 * @brief Newline string
104 */
105#if !defined(SHELL_NEWLINE_STR) || defined(__DOXYGEN__)
106#define SHELL_NEWLINE_STR "\r\n"
107#endif
108
109/**
110 * @brief Default shell thread name.
111 */
112#if !defined(SHELL_THREAD_NAME) || defined(__DOXYGEN__)
113#define SHELL_THREAD_NAME "shell"
114#endif
115
116/*===========================================================================*/
117/* Derived constants and error checks. */
118/*===========================================================================*/
119
120/*===========================================================================*/
121/* Module data structures and types. */
122/*===========================================================================*/
123
124/**
125 * @brief Command handler function type.
126 */
127typedef void (*shellcmd_t)(BaseSequentialStream *chp, int argc, char *argv[]);
128
129/**
130 * @brief Custom command entry type.
131 */
132typedef struct {
133 const char *sc_name; /**< @brief Command name. */
134 shellcmd_t sc_function; /**< @brief Command function. */
135} ShellCommand;
136
137/**
138 * @brief Shell history type.
139 */
140typedef struct {
141 char *sh_buffer; /**< @brief Buffer to store command
142 history. */
143 const int sh_size; /**< @brief Shell history buffer
144 size. */
145 int sh_beg; /**< @brief Beginning command index
146 in buffer. */
147 int sh_end; /**< @brief Ending command index
148 in buffer. */
149 int sh_cur; /**< @brief Currently selected
150 command in buffer. */
151} ShellHistory;
152
153/**
154 * @brief Shell descriptor type.
155 */
156typedef struct {
157 BaseSequentialStream *sc_channel; /**< @brief I/O channel associated
158 to the shell. */
159 const ShellCommand *sc_commands; /**< @brief Shell extra commands
160 table. */
161#if (SHELL_USE_HISTORY == TRUE) || defined(__DOXYGEN__)
162 char *sc_histbuf; /**< @brief Shell command history
163 buffer. */
164 const int sc_histsize; /**< @brief Shell history buffer
165 size. */
166#endif
167#if (SHELL_USE_COMPLETION == TRUE) || defined(__DOXYGEN__)
168 char **sc_completion; /**< @brief Shell command completion
169 buffer. */
170#endif
171} ShellConfig;
172
173/*===========================================================================*/
174/* Module macros. */
175/*===========================================================================*/
176
177/**
178 * @brief Send escape codes to move cursor to the beginning of the line
179 *
180 * @param[in] stream pointer to a @p BaseSequentialStream object
181 *
182 * @notapi
183 */
184#define _shell_reset_cur(stream) chprintf(stream, "\033[%dD\033[%dC", \
185 SHELL_MAX_LINE_LENGTH + \
186 strlen(SHELL_PROMPT_STR) + 2, \
187 strlen(SHELL_PROMPT_STR))
188
189/**
190 * @brief Send escape codes to clear the rest of the line
191 *
192 * @param[in] stream pointer to a @p BaseSequentialStream object
193 *
194 * @notapi
195 */
196#define _shell_clr_line(stream) chprintf(stream, "\033[K")
197
198/**
199 * @brief Prints out usage message
200 *
201 * @param[in] stream pointer to a @p BaseSequentialStream object
202 * @param[in] message pointer to message string
203 *
204 * @api
205 */
206#define shellUsage(stream, message) \
207 chprintf(stream, "Usage: %s" SHELL_NEWLINE_STR, message)
208
209/*===========================================================================*/
210/* External declarations. */
211/*===========================================================================*/
212
213#if !defined(__DOXYGEN__)
214extern event_source_t shell_terminated;
215#endif
216
217#ifdef __cplusplus
218extern "C" {
219#endif
220 void shellInit(void);
221 THD_FUNCTION(shellThread, p);
222 void shellExit(msg_t msg);
223 bool shellGetLine(ShellConfig *scfg, char *line,
224 unsigned size, ShellHistory *shp);
225#ifdef __cplusplus
226}
227#endif
228
229/*===========================================================================*/
230/* Module inline functions. */
231/*===========================================================================*/
232
233#endif /* SHELL_H */
234
235/** @} */
diff --git a/lib/chibios/os/various/shell/shell.mk b/lib/chibios/os/various/shell/shell.mk
new file mode 100644
index 000000000..66a9d6bea
--- /dev/null
+++ b/lib/chibios/os/various/shell/shell.mk
@@ -0,0 +1,9 @@
1# RT Shell files.
2SHELLSRC = $(CHIBIOS)/os/various/shell/shell.c \
3 $(CHIBIOS)/os/various/shell/shell_cmd.c
4
5SHELLINC = $(CHIBIOS)/os/various/shell
6
7# Shared variables
8ALLCSRC += $(SHELLSRC)
9ALLINC += $(SHELLINC)
diff --git a/lib/chibios/os/various/shell/shell_cmd.c b/lib/chibios/os/various/shell/shell_cmd.c
new file mode 100644
index 000000000..45ff5194c
--- /dev/null
+++ b/lib/chibios/os/various/shell/shell_cmd.c
@@ -0,0 +1,248 @@
1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/**
18 * @file shell_cmd.c
19 * @brief Simple CLI shell common commands code.
20 *
21 * @addtogroup SHELL
22 * @{
23 */
24
25#include <string.h>
26
27#include "ch.h"
28#include "hal.h"
29#include "shell.h"
30#include "shell_cmd.h"
31#include "chprintf.h"
32
33#if (SHELL_CMD_TEST_ENABLED == TRUE) || defined(__DOXYGEN__)
34#include "rt_test_root.h"
35#include "oslib_test_root.h"
36#endif
37
38/*===========================================================================*/
39/* Module local definitions. */
40/*===========================================================================*/
41
42/*===========================================================================*/
43/* Module exported variables. */
44/*===========================================================================*/
45
46/*===========================================================================*/
47/* Module local types. */
48/*===========================================================================*/
49
50/*===========================================================================*/
51/* Module local variables. */
52/*===========================================================================*/
53
54/*===========================================================================*/
55/* Module local functions. */
56/*===========================================================================*/
57
58#if ((SHELL_CMD_EXIT_ENABLED == TRUE) && !defined(_CHIBIOS_NIL_)) || \
59 defined(__DOXYGEN__)
60static void cmd_exit(BaseSequentialStream *chp, int argc, char *argv[]) {
61
62 (void)argv;
63 if (argc > 0) {
64 shellUsage(chp, "exit");
65 return;
66 }
67
68 shellExit(MSG_OK);
69}
70#endif
71
72#if (SHELL_CMD_INFO_ENABLED == TRUE) || defined(__DOXYGEN__)
73static void cmd_info(BaseSequentialStream *chp, int argc, char *argv[]) {
74
75 (void)argv;
76 if (argc > 0) {
77 shellUsage(chp, "info");
78 return;
79 }
80
81 chprintf(chp, "Kernel: %s" SHELL_NEWLINE_STR, CH_KERNEL_VERSION);
82#ifdef PORT_COMPILER_NAME
83 chprintf(chp, "Compiler: %s" SHELL_NEWLINE_STR, PORT_COMPILER_NAME);
84#endif
85 chprintf(chp, "Architecture: %s" SHELL_NEWLINE_STR, PORT_ARCHITECTURE_NAME);
86#ifdef PORT_CORE_VARIANT_NAME
87 chprintf(chp, "Core Variant: %s" SHELL_NEWLINE_STR, PORT_CORE_VARIANT_NAME);
88#endif
89#ifdef PORT_INFO
90 chprintf(chp, "Port Info: %s" SHELL_NEWLINE_STR, PORT_INFO);
91#endif
92#ifdef PLATFORM_NAME
93 chprintf(chp, "Platform: %s" SHELL_NEWLINE_STR, PLATFORM_NAME);
94#endif
95#ifdef BOARD_NAME
96 chprintf(chp, "Board: %s" SHELL_NEWLINE_STR, BOARD_NAME);
97#endif
98#ifdef __DATE__
99#ifdef __TIME__
100 chprintf(chp, "Build time: %s%s%s" SHELL_NEWLINE_STR, __DATE__, " - ", __TIME__);
101#endif
102#endif
103}
104#endif
105
106#if (SHELL_CMD_ECHO_ENABLED == TRUE) || defined(__DOXYGEN__)
107static void cmd_echo(BaseSequentialStream *chp, int argc, char *argv[]) {
108
109 (void)argv;
110 if (argc != 1) {
111 shellUsage(chp, "echo \"message\"");
112 return;
113 }
114 chprintf(chp, "%s" SHELL_NEWLINE_STR, argv[0]);
115}
116#endif
117
118#if (SHELL_CMD_SYSTIME_ENABLED == TRUE) || defined(__DOXYGEN__)
119static void cmd_systime(BaseSequentialStream *chp, int argc, char *argv[]) {
120
121 (void)argv;
122 if (argc > 0) {
123 shellUsage(chp, "systime");
124 return;
125 }
126 chprintf(chp, "%lu" SHELL_NEWLINE_STR, (unsigned long)chVTGetSystemTime());
127}
128#endif
129
130#if (SHELL_CMD_MEM_ENABLED == TRUE) || defined(__DOXYGEN__)
131static void cmd_mem(BaseSequentialStream *chp, int argc, char *argv[]) {
132 size_t n, total, largest;
133
134 (void)argv;
135 if (argc > 0) {
136 shellUsage(chp, "mem");
137 return;
138 }
139 n = chHeapStatus(NULL, &total, &largest);
140 chprintf(chp, "core free memory : %u bytes" SHELL_NEWLINE_STR, chCoreGetStatusX());
141 chprintf(chp, "heap fragments : %u" SHELL_NEWLINE_STR, n);
142 chprintf(chp, "heap free total : %u bytes" SHELL_NEWLINE_STR, total);
143 chprintf(chp, "heap free largest: %u bytes" SHELL_NEWLINE_STR, largest);
144}
145#endif
146
147#if (SHELL_CMD_THREADS_ENABLED == TRUE) || defined(__DOXYGEN__)
148static void cmd_threads(BaseSequentialStream *chp, int argc, char *argv[]) {
149 static const char *states[] = {CH_STATE_NAMES};
150 thread_t *tp;
151
152 (void)argv;
153 if (argc > 0) {
154 shellUsage(chp, "threads");
155 return;
156 }
157 chprintf(chp, "stklimit stack addr refs prio state name\r\n" SHELL_NEWLINE_STR);
158 tp = chRegFirstThread();
159 do {
160#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE)
161 uint32_t stklimit = (uint32_t)tp->wabase;
162#else
163 uint32_t stklimit = 0U;
164#endif
165 chprintf(chp, "%08lx %08lx %08lx %4lu %4lu %9s %12s" SHELL_NEWLINE_STR,
166 stklimit, (uint32_t)tp->ctx.sp, (uint32_t)tp,
167 (uint32_t)tp->refs - 1,
168 (uint32_t)tp->hdr.pqueue.prio, states[tp->state],
169 tp->name == NULL ? "" : tp->name);
170 tp = chRegNextThread(tp);
171 } while (tp != NULL);
172}
173#endif
174
175#if (SHELL_CMD_TEST_ENABLED == TRUE) || defined(__DOXYGEN__)
176static THD_FUNCTION(test_rt, arg) {
177 BaseSequentialStream *chp = (BaseSequentialStream *)arg;
178 test_execute(chp, &rt_test_suite);
179}
180
181static THD_FUNCTION(test_oslib, arg) {
182 BaseSequentialStream *chp = (BaseSequentialStream *)arg;
183 test_execute(chp, &oslib_test_suite);
184}
185
186static void cmd_test(BaseSequentialStream *chp, int argc, char *argv[]) {
187 thread_t *tp;
188 tfunc_t tfp;
189
190 (void)argv;
191 if (argc != 1) {
192 shellUsage(chp, "test rt|oslib");
193 return;
194 }
195 if (!strcmp(argv[0], "rt")) {
196 tfp = test_rt;
197 }
198 else if (!strcmp(argv[0], "oslib")) {
199 tfp = test_oslib;
200 }
201 else {
202 shellUsage(chp, "test rt|oslib");
203 return;
204 }
205 tp = chThdCreateFromHeap(NULL, SHELL_CMD_TEST_WA_SIZE,
206 "test", chThdGetPriorityX(),
207 tfp, chp);
208 if (tp == NULL) {
209 chprintf(chp, "out of memory" SHELL_NEWLINE_STR);
210 return;
211 }
212 chThdWait(tp);
213}
214#endif
215
216/*===========================================================================*/
217/* Module exported functions. */
218/*===========================================================================*/
219
220/**
221 * @brief Array of the default commands.
222 */
223const ShellCommand shell_local_commands[] = {
224#if (SHELL_CMD_EXIT_ENABLED == TRUE) && !defined(_CHIBIOS_NIL_)
225 {"exit", cmd_exit},
226#endif
227#if SHELL_CMD_INFO_ENABLED == TRUE
228 {"info", cmd_info},
229#endif
230#if SHELL_CMD_ECHO_ENABLED == TRUE
231 {"echo", cmd_echo},
232#endif
233#if SHELL_CMD_SYSTIME_ENABLED == TRUE
234 {"systime", cmd_systime},
235#endif
236#if SHELL_CMD_MEM_ENABLED == TRUE
237 {"mem", cmd_mem},
238#endif
239#if SHELL_CMD_THREADS_ENABLED == TRUE
240 {"threads", cmd_threads},
241#endif
242#if SHELL_CMD_TEST_ENABLED == TRUE
243 {"test", cmd_test},
244#endif
245 {NULL, NULL}
246};
247
248/** @} */
diff --git a/lib/chibios/os/various/shell/shell_cmd.h b/lib/chibios/os/various/shell/shell_cmd.h
new file mode 100644
index 000000000..06e4f90e1
--- /dev/null
+++ b/lib/chibios/os/various/shell/shell_cmd.h
@@ -0,0 +1,114 @@
1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/**
18 * @file shell_cmd.h
19 * @brief Simple CLI shell common commands header.
20 *
21 * @addtogroup SHELL
22 * @{
23 */
24
25#ifndef SHELLCMD_H
26#define SHELLCMD_H
27
28/*===========================================================================*/
29/* Module constants. */
30/*===========================================================================*/
31
32/*===========================================================================*/
33/* Module pre-compile time settings. */
34/*===========================================================================*/
35
36#if !defined(SHELL_CMD_EXIT_ENABLED) || defined(__DOXYGEN__)
37#define SHELL_CMD_EXIT_ENABLED TRUE
38#endif
39
40#if !defined(SHELL_CMD_INFO_ENABLED) || defined(__DOXYGEN__)
41#define SHELL_CMD_INFO_ENABLED TRUE
42#endif
43
44#if !defined(SHELL_CMD_ECHO_ENABLED) || defined(__DOXYGEN__)
45#define SHELL_CMD_ECHO_ENABLED TRUE
46#endif
47
48#if !defined(SHELL_CMD_SYSTIME_ENABLED) || defined(__DOXYGEN__)
49#define SHELL_CMD_SYSTIME_ENABLED TRUE
50#endif
51
52#if !defined(SHELL_CMD_MEM_ENABLED) || defined(__DOXYGEN__)
53#define SHELL_CMD_MEM_ENABLED TRUE
54#endif
55
56#if !defined(SHELL_CMD_THREADS_ENABLED) || defined(__DOXYGEN__)
57#define SHELL_CMD_THREADS_ENABLED TRUE
58#endif
59
60#if !defined(SHELL_CMD_TEST_ENABLED) || defined(__DOXYGEN__)
61#define SHELL_CMD_TEST_ENABLED TRUE
62#endif
63
64#if !defined(SHELL_CMD_TEST_WA_SIZE) || defined(__DOXYGEN__)
65#define SHELL_CMD_TEST_WA_SIZE THD_WORKING_AREA_SIZE(256)
66#endif
67
68/*===========================================================================*/
69/* Derived constants and error checks. */
70/*===========================================================================*/
71
72#if (SHELL_CMD_MEM_ENABLED == TRUE) && (CH_CFG_USE_MEMCORE == FALSE)
73#error "SHELL_CMD_MEM_ENABLED requires CH_CFG_USE_MEMCORE"
74#endif
75
76#if (SHELL_CMD_MEM_ENABLED == TRUE) && (CH_CFG_USE_HEAP == FALSE)
77#error "SHELL_CMD_MEM_ENABLED requires CH_CFG_USE_HEAP"
78#endif
79
80#if (SHELL_CMD_THREADS_ENABLED == TRUE) && (CH_CFG_USE_REGISTRY == FALSE)
81#error "SHELL_CMD_THREADS_ENABLED requires CH_CFG_USE_REGISTRY"
82#endif
83
84/*===========================================================================*/
85/* Module data structures and types. */
86/*===========================================================================*/
87
88/*===========================================================================*/
89/* Module macros. */
90/*===========================================================================*/
91
92/*===========================================================================*/
93/* External declarations. */
94/*===========================================================================*/
95
96#if !defined(__DOXYGEN__)
97extern const ShellCommand shell_local_commands[];
98#endif
99
100#ifdef __cplusplus
101extern "C" {
102#endif
103
104#ifdef __cplusplus
105}
106#endif
107
108/*===========================================================================*/
109/* Module inline functions. */
110/*===========================================================================*/
111
112#endif /* SHELLCMD_H */
113
114/** @} */