#include #include #include #include #include #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); exit(0); } void dump(const char *label, uint8_t *data, int len) { int i; printf("%s: ", label); for (i = 0; i < len; i++) printf("%02hhx ", data[i]); printf("\n"); } ntime_t gettime(const char *str) { 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; } 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"); } // 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 = {}; // Set message header head.header = MSG_HEADER; head.msgid = MSG_ID_INIT; head.length = sizeof(init_msg_t); head.cksum = 0; // todo // Set valid flags body.control = MSG_CTL_VALID_DEVICE | MSG_CTL_VALID_START | MSG_CTL_VALID_PERIOD | MSG_CTL_VALID_WORLD | (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; 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 if (opt_verbose > 2) { dump("head", (uint8_t*)&head, sizeof(head)); dump("body", (uint8_t*)&body, sizeof(body)); } return 0; }