]> Pileus Git - ~andy/csm213a-hw/blob - hw2/control.c
Make control script more configurable
[~andy/csm213a-hw] / hw2 / control.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include <time.h>
6 #include <getopt.h>
7
8 #include "messages.h"
9
10 // Options
11 char    *opt_tty;
12 int      opt_pretend;
13 int      opt_verbose;
14
15 int      opt_device;
16 ntime_t  opt_world;
17 ntime_t  opt_start;
18 ntime_t  opt_period;
19 int      opt_relay;
20 int      opt_sync;
21
22 // Helper functions
23 uint64_t ipow(int i) {
24         int num = 1;
25         while (i-- > 0)
26                 num *= 10;
27         return num;
28 }
29
30 void error(char *msg)
31 {
32         printf("Error: %s\n", msg);
33         exit(0);
34 }
35
36 void dump(const char *label, uint8_t *data, int len)
37 {
38         int i;
39         printf("%s: ", label);
40         for (i = 0; i < len; i++)
41                 printf("%02hhx ", data[i]);
42         printf("\n");
43 }
44
45 ntime_t gettime(const char *str)
46 {
47         ntime_t time = {};
48         int start, end;
49         sscanf(str, "%u.%n%u%n", &time.seconds, &start, &time.nanosec, &end);
50         time.nanosec *= ipow(9-(end-start));
51         return time;
52 }
53
54 void usage(void)
55 {
56         printf("usage: control [OPTIONS] [TTY]\n");
57         printf("\n");
58         printf("Options:\n");
59         printf("  -d,--device=id     mbed Device ID\n");
60         printf("  -w,--world=time    initial world time\n");
61         printf("  -s,--start=time    emit start time\n");
62         printf("  -p,--period=time   emit period\n");
63         printf("  -r,--relay         enable relay mode\n");
64         printf("  -y,--sync          enable time sync\n");
65         printf("  -n,--pretend       do not send message\n");
66         printf("  -v,--verbose       print debug messages\n");
67         printf("  -h,--help          print this usage\n");
68 }
69
70 // Argument parsing
71 void parse(int argc, char **argv)
72 {
73         // Get timestamp
74         struct timespec ts;
75         clock_gettime(CLOCK_REALTIME, &ts);
76
77         // Default arguments;
78         opt_tty    = "/dev/ttyACM0";
79         opt_device = 1;
80         opt_world  = (ntime_t){ts.tv_sec, ts.tv_nsec};
81         opt_start  = (ntime_t){0, 0};
82         opt_period = (ntime_t){1, 0};
83
84         // Long options
85         struct option long_options[] = {
86                 {"device",  required_argument },
87                 {"world",   required_argument },
88                 {"start",   required_argument },
89                 {"period",  required_argument },
90                 {"relay",   no_argument       },
91                 {"sync",    no_argument       },
92                 {"pretend", no_argument       },
93                 {"verbose", no_argument       },
94                 {"help",    no_argument       },
95                 {0,         0                 },
96         };
97
98         // Run parser
99         while (1) {
100                 int opt = getopt_long(argc, argv, "d:w:s:p:rynvh", long_options, 0);
101                 if (opt == -1)
102                         break;
103                 switch (opt) {
104                         case 'd': opt_device  = atoi(optarg);    break;
105                         case 'w': opt_world   = gettime(optarg); break;
106                         case 's': opt_start   = gettime(optarg); break;
107                         case 'p': opt_period  = gettime(optarg); break;
108                         case 'r': opt_relay   = 1; break;
109                         case 'y': opt_sync    = 1; break;
110                         case 'n': opt_pretend = 1; break;
111                         case 'v': opt_verbose++;   break;
112                         case 'h': usage(); exit(0); break;
113                         default:  usage(); exit(1); break;
114                 }
115         }
116         if (optind < argc)
117                 opt_tty = argv[optind];
118 }
119
120 // Main
121 int main(int argc, char **argv)
122 {
123         // Lookup current wall-clock time
124         parse(argc, argv);
125
126         // Debug output
127         if (opt_verbose) {
128                 printf("options:\n");
129                 printf("    tty     = %s\n",      opt_tty);
130                 printf("    device  = %d\n",      opt_device);
131                 printf("    world   = %d.%09u\n", opt_world.seconds,   opt_world.nanosec);
132                 printf("    start   = %d.%09u\n", opt_start.seconds,   opt_start.nanosec);
133                 printf("    period  = %d.%09u\n", opt_period.seconds,  opt_period.nanosec);
134                 printf("    relay   = %s\n",      opt_relay    ? "true" : "false");
135                 printf("    sync    = %s\n",      opt_sync     ? "true" : "false");
136                 printf("    pretend = %s\n",      opt_pretend  ? "true" : "false");
137                 printf("    verbose = %s\n",      opt_verbose  ? "true" : "false");
138         }
139
140         // Message buffers
141         header_t   head = {};
142         init_msg_t body = {};
143
144         // Set message header
145         head.header  = MSG_HEADER;
146         head.msgid   = MSG_ID_INIT;
147         head.length  = sizeof(init_msg_t);
148         head.cksum   = 0; // todo
149
150         // Set valid flags
151         body.control = MSG_CTL_VALID_DEVICE
152                      | MSG_CTL_VALID_START
153                      | MSG_CTL_VALID_PERIOD
154                      | MSG_CTL_VALID_WORLD
155                      | (opt_relay ? MSG_CTL_RELAY_MODE : 0)
156                      | (opt_sync  ? MSG_CTL_BEGIN_SYNC : 0);
157
158         body.device  = opt_device;
159         body.world   = opt_world;
160         body.start   = opt_start;
161         body.period  = opt_period;
162
163         // Transmit message
164         FILE *fd = fopen(opt_tty, "a+");
165         if (!fd) error("opening device");
166         int len = 0;
167         if (!opt_pretend) {
168                 len += fwrite(&head, 1, sizeof(head), fd);
169                 len += fwrite(&body, 1, sizeof(body), fd);
170         }
171         fclose(fd);
172         if (opt_verbose > 2)
173                 printf("wrote %d bytes\n", len);
174
175         // Debug output
176         if (opt_verbose > 2) {
177                 dump("head", (uint8_t*)&head, sizeof(head));
178                 dump("body", (uint8_t*)&body, sizeof(body));
179         }
180
181         return 0;
182 }