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;
}

Reply via email to