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
Diff: UI/shell.cpp
- Revision:
- 12:5dfa1ab47838
- Parent:
- 0:a6a169de725f
- Child:
- 15:01fb4916a5cd
--- a/UI/shell.cpp Thu Nov 29 16:35:31 2018 +0000 +++ b/UI/shell.cpp Thu Nov 29 16:50:46 2018 +0000 @@ -1,149 +1,177 @@ #include <stdio.h> +#include <string.h> #include "mbed.h" -#include "stdint.h" +#include "globals.h" +#include "updater.h" +#include "print.h" #include "DirHandle.h" -#include "SDHCFileSystem.h" +#include "SDFileSystem.h" #include "util.h" #include "Buttons.h" -extern SDFileSystem sd; -extern Serial pc; -extern Buttons keypad; +#define MAXBUF 128 +#define MAXCMDARR 21 + +char cwd[MAXBUF]; +char buf[MAXBUF]; +char path[MAXBUF]; +int status; +bool debug=false; +bool done=false; -char cwd[64]; -char buf[128]; -bool debug=false; +typedef struct { + const char *cmd; + int (*f)(char *arg0); + const char *desc; +} cmd; -void shell(void); +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(char *path, char *dirname, char *basename); -void ls(char *path); -void cd(char *path); -void pwd(void); -void touch(char *path); -void head(char *path); -void cat(char *path); -void send(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); -void shell() { - FILE *fp; - char newpath[64], *arg, cmd[64], cmdline[64]; - bool done=false; +// TODO 3 multiple arguments - //Logger.SelectCRCMode(1); - - //pc.printf("Formatting...\n"); - //int i = Logger.format(32); - //pc.printf("format result: %d\n", i); +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 } +}; - if ((fp = fopen("/log/message.txt", "w")) != NULL) { - for (int i=0; i < 20; i++) - fprintf(fp, "Hello, World!\n"); - fclose(fp); - //pc.printf("created!\n"); - } else { - pc.printf("Error creating file\n"); - } - pc.printf("\n"); - +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); - arg = split(cmd, cmdline, 64, ' '); - resolveDirectory(newpath, arg); - + + // interrupt operation if keypad button is pressed if (keypad.pressed) { keypad.pressed = false; break; } - - if (debug) pc.printf("cmdline:<%s> cmd:<%s> arg:<%s> newpath:<%s>\n", cmdline, cmd, arg, newpath); - - if (!strcmp(cmd, "ls")) { - ls(newpath); - } else if (!strcmp(cmd, "cd")) { - cd(newpath); - } else if (!strcmp(cmd, "pwd")) { - pwd(); - } else if (!strcmp(cmd, "head")) { - head(newpath); - } else if (!strcmp(cmd, "cat")) { - cat(newpath); - } else if (!strcmp(cmd, "send")) { - send(newpath); - } else if (!strcmp(cmd, "mkdir")) { - mkdir(newpath, 1023); - } else if (!strcmp(cmd, "debug")) { - debug = !debug; - } else if (!strcmp(cmd, "touch")) { - touch(newpath); - } else if (!strcmp(cmd, "rm")) { - remove(newpath); - } else if (!strcmp(cmd, "exit")) { - done = true; - } else if (cmd[0] == '\0') { - // ignore - } else { - pc.printf("%s: command not found\n", cmd); + + 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); } } -/* - pc.printf("Printing splitName()\n"); - splitName("/SDCard/testdir", dirname, basename); - pc.printf("%s %s\n", dirname, basename); - - pc.printf("Printing resolveDirectory()\n"); - resolveDirectory(newpath, "test"); - pc.printf("%s\n", newpath); -*/ - -// remove("/SDCard/testdir/TEST.txt"); - - /* - int test = rename("/SDCard/message.txt", "/SDCard/message2.txt"); - fp = fopen("/SDCard/message.txt", "a"); - fprintf(fp, " Result = %d", test); - fclose(fp); - */ - - pc.printf ("exiting shell\n"); - return; } /** termInput - * + * read input from the terminal */ void termInput(char *cmd) { int i=0; char c; bool done = false; - memset(cmd, 0, 64); - - pc.printf("# ", cwd); + memset(cmd, 0, MAXBUF); + fputc('(', stdout); + fputs(cwd, stdout); + fputs(")# ", stdout); do { cmd[i] = 0; - c = pc.getc(); + c = fgetc(stdin); if (c == '\r') { // if return is hit, we're done, don't add \r to cmd done = true; - } else if (i < 64-1) { + } 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--; - pc.printf("\b \b"); + fputs("\b \b", stdout); + } } else { - pc.printf("%c", c); + fputc(c, stdout); cmd[i++] = c; } } } while (!done); - pc.printf("\n"); + fputc('\n', stdout); + + } /** resolveDirectory @@ -172,10 +200,12 @@ } } -// 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 +/** 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; @@ -192,121 +222,168 @@ } } *s = 0; - + return t; } /** splitName * split the path into a dirname and a */ -void splitName(char *path, char *dirname, char *basename) { +void splitName(const char *path, char *dirname, char *basename) { int sep; sep = 0; - if (debug) pc.printf("%d\n", strlen(path)); + //if (debug) fprintf(stdout, "%d\n", strlen(path)); for (int i=strlen(path)-1; i >= 0; i--) { - if (debug) pc.printf("- %c\n", path[i]); + //if (debug) fprintf(stdout, "- %c\n", path[i]); sep = i; if (path[i] == '/') break; } for (int j=0; j < sep; j++) { - if (debug) pc.printf("> %c\n", path[j]); + //if (debug) fprintf(stdout, "> %c\n", path[j]); dirname[j] = path[j]; dirname[j+1] = 0; } - for (int k=sep+1; k < strlen(path); k++) { - if (debug) pc.printf("* %c\n", path[k]); + 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) pc.printf("d:<%s> b:<%s>\n", dirname, basename); + //if (debug) fprintf(stdout, "d:<%s> b:<%s>\n", dirname, basename); + + } /** ls * lists files in the current working directory, 4 columns */ -void ls(char *path) { - if (debug) pc.printf("%s\n", cwd); +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) { - pc.printf("%12s", p->d_name); + int pad = 20 - strlen(p->d_name); + while (pad-- > 0) fputc(' ', stdout); + fputs(p->d_name, stdout); if (count++ >= 3) { count = 0; - pc.printf("\n"); + fputc('\n', stdout); } } - pc.printf("\n"); + fputc('\n', stdout); if (count < 3) - pc.printf("\n"); + fputc('\n', stdout); closedir(d); + status = 0; } else { - pc.printf("%s: No such directory\n", path); + fputs(path, stdout); + fputs(": No such directory\n", stdout); + status = 1; } + + return status; } /** cd * changes current working directory */ -void cd(char *path) { +int docd(char *arg) { + + resolveDirectory(path, arg); strcpy(cwd, path); + + return 0; } /** pwd * print current working directory */ -void pwd() { - pc.printf("%s\n", cwd); +int dopwd(char *arg) { + fputs(cwd, stdout); + fputc('\n', stdout); + //fprintf(stdout, "%s\n", cwd); + + return 0; } /** touch * create an empty file */ -void touch(char *path) { +int dotouch(char *arg) { FILE *fp; + + resolveDirectory(path, arg); if ((fp = fopen(path, "w")) != NULL) { fclose(fp); + status = 0; } else { - pc.printf("%s: No such file\n", path); + 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 */ -void head(char *path) { +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); - pc.printf("%s", buf); + fputs(buf, stdout); } fclose(fp); + status = 0; } else { - pc.printf("%s: No such file\n", path); + fputs(path, stdout); + fputs(": No such file\n", stdout); + status = 1; } + + return status; } /** cat * display the content of a file */ -void cat(char *path) { +int docat(char *arg) { FILE *fp; + resolveDirectory(path, arg); if ((fp = fopen(path, "r")) != NULL) { - while (!feof(fp)) { - if (fgets(buf, 127, fp) != NULL) - pc.printf("%s", buf); + while (fgets(buf, 127, fp)) { + fputs(buf, stdout); } fclose(fp); + status = 0; } else { - pc.printf("%s: No such file\n", path); + fputs(path, stdout); + fputs(": No such file\n", stdout); + status = 1; } + + return status; } /** send @@ -314,20 +391,136 @@ * Initiates escape sequence: ^A^B, sends filename, ^C, and then file * contents followed by ^D */ -void send(char *path) { +int dosend(char *arg) { FILE *fp; char dirname[32], basename[16]; + resolveDirectory(path, arg); if ((fp = fopen(path, "r")) != NULL) { splitName(path, dirname, basename); - pc.printf("%c%c%s%c", 1, 2, basename, 3); + fputc(0x01, stdout); + fputc(0x02, stdout); + fputs(basename, stdout); + fputc(0x03, stdout); while (!feof(fp)) { if (fgets(buf, 127, fp) != NULL) - pc.printf("%s", buf); + fputs(buf, stdout); } fclose(fp); - pc.printf("%c", 4); + fputc(0x04, stdout); + status = 0; } else { - pc.printf("%s: No such file\n", path); + 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