]> Pileus Git - ~andy/csm213a-hw/blobdiff - hw2/control.c
Make control script more configurable
[~andy/csm213a-hw] / hw2 / control.c
index bae3e98fdda288b459f53d54166b929b4df71541..09694bb52ac5ea7bb5990d9f3b52eb6b306cc00a 100644 (file)
@@ -3,9 +3,30 @@
 #include <string.h>
 
 #include <time.h>
+#include <getopt.h>
 
 #include "messages.h"
 
+// Options
+char    *opt_tty;
+int      opt_pretend;
+int      opt_verbose;
+
+int      opt_device;
+ntime_t  opt_world;
+ntime_t  opt_start;
+ntime_t  opt_period;
+int      opt_relay;
+int      opt_sync;
+
+// Helper functions
+uint64_t ipow(int i) {
+       int num = 1;
+       while (i-- > 0)
+               num *= 10;
+       return num;
+}
+
 void error(char *msg)
 {
        printf("Error: %s\n", msg);
@@ -21,22 +42,101 @@ void dump(const char *label, uint8_t *data, int len)
        printf("\n");
 }
 
-int main(int argc, char **argv)
+ntime_t gettime(const char *str)
 {
-       if (argc < 3)
-               error("usage: control /dev/ttyACM0 0 sync");
+       ntime_t time = {};
+       int start, end;
+       sscanf(str, "%u.%n%u%n", &time.seconds, &start, &time.nanosec, &end);
+       time.nanosec *= ipow(9-(end-start));
+       return time;
+}
 
-       // Parse args
-       char *opt_tty    = argv[1];
-       int   opt_device = atoi(argv[2]);
-       int   opt_sync   = argv[3] && !strcmp(argv[3], "sync") ?
-                          MSG_CTL_VALID_SYNC : 0;
-       int   opt_relay  = opt_device == 2;
+void usage(void)
+{
+       printf("usage: control [OPTIONS] [TTY]\n");
+       printf("\n");
+       printf("Options:\n");
+       printf("  -d,--device=id     mbed Device ID\n");
+       printf("  -w,--world=time    initial world time\n");
+       printf("  -s,--start=time    emit start time\n");
+       printf("  -p,--period=time   emit period\n");
+       printf("  -r,--relay         enable relay mode\n");
+       printf("  -y,--sync          enable time sync\n");
+       printf("  -n,--pretend       do not send message\n");
+       printf("  -v,--verbose       print debug messages\n");
+       printf("  -h,--help          print this usage\n");
+}
 
-       // Lookup current wall-clock time
+// Argument parsing
+void parse(int argc, char **argv)
+{
+       // Get timestamp
        struct timespec ts;
        clock_gettime(CLOCK_REALTIME, &ts);
 
+       // Default arguments;
+       opt_tty    = "/dev/ttyACM0";
+       opt_device = 1;
+       opt_world  = (ntime_t){ts.tv_sec, ts.tv_nsec};
+       opt_start  = (ntime_t){0, 0};
+       opt_period = (ntime_t){1, 0};
+
+       // Long options
+       struct option long_options[] = {
+               {"device",  required_argument },
+               {"world",   required_argument },
+               {"start",   required_argument },
+               {"period",  required_argument },
+               {"relay",   no_argument       },
+               {"sync",    no_argument       },
+               {"pretend", no_argument       },
+               {"verbose", no_argument       },
+               {"help",    no_argument       },
+               {0,         0                 },
+       };
+
+       // Run parser
+       while (1) {
+               int opt = getopt_long(argc, argv, "d:w:s:p:rynvh", long_options, 0);
+               if (opt == -1)
+                       break;
+               switch (opt) {
+                       case 'd': opt_device  = atoi(optarg);    break;
+                       case 'w': opt_world   = gettime(optarg); break;
+                       case 's': opt_start   = gettime(optarg); break;
+                       case 'p': opt_period  = gettime(optarg); break;
+                       case 'r': opt_relay   = 1; break;
+                       case 'y': opt_sync    = 1; break;
+                       case 'n': opt_pretend = 1; break;
+                       case 'v': opt_verbose++;   break;
+                       case 'h': usage(); exit(0); break;
+                       default:  usage(); exit(1); break;
+               }
+       }
+       if (optind < argc)
+               opt_tty = argv[optind];
+}
+
+// Main
+int main(int argc, char **argv)
+{
+       // Lookup current wall-clock time
+       parse(argc, argv);
+
+       // Debug output
+       if (opt_verbose) {
+               printf("options:\n");
+               printf("    tty     = %s\n",      opt_tty);
+               printf("    device  = %d\n",      opt_device);
+               printf("    world   = %d.%09u\n", opt_world.seconds,   opt_world.nanosec);
+               printf("    start   = %d.%09u\n", opt_start.seconds,   opt_start.nanosec);
+               printf("    period  = %d.%09u\n", opt_period.seconds,  opt_period.nanosec);
+               printf("    relay   = %s\n",      opt_relay    ? "true" : "false");
+               printf("    sync    = %s\n",      opt_sync     ? "true" : "false");
+               printf("    pretend = %s\n",      opt_pretend  ? "true" : "false");
+               printf("    verbose = %s\n",      opt_verbose  ? "true" : "false");
+       }
+
        // Message buffers
        header_t   head = {};
        init_msg_t body = {};
@@ -52,32 +152,31 @@ int main(int argc, char **argv)
                     | MSG_CTL_VALID_START
                     | MSG_CTL_VALID_PERIOD
                     | MSG_CTL_VALID_WORLD
-                    | opt_relay
-                    | opt_sync;
-
-       // Set message body
-       body.device         = opt_device;
-       body.world.seconds  = ts.tv_sec;
-       body.world.nanosec  = ts.tv_nsec;
-       body.start.seconds  = ts.tv_sec;
-       body.start.nanosec  = 0; //ts.tv_nsec;
-       body.period.seconds = 0;
-       body.period.nanosec =  100000000;
-       //                  [s][m][u][n]
+                    | (opt_relay ? MSG_CTL_RELAY_MODE : 0)
+                    | (opt_sync  ? MSG_CTL_BEGIN_SYNC : 0);
+
+       body.device  = opt_device;
+       body.world   = opt_world;
+       body.start   = opt_start;
+       body.period  = opt_period;
 
        // Transmit message
        FILE *fd = fopen(opt_tty, "a+");
        if (!fd) error("opening device");
        int len = 0;
-       len += fwrite(&head, 1, sizeof(head), fd);
-       len += fwrite(&body, 1, sizeof(body), fd);
+       if (!opt_pretend) {
+               len += fwrite(&head, 1, sizeof(head), fd);
+               len += fwrite(&body, 1, sizeof(body), fd);
+       }
        fclose(fd);
+       if (opt_verbose > 2)
+               printf("wrote %d bytes\n", len);
 
        // Debug output
-       dump("head", (uint8_t*)&head, sizeof(head));
-       dump("body", (uint8_t*)&body, sizeof(body));
-
-       printf("wrote %d bytes\n", len);
+       if (opt_verbose > 2) {
+               dump("head", (uint8_t*)&head, sizeof(head));
+               dump("body", (uint8_t*)&body, sizeof(body));
+       }
 
        return 0;
 }