tech-userlevel archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
C tty/tcsetattrs question
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 <bouyer%antioche.eu.org@localhost>
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;
}
Home |
Main Index |
Thread Index |
Old Index