User Tools

Site Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

c:tiny-shell [2018-05-29 09:33] (current)
Line 1: Line 1:
 +{{ :​c:​sunfounder-electronic-diy-robotic-arm-kit-4-axis-servo-control-rollarm-with-wired-controller-for-arduino.jpg?​240|}}
  
 +=====AVR 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===
 +
 +  * [[https://​github.com/​onborodin/​arduino-tiny-shell]]
 +  * [[c:​tiny-shell-code|]]
 +
 +===Arduino example===
 +
 +[{{:​c:​screenshot-2018-02-12-09-58-27.png|}}]
 +
 +===Prototype code===
 +
 +  * Arduino code place here [[https://​github.com/​onborodin/​arduino-tiny-shell]]
 +
 +
 +<code C 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
 +</​code>​
 +
 +===Host sample===
 +<​code>​
 +# make hello && ./​hello ​
 +gcc -c -o hello.o hello.c
 +gcc -s -o hello hello.o
 +Hello!
 +Hello, Body!
 +</​code>​
 +
 +
 +----
 +[<>]