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); } }
Revision 0:dbde48ca1e30, committed 2015-04-28
- Comitter:
- vpcola
- Date:
- Tue Apr 28 16:56:21 2015 +0000
- Child:
- 1:25fa46a375dd
- Commit message:
- Simple Serial shell running on its own thread
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Shell.cpp Tue Apr 28 16:56:21 2015 +0000 @@ -0,0 +1,181 @@ +#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" +#include "Utility.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; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Shell.h Tue Apr 28 16:56:21 2015 +0000 @@ -0,0 +1,46 @@ +#ifndef _SERIAL_SHELL_H_ +#define _SERIAL_SHELL_H_ + +#include "mbed.h" +#include "rtos.h" + +#include <string> +#include <map> + +#define SHELL_MAX_LINE_LENGTH 64 +#define SHELL_MAX_ARGUMENTS 4 + +typedef void (*shellcmd_t) (Stream *, int , char **); + +class Shell { + public: + Shell(Stream * channel); + virtual ~Shell() {} + + void addCommand(std::string name, shellcmd_t func); + void start(osPriority priority = osPriorityNormal, + int stackSize = 1024, + unsigned char *stack_pointer=NULL); + + private: + static void threadHelper(const void * arg); + + void shellMain(); + void shellUsage(const char *p); + bool shellGetLine(char *line, unsigned size); + void listCommands(); + bool cmdExec(char * name, int argc, char *argv[]); + + Stream * _chp; + Thread * _thread; + + // UART/Serial buffers for + // parsing command line + char line[SHELL_MAX_LINE_LENGTH]; + char *args[SHELL_MAX_ARGUMENTS + 1]; + + // commands + std::map<std::string, shellcmd_t> _commands; +}; + +#endif