Code for autonomous rover for Sparkfun AVC. DataBus won 3rd in 2012 and the same code was used on Troubled Child, a 1986 Jeep Grand Wagoneer to win 1st in 2014.

Dependencies:   mbed Watchdog SDFileSystem DigoleSerialDisp

UI/shell.cpp

Committer:
shimniok
Date:
2018-11-29
Revision:
12:5dfa1ab47838
Parent:
0:a6a169de725f
Child:
15:01fb4916a5cd

File content as of revision 12:5dfa1ab47838:

#include <stdio.h>
#include <string.h>
#include "mbed.h"
#include "globals.h"
#include "updater.h"
#include "print.h"
#include "DirHandle.h"
#include "SDFileSystem.h"
#include "util.h"
#include "Buttons.h"

#define MAXBUF      128
#define MAXCMDARR   21

char cwd[MAXBUF];
char buf[MAXBUF];
char path[MAXBUF];
int status;
bool debug=false;
bool done=false;

typedef struct {
    const char *cmd;
    int (*f)(char *arg0);
    const char *desc;
} cmd;

extern int autonomousMode();
extern int resetMe();
extern int gyroSwing();

extern "C" {

void shell(void *args);
void docmd(char *cmdline);
void termInput(char *cmd);
void resolveDirectory(char *newpath, char *path);
void splitName(const char *path, char *dirname, char *basename);
int dols(char *arg);
int docd(char *path);
int dopwd(char *s);
int dotouch(char *path);
int dorm(char *path);
int domkdir(char *path);
int dohead(char *path);
int docat(char *path);
int dosend(char *path);
int doprintfree(char *path);
int doexit(char *s);
int dodebug(char *s);
int dohelp(char *s);
int dogyroswing(char *s);
int doreset(char *s);
int doautonomous(char *s);
int dospeed(char *arg);
int dosteer(char *arg);
int dotimes(char *arg);

// TODO 3 multiple arguments

const cmd command[MAXCMDARR] = {
        { "help", dohelp, "print this help" },
        { "ls", dols, "list files" },
        { "cd", docd, "change directory" },
        { "pwd", dopwd, "print working directory" },
        { "touch", dotouch, "create, update file" },
        { "mkdir", domkdir, "make directory" },
        { "head", dohead, "output first part of file" },
        { "cat", docat, "output file" },
        { "send", dosend, "send file to terminal" },
        { "rm", dorm, "remove file" },
        { "debug", dodebug, "toggle debug mode" },
        { "gyro", dogyroswing, "gyro swing" },
        { "auto", doautonomous, "run autonomous mode" },
        { "reset", doreset, "reset the MCU" },
        { "free", doprintfree, "heap bytes available" },
        { "speed", dospeed, "set speed servo output" },
        { "steer", dosteer, "set steering servo output" },
        { "time", dotimes, "display update timing stats" },
//      { "exit", doexit, "exit shell" },
        { 0, 0, 0 }
};

void shell(void *args) {
    char cmdline[MAXBUF];

    pc.baud(115200);

    strcpy(cwd, "/log");

    fputs("Type help for assistance.\n", stdout);

    status=0;
    done=false;
    while (!done) {
        termInput(cmdline);

        // interrupt operation if keypad button is pressed
        if (keypad.pressed) {
            keypad.pressed = false;
            break;
        }        

        docmd(cmdline);
    }
    fputs("exiting shell\n", stdout);

    return;
}


/** docmd
 * Run a command by looking it up the command requested on the shell command line in the
 * command array.  If it's found, run the associated function. If not, print an error.
 */
void docmd(char *cmdline) {
    char *arg;
    char cmd[MAXBUF];
    bool found = false;

    arg = split(cmd, cmdline, MAXBUF, ' ');
    if (strlen(cmd) > 0) {
        //if (debug) fprintf(stdout, "cmdline:<%s> cmd:<%s> arg:<%s>\n", cmdline, cmd, arg);

        for (int i=0; command[i].cmd; i++) {
            if (!strcmp(cmd, command[i].cmd)) {
                found = true;
                command[i].f(arg);
            }
        }

        if (!found) {
            fputs(cmd, stdout);
            fputs(": command not found\n", stdout);
        }
    }

    return;
}


/** termInput
 * read input from the terminal
 */
void termInput(char *cmd) {
    int i=0;
    char c;
    bool done = false;
    
    memset(cmd, 0, MAXBUF);
    fputc('(', stdout);
    fputs(cwd, stdout);
    fputs(")# ", stdout);
    do {
        cmd[i] = 0;
        c = fgetc(stdin);
        if (c == '\r') { // if return is hit, we're done, don't add \r to cmd
            done = true;
        } else if (i < MAXBUF-1) {
            if (c == 0x7f || c == '\b') { // backspace or delete
                if (i > 0) { // if we're at the beginning, do nothing
                    i--;
                    fputs("\b \b", stdout);

                }
            } else {
                fputc(c, stdout);
                cmd[i++] = c;
            }
        }
    } while (!done);
    fputc('\n', stdout);


} 

/** resolveDirectory
 * resolve the directory path provided, given the cwd
 */
void resolveDirectory(char *newpath, char *path) {
    char dirname[32], basename[16];
    
    /** absolute path */
    if (path[0] == '/') {
        strcpy(newpath, path);
    }
    /** relative path */
    else {
        strcpy(newpath, cwd);
        if (path[0] != 0) {
            if (newpath[strlen(newpath)-1] != '/')
                strcat(newpath, "/");
            strcat(newpath, path);    
        }
        /** Resolve .. references */
        splitName(newpath, dirname, basename);
        if (!strcmp(basename, "..")) {
            splitName(dirname, newpath, basename);
        }
    }
}

/** splitCmd
 * copy t to s until space is reached
 * return location of delimiter+1 in t
 * if space not found, return t pointing to end of string
 * if s or t null, return null
 */
char *splitCmd(char *s, char *t, int max)
{
  int i = 0;
  
  if (s == 0 || t == 0)
    return 0;

  while (*t != 0 && i < max) {
    *s++ = *t++;
    i++;
    if (*t == ' ') {
        t++;
        break;
    }
  }
  *s = 0;

  return t;
}

/** splitName
 * split the path into a dirname and a 
 */
void splitName(const char *path, char *dirname, char *basename) {
    int sep;
    
    sep = 0;
    //if (debug) fprintf(stdout, "%d\n", strlen(path));
    for (int i=strlen(path)-1; i >= 0; i--) {
        //if (debug) fprintf(stdout, "- %c\n", path[i]);
        sep = i;
        if (path[i] == '/') break;
    }
    for (int j=0; j < sep; j++) {
        //if (debug) fprintf(stdout, "> %c\n", path[j]);
        dirname[j] = path[j];
        dirname[j+1] = 0;
    }
    for (unsigned int k=sep+1; k != strlen(path); k++) {
        //if (debug) fprintf(stdout, "* %c\n", path[k]);
        basename[k-(sep+1)] = path[k];
        basename[k-sep] = 0;    
    }
    //if (debug) fprintf(stdout, "d:<%s> b:<%s>\n", dirname, basename);


}

/** ls
 * lists files in the current working directory, 4 columns
 */
int dols(char *arg) {
    //if (debug) fprintf(stdout, "%s\n", cwd);
    DIR *d;
    struct dirent *p;

    resolveDirectory(path, arg);

    int count=0;
    if ((d = opendir(path)) != NULL) {
        while ((p = readdir(d)) != NULL) {
            int pad = 20 - strlen(p->d_name);
            while (pad-- > 0) fputc(' ', stdout);
            fputs(p->d_name, stdout);
            if (count++ >= 3) {
                count = 0;
                fputc('\n', stdout);
            }
        }
        fputc('\n', stdout);
        if (count < 3)
            fputc('\n', stdout);
        closedir(d);
        status = 0;
    } else {
        fputs(path, stdout);
        fputs(": No such directory\n", stdout);
        status = 1;
    }

    return status;
}

/** cd
 * changes current working directory
 */
int docd(char *arg) {

    resolveDirectory(path, arg);
    strcpy(cwd, path);

    return 0;
}

/** pwd
 * print current working directory
 */
int dopwd(char *arg) {
    fputs(cwd, stdout);
    fputc('\n', stdout);
    //fprintf(stdout, "%s\n", cwd);

    return 0;
}

/** touch
 * create an empty file
 */
int dotouch(char *arg) {
    FILE *fp;

    resolveDirectory(path, arg);
    if ((fp = fopen(path, "w")) != NULL) {
        fclose(fp);
        status = 0;
    } else {
        fputs(path, stdout);
        fputs(": No such file\n", stdout);
        status = 1;
    }

    return status;
} 

int dorm(char *arg) {
    resolveDirectory(path, arg);
    return remove(path);
}

int domkdir(char *arg) {
    resolveDirectory(path, arg);
    return mkdir(path, S_IRWXU|S_IRWXG|S_IRWXO);
}

/** head
 * print the first 10 lines of a file
 */
int dohead(char *arg) {
    FILE *fp;
    char line = 0;

    resolveDirectory(path, arg);
    if ((fp = fopen(path, "r")) != NULL) {
        while (!feof(fp) && line++ < 10) {
            fgets(buf, 128, fp);
            fputs(buf, stdout);
        }
        fclose(fp);
        status = 0;
    } else {
        fputs(path, stdout);
        fputs(": No such file\n", stdout);
        status = 1;
    }

    return status;
}

/** cat
 * display the content of a file
 */
int docat(char *arg) {
    FILE *fp;

    resolveDirectory(path, arg);
    if ((fp = fopen(path, "r")) != NULL) {
        while (fgets(buf, 127, fp)) {
            fputs(buf, stdout);
        }
        fclose(fp);
        status = 0;
    } else {
        fputs(path, stdout);
        fputs(": No such file\n", stdout);
        status = 1;
    }

    return status;
}

/** send
 * Simple serial file transfer protocol
 * Initiates escape sequence: ^A^B, sends filename, ^C, and then file
 * contents followed by ^D
 */
int dosend(char *arg) {
    FILE *fp;
    char dirname[32], basename[16];

    resolveDirectory(path, arg);
    if ((fp = fopen(path, "r")) != NULL) {
        splitName(path, dirname, basename);
        fputc(0x01, stdout);
        fputc(0x02, stdout);
        fputs(basename, stdout);
        fputc(0x03, stdout);
        while (!feof(fp)) {
            if (fgets(buf, 127, fp) != NULL)
                fputs(buf, stdout);
        }
        fclose(fp);
        fputc(0x04, stdout);
        status = 0;
    } else {
        fputs(path, stdout);
        fputs(": No such file\n", stdout);
        status = 1;
    }

    return status;
}

int doprintfree(char *arg) {
    //printInt(stdout, xPortGetFreeHeapSize());
    fputs(" bytes free.\n", stdout);

    return 0;
}

/** doexit
 * set a flag to exit the shell
 */
int doexit(char *arg) {
    done = true;

    return 0;
}

/** dodebug
 * toggle the debug state variable
 */
int dodebug(char *arg) {
    debug = !debug;

    return 0;
}

/** dohelp
 * print the list of commands and descriptions
 */
int dohelp(char *arg) {
    for (int i=0; command[i].cmd; i++) {
        int pad = 10 - strlen(command[i].cmd);
        while (pad--) fputc(' ', stdout);
        fputs(command[i].cmd, stdout);
        fputs(": ", stdout);
        fputs(command[i].desc, stdout);
        fputc('\n', stdout);
    }

    return 0;
}

/** dogyroswing
 * perform gyro swing, call external function
 */
int dogyroswing(char *arg) {
    gyroSwing();

    return 0;
}

/** doreset
 * reset the processor
 */
int doreset(char *arg) {
    resetMe();
    return 0; // won't ever reach this line...
}

/** doautonomous
 * call external doAutonomous mode to perform an autonomous run
 */
int doautonomous(char *arg) {
    autonomousMode();

    return 0;
}


int dospeed(char *arg) {
    // TODO 3 dospeed()
//  int v = atoi(arg);
//  if (config.escMin < v && v < config.escMax {
//      fputs("speed=", stdout);
//      setThrottle(v);
//      printFloat(stdout, getThrottle(), 4);
//      fputc('\n', stdout);
//  }
    return 0;
}

int dosteer(char *arg) {
    float v = cvstof(arg);
    fputs("angle=", stdout);
    printFloat(stdout, v, 4);
    fputs(" servo=", stdout);
    setSteering(v);
    // TODO 4 printFloat(stdout, getSteering(), 4);
    fputc('\n', stdout);
    return 0;
}

int dotimes(char *arg) {
    int i;
    for (i = 1; i < 8; i++) {
        printInt(stdout, i);
        fputc(':', stdout);
        // TODO 4 printInt(stdout, getUpdateTime(i)-getUpdateTime(i-1));
        fputc('\n', stdout);
    }
    fputs("total:", stdout);
    // TODO 4 printInt(stdout, getUpdateTime(7)-getUpdateTime(0));
    fputc('\n', stdout);
    return 0;
}

} // extern C