Utility to set the time on a Hayes Stack Chronograph
at main 168 lines 3.8 kB view raw
1/* 2 * Copyright (c) 2021 joshua stein <jcs@jcs.org> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17#include <err.h> 18#include <errno.h> 19#include <fcntl.h> 20#include <poll.h> 21#include <stdio.h> 22#include <stdlib.h> 23#include <string.h> 24#include <termios.h> 25#include <time.h> 26#include <unistd.h> 27#include <vis.h> 28#include <sys/ioctl.h> 29#include <sys/time.h> 30#include <sys/types.h> 31 32static int debug = 0; 33static char vbuf[512]; 34static int serial_fd = -1; 35 36void usage(const char *); 37void serial_setup(int, speed_t); 38size_t serial_read(void *, size_t); 39size_t serial_write(const void *, size_t); 40 41void 42usage(const char *progname) 43{ 44 fprintf(stderr, "usage: %s [-d] [-s serial speed] <serial device>\n", 45 progname); 46 exit(1); 47} 48 49void 50serial_setup(int fd, speed_t speed) 51{ 52 struct termios tty; 53 54 if (ioctl(fd, TIOCEXCL) != 0) 55 err(1, "ioctl(TIOCEXCL)"); 56 if (tcgetattr(fd, &tty) < 0) 57 err(1, "tcgetattr"); 58 59 tty.c_cflag |= CREAD; 60 tty.c_cflag &= ~CSIZE; 61 tty.c_cflag |= CS8; /* 8-bit characters */ 62 tty.c_cflag &= ~PARENB; /* no parity bit */ 63 tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */ 64 65 /* setup for non-canonical mode */ 66 tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); 67 tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 68 tty.c_oflag &= ~OPOST; 69 70 /* fetch bytes as they become available */ 71 tty.c_cc[VMIN] = 1; 72 tty.c_cc[VTIME] = 1; 73 74 cfsetspeed(&tty, speed); 75 76 if (tcsetattr(fd, TCSAFLUSH, &tty) != 0) 77 err(1, "tcsetattr"); 78} 79 80size_t 81serial_read(void *buf, size_t nbytes) 82{ 83 size_t ret; 84 85 ret = read(serial_fd, buf, nbytes); 86 87 if (debug && ret > 0) { 88 strvisx(vbuf, buf, ret, VIS_NL | VIS_CSTYLE | VIS_OCTAL); 89 printf("<<< %s\n", vbuf); 90 } 91 92 return ret; 93} 94 95size_t 96serial_write(const void *buf, size_t nbytes) 97{ 98 if (debug) { 99 strvisx(vbuf, buf, nbytes, VIS_NL | VIS_CSTYLE | VIS_OCTAL); 100 printf(">>> %s\n", vbuf); 101 } 102 103 return write(serial_fd, buf, nbytes); 104} 105 106int 107main(int argc, char *argv[]) 108{ 109 struct timeval tp; 110 struct tm *tm; 111 char *serial_dev = NULL; 112 char buf[64]; 113 int serial_speed = B1200; 114 int ch; 115 116 if (argc == 1) 117 usage(argv[0]); 118 119 while ((ch = getopt(argc, argv, "ds:")) != -1) { 120 switch (ch) { 121 case 'd': 122 debug = 1; 123 break; 124 case 's': 125 serial_speed = (unsigned)strtol(optarg, NULL, 0); 126 if (errno) 127 err(1, "invalid serial port speed value"); 128 break; 129 default: 130 usage(argv[0]); 131 } 132 } 133 argc -= optind; 134 argv += optind; 135 136 if (argc == 0) 137 usage(argv[0]); 138 139 serial_dev = argv[0]; 140 serial_fd = open(serial_dev, O_RDWR|O_SYNC); 141 if (serial_fd < 0) 142 err(1, "open %s", serial_dev); 143 144 serial_setup(serial_fd, serial_speed); 145 146 for (;;) { 147 gettimeofday(&tp, NULL); 148 tm = localtime(&tp.tv_sec); 149 if (debug) 150 printf("currently: %02d:%02d:%02d\n", tm->tm_hour, 151 tm->tm_min, tm->tm_sec); 152 if (tm->tm_sec == 0) { 153 if (debug) 154 printf("setting chronograph to %02d%02d00\n", 155 tm->tm_hour, tm->tm_min); 156 sprintf(buf, "\rATST%02d%02d00\r", tm->tm_hour, 157 tm->tm_min); 158 serial_write(buf, strlen(buf)); 159 break; 160 } else { 161 usleep(500000); /* half a sec */ 162 } 163 } 164 165 close(serial_fd); 166 167 return 0; 168}