2 * refclock_nmea.c - clock driver for an NMEA GPS CLOCK
3 * Michael Petry Jun 20, 1994
4 * based on refclock_heathn.c
10 #if defined(REFCLOCK) && defined(CLOCK_NMEA)
17 #include "ntp_unixtime.h"
18 #include "ntp_refclock.h"
19 #include "ntp_stdlib.h"
22 # include "ppsapi_timepps.h"
23 #endif /* HAVE_PPSAPI */
26 extern int async_write(int, const void *, unsigned int);
28 #define write(fd, data, octets) async_write(fd, data, octets)
32 * This driver supports the NMEA GPS Receiver with
34 * Protype was refclock_trak.c, Thanks a lot.
36 * The receiver used spits out the NMEA sentences for boat navigation.
37 * And you thought it was an information superhighway. Try a raging river
38 * filled with rapids and whirlpools that rip away your data and warp time.
40 * If HAVE_PPSAPI is defined code to use the PPSAPI will be compiled in.
41 * On startup if initialization of the PPSAPI fails, it will fall back
42 * to the "normal" timestamps.
44 * The PPSAPI part of the driver understands fudge flag2 and flag3. If
45 * flag2 is set, it will use the clear edge of the pulse. If flag3 is
46 * set, kernel hardpps is enabled.
48 * GPS sentences other than RMC (the default) may be enabled by setting
49 * the relevent bits of 'mode' in the server configuration line
50 * server 127.127.20.x mode X
52 * bit 0 - enables RMC (1)
53 * bit 1 - enables GGA (2)
54 * bit 2 - enables GLL (4)
55 * multiple sentences may be selected
62 # define DEVICE "COM%d:" /* COM 1 - 3 supported */
64 # define DEVICE "/dev/gps%d" /* name of radio device */
66 #define SPEED232 B4800 /* uart speed (4800 bps) */
67 #define PRECISION (-9) /* precision assumed (about 2 ms) */
68 #define PPS_PRECISION (-20) /* precision assumed (about 1 us) */
69 #define REFID "GPS\0" /* reference id */
70 #define DESCRIPTION "NMEA GPS Clock" /* who we are */
71 #define NANOSECOND 1000000000 /* one second (ns) */
72 #define RANGEGATE 500000 /* range gate (ns) */
74 #define LENNMEA 75 /* min timecode length */
77 * Tables to compute the ddd of year form icky dd/mm timecode. Viva la
80 static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
81 static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
84 * Unit control structure
87 int pollcnt; /* poll message counter */
88 int polled; /* Hand in a sample? */
89 l_fp tstamp; /* timestamp of last poll */
91 struct timespec ts; /* last timestamp */
92 pps_params_t pps_params; /* pps parameters */
93 pps_info_t pps_info; /* last pps data */
94 pps_handle_t handle; /* pps handlebars */
95 #endif /* HAVE_PPSAPI */
101 static int nmea_start P((int, struct peer *));
102 static void nmea_shutdown P((int, struct peer *));
104 static void nmea_control P((int, struct refclockstat *, struct
105 refclockstat *, struct peer *));
106 static int nmea_ppsapi P((struct peer *, int, int));
107 static int nmea_pps P((struct nmeaunit *, l_fp *));
108 #endif /* HAVE_PPSAPI */
109 static void nmea_receive P((struct recvbuf *));
110 static void nmea_poll P((int, struct peer *));
111 static void gps_send P((int, const char *, struct peer *));
112 static char *field_parse P((char *, int));
117 struct refclock refclock_nmea = {
118 nmea_start, /* start up driver */
119 nmea_shutdown, /* shut down driver */
120 nmea_poll, /* transmit poll message */
122 nmea_control, /* fudge control */
124 noentry, /* fudge control */
125 #endif /* HAVE_PPSAPI */
126 noentry, /* initialize driver */
127 noentry, /* buginfo */
128 NOFLAGS /* not used */
132 * nmea_start - open the GPS devices and initialize data for processing
140 register struct nmeaunit *up;
141 struct refclockproc *pp;
146 * Open serial port. Use CLK line discipline, if available.
148 (void)sprintf(device, DEVICE, unit);
150 fd = refclock_open(device, SPEED232, LDISC_CLK);
153 /* nmead support added by Jon Miner (cp_n18@yahoo.com)
155 * See http://home.hiwaay.net/~taylorc/gps/nmea-server/
156 * for information about nmead
158 * To use this, you need to create a link from /dev/gpsX to
159 * the server:port where nmead is running. Something like this:
161 * ln -s server:port /dev/gps1
169 struct sockaddr_in so_addr;
171 if ((len = readlink(device,buffer,sizeof(buffer))) == -1)
175 if ((nmea_host = strtok(buffer,":")) == NULL)
178 nmea_port = atoi(strtok(NULL,":"));
180 if ((he = gethostbyname(nmea_host)) == NULL)
182 if ((p = getprotobyname("ip")) == NULL)
184 so_addr.sin_family = AF_INET;
185 so_addr.sin_port = htons(nmea_port);
186 so_addr.sin_addr = *((struct in_addr *) he->h_addr);
188 if ((fd = socket(PF_INET,SOCK_STREAM,p->p_proto)) == -1)
190 if (connect(fd,(struct sockaddr *)&so_addr,SOCKLEN(&so_addr)) == -1) {
200 * Allocate and initialize unit structure
202 up = (struct nmeaunit *)emalloc(sizeof(struct nmeaunit));
207 memset((char *)up, 0, sizeof(struct nmeaunit));
209 pp->io.clock_recv = nmea_receive;
210 pp->io.srcclock = (caddr_t)peer;
213 if (!io_addclock(&pp->io)) {
218 pp->unitptr = (caddr_t)up;
221 * Initialize miscellaneous variables
223 peer->precision = PRECISION;
224 pp->clockdesc = DESCRIPTION;
225 memcpy((char *)&pp->refid, REFID, 4);
227 gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer);
231 * Start the PPSAPI interface if it is there. Default to use
232 * the assert edge and do not enable the kernel hardpps.
234 if (time_pps_create(fd, &up->handle) < 0) {
237 "refclock_nmea: time_pps_create failed: %m");
240 return(nmea_ppsapi(peer, 0, 0));
243 #endif /* HAVE_PPSAPI */
247 * nmea_shutdown - shut down a GPS clock
255 register struct nmeaunit *up;
256 struct refclockproc *pp;
259 up = (struct nmeaunit *)pp->unitptr;
262 time_pps_destroy(up->handle);
263 #endif /* HAVE_PPSAPI */
264 io_closeclock(&pp->io);
270 * nmea_control - fudge control
274 int unit, /* unit (not used */
275 struct refclockstat *in, /* input parameters (not uded) */
276 struct refclockstat *out, /* output parameters (not used) */
277 struct peer *peer /* peer structure pointer */
280 struct refclockproc *pp;
283 nmea_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2,
284 pp->sloppyclockflag & CLK_FLAG3);
293 struct peer *peer, /* peer structure pointer */
294 int enb_clear, /* clear enable */
295 int enb_hardpps /* hardpps enable */
298 struct refclockproc *pp;
303 up = (struct nmeaunit *)pp->unitptr;
304 if (time_pps_getcap(up->handle, &capability) < 0) {
306 "refclock_nmea: time_pps_getcap failed: %m");
309 memset(&up->pps_params, 0, sizeof(pps_params_t));
311 up->pps_params.mode = capability & PPS_CAPTURECLEAR;
313 up->pps_params.mode = capability & PPS_CAPTUREASSERT;
314 if (!up->pps_params.mode) {
316 "refclock_nmea: invalid capture edge %d",
320 up->pps_params.mode |= PPS_TSFMT_TSPEC;
321 if (time_pps_setparams(up->handle, &up->pps_params) < 0) {
323 "refclock_nmea: time_pps_setparams failed: %m");
327 if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS,
328 up->pps_params.mode & ~PPS_TSFMT_TSPEC,
329 PPS_TSFMT_TSPEC) < 0) {
331 "refclock_nmea: time_pps_kcbind failed: %m");
336 peer->precision = PPS_PRECISION;
340 time_pps_getparams(up->handle, &up->pps_params);
342 "refclock_ppsapi: capability 0x%x version %d mode 0x%x kern %d\n",
343 capability, up->pps_params.api_version,
344 up->pps_params.mode, enb_hardpps);
352 * Get PPSAPI timestamps.
354 * Return 0 on failure and 1 on success.
363 struct timespec timeout, ts;
368 * Convert the timespec nanoseconds field to ntp l_fp units.
374 memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
375 if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info,
378 if (up->pps_params.mode & PPS_CAPTUREASSERT) {
379 if (pps_info.assert_sequence ==
380 up->pps_info.assert_sequence)
382 ts = up->pps_info.assert_timestamp;
383 } else if (up->pps_params.mode & PPS_CAPTURECLEAR) {
384 if (pps_info.clear_sequence ==
385 up->pps_info.clear_sequence)
387 ts = up->pps_info.clear_timestamp;
391 if ((up->ts.tv_sec == ts.tv_sec) && (up->ts.tv_nsec == ts.tv_nsec))
395 tstmp.l_ui = ts.tv_sec + JAN_1970;
396 dtemp = ts.tv_nsec * FRAC / 1e9;
397 tstmp.l_uf = (u_int32)dtemp;
401 #endif /* HAVE_PPSAPI */
404 * nmea_receive - receive data from the serial interface
408 struct recvbuf *rbufp
411 register struct nmeaunit *up;
412 struct refclockproc *pp;
418 /* Use these variables to hold data until we decide its worth keeping */
419 char rd_lastcode[BMAX];
424 * Initialize pointers and read the timecode and timestamp
426 peer = (struct peer *)rbufp->recv_srcclock;
428 up = (struct nmeaunit *)pp->unitptr;
429 rd_lencode = (u_short)refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
432 * There is a case that a <CR><LF> gives back a "blank" line
439 printf("nmea: gpsread %d %s\n", rd_lencode,
444 * We check the timecode format and decode its contents. The
445 * we only care about a few of them. The most important being
447 * $GPRMC,hhmmss,a,fddmm.xx,n,dddmmm.xx,w,zz.z,yyy.,ddmmyy,dd,v*CC
448 * For Magellan (ColorTrak) GLL probably datum (order of sentences)
449 * also mode (0,1,2,3) select sentence ANY/ALL, RMC, GGA, GLL
450 * $GPGLL,3513.8385,S,14900.7851,E,232420.594,A*21
451 * $GPGGA,232420.59,3513.8385,S,14900.7851,E,1,05,3.4,00519,M,,,,*3F
453 * $GPRMC,232418.19,A,3513.8386,S,14900.7853,E,00.0,000.0,121199,12.,E*77
465 if(strncmp(cp,"$GPRMC",6)==0) {
468 else if(strncmp(cp,"$GPGGA",6)==0) {
471 else if(strncmp(cp,"$GPGLL",6)==0) {
474 else if(strncmp(cp,"$GPXXX",6)==0) {
481 /* See if I want to process this message type */
482 if ( ((peer->ttl == 0) && (cmdtype != GPRMC))
483 || ((peer->ttl != 0) && !(cmdtype & peer->ttl)) )
486 pp->lencode = rd_lencode;
487 strcpy(pp->a_lastcode,rd_lastcode);
490 pp->lastrec = up->tstamp = rd_tmp;
495 printf("nmea: timecode %d %s\n", pp->lencode,
500 /* Grab field depending on clock string type */
504 * Test for synchronization. Check for quality byte.
506 dp = field_parse(cp,2);
508 pp->leap = LEAP_NOTINSYNC;
510 pp->leap = LEAP_NOWARNING;
512 /* Now point at the time field */
513 dp = field_parse(cp,1);
519 * Test for synchronization. Check for quality byte.
521 dp = field_parse(cp,6);
523 pp->leap = LEAP_NOTINSYNC;
525 pp->leap = LEAP_NOWARNING;
527 /* Now point at the time field */
528 dp = field_parse(cp,1);
534 * Test for synchronization. Check for quality byte.
536 dp = field_parse(cp,6);
538 pp->leap = LEAP_NOTINSYNC;
540 pp->leap = LEAP_NOWARNING;
542 /* Now point at the time field */
543 dp = field_parse(cp,5);
555 * Check time code format of NMEA
558 if( !isdigit((int)dp[0]) ||
559 !isdigit((int)dp[1]) ||
560 !isdigit((int)dp[2]) ||
561 !isdigit((int)dp[3]) ||
562 !isdigit((int)dp[4]) ||
565 refclock_report(peer, CEVNT_BADREPLY);
571 * Convert time and check values.
573 pp->hour = ((dp[0] - '0') * 10) + dp[1] - '0';
574 pp->minute = ((dp[2] - '0') * 10) + dp[3] - '0';
575 pp->second = ((dp[4] - '0') * 10) + dp[5] - '0';
576 /* Default to 0 milliseconds, if decimal convert milliseconds in
577 one, two or three digits
581 if (isdigit((int)dp[7])) {
582 pp->nsec = (dp[7] - '0') * 100000000;
583 if (isdigit((int)dp[8])) {
584 pp->nsec += (dp[8] - '0') * 10000000;
585 if (isdigit((int)dp[9])) {
586 pp->nsec += (dp[9] - '0') * 1000000;
592 if (pp->hour > 23 || pp->minute > 59 || pp->second > 59
593 || pp->nsec > 1000000000) {
594 refclock_report(peer, CEVNT_BADTIME);
600 * Convert date and check values.
602 if (cmdtype==GPRMC) {
603 dp = field_parse(cp,9);
605 day = (day * 10) + dp[1] - '0';
607 month = (month * 10) + dp[3] - '0';
608 pp->year = dp[4] - '0';
609 pp->year = (pp->year * 10) + dp[5] - '0';
613 time_t tt = time(NULL);
614 struct tm * t = gmtime(&tt);
616 month = t->tm_mon + 1;
617 pp->year= t->tm_year;
620 if (month < 1 || month > 12 || day < 1) {
621 refclock_report(peer, CEVNT_BADTIME);
625 /* Hmmmm this will be a nono for 2100,2200,2300 but I don't think I'll be here */
626 /* good thing that 2000 is a leap year */
627 /* pp->year will be 00-99 if read from GPS, 00-> (years since 1900) from tm_year */
629 if (day > day1tab[month - 1]) {
630 refclock_report(peer, CEVNT_BADTIME);
633 for (i = 0; i < month - 1; i++)
636 if (day > day2tab[month - 1]) {
637 refclock_report(peer, CEVNT_BADTIME);
640 for (i = 0; i < month - 1; i++)
648 * If the PPSAPI is working, rather use its timestamps.
649 * assume that the PPS occurs on the second so blow any msec
651 if (nmea_pps(up, &rd_tmp) == 1) {
652 pp->lastrec = up->tstamp = rd_tmp;
655 #endif /* HAVE_PPSAPI */
658 * Process the new sample in the median filter and determine the
659 * reference clock offset and dispersion. We use lastrec as both
660 * the reference time and receive time, in order to avoid being
661 * cute, like setting the reference time later than the receive
662 * time, which may cause a paranoid protocol module to chuck out
666 if (!refclock_process(pp)) {
667 refclock_report(peer, CEVNT_BADTIME);
674 * Only go on if we had been polled.
679 pp->lastref = pp->lastrec;
680 refclock_receive(peer);
682 /* If we get here - what we got from the clock is OK, so say so */
683 refclock_report(peer, CEVNT_NOMINAL);
685 record_clock_stats(&peer->srcadr, pp->a_lastcode);
690 * nmea_poll - called by the transmit procedure
692 * We go to great pains to avoid changing state here, since there may be
693 * more than one eavesdropper receiving the same timecode.
701 register struct nmeaunit *up;
702 struct refclockproc *pp;
705 up = (struct nmeaunit *)pp->unitptr;
706 if (up->pollcnt == 0)
707 refclock_report(peer, CEVNT_TIMEOUT);
714 * usually nmea_receive can get a timestamp every second
717 gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer);
722 * gps_send(fd,cmd, peer) Sends a command to the GPS receiver.
723 * as gps_send(fd,"rqts,u\r", peer);
725 * We don't currently send any data, but would like to send
726 * RTCM SC104 messages for differential positioning. It should
727 * also give us better time. Without a PPS output, we're
728 * Just fooling ourselves because of the serial code paths
739 if (write(fd, cmd, strlen(cmd)) == -1) {
740 refclock_report(peer, CEVNT_FAULT);
753 for (tp = cp; *tp != '\0'; tp++) {
762 int refclock_nmea_bs;
763 #endif /* REFCLOCK */