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
- Committer:
- vpcola
- Date:
- 2015-04-29
- Revision:
- 2:3db531afe4fc
- Parent:
- 0:dbde48ca1e30
File content as of revision 2:3db531afe4fc:
#include "mbed.h" #include "cmsis_os.h" #include <stdlib.h> #include <string.h> #include <stdarg.h> // cpp headers #include <string> #include <cctype> #include "Shell.h" 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; } Shell::Shell(Stream * channel) :_chp(channel) { _commands.clear(); } void Shell::addCommand(std::string name, shellcmd_t func) { _commands.insert(std::pair<std::string, shellcmd_t>(name, func)); } void Shell::start(osPriority priority, int stackSize, unsigned char *stack_pointer) { _thread = new Thread(Shell::threadHelper, this, priority, stackSize, stack_pointer); } void Shell::threadHelper(const void * arg) { Shell * pinstance = static_cast<Shell *>(const_cast<void *>(arg)); pinstance->shellMain(); } void Shell::shellUsage(const char *p) { _chp->printf("Usage: %s\r\n", p); } void Shell::listCommands() { std::map<std::string, shellcmd_t>::iterator it; for (it = _commands.begin(); it != _commands.end(); it++) _chp->printf("%s ", (*it).first.c_str()); } bool Shell::cmdExec(char * name, int argc, char *argv[]) { std::map<std::string, shellcmd_t>::iterator it; it = _commands.find(std::string(name)); if (it != _commands.end()) { it->second(_chp, argc, argv); return true; } return false; } void Shell::shellMain() { int n; char *lp, *cmd, *tokp; _chp->printf("\r\nEmbed/RX Shell\r\n"); while (true) { _chp->printf(">> "); if (shellGetLine(line, sizeof(line))) { _chp->printf("\r\nlogout"); break; } // Get the command lp = _strtok(line, " \t", &tokp); cmd = lp; // Get the arguments n = 0; while ((lp = _strtok(NULL, " \t", &tokp)) != NULL) { if (n >= SHELL_MAX_ARGUMENTS) { _chp->printf("too many arguments\r\n"); cmd = NULL; break; } args[n++] = lp; } args[n] = NULL; // Determine the command if (cmd != NULL) { if (strcasecmp(cmd, "exit") == 0) // If "exit" { if (n > 0) { shellUsage("exit"); continue; } // Break here breaks the outer loop // hence, we exit the shell. break; } else if (strcasecmp(cmd, "help") == 0) // If "help" { if (n > 0) { shellUsage("help"); continue; } _chp->printf("Commands: help exit "); listCommands(); _chp->printf("\r\n"); } else if (!cmdExec(cmd, n, args)) // Finally call exec on the command { // If the command is unknown _chp->printf("%s", cmd); _chp->printf(" ?\r\n"); } } // cmd != NULL } } bool Shell::shellGetLine(char *line, unsigned size) { char *p = line; while (true) { char c; if ((c = _chp->getc()) == 0) return true; if (c == 4) { _chp->printf("^D"); return true; } if (c == 8) { if (p != line) { _chp->putc(c); _chp->putc(0x20); _chp->putc(c); p--; } continue; } if (c == '\r') { _chp->printf("\r\n"); *p = 0; return false; } if (c < 0x20) continue; if (p < line + size - 1) { _chp->putc(c); *p++ = (char)c; } } }