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
Child:
2:3db531afe4fc
--- /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;
+    }
+  }
+}