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

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