Hello, I have a GPS device connected to a serial port. It defaults to 9600bps NMEA messages, but I need to switch it to 4800bps. There are NMEA commands for this, and I can properly do this using cu(1).
Now I'm trying to write a program to do this at boot time. First I need to determine if the GPS is outputting at 4800 or 9600bps (the CPU may be rebooted, or even powered off wihout resetting the GPS module). I wrote the attached C program, but the cfsetspeed() doesn't seem to have any effect: with the GPS running at 9600bps, if I start with the tty set to 9600 (for example from a previous cu(1) run) I get proper NMEA sentences on both check_term() calls, and if I start with the tty set to 4800 (e.g. from a previous cu(1) run) I get either nothing or garbage (not getting anything from the tty is a valid case, as the tty is in canon mode select() will return a read event only if the serial port got something that looks like a line). Does anyone see an obvious error or something I missed ? -- Manuel Bouyer <bou...@antioche.eu.org> NetBSD: 26 ans d'experience feront toujours la difference --
#include <stdio.h> #include <stdlib.h> #include <termios.h> #include <errno.h> #include <signal.h> #include <fcntl.h> #include <sys/select.h> struct termios orig_t; int term_fd = -1; static void exit_handler(void) { if (term_fd >= 0) { tcsetattr(term_fd, TCSAFLUSH, &orig_t); } } static void sig_hanlder(int sig) { exit_handler(); exit(1); } static int check_term(int fd) { fd_set rset; struct timeval timeout; int tries = 10; int ret; char buf[100]; FILE *f = fdopen(fd, "r"); if (f == NULL) { err(EXIT_FAILURE, "fdopen() failed"); } while (tries > 0) { FD_ZERO(&rset); FD_SET(fd, &rset); timeout.tv_sec = 1; timeout.tv_usec = 0; ret = select(fd + 1, &rset, NULL, NULL, &timeout); switch(ret) { case -1: err(EXIT_FAILURE, "select() failed"); break; case 0: printf("timeout %d\n", tries); tries--; break; default: if (FD_ISSET(fd, &rset)) { if (fgets(buf, sizeof(buf), f) != NULL) { printf("got: -- %s --\n", buf); if (strncmp(buf, "$GP", 3) == 0) { return 1; } } tries--; } } } return 0; } int main(int argc, const char *argv[]) { static struct termios working_t; if (argc != 2) { fprintf(stderr, "usage: %s <tty>\n", argv[0]); exit(1); } term_fd = open(argv[1], O_RDWR, 0); if (term_fd < 0) { fprintf(stderr, "open %s: %s\n", argv[1], strerror(errno)); exit(1); } if (tcgetattr(term_fd, &orig_t) < 0) { perror("tcgetattr"); exit(1); } atexit(exit_handler); signal(SIGINT, sig_hanlder); signal(SIGTERM, sig_hanlder); working_t = orig_t; #if 0 working_t.c_iflag =~ (IGNBRK | IXON | IXOFF | IMAXBEL); working_t.c_iflag |= IGNCR; #endif working_t.c_iflag = 0; working_t.c_oflag =~ (OPOST); working_t.c_cflag =~ (CSIZE | CSTOPB | PARENB | CRTSCTS | MDMBUF); working_t.c_cflag |= CS8 | CLOCAL; working_t.c_lflag = ICANON | NOKERNINFO; again: printf("test 4800\n"); if (cfsetspeed(&working_t, B4800) != 0) err(EXIT_FAILURE, "setting speed to 4800"); if (tcsetattr(term_fd, TCSAFLUSH, &working_t) != 0) { perror("tcsetattr 1"); exit(1); } if (check_term(term_fd)) { printf("already at 4800\n"); } printf("test 9600\n"); if (cfsetspeed(&working_t, B9600) != 0) err(EXIT_FAILURE, "setting speed to 9600"); if (tcsetattr(term_fd, TCSAFLUSH, &working_t) != 0) { perror("tcsetattr 2"); exit(1); } if (check_term(term_fd)) { printf("switch to 4800\n"); } goto again; }