diff --git a/pc/Makefile b/pc/Makefile index 7fc197b..20fe01f 100644 --- a/pc/Makefile +++ b/pc/Makefile @@ -1 +1,13 @@ +CFLAGS=-Wall -Werror + all: read calibrate + +serial-util.o: serial-util.h + +read.o: serial-util.h + +calibrate.o: serial-util.h + +read: read.o serial-util.o + +calibrate: calibrate.o serial-util.o diff --git a/pc/calibrate.c b/pc/calibrate.c index 9ef6608..41f7281 100644 --- a/pc/calibrate.c +++ b/pc/calibrate.c @@ -1,18 +1,16 @@ #include #include -#include #include -#include #include #include #include #include #include #include -#include #include #include #include +#include "serial-util.h" int zoom, gpib; @@ -26,62 +24,11 @@ void handle_sig(int sig) quit = 1; } -int serial_open(const char *device, int rate) -{ - struct termios options; - struct serial_struct serinfo; - int fd; - int speed = 0; - - /* Open and configure serial port */ - if ((fd = open(device,O_RDWR|O_NOCTTY)) == -1) - err(1, "%s", device); - - switch (rate) { - case 9600: speed = B9600; break; - case 115200: speed = B115200; break; - } - - if (speed == 0) { - serinfo.reserved_char[0] = 0; - if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) - err(1, "%s: TIOCGSERIAL", device); - serinfo.flags &= ~ASYNC_SPD_MASK; - serinfo.flags |= ASYNC_SPD_CUST; - serinfo.custom_divisor = (serinfo.baud_base + (rate / 2)) / rate; - if (serinfo.custom_divisor < 1) - serinfo.custom_divisor = 1; - if (ioctl(fd, TIOCSSERIAL, &serinfo) < 0) - err(1, "%s: TIOCSSERIAL", device); - if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) - err(1, "%s: TIOCGSERIAL 2", device); - if (serinfo.custom_divisor * rate != serinfo.baud_base) { - warnx("actual baudrate is %d / %d = %f", - serinfo.baud_base, serinfo.custom_divisor, - (float)serinfo.baud_base / serinfo.custom_divisor); - } - } - - fcntl(fd, F_SETFL, 0); - tcgetattr(fd, &options); - cfsetispeed(&options, speed ?: B38400); - cfsetospeed(&options, speed ?: B38400); - cfmakeraw(&options); - options.c_cflag |= (CLOCAL | CREAD); - options.c_cflag &= ~CRTSCTS; - if (tcsetattr(fd, TCSANOW, &options) != 0) - err(1, "TCSANOW"); - - return fd; -} - int main(int argc, char *argv[]) { char *zoomdev=strdup("/dev/ttyUSB1"); char *gpibdev=strdup("/dev/ttyUSB0"); int getopt_index; - int i; - char buf[1024]; static struct option long_opts[] = { { "zoom-device", required_argument, NULL, 'z' }, @@ -92,6 +39,16 @@ int main(int argc, char *argv[]) int help=0; char c; + { + char buf[1024]; + drain(0); + fdprintf(1,"type a string in 5 sec: "); + fdgets(buf, 1024, 0, 5000); + chomp(buf); + fdprintf(1,"you typed: '%s' len %d\n", buf, strlen(buf)); + abort(); + } + while ((c = getopt_long(argc, argv, "z:g:h?", long_opts, &getopt_index)) != -1) { switch(c) diff --git a/pc/read.c b/pc/read.c index af964a4..bce1de9 100644 --- a/pc/read.c +++ b/pc/read.c @@ -1,17 +1,15 @@ #include #include -#include #include -#include #include #include #include #include #include #include -#include #include #include +#include "serial-util.h" int hex = 0; int dec = 0; @@ -21,54 +19,12 @@ int total = 0; int process(const uint8_t *buf, int len); -int serial_open(const char *device, int rate) -{ - struct termios options; - struct serial_struct serinfo; - int fd; - - /* Open and configure serial port */ - if ((fd = open(device,O_RDWR|O_NOCTTY)) == -1) - err(1, "%s", device); - - serinfo.reserved_char[0] = 0; - if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) - err(1, "%s: TIOCGSERIAL", device); - serinfo.flags &= ~ASYNC_SPD_MASK; - serinfo.flags |= ASYNC_SPD_CUST; - serinfo.custom_divisor = (serinfo.baud_base + (rate / 2)) / rate; - if (serinfo.custom_divisor < 1) - serinfo.custom_divisor = 1; - if (ioctl(fd, TIOCSSERIAL, &serinfo) < 0) - err(1, "%s: TIOCSSERIAL", device); - if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) - err(1, "%s: TIOCGSERIAL 2", device); - if (serinfo.custom_divisor * rate != serinfo.baud_base) { - warnx("actual baudrate is %d / %d = %f", - serinfo.baud_base, serinfo.custom_divisor, - (float)serinfo.baud_base / serinfo.custom_divisor); - } - - fcntl(fd, F_SETFL, 0); - tcgetattr(fd, &options); - cfsetispeed(&options, B38400); - cfsetospeed(&options, B38400); - cfmakeraw(&options); - options.c_cflag |= (CLOCAL | CREAD); - options.c_cflag &= ~CRTSCTS; - if (tcsetattr(fd, TCSANOW, &options) != 0) - err(1, "TCSANOW"); - - return fd; -} - int main(int argc, char *argv[]) { char *device=strdup("/dev/ttyUSB0"); int rate=500000; int fd; int getopt_index; - int i; char buf[1024]; int len; @@ -146,7 +102,7 @@ int main(int argc, char *argv[]) if (n <= 0) err(1, "read"); len += n; - processed = process(buf, len); + processed = process((uint8_t *) buf, len); memmove(buf, buf + processed, len - processed); len -= processed; } diff --git a/pc/serial-util.c b/pc/serial-util.c new file mode 100644 index 0000000..6d14ce1 --- /dev/null +++ b/pc/serial-util.c @@ -0,0 +1,199 @@ +/* + * Serial I/O helper routines + * + * Jim Paris + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "serial-util.h" + +static int rate_to_constant(int baudrate) { +#define B(x) case x: return B##x + switch(baudrate) { + B(50); B(75); B(110); B(134); B(150); + B(200); B(300); B(600); B(1200); B(1800); + B(2400); B(4800); B(9600); B(19200); B(38400); + B(57600); B(115200); B(230400); B(460800); B(500000); + B(576000); B(921600); B(1000000);B(1152000);B(1500000); + default: return 0; + } +#undef B +} + +/* Open serial port in raw mode, with custom baudrate if necessary */ +int serial_open(const char *device, int rate) +{ + struct termios options; + struct serial_struct serinfo; + int fd; + int speed = 0; + + /* Open and configure serial port */ + if ((fd = open(device,O_RDWR|O_NOCTTY)) == -1) + return -1; + + speed = rate_to_constant(rate); + + if (speed == 0) { + serinfo.reserved_char[0] = 0; + if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) + return -1; + serinfo.flags &= ~ASYNC_SPD_MASK; + serinfo.flags |= ASYNC_SPD_CUST; + serinfo.custom_divisor = (serinfo.baud_base + (rate / 2)) / rate; + if (serinfo.custom_divisor < 1) + serinfo.custom_divisor = 1; + if (ioctl(fd, TIOCSSERIAL, &serinfo) < 0) + return -1; + if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) + return -1; + if (serinfo.custom_divisor * rate != serinfo.baud_base) { + warnx("actual baudrate is %d / %d = %f", + serinfo.baud_base, serinfo.custom_divisor, + (float)serinfo.baud_base / serinfo.custom_divisor); + } + } + + fcntl(fd, F_SETFL, 0); + tcgetattr(fd, &options); + cfsetispeed(&options, speed ?: B38400); + cfsetospeed(&options, speed ?: B38400); + cfmakeraw(&options); + options.c_cflag |= (CLOCAL | CREAD); + options.c_cflag &= ~CRTSCTS; + if (tcsetattr(fd, TCSANOW, &options) != 0) + return -1; + + return fd; +} + +/* Like read(), but restarts after EINTR, and reads until count bytes + are received or a timeout occurs. */ +int saferead_timeout(int fd, void *buf, size_t count, int timeout_ms) +{ + struct pollfd pfd; + int r; + size_t nread = 0; + + while (count > 0) { + pfd.fd = fd; + pfd.events = POLLIN; + r = poll(&pfd, 1, timeout_ms); + if (r < 0 && errno == EINTR) /* retry */ + continue; + else if (r == 0) /* timeout */ + return nread; + else if (r == 1 && (pfd.revents & POLLIN)) { /* readable */ + r = read(fd, buf, count); + if (r < 0 && errno == EINTR) /* retry */ + continue; + if (r < 0) /* error */ + return r; + if (r == 0) /* EOF */ + return nread; + buf = (char *) buf + r; + count -= r; + nread += r; + } else { + /* error */ + return -1; + } + } + return nread; +} + +/* Like write(), but restarts after EINTR */ +ssize_t safewrite(int fd, const void *buf, size_t count) +{ + size_t nwritten = 0; + while (count > 0) { + ssize_t r = write(fd, buf, count); + + if (r < 0 && errno == EINTR) + continue; + if (r < 0) + return r; + if (r == 0) + return nwritten; + buf = (const char *)buf + r; + count -= r; + nwritten += r; + } + return nwritten; +} + +/* Read bytes until no more are available for 0.1 sec */ +int drain(int fd) +{ + char buf[1024]; + int ret; + while (1) { + ret = saferead_timeout(fd, buf, sizeof(buf), 100); + if (ret <= 0) + return ret; + } +} + +/* Like fprintf, but to a fd, using safewrite. */ +static int vfdprintf(int fd, const char *fmt, va_list args) +{ + static char buf[1024]; + vsnprintf(buf, sizeof(buf), fmt, args); + return safewrite(fd, buf, strlen(buf)); +} +int fdprintf(int fd, const char *fmt, ...) +{ + int ret; + va_list args; + va_start(args, fmt); + ret = vfdprintf(fd, fmt, args); + va_end(args); + return ret; +} + +/* Like fgets, but from a fd, using saferead_timeout. */ +char *fdgets(char *s, int size, int fd, int timeout_ms) +{ + int ret; + int nread = 0; + + /* Not very efficient, needs to read one char at a time to avoid buffering */ + while (nread < (size - 1)) { + ret = saferead_timeout(fd, &s[nread], 1, timeout_ms); + if (ret <= 0) { + s[nread] = '\0'; + return NULL; + } + if (ret == 1) { + nread++; + + /* found terminator? */ + if (s[nread-1] == '\n') + break; + } + } + s[nread] = '\0'; + return s; +} + +/* Like perl chomp. */ +void chomp(char *s) +{ + int len = strlen(s); + /* do it twice to remove \r\n as well */ + if (len > 1 && (s[len - 1] == '\r' || s[len - 1] == '\n')) s[--len] = '\0'; + if (len > 1 && (s[len - 1] == '\r' || s[len - 1] == '\n')) s[--len] = '\0'; +} diff --git a/pc/serial-util.h b/pc/serial-util.h new file mode 100644 index 0000000..82dc596 --- /dev/null +++ b/pc/serial-util.h @@ -0,0 +1,34 @@ +/* + * Serial I/O helper routines + * + * Jim Paris + * $Id$ + */ +#ifndef UTIL_H +#define UTIL_H + +#include + +/* Open serial port in raw mode, with custom baudrate if necessary */ +int serial_open(const char *device, int rate); + +/* Like read(), but restarts after EINTR, and reads until count bytes + are received or a timeout occurs. */ +int saferead_timeout(int fd, void *buf, size_t count, int timeout_ms); + +/* Like write(), but restarts after EINTR */ +ssize_t safewrite(int fd, const void *buf, size_t count); + +/* Read bytes until no more are available for 0.1 sec */ +int drain(int fd); + +/* Like fprintf, but to a fd, using safewrite */ +int fdprintf(int fd, const char *fmt, ...); + +/* Like fgets, but from a fd, using saferead_timeout. */ +char *fdgets(char *s, int size, int fd, int timeout_ms); + +/* Like perl chomp. */ +void chomp(char *s); + +#endif