literm is a small terminal for the mbed This library allows mbed users to easily create a terminal for their mbed and simplify developpment. Users can simply add their own commands by using the LITERM_CMD macro. Each command is described by a name a description and a fallback which can get literm context and commands arguments. Please refers to the documentation, examples and don't hesitate to submit bugs, advices or request.

Files at this revision

API Documentation at this revision

Comitter:
garfunkheul
Date:
Tue Oct 08 20:14:17 2013 +0000
Commit message:
this is the first commit, introducing literm. Literm is a small terminal for the mbed which supports: simple command adding, auto help, small history, ctrl+c and ctrl+d.

Changed in this revision

literm.cpp Show annotated file Show diff for this revision Revisions of this file
literm.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r ae9f1dd56e92 literm.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/literm.cpp	Tue Oct 08 20:14:17 2013 +0000
@@ -0,0 +1,176 @@
+#include "literm.h"
+#include "mbed.h"
+
+void literm::redraw(const char *line)
+{
+    out->printf("\x1B[1K");     /* Clear line */
+    out->printf("\x1B[140D");   /* Move cursor to Left */
+    out->printf("%s%s", prompt, line);
+}
+
+int do_help(literm *term, char *args)
+{
+    struct literm_cmd *pcmd = term->get_cmds();
+    Serial *out = term->get_out();
+
+    while (pcmd->prev != NULL) {
+        out->printf("\r\n%s - %s", pcmd->name, pcmd->desc);
+        pcmd = pcmd->prev;
+    }
+
+    return 0;
+}
+
+literm::literm(Serial *_out)
+{
+    out = _out;
+    
+    /* Register default config */
+    sprintf(prompt, "mbed > ");
+    sprintf(welcome, "\r\n\r\nHello from literm library");
+    
+    /* Register Help command which is the first one */
+    sprintf(help_cmd.name, "help");
+    help_cmd.prev = NULL;    
+    help_cmd.func = do_help;
+    cmd_list = &help_cmd;
+}
+
+void literm::loop()
+{
+    int hist_begin = -1; /* -1 = empty hist */
+    int hist_end = 0;
+    int hist_cur;
+    int hist_full = 0;
+    char hist[HIST_SIZE][MAX_CMDLINE_SIZE];
+    
+    char cmdline[MAX_CMDLINE_SIZE];
+    int max_cmdline, i;
+    struct literm_cmd *pcmd;
+
+    out->printf(welcome);
+
+    while (1) {
+begin:
+        pcmd = cmd_list;
+        max_cmdline = 0;
+        hist_cur = -1; /* -1 = no hist used */
+
+        out->printf("\r\n%s",prompt);
+        do {
+            if (out->readable()) {
+                cmdline[max_cmdline] = out->getc();
+                
+                if (cmdline[max_cmdline] == 3)
+                    goto begin;
+                if (cmdline[max_cmdline] == 4)
+                    goto exit;
+                if (cmdline[max_cmdline] == 8 || cmdline[max_cmdline] == 127) {
+                    if (max_cmdline > 0) {
+                        max_cmdline--;
+                        cmdline[max_cmdline] = '\0';
+                        redraw(cmdline);
+                    }
+                } else if (cmdline[max_cmdline] == 27) {
+                    out->getc(); /* trash useless value */
+                    char tmp = out->getc();
+                    if (tmp == 65) { /* up */
+                        if (hist_cur != hist_end && hist_begin != -1) {
+                            if (hist_cur == -1)
+                                hist_cur = hist_begin;
+                            else
+                                hist_cur--;
+                            if (hist_cur < 0)
+                                hist_cur = HIST_SIZE - 1;
+                            redraw(hist[hist_cur]);
+                        }                    
+                    } else if (tmp == 66) { /* down */
+                        if (hist_cur != hist_begin) {
+                            hist_cur++;
+                            if(hist_cur >= HIST_SIZE)
+                                hist_cur = 0;
+                            redraw(hist[hist_cur]);
+                        }
+                    }
+                } else
+                    out->putc(cmdline[max_cmdline++]);
+            }
+        } while (cmdline[max_cmdline - 1] != 13);
+      
+        /* use a command from history */
+        if (hist_cur != -1) {
+            strncpy(cmdline, hist[hist_cur], MAX_CMDLINE_SIZE - 1);
+            max_cmdline = strlen(cmdline);
+            if (hist_cur == hist_begin)
+                goto proceed;
+        
+        /* use a new command */    
+        } else {
+            /* deal with empty lines */
+            if (max_cmdline < 2 && hist_cur == -1)
+                goto begin;
+      
+            cmdline[max_cmdline - 1] = '\0';  
+        }      
+          
+        /* Update History */
+        hist_begin++;
+        if (hist_begin >= HIST_SIZE) {
+            hist_begin = 0;
+            hist_full = 1;
+        }
+        if (hist_full)
+            hist_end++;
+        if (hist_end >= HIST_SIZE)
+            hist_end = 0;
+        strncpy(hist[hist_begin], cmdline, MAX_CMDLINE_SIZE - 1);
+                
+proceed:
+        for (i = 0; i < max_cmdline; ++i) {
+            if (cmdline[i] == ' ') {
+                cmdline[i] = '\0';
+                break;
+            }
+            if (cmdline[i] == '\0') {
+                cmdline[i + 1] = '\0';
+                break;
+            }
+        }
+        
+        while (strcmp(pcmd->name, cmdline) && pcmd != NULL)
+            pcmd = pcmd->prev;
+            
+        if (pcmd != NULL)
+                (*pcmd->func)(this, cmdline + i + 1);
+        else
+            out->printf("\r\n%s not found", cmdline);
+    }
+exit:
+    out->printf("\r\nExiting small cli\r\n");
+}
+
+literm_cmd* literm::get_cmds()
+{
+    return cmd_list;
+}
+
+Serial* literm::get_out()
+{
+    return out;
+}
+
+void literm::set_hostname(char *name)
+{
+    snprintf(prompt, sizeof(prompt) - 1, "%s > ", name);
+}
+
+void literm::set_welcome(char *message)
+{
+    snprintf(welcome, sizeof(welcome) - 1, "\r\n\r\n%s", message);
+}
+
+void literm::add_cmd(literm_cmd *_cmd)
+{
+    _cmd->prev = cmd_list;
+    cmd_list = _cmd;
+}
diff -r 000000000000 -r ae9f1dd56e92 literm.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/literm.h	Tue Oct 08 20:14:17 2013 +0000
@@ -0,0 +1,134 @@
+#ifndef _LITERM_H_
+#define _LITERM_H_
+
+#include "mbed.h"
+
+#define HIST_SIZE 5
+#define MAX_CMDLINE_SIZE 128
+
+class literm;
+
+struct literm_cmd {
+    char name[8];
+    char desc[64];
+    int (*func)(literm *, char *);
+    
+    literm_cmd *prev;
+};
+
+#define LITERM_CMD(_name, _desc)          \
+    struct literm_cmd _name##_cmd = {     \
+        .name = #_name,                 \
+        .desc = _desc,                  \
+        .func = do_##_name, };
+
+/** Small terminal class.
+ *  This class intends to provide a small terminal for the mbed. It supports the following features:
+ *    - Add command based on a name, a description and a callback
+ *    - Auto help command based on name and description declarations.
+ *    - Ctrl-C to clear written command.
+ *    - Delete last char with backspace (if VT100 supported).
+ *    - Exit the CLI with ctrl-D.
+ *    - Small History (with up and down arrows)
+ *
+ * Example:
+ * @code
+ * #include "mbed.h"
+ * #include "literm.h"
+ * 
+ * int do_get(literm *term, char * args)
+ * {
+ *     Serial *out = term->get_out();
+ *     
+ *     out->printf("\r\nGetting!");
+ *     
+ *     return 0;
+ * }
+ * 
+ * int do_set(literm *term, char * args)
+ * {
+ *     Serial *out = term->get_out();
+ * 
+ *     out->printf("\r\nSetting!");
+ *     
+ *     return 0;
+ * }
+ * 
+ * LITERM_CMD(get, "getting something");
+ * LITERM_CMD(set, "setting something");
+ * 
+ * int main() 
+ * {
+ *     Serial pc(USBTX, USBRX);
+ *     literm term(&pc);
+ *     
+ *     pc.baud(115200);
+ *     pc.format(8, Serial::None, 1);
+ *    
+ *     term.set_hostname("mbed cli 1");
+ *     term.set_welcome("Bonjour et bienvenue!");
+ *     
+ *     term.add_cmd(&get_cmd);
+ *     term.add_cmd(&set_cmd);
+ *     term.loop();
+ *     
+ *     term.set_hostname("mbed cli 2");
+ *     term.loop();
+ * }
+ * @endcode
+ */
+class literm
+{
+
+ public:
+ 
+    /** Create a literm instance.
+     * @param _out serial output used to print and received
+     */
+    literm(Serial * _out);
+    
+    /** Versatile loop which start and manage the cli.
+     */
+    void loop();
+    
+    /** Set the hostname used by the cli.
+     *
+     * @param name hostname to use, must be < 12 chars
+     */
+    void set_hostname(char *name);
+    
+    /** Set the welcome message used by the cli.
+     *
+     * @param message welcome message to use, must be < 126 chars
+     */
+    void set_welcome(char *message);
+    
+    /** Add a command to the smal command line.
+     *
+     * @param _cmd pointer to a command to add. Commands are created with LITERM_CMD macro
+     */
+    void add_cmd(literm_cmd *_cmd);
+    
+    /** Return a pointer to the command stack.
+     *
+     * @returns stack command pointer
+     */
+    literm_cmd* get_cmds();
+    
+    /** Return a pointer to the Serial used as input/output for cli.
+     *
+     * @returns serial input/ouput 
+     */
+    Serial * get_out();
+
+ private:
+    Serial *out;
+    char prompt[16];
+    char welcome[128];
+    
+    void redraw(const char* line);
+    literm_cmd *cmd_list;
+    literm_cmd help_cmd;
+};
+
+#endif