A simple serial shell running on its own thread (stack is statically allocated).
Dependents: FRDM_K64F_IOT lpc1768_blinky
A simple serial shell running on its own thread. The thread is not started until a call to start(). A start() call creates a thread either using static allocation (pre-defined stack size).
Sample Usage
#include "mbed.h" #include "rtos.h" #include "Shell.h" Serial pc(p9,p10); #define SHELL_STACK_SIZ 1024 // Pre-allocate the shell's stack (on global mem) unsigned char shellStack[SHELL_STACK_SIZ]; Shell shell(&pc); // Shell Commands /** * \brief Gets the amount of free memory * \param none * \return none **/ static void cmd_mem(Stream * strm, int argc, char * argv[]) { // In order to get free mem within RTOS // we need to get the main thread's stack pointer // and subtract it with the top of the heap // ------+-------------------+ Last Address of RAM (INITIAL_SP) // | Scheduler Stack | // +-------------------+ // | Main Thread Stack | // | | | // | v | // +-------------------+ <- bottom_of_stack/__get_MSP() // RAM | | // | Available RAM | // | | // +-------------------+ <- top_of_heap // | ^ | // | | | // | Heap | // +-------------------+ <- __end__ / HEAP_START (linker defined var) // | ZI | // +-------------------+ // | ZI: Shell Stack | // +-------------------+ // | ZI: Idle Stack | // +-------------------+ // | ZI: Timer Stack | // +-------------------+ // | RW | // ------+===================+ First Address of RAM // | | // Flash | | // uint32_t bottom_of_stack = __get_MSP(); char * top_of_heap = (char *) malloc(sizeof(char)); uint32_t diff = bottom_of_stack - (uint32_t) top_of_heap; free((void *) top_of_heap); strm->printf("Available Memory : %d bytes\r\n", diff); } int main() { // Start the shell pc.printf("Starting debug shell ...\r\n"); shell.addCommand("mem", cmd_mem); shell.start(osPriorityNormal, SHELL_STACK_SIZ, shellStack); while(1) { wait(0.2); } }
Shell.cpp@2:3db531afe4fc, 2015-04-29 (annotated)
- Committer:
- vpcola
- Date:
- Wed Apr 29 06:13:20 2015 +0000
- Revision:
- 2:3db531afe4fc
- Parent:
- 0:dbde48ca1e30
Removed unused headers;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
vpcola | 0:dbde48ca1e30 | 1 | #include "mbed.h" |
vpcola | 0:dbde48ca1e30 | 2 | #include "cmsis_os.h" |
vpcola | 0:dbde48ca1e30 | 3 | |
vpcola | 0:dbde48ca1e30 | 4 | #include <stdlib.h> |
vpcola | 0:dbde48ca1e30 | 5 | #include <string.h> |
vpcola | 0:dbde48ca1e30 | 6 | #include <stdarg.h> |
vpcola | 0:dbde48ca1e30 | 7 | // cpp headers |
vpcola | 0:dbde48ca1e30 | 8 | #include <string> |
vpcola | 0:dbde48ca1e30 | 9 | #include <cctype> |
vpcola | 0:dbde48ca1e30 | 10 | |
vpcola | 0:dbde48ca1e30 | 11 | |
vpcola | 0:dbde48ca1e30 | 12 | |
vpcola | 0:dbde48ca1e30 | 13 | #include "Shell.h" |
vpcola | 2:3db531afe4fc | 14 | |
vpcola | 0:dbde48ca1e30 | 15 | |
vpcola | 0:dbde48ca1e30 | 16 | static char *_strtok(char *str, const char *delim, char **saveptr) |
vpcola | 0:dbde48ca1e30 | 17 | { |
vpcola | 0:dbde48ca1e30 | 18 | char *token; |
vpcola | 0:dbde48ca1e30 | 19 | if (str) |
vpcola | 0:dbde48ca1e30 | 20 | *saveptr = str; |
vpcola | 0:dbde48ca1e30 | 21 | token = *saveptr; |
vpcola | 0:dbde48ca1e30 | 22 | |
vpcola | 0:dbde48ca1e30 | 23 | if (!token) |
vpcola | 0:dbde48ca1e30 | 24 | return NULL; |
vpcola | 0:dbde48ca1e30 | 25 | |
vpcola | 0:dbde48ca1e30 | 26 | token += strspn(token, delim); |
vpcola | 0:dbde48ca1e30 | 27 | *saveptr = strpbrk(token, delim); |
vpcola | 0:dbde48ca1e30 | 28 | if (*saveptr) |
vpcola | 0:dbde48ca1e30 | 29 | *(*saveptr)++ = '\0'; |
vpcola | 0:dbde48ca1e30 | 30 | |
vpcola | 0:dbde48ca1e30 | 31 | return *token ? token : NULL; |
vpcola | 0:dbde48ca1e30 | 32 | } |
vpcola | 0:dbde48ca1e30 | 33 | |
vpcola | 0:dbde48ca1e30 | 34 | |
vpcola | 0:dbde48ca1e30 | 35 | Shell::Shell(Stream * channel) |
vpcola | 0:dbde48ca1e30 | 36 | :_chp(channel) |
vpcola | 0:dbde48ca1e30 | 37 | { |
vpcola | 0:dbde48ca1e30 | 38 | _commands.clear(); |
vpcola | 0:dbde48ca1e30 | 39 | } |
vpcola | 0:dbde48ca1e30 | 40 | |
vpcola | 0:dbde48ca1e30 | 41 | void Shell::addCommand(std::string name, shellcmd_t func) |
vpcola | 0:dbde48ca1e30 | 42 | { |
vpcola | 0:dbde48ca1e30 | 43 | _commands.insert(std::pair<std::string, shellcmd_t>(name, func)); |
vpcola | 0:dbde48ca1e30 | 44 | } |
vpcola | 0:dbde48ca1e30 | 45 | |
vpcola | 0:dbde48ca1e30 | 46 | void Shell::start(osPriority priority, |
vpcola | 0:dbde48ca1e30 | 47 | int stackSize, |
vpcola | 0:dbde48ca1e30 | 48 | unsigned char *stack_pointer) |
vpcola | 0:dbde48ca1e30 | 49 | { |
vpcola | 0:dbde48ca1e30 | 50 | _thread = new Thread(Shell::threadHelper, this, priority, stackSize, stack_pointer); |
vpcola | 0:dbde48ca1e30 | 51 | } |
vpcola | 0:dbde48ca1e30 | 52 | |
vpcola | 0:dbde48ca1e30 | 53 | void Shell::threadHelper(const void * arg) |
vpcola | 0:dbde48ca1e30 | 54 | { |
vpcola | 0:dbde48ca1e30 | 55 | Shell * pinstance = static_cast<Shell *>(const_cast<void *>(arg)); |
vpcola | 0:dbde48ca1e30 | 56 | |
vpcola | 0:dbde48ca1e30 | 57 | pinstance->shellMain(); |
vpcola | 0:dbde48ca1e30 | 58 | } |
vpcola | 0:dbde48ca1e30 | 59 | |
vpcola | 0:dbde48ca1e30 | 60 | void Shell::shellUsage(const char *p) |
vpcola | 0:dbde48ca1e30 | 61 | { |
vpcola | 0:dbde48ca1e30 | 62 | _chp->printf("Usage: %s\r\n", p); |
vpcola | 0:dbde48ca1e30 | 63 | } |
vpcola | 0:dbde48ca1e30 | 64 | |
vpcola | 0:dbde48ca1e30 | 65 | void Shell::listCommands() |
vpcola | 0:dbde48ca1e30 | 66 | { |
vpcola | 0:dbde48ca1e30 | 67 | std::map<std::string, shellcmd_t>::iterator it; |
vpcola | 0:dbde48ca1e30 | 68 | for (it = _commands.begin(); it != _commands.end(); it++) |
vpcola | 0:dbde48ca1e30 | 69 | _chp->printf("%s ", (*it).first.c_str()); |
vpcola | 0:dbde48ca1e30 | 70 | } |
vpcola | 0:dbde48ca1e30 | 71 | |
vpcola | 0:dbde48ca1e30 | 72 | bool Shell::cmdExec(char * name, int argc, char *argv[]) |
vpcola | 0:dbde48ca1e30 | 73 | { |
vpcola | 0:dbde48ca1e30 | 74 | std::map<std::string, shellcmd_t>::iterator it; |
vpcola | 0:dbde48ca1e30 | 75 | it = _commands.find(std::string(name)); |
vpcola | 0:dbde48ca1e30 | 76 | if (it != _commands.end()) |
vpcola | 0:dbde48ca1e30 | 77 | { |
vpcola | 0:dbde48ca1e30 | 78 | it->second(_chp, argc, argv); |
vpcola | 0:dbde48ca1e30 | 79 | return true; |
vpcola | 0:dbde48ca1e30 | 80 | } |
vpcola | 0:dbde48ca1e30 | 81 | |
vpcola | 0:dbde48ca1e30 | 82 | return false; |
vpcola | 0:dbde48ca1e30 | 83 | } |
vpcola | 0:dbde48ca1e30 | 84 | |
vpcola | 0:dbde48ca1e30 | 85 | |
vpcola | 0:dbde48ca1e30 | 86 | void Shell::shellMain() |
vpcola | 0:dbde48ca1e30 | 87 | { |
vpcola | 0:dbde48ca1e30 | 88 | int n; |
vpcola | 0:dbde48ca1e30 | 89 | char *lp, *cmd, *tokp; |
vpcola | 0:dbde48ca1e30 | 90 | |
vpcola | 0:dbde48ca1e30 | 91 | _chp->printf("\r\nEmbed/RX Shell\r\n"); |
vpcola | 0:dbde48ca1e30 | 92 | while (true) { |
vpcola | 0:dbde48ca1e30 | 93 | _chp->printf(">> "); |
vpcola | 0:dbde48ca1e30 | 94 | if (shellGetLine(line, sizeof(line))) { |
vpcola | 0:dbde48ca1e30 | 95 | _chp->printf("\r\nlogout"); |
vpcola | 0:dbde48ca1e30 | 96 | break; |
vpcola | 0:dbde48ca1e30 | 97 | } |
vpcola | 0:dbde48ca1e30 | 98 | // Get the command |
vpcola | 0:dbde48ca1e30 | 99 | lp = _strtok(line, " \t", &tokp); |
vpcola | 0:dbde48ca1e30 | 100 | cmd = lp; |
vpcola | 0:dbde48ca1e30 | 101 | |
vpcola | 0:dbde48ca1e30 | 102 | // Get the arguments |
vpcola | 0:dbde48ca1e30 | 103 | n = 0; |
vpcola | 0:dbde48ca1e30 | 104 | while ((lp = _strtok(NULL, " \t", &tokp)) != NULL) { |
vpcola | 0:dbde48ca1e30 | 105 | if (n >= SHELL_MAX_ARGUMENTS) { |
vpcola | 0:dbde48ca1e30 | 106 | _chp->printf("too many arguments\r\n"); |
vpcola | 0:dbde48ca1e30 | 107 | cmd = NULL; |
vpcola | 0:dbde48ca1e30 | 108 | break; |
vpcola | 0:dbde48ca1e30 | 109 | } |
vpcola | 0:dbde48ca1e30 | 110 | args[n++] = lp; |
vpcola | 0:dbde48ca1e30 | 111 | } |
vpcola | 0:dbde48ca1e30 | 112 | args[n] = NULL; |
vpcola | 0:dbde48ca1e30 | 113 | |
vpcola | 0:dbde48ca1e30 | 114 | // Determine the command |
vpcola | 0:dbde48ca1e30 | 115 | if (cmd != NULL) |
vpcola | 0:dbde48ca1e30 | 116 | { |
vpcola | 0:dbde48ca1e30 | 117 | if (strcasecmp(cmd, "exit") == 0) // If "exit" |
vpcola | 0:dbde48ca1e30 | 118 | { |
vpcola | 0:dbde48ca1e30 | 119 | if (n > 0) { |
vpcola | 0:dbde48ca1e30 | 120 | shellUsage("exit"); |
vpcola | 0:dbde48ca1e30 | 121 | continue; |
vpcola | 0:dbde48ca1e30 | 122 | } |
vpcola | 0:dbde48ca1e30 | 123 | // Break here breaks the outer loop |
vpcola | 0:dbde48ca1e30 | 124 | // hence, we exit the shell. |
vpcola | 0:dbde48ca1e30 | 125 | break; |
vpcola | 0:dbde48ca1e30 | 126 | } |
vpcola | 0:dbde48ca1e30 | 127 | else if (strcasecmp(cmd, "help") == 0) // If "help" |
vpcola | 0:dbde48ca1e30 | 128 | { |
vpcola | 0:dbde48ca1e30 | 129 | if (n > 0) { |
vpcola | 0:dbde48ca1e30 | 130 | shellUsage("help"); |
vpcola | 0:dbde48ca1e30 | 131 | continue; |
vpcola | 0:dbde48ca1e30 | 132 | } |
vpcola | 0:dbde48ca1e30 | 133 | _chp->printf("Commands: help exit "); |
vpcola | 0:dbde48ca1e30 | 134 | listCommands(); |
vpcola | 0:dbde48ca1e30 | 135 | _chp->printf("\r\n"); |
vpcola | 0:dbde48ca1e30 | 136 | } |
vpcola | 0:dbde48ca1e30 | 137 | else if (!cmdExec(cmd, n, args)) // Finally call exec on the command |
vpcola | 0:dbde48ca1e30 | 138 | { |
vpcola | 0:dbde48ca1e30 | 139 | // If the command is unknown |
vpcola | 0:dbde48ca1e30 | 140 | _chp->printf("%s", cmd); |
vpcola | 0:dbde48ca1e30 | 141 | _chp->printf(" ?\r\n"); |
vpcola | 0:dbde48ca1e30 | 142 | } |
vpcola | 0:dbde48ca1e30 | 143 | } // cmd != NULL |
vpcola | 0:dbde48ca1e30 | 144 | } |
vpcola | 0:dbde48ca1e30 | 145 | } |
vpcola | 0:dbde48ca1e30 | 146 | |
vpcola | 0:dbde48ca1e30 | 147 | bool Shell::shellGetLine(char *line, unsigned size) |
vpcola | 0:dbde48ca1e30 | 148 | { |
vpcola | 0:dbde48ca1e30 | 149 | char *p = line; |
vpcola | 0:dbde48ca1e30 | 150 | |
vpcola | 0:dbde48ca1e30 | 151 | while (true) { |
vpcola | 0:dbde48ca1e30 | 152 | char c; |
vpcola | 0:dbde48ca1e30 | 153 | |
vpcola | 0:dbde48ca1e30 | 154 | if ((c = _chp->getc()) == 0) |
vpcola | 0:dbde48ca1e30 | 155 | return true; |
vpcola | 0:dbde48ca1e30 | 156 | if (c == 4) { |
vpcola | 0:dbde48ca1e30 | 157 | _chp->printf("^D"); |
vpcola | 0:dbde48ca1e30 | 158 | return true; |
vpcola | 0:dbde48ca1e30 | 159 | } |
vpcola | 0:dbde48ca1e30 | 160 | if (c == 8) { |
vpcola | 0:dbde48ca1e30 | 161 | if (p != line) { |
vpcola | 0:dbde48ca1e30 | 162 | _chp->putc(c); |
vpcola | 0:dbde48ca1e30 | 163 | _chp->putc(0x20); |
vpcola | 0:dbde48ca1e30 | 164 | _chp->putc(c); |
vpcola | 0:dbde48ca1e30 | 165 | p--; |
vpcola | 0:dbde48ca1e30 | 166 | } |
vpcola | 0:dbde48ca1e30 | 167 | continue; |
vpcola | 0:dbde48ca1e30 | 168 | } |
vpcola | 0:dbde48ca1e30 | 169 | if (c == '\r') { |
vpcola | 0:dbde48ca1e30 | 170 | _chp->printf("\r\n"); |
vpcola | 0:dbde48ca1e30 | 171 | *p = 0; |
vpcola | 0:dbde48ca1e30 | 172 | return false; |
vpcola | 0:dbde48ca1e30 | 173 | } |
vpcola | 0:dbde48ca1e30 | 174 | if (c < 0x20) |
vpcola | 0:dbde48ca1e30 | 175 | continue; |
vpcola | 0:dbde48ca1e30 | 176 | if (p < line + size - 1) { |
vpcola | 0:dbde48ca1e30 | 177 | _chp->putc(c); |
vpcola | 0:dbde48ca1e30 | 178 | *p++ = (char)c; |
vpcola | 0:dbde48ca1e30 | 179 | } |
vpcola | 0:dbde48ca1e30 | 180 | } |
vpcola | 0:dbde48ca1e30 | 181 | } |