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);
    }      
}


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?

UserRevisionLine numberNew 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 }