User Tools

Site Tools


Arduino Tiny Shell

Here I present sample arduino micro-application with

  • ring buffer for input and output with hook to interrupts (wide shared ring buffer code with my adaptation and inmprovement)
  • extensible tiny sheel for command execution
  • some data manipulation function
  • PWM timers and interrupts sample

Shell really is tiny and used only ~850 bytes of microcontroller code. Shell don't use malloc and use line parsing “in-place”.

Well, if in truth, I wrote this code for the toys of my youngest son =)

We can add own function call. The agreement about the called functions is very simple:

  • function must accept string arguments uint8_t*
  • and return an integer, now is int16_t

The syntax of the shell is also simple:

command [arg [arg]];

where arg can be string or signed/unsigned integer. There is nothing difficult to add your types. To do this, you need to write the translation functions that are called inside the command handler function.

The argument delimiter is a space, the command terminator is a semicolon ;.

Arduino source code

Arduino example

Prototype code

hello.c
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
 
#define MAX_LINE_LEN 128
 
bool str_cmp(uint8_t * str1, uint8_t * str2) {
    uint8_t i = 0;
    while (str1[i] != 0 && str2[i] != 0) {
        if ((str1[i] != str2[i]) || (str1[i + 1] != str2[i + 1]))
            return false;
        i++;
    }
    return true;
}
 
uint8_t *ltrim(uint8_t ** headp, uint8_t c, uint8_t t) {
    while ((*headp)[0] == c || (*headp)[0] == t) {
        (*headp)++;
    }
    return (*headp);
}
 
bool gettseq(uint8_t ** headp, uint8_t ** tailp, uint8_t c, uint8_t t) {
    if ((*headp)[0] == 0)
        return false;
 
    while ((*headp)[0] == c || (*headp)[0] == t)
        (*headp)++;
    if ((*headp)[0] == 0)
        return false;
 
    (*tailp) = (*headp);
    while ((*tailp)[0] != t && (*tailp)[0] != 0) {
        (*tailp)++;
    }
    if ((*tailp)[0] != t)
        return false;
 
    (*tailp)[0] = 0;
    (*tailp)++;
    return true;
}
 
bool getcseq(uint8_t ** headp, uint8_t ** tailp, uint8_t ** endp, const uint8_t c) {
    while ((*headp)[0] == c && (*headp)[0] != 0)
        (*headp)++;
    if ((*headp)[0] == 0)
        return false;
 
    (*tailp) = (*headp);
    while ((*tailp)[0] != c && (*tailp)[0] != 0) {
        (*tailp)++;
    }
 
    if ((*tailp) >= (*endp))
        return false;
 
    (*tailp)[0] = 0;
    (*tailp)++;
    return true;
}
 
#define MAX_ARGC 4
typedef struct cmd {
    uint8_t *arg[MAX_ARGC];
    uint8_t argc;
} cmd_t;
 
 
typedef void (*funcp_t) ();
 
typedef struct cdef {
    uint8_t *name;
    funcp_t func;
    uint8_t argc;
} cdef_t;
 
void cmd_hello0(void) {
    printf("Hello!\n");
}
 
void cmd_hello1(uint8_t *str) {
    printf("Hello, %s!", str);
}
 
void shell (uint8_t *str) {
    uint8_t space = ' ', semic = ';', null = 0, newl = '\n';
    uint8_t *head = str;
    uint8_t *tail;
 
    while (gettseq(&head, &tail, space, semic)) {
        uint8_t *cmdhead = head;
        uint8_t *cmdtail;
 
        cmd_t cmd = { };
        cmd.argc = 0;
 
        while (getcseq(&cmdhead, &cmdtail, &tail, space) && (cmd.argc < MAX_ARGC)) {
            cmd.arg[cmd.argc] = cmdhead;
            cmd.argc++;
            cmdhead = cmdtail;
        };
 
        uint8_t i = 0, n = sizeof(cmdl) / sizeof(cdef_t), m = 0;
        while (i < n) {
            if (str_cmp(cmd.arg[0], cmdl[i].name)) {
 
                if (cmd.argc < cmdl[i].argc)
                    break;
 
                switch (cmdl[i].argc) {
                case 0:
                    (cmdl[i].func) ();
                    break;
                case 1:
                    (cmdl[i].func) (cmd.arg[1]);
                    break;
                case 2:
                    break;
                };
                break;
            }
            i++;
        }
        head = tail;
    }
}
 
cdef_t cmdl[] = {
    {"hello0", &cmd_hello0, 0},
    {"hello1", &cmd_hello1, 1},
};
 
int main(void) {
    uint8_t str[164] = "hello0 Body ; hello1 Body ; dummy comm;";
    shell(str);
}
//EOF

Host sample

# make hello && ./hello 
gcc -c -o hello.o hello.c
gcc -s -o hello hello.o
Hello!
Hello, Body!

First PagePrevious PageBack to overview