From 91d01c52e8c36008fbedcb1671f2b5b5ea20ac62 Mon Sep 17 00:00:00 2001 From: Pascal Martin Date: Sun, 19 Jan 2020 23:22:55 -0800 Subject: [PATCH] Set the GPS device in raw mode and no delay, to cope with different GPS receivers behavior --- Makefile | 2 +- hc_nmea.c | 20 +++++----- hc_tty.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ hc_tty.h | 24 ++++++++++++ 4 files changed, 148 insertions(+), 10 deletions(-) create mode 100644 hc_tty.c create mode 100644 hc_tty.h diff --git a/Makefile b/Makefile index 176bb2e..a6daa80 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -OBJS= hc_db.o hc_http.o hc_clock.o hc_nmea.o hc_broadcast.o hc_ntp.o houseclock.o +OBJS= hc_db.o hc_http.o hc_clock.o hc_tty.o hc_nmea.o hc_broadcast.o hc_ntp.o houseclock.o all: houseclock diff --git a/hc_nmea.c b/hc_nmea.c index 9b06ee5..1ea0405 100644 --- a/hc_nmea.c +++ b/hc_nmea.c @@ -69,8 +69,10 @@ * -gps= Name of the system device to read the NMEA data from. * -latency= Delay between the GPS fix and the 1st sentence (ms). * -burst Use burst start as the GPS fix timing reference. + * -baud= GPS line baud speed. * - * The default GPS device is /dev/ttyACM0. + * The default GPS device is /dev/ttyACM0. If no baud option is used, + * the default OS configuration is used. * * The latency depends on the GPS device. It can be estimated by using * the options -drift and -latency=0, and then estimating the average @@ -122,11 +124,11 @@ #include #include #include -#include #include "houseclock.h" #include "hc_db.h" #include "hc_clock.h" +#include "hc_tty.h" #include "hc_nmea.h" static int gpsLatency; @@ -149,6 +151,7 @@ static int gpsTty = -1; static int gpsUseBurst = 0; static int gpsPrivacy = 0; static int gpsShowNmea = 0; +static int gpsSpeed = 0; static time_t gpsInitialized = 0; @@ -157,9 +160,10 @@ static hc_nmea_status *hc_nmea_status_db = 0; const char *hc_nmea_help (int level) { static const char *nmeaHelp[] = { - " [-gps=DEV] [-latency=N] [-burst] [-privacy]", + " [-gps=DEV] [-baud=N] [-latency=N] [-burst] [-privacy]", "-gps=DEV: device from which to read the NMEA data (/dev/ttyACM0).", "-latency=N: delay between the GPS fix and the 1st NMEA sentence (70).", + "-baud=N: GPS device's baud speed (default: use OS default).", "-show-nmea: trace NMEA sentences.", "-burst: Use burst start as the GPS timing reference", "-privacy: do not export location", @@ -189,18 +193,21 @@ int hc_nmea_initialize (int argc, const char **argv) { int i; const char *latency_option = "70"; + const char *speed_option = "0"; gpsDevice = "/dev/ttyACM0"; gpsUseBurst = 0; for (i = 1; i < argc; ++i) { hc_match ("-gps=", argv[i], &gpsDevice); + hc_match ("-baud=", argv[i], &speed_option); hc_match ("-latency=", argv[i], &latency_option); if (hc_present ("-burst", argv[i])) gpsUseBurst = 1; if (hc_present ("-privacy", argv[i])) gpsPrivacy = 1; if (hc_present ("-show-nmea", argv[i])) gpsShowNmea = 1; } gpsLatency = atoi(latency_option); + gpsSpeed = atoi(speed_option); if (hc_nmea_status_db == 0) { i = hc_db_new (HC_NMEA_STATUS, sizeof(hc_nmea_status), 1); @@ -217,12 +224,7 @@ int hc_nmea_initialize (int argc, const char **argv) { // Remove echo of characters from the GPS device. if (gpsTty >= 0) { - struct termios options; - int status = tcgetattr(gpsTty, &options); - if (status == 0) { - options.c_lflag &= (~(ECHO+ECHONL)); - tcsetattr(gpsTty, TCSANOW, &options); - } + hc_tty_set (gpsTty, gpsSpeed); } gpsInitialized = time(0); diff --git a/hc_tty.c b/hc_tty.c new file mode 100644 index 0000000..8076f5f --- /dev/null +++ b/hc_tty.c @@ -0,0 +1,112 @@ +/* houseclock - A simple GPS Time Server with Web console + * + * Copyright 2019, Pascal Martin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * + * hc_tty.c - Handle setting up a TTY device. + * + * This module hides the TTY configuration's OS interface. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hc_tty.h" + +int hc_tty_set (int fd, int baud) { + + int speed; + struct termios settings; + + if (! isatty(fd)) return 0; // No need to setup anything. + + if (tcgetattr(fd,&settings) != 0) return errno; + + // Optionally set the speed (if not 0). This is mostly useless with + // current USB GPS devices, but let's still allow it for special cases. + + switch(baud) { + case 0: speed = B0; break; + case 50: speed = B50; break; + case 75: speed = B75; break; + case 110: speed = B110; break; + case 134: speed = B134; break; + case 150: speed = B150; break; + case 200: speed = B200; break; + case 300: speed = B300; break; + case 600: speed = B600; break; + case 1200: speed = B1200; break; + case 1800: speed = B1800; break; + case 2400: speed = B2400; break; + case 4800: speed = B4800; break; + case 9600: speed = B9600; break; + case 19200: speed = B19200; break; + case 38400: speed = B38400; break; + case 57600: speed = B57600; break; + case 115200: speed = B115200; break; +#ifdef B230400 + case 230400: speed = B230400; break; +#endif +#ifdef B460800 + case 460800: speed = B460800; break; +#endif +#ifdef B921600 + case 921600: speed = B921600; break; +#endif + default: speed = B4800; break; + } + + if (speed != B0) { + cfsetispeed(&settings, speed); + cfsetospeed(&settings, speed); + } + + // Set the TTY as raw & non-blocking, 8 bits no parity, 1 stop bit, + // and VMIN = 0 and VTIME = 0 (return NMEA data as soon as received, + // so that the timing calculations means something). + + memset(settings.c_cc, 0, sizeof(settings.c_cc)); + + settings.c_iflag = settings.c_oflag = settings.c_lflag = 0; + + settings.c_cflag &= ~(CSTOPB | PARENB | PARODD | CRTSCTS | CSIZE); + settings.c_cflag |= (CREAD | CLOCAL | CS8); + + if (tcsetattr(fd, TCSANOW, &settings) != 0) return errno; + if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & !O_NONBLOCK) != 0) return errno; + + tcflush(fd, TCIOFLUSH); + return 0; +} + +#ifdef TTY_TEST +int main (int argc, char **argv) { + + hc_tty_set (open (argv[1], O_RDWR|O_NONBLOCK|O_NOCTTY), 4800); + + // Just wait until killed. + for (;;) sleep(1); +} +#endif + diff --git a/hc_tty.h b/hc_tty.h new file mode 100644 index 0000000..6e76008 --- /dev/null +++ b/hc_tty.h @@ -0,0 +1,24 @@ +/* houseclock - A simple GPS Time Server with Web console + * + * Copyright 2019, Pascal Martin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * + * hc_tty.h - tty configuration's OS interface. + */ +int hc_tty_set (int fd, int baud); +