1 /* $NetBSD: refclock_nmea.c,v 1.15 2024/08/18 20:47:18 christos Exp $ */
2
3 /*
4 * refclock_nmea.c - clock driver for an NMEA GPS CLOCK
5 * Michael Petry Jun 20, 1994
6 * based on refclock_heathn.c
7 *
8 * Updated to add support for Accord GPS Clock
9 * Venu Gopal Dec 05, 2007
10 * neo.venu@gmail.com, venugopal_d@pgad.gov.in
11 *
12 * Updated to process 'time1' fudge factor
13 * Venu Gopal May 05, 2008
14 *
15 * Converted to common PPSAPI code, separate PPS fudge time1
16 * from serial timecode fudge time2.
17 * Dave Hart July 1, 2009
18 * hart@ntp.org, davehart@davehart.com
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include "ntp_types.h"
26
27 #if defined(REFCLOCK) && defined(CLOCK_NMEA)
28
29 #define NMEA_WRITE_SUPPORT 0 /* no write support at the moment */
30
31 #include <sys/stat.h>
32 #include <stdio.h>
33 #include <ctype.h>
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
36 #endif
37
38 #include "ntpd.h"
39 #include "ntp_io.h"
40 #include "ntp_unixtime.h"
41 #include "ntp_refclock.h"
42 #include "ntp_stdlib.h"
43 #include "ntp_calgps.h"
44 #include "timespecops.h"
45
46 #ifdef HAVE_PPSAPI
47 # include "ppsapi_timepps.h"
48 # include "refclock_atom.h"
49 #endif /* HAVE_PPSAPI */
50
51
52 /*
53 * This driver supports NMEA-compatible GPS receivers
54 *
55 * Prototype was refclock_trak.c, Thanks a lot.
56 *
57 * The receiver used spits out the NMEA sentences for boat navigation.
58 * And you thought it was an information superhighway. Try a raging river
59 * filled with rapids and whirlpools that rip away your data and warp time.
60 *
61 * If HAVE_PPSAPI is defined code to use the PPSAPI will be compiled in.
62 * On startup if initialization of the PPSAPI fails, it will fall back
63 * to the "normal" timestamps.
64 *
65 * The PPSAPI part of the driver understands fudge flag2 and flag3. If
66 * flag2 is set, it will use the clear edge of the pulse. If flag3 is
67 * set, kernel hardpps is enabled.
68 *
69 * GPS sentences other than RMC (the default) may be enabled by setting
70 * the relevent bits of 'mode' in the server configuration line
71 * server 127.127.20.x mode X
72 *
73 * bit 0 - enables RMC (1)
74 * bit 1 - enables GGA (2)
75 * bit 2 - enables GLL (4)
76 * bit 3 - enables ZDA (8) - Standard Time & Date
77 * bit 3 - enables ZDG (8) - Accord GPS Clock's custom sentence with GPS time
78 * very close to standard ZDA
79 *
80 * Multiple sentences may be selected except when ZDG/ZDA is selected.
81 *
82 * bit 4/5/6 - selects the baudrate for serial port :
83 * 0 for 4800 (default)
84 * 1 for 9600
85 * 2 for 19200
86 * 3 for 38400
87 * 4 for 57600
88 * 5 for 115200
89 */
90 #define NMEA_MESSAGE_MASK 0x0000FF0FU
91 #define NMEA_BAUDRATE_MASK 0x00000070U
92 #define NMEA_BAUDRATE_SHIFT 4
93
94 #define NMEA_DELAYMEAS_MASK 0x00000080U
95 #define NMEA_EXTLOG_MASK 0x00010000U
96 #define NMEA_QUIETPPS_MASK 0x00020000U
97 #define NMEA_DATETRUST_MASK 0x00040000U
98 #define NMEA_IGNSTATUS_MASK 0x00080000U
99
100 #define NMEA_PROTO_IDLEN 4 /* tag name must be at least 4 chars */
101 #define NMEA_PROTO_MINLEN 6 /* min chars in sentence, excluding CS */
102 #define NMEA_PROTO_MAXLEN 80 /* max chars in sentence, excluding CS */
103 #define NMEA_PROTO_FIELDS 32 /* not official; limit on fields per record */
104
105 /*
106 * We check the timecode format and decode its contents. We only care
107 * about a few of them, the most important being the $GPRMC format:
108 *
109 * $GPRMC,hhmmss,a,fddmm.xx,n,dddmmm.xx,w,zz.z,yyy.,ddmmyy,dd,v*CC
110 *
111 * mode (0,1,2,3) selects sentence ANY/ALL, RMC, GGA, GLL, ZDA
112 * $GPGLL,3513.8385,S,14900.7851,E,232420.594,A*21
113 * $GPGGA,232420.59,3513.8385,S,14900.7851,E,1,05,3.4,00519,M,,,,*3F
114 * $GPRMC,232418.19,A,3513.8386,S,14900.7853,E,00.0,000.0,121199,12.,E*77
115 *
116 * Defining GPZDA to support Standard Time & Date
117 * sentence. The sentence has the following format
118 *
119 * $--ZDA,HHMMSS.SS,DD,MM,YYYY,TH,TM,*CS<CR><LF>
120 *
121 * Apart from the familiar fields,
122 * 'TH' Time zone Hours
123 * 'TM' Time zone Minutes
124 *
125 * Defining GPZDG to support Accord GPS Clock's custom NMEA
126 * sentence. The sentence has the following format
127 *
128 * $GPZDG,HHMMSS.S,DD,MM,YYYY,AA.BB,V*CS<CR><LF>
129 *
130 * It contains the GPS timestamp valid for next PPS pulse.
131 * Apart from the familiar fields,
132 * 'AA.BB' denotes the signal strength( should be < 05.00 )
133 * 'V' denotes the GPS sync status :
134 * '0' indicates INVALID time,
135 * '1' indicates accuracy of +/-20 ms
136 * '2' indicates accuracy of +/-100 ns
137 *
138 * Defining PGRMF for Garmin GPS Fix Data
139 * $PGRMF,WN,WS,DATE,TIME,LS,LAT,LAT_DIR,LON,LON_DIR,MODE,FIX,SPD,DIR,PDOP,TDOP
140 * WN -- GPS week number (weeks since 1980-01-06, mod 1024)
141 * WS -- GPS seconds in week
142 * LS -- GPS leap seconds, accumulated ( UTC + LS == GPS )
143 * FIX -- Fix type: 0=nofix, 1=2D, 2=3D
144 * DATE/TIME are standard date/time strings in UTC time scale
145 *
146 * The GPS time can be used to get the full century for the truncated
147 * date spec.
148 */
149
150 /*
151 * Definitions
152 */
153 #define DEVICE "/dev/gps%d" /* GPS serial device */
154 #define PPSDEV "/dev/gpspps%d" /* PPSAPI device override */
155 #define SPEED232 B4800 /* uart speed (4800 bps) */
156 #define PRECISION (-9) /* precision assumed (about 2 ms) */
157 #define PPS_PRECISION (-20) /* precision assumed (about 1 us) */
158 #define DATE_HOLD 16 /* seconds to hold on provided GPS date */
159 #define DATE_HLIM 4 /* when do we take ANY date format */
160 #define REFID "GPS\0" /* reference id */
161 #define DESCRIPTION "NMEA GPS Clock" /* who we are */
162 #ifndef O_NOCTTY
163 #define M_NOCTTY 0
164 #else
165 #define M_NOCTTY O_NOCTTY
166 #endif
167 #ifndef O_NONBLOCK
168 #define M_NONBLOCK 0
169 #else
170 #define M_NONBLOCK O_NONBLOCK
171 #endif
172 #define PPSOPENMODE (O_RDWR | M_NOCTTY | M_NONBLOCK)
173
174 /* NMEA sentence array indexes for those we use */
175 #define NMEA_GPRMC 0 /* recommended min. nav. */
176 #define NMEA_GPGGA 1 /* fix and quality */
177 #define NMEA_GPGLL 2 /* geo. lat/long */
178 #define NMEA_GPZDA 3 /* date/time */
179 /*
180 * $GPZDG is a proprietary sentence that violates the spec, by not
181 * using $P and an assigned company identifier to prefix the sentence
182 * identifier. When used with this driver, the system needs to be
183 * isolated from other NTP networks, as it operates in GPS time, not
184 * UTC as is much more common. GPS time is >15 seconds different from
185 * UTC due to not respecting leap seconds since 1970 or so. Other
186 * than the different timebase, $GPZDG is similar to $GPZDA.
187 */
188 #define NMEA_GPZDG 4
189 #define NMEA_PGRMF 5
190 #define NMEA_PUBX04 6
191 #define NMEA_ARRAY_SIZE (NMEA_PUBX04 + 1)
192
193 /*
194 * Sentence selection mode bits
195 */
196 #define USE_GPRMC 0x00000001u
197 #define USE_GPGGA 0x00000002u
198 #define USE_GPGLL 0x00000004u
199 #define USE_GPZDA 0x00000008u
200 #define USE_PGRMF 0x00000100u
201 #define USE_PUBX04 0x00000200u
202
203 /* mapping from sentence index to controlling mode bit */
204 static const u_int32 sentence_mode[NMEA_ARRAY_SIZE] =
205 {
206 USE_GPRMC,
207 USE_GPGGA,
208 USE_GPGLL,
209 USE_GPZDA,
210 USE_GPZDA,
211 USE_PGRMF,
212 USE_PUBX04
213 };
214
215 /* date formats we support */
216 enum date_fmt {
217 DATE_1_DDMMYY, /* use 1 field with 2-digit year */
218 DATE_3_DDMMYYYY /* use 3 fields with 4-digit year */
219 };
220
221 /* date type */
222 enum date_type {
223 DTYP_NONE,
224 DTYP_Y2D, /* 2-digit year */
225 DTYP_W10B, /* 10-bit week in GPS epoch */
226 DTYP_Y4D, /* 4-digit (full) year */
227 DTYP_WEXT /* extended week in GPS epoch */
228 };
229
230 /* results for 'field_init()'
231 *
232 * Note: If a checksum is present, the checksum test must pass OK or the
233 * sentence is tagged invalid.
234 */
235 #define CHECK_EMPTY -1 /* no data */
236 #define CHECK_INVALID 0 /* not a valid NMEA sentence */
237 #define CHECK_VALID 1 /* valid but without checksum */
238 #define CHECK_CSVALID 2 /* valid with checksum OK */
239
240 /*
241 * Unit control structure
242 */
243 struct refclock_atom;
244 typedef struct refclock_atom TAtomUnit;
245 typedef struct {
246 # ifdef HAVE_PPSAPI
247 TAtomUnit atom; /* PPSAPI structure */
248 int ppsapi_fd; /* fd used with PPSAPI */
249 u_char ppsapi_tried; /* attempt PPSAPI once */
250 u_char ppsapi_lit; /* time_pps_create() worked */
251 # endif /* HAVE_PPSAPI */
252 uint16_t rcvtout; /* one-shot for sample expiration */
253 u_char ppsapi_gate; /* system is on PPS */
254 u_char gps_time; /* use GPS time, not UTC */
255 l_fp last_reftime; /* last processed reference stamp */
256 TNtpDatum last_gpsdate; /* last processed split date/time */
257 u_short hold_gpsdate; /* validity ticker for above */
258 u_short type_gpsdate; /* date info type for above */
259 /* tally stats, reset each poll cycle */
260 struct
261 {
262 u_int total;
263 u_int accepted;
264 u_int rejected; /* GPS said not enough signal */
265 u_int malformed; /* Bad checksum, invalid date or time */
266 u_int filtered; /* mode bits, not GPZDG, same second */
267 u_int pps_used;
268 }
269 tally;
270 /* per sentence checksum seen flag */
271 u_char cksum_type[NMEA_ARRAY_SIZE];
272
273 /* line assembly buffer (NMEAD support) */
274 u_short lb_len;
275 char lb_buf[BMAX]; /* assembly buffer */
276 } nmea_unit;
277
278 /*
279 * helper for faster field access
280 */
281 typedef struct {
282 char *base; /* buffer base */
283 char *cptr; /* current field ptr */
284 int blen; /* buffer length */
285 int cidx; /* current field index */
286 } nmea_data;
287
288 /*
289 * Function prototypes
290 */
291 static int nmea_start (int, struct peer *);
292 static void nmea_shutdown (int, struct peer *);
293 static void nmea_receive (struct recvbuf *);
294 static void nmea_poll (int, struct peer *);
295 static void nmea_procrec (struct peer * const, l_fp);
296 #ifdef HAVE_PPSAPI
297 static double tabsdiffd (l_fp, l_fp);
298 static void nmea_control (int, const struct refclockstat *,
299 struct refclockstat *, struct peer *);
300 #define NMEA_CONTROL nmea_control
301 #else
302 #define NMEA_CONTROL noentry
303 #endif /* HAVE_PPSAPI */
304 static void nmea_timer (int, struct peer *);
305
306 /* parsing helpers */
307 static int field_init (nmea_data * data, char * cp, int len);
308 static char * field_parse (nmea_data * data, int fn);
309 static void field_wipe (nmea_data * data, ...);
310 static u_char parse_qual (nmea_data * data, int idx,
311 char tag, int inv);
312 static int parse_time (TCivilDate * jd, l_fp * fofs,
313 nmea_data *, int idx);
314 static int parse_date (TCivilDate * jd, nmea_data *,
315 int idx, enum date_fmt fmt);
316 static int parse_gpsw (TGpsDatum *, nmea_data *,
317 int weekidx, int timeidx, int leapidx);
318
319 static int nmead_open (const char * device);
320
321 /*
322 * If we want the driver to output sentences, too: re-enable the send
323 * support functions by defining NMEA_WRITE_SUPPORT to non-zero...
324 */
325 #if NMEA_WRITE_SUPPORT
326 static void gps_send(int, const char *, struct peer *);
327 #endif /* NMEA_WRITE_SUPPORT */
328
329 /*
330 * -------------------------------------------------------------------
331 * Transfer vector
332 * -------------------------------------------------------------------
333 */
334 struct refclock refclock_nmea = {
335 nmea_start, /* start up driver */
336 nmea_shutdown, /* shut down driver */
337 nmea_poll, /* transmit poll message */
338 NMEA_CONTROL, /* fudge control */
339 noentry, /* initialize driver */
340 noentry, /* buginfo */
341 nmea_timer /* called once per second */
342 };
343
344
345 /*
346 * -------------------------------------------------------------------
347 * nmea_start - open the GPS devices and initialize data for processing
348 *
349 * return 0 on error, 1 on success. Even on error the peer structures
350 * must be in a state that permits 'nmea_shutdown()' to clean up all
351 * resources, because it will be called immediately to do so.
352 * -------------------------------------------------------------------
353 */
354 static int
nmea_start(int unit,struct peer * peer)355 nmea_start(
356 int unit,
357 struct peer * peer
358 )
359 {
360 struct refclockproc * const pp = peer->procptr;
361 nmea_unit * const up = emalloc_zero(sizeof(*up));
362 char device[20];
363 size_t devlen;
364 u_int32 rate;
365 int baudrate;
366
367 /* Get baudrate choice from mode byte bits 4/5/6 */
368 rate = (peer->ttl & NMEA_BAUDRATE_MASK) >> NMEA_BAUDRATE_SHIFT;
369
370 switch (rate) {
371 default:
372 case 0:
373 baudrate = SPEED232;
374 break;
375 case 1:
376 baudrate = B9600;
377 break;
378 case 2:
379 baudrate = B19200;
380 break;
381 case 3:
382 baudrate = B38400;
383 break;
384 # ifdef B57600
385 case 4:
386 baudrate = B57600;
387 break;
388 # endif
389 # ifdef B115200
390 case 5:
391 baudrate = B115200;
392 break;
393 # endif
394 }
395
396 /* Allocate and initialize unit structure */
397 pp->unitptr = (caddr_t)up;
398 pp->io.fd = -1;
399 pp->io.clock_recv = nmea_receive;
400 pp->io.srcclock = peer;
401 pp->io.datalen = 0;
402 /* force change detection on first valid message */
403 memset(&up->last_reftime, 0xFF, sizeof(up->last_reftime));
404 memset(&up->last_gpsdate, 0x00, sizeof(up->last_gpsdate));
405 /* force checksum on GPRMC, see below */
406 up->cksum_type[NMEA_GPRMC] = CHECK_CSVALID;
407 # ifdef HAVE_PPSAPI
408 up->ppsapi_fd = -1;
409 # endif /* HAVE_PPSAPI */
410 ZERO(up->tally);
411
412 /* Initialize miscellaneous variables */
413 peer->precision = PRECISION;
414 pp->clockdesc = DESCRIPTION;
415 memcpy(&pp->refid, REFID, 4);
416
417 /* Open serial port. Use CLK line discipline, if available. */
418 devlen = snprintf(device, sizeof(device), DEVICE, unit);
419 if (devlen >= sizeof(device)) {
420 msyslog(LOG_ERR, "%s clock device name too long",
421 refnumtoa(&peer->srcadr));
422 return FALSE; /* buffer overflow */
423 }
424 pp->io.fd = refclock_open(&peer->srcadr, device, baudrate, LDISC_CLK);
425 if (0 >= pp->io.fd) {
426 pp->io.fd = nmead_open(device);
427 if (-1 == pp->io.fd)
428 return FALSE;
429 }
430
431 /* succeed if this clock can be added */
432 return io_addclock(&pp->io) != 0;
433 }
434
435 /*
436 * -------------------------------------------------------------------
437 * nmea_shutdown - shut down a GPS clock
438 *
439 * NOTE this routine is called after nmea_start() returns failure,
440 * as well as during a normal shutdown due to ntpq :config unpeer.
441 * -------------------------------------------------------------------
442 */
443 static void
nmea_shutdown(int unit,struct peer * peer)444 nmea_shutdown(
445 int unit,
446 struct peer * peer
447 )
448 {
449 struct refclockproc * const pp = peer->procptr;
450 nmea_unit * const up = (nmea_unit *)pp->unitptr;
451
452 UNUSED_ARG(unit);
453
454 if (up != NULL) {
455 # ifdef HAVE_PPSAPI
456 if (up->ppsapi_lit)
457 time_pps_destroy(up->atom.handle);
458 ppsdev_close(pp->io.fd, up->ppsapi_fd);
459 # endif
460 free(up);
461 }
462 pp->unitptr = (caddr_t)NULL;
463 if (-1 != pp->io.fd)
464 io_closeclock(&pp->io);
465 pp->io.fd = -1;
466 }
467
468 /*
469 * -------------------------------------------------------------------
470 * nmea_control - configure fudge params
471 * -------------------------------------------------------------------
472 */
473 #ifdef HAVE_PPSAPI
474 static void
nmea_control(int unit,const struct refclockstat * in_st,struct refclockstat * out_st,struct peer * peer)475 nmea_control(
476 int unit,
477 const struct refclockstat * in_st,
478 struct refclockstat * out_st,
479 struct peer * peer
480 )
481 {
482 struct refclockproc * const pp = peer->procptr;
483 nmea_unit * const up = (nmea_unit *)pp->unitptr;
484
485 char device[32];
486 size_t devlen;
487
488 UNUSED_ARG(in_st);
489 UNUSED_ARG(out_st);
490
491 /*
492 * PPS control
493 *
494 * If /dev/gpspps$UNIT can be opened that will be used for
495 * PPSAPI. On Linux, a PPS device mathing the TTY will be
496 * searched for and possibly created on the fly. Otherwise, the
497 * GPS serial device /dev/gps$UNIT already opened is used for
498 * PPSAPI as well. (This might not work, in which case the PPS
499 * API remains unavailable...)
500 */
501
502 /* Light up the PPSAPI interface if not yet attempted. */
503 if ((CLK_FLAG1 & pp->sloppyclockflag) && !up->ppsapi_tried) {
504 const char *ppsname = device;
505 up->ppsapi_tried = TRUE;
506 /* get FD for the pps device; might be the tty itself! */
507 devlen = snprintf(device, sizeof(device), PPSDEV, unit);
508 if (devlen >= sizeof(device)) {
509 msyslog(LOG_ERR, "%s PPS device name too long",
510 refnumtoa(&peer->srcadr));
511 ppsname = NULL;
512 }
513 up->ppsapi_fd = ppsdev_reopen(
514 &peer->srcadr,
515 pp->io.fd, up->ppsapi_fd,
516 ppsname, PPSOPENMODE, (S_IRUSR|S_IWUSR));
517 /* note 1: the pps fd might be the same as the tty fd
518 * note 2: the current PPS fd remains valid until
519 * - the clock is shut down
520 * - flag1 is set again after being cleared
521 */
522 if (refclock_ppsapi(up->ppsapi_fd, &up->atom)) {
523 /* use the PPS API for our own purposes now. */
524 up->ppsapi_lit = refclock_params(
525 pp->sloppyclockflag, &up->atom);
526 if (!up->ppsapi_lit) {
527 /* failed to configure, drop PPS unit */
528 time_pps_destroy(up->atom.handle);
529 msyslog(LOG_WARNING,
530 "%s set PPSAPI params fails",
531 refnumtoa(&peer->srcadr));
532 }
533 } else {
534 msyslog(LOG_WARNING,
535 "%s flag1 1 but PPSAPI fails",
536 refnumtoa(&peer->srcadr));
537 }
538 }
539
540 /* shut down PPS API if activated */
541 if ( !(CLK_FLAG1 & pp->sloppyclockflag) && up->ppsapi_tried) {
542 /* shutdown PPS API */
543 if (up->ppsapi_lit)
544 time_pps_destroy(up->atom.handle);
545 up->atom.handle = 0;
546 /* do !!NOT!! close/drop PPS fd here! */
547
548 /* clear markers and peer items */
549 up->ppsapi_gate = FALSE;
550 up->ppsapi_lit = FALSE;
551 up->ppsapi_tried = FALSE;
552
553 peer->flags &= ~FLAG_PPS;
554 peer->precision = PRECISION;
555 }
556 }
557 #endif /* HAVE_PPSAPI */
558
559 /*
560 * -------------------------------------------------------------------
561 * nmea_timer - called once per second
562 *
563 * Usually 'nmea_receive()' can get a timestamp every second, but at
564 * least one Motorola unit needs prompting each time. Doing so in
565 * 'nmea_poll()' gives only one sample per poll cycle, which actually
566 * defeats the purpose of the median filter. Polling once per second
567 * seems a much better idea.
568 *
569 * Also takes care of sample expiration if the receiver fails to
570 * provide new input data.
571 * -------------------------------------------------------------------
572 */
573 static void
nmea_timer(int unit,struct peer * peer)574 nmea_timer(
575 int unit,
576 struct peer * peer
577 )
578 {
579 struct refclockproc * const pp = peer->procptr;
580 nmea_unit * const up = (nmea_unit *)pp->unitptr;
581
582 UNUSED_ARG(unit);
583
584 # if NMEA_WRITE_SUPPORT
585
586 if (-1 != pp->io.fd) /* any mode bits to evaluate here? */
587 gps_send(pp->io.fd, "$PMOTG,RMC,0000*1D\r\n", peer);
588
589 # endif /* NMEA_WRITE_SUPPORT */
590
591 /* receive timeout occurred? */
592 if (up->rcvtout) {
593 --up->rcvtout;
594 } else if (pp->codeproc != pp->coderecv) {
595 /* expire one (the oldest) sample, if any */
596 refclock_samples_expire(pp, 1);
597 /* reset message assembly buffer */
598 up->lb_buf[0] = '\0';
599 up->lb_len = 0;
600 }
601
602 if (up->hold_gpsdate && (--up->hold_gpsdate < DATE_HLIM))
603 up->type_gpsdate = DTYP_NONE;
604 }
605
606 /*
607 * -------------------------------------------------------------------
608 * nmea_procrec - receive data from the serial interface
609 *
610 * This is the workhorse for NMEA data evaluation:
611 *
612 * + it checks all NMEA data, and rejects sentences that are not valid
613 * NMEA sentences
614 * + it checks whether a sentence is known and to be used
615 * + it parses the time and date data from the NMEA data string and
616 * augments the missing bits. (century in date, whole date, ...)
617 * + it rejects data that is not from the first accepted sentence in a
618 * burst
619 * + it eventually replaces the receive time with the PPS edge time.
620 * + it feeds the data to the internal processing stages.
621 *
622 * This function assumes a non-empty line in the unit line buffer.
623 * -------------------------------------------------------------------
624 */
625 static void
nmea_procrec(struct peer * const peer,l_fp rd_timestamp)626 nmea_procrec(
627 struct peer * const peer,
628 l_fp rd_timestamp
629 )
630 {
631 /* declare & init control structure pointers */
632 struct refclockproc * const pp = peer->procptr;
633 nmea_unit * const up = (nmea_unit*)pp->unitptr;
634
635 /* Use these variables to hold data until we decide its worth keeping */
636 nmea_data rdata;
637 l_fp rd_reftime;
638
639 /* working stuff */
640 TCivilDate date; /* to keep & convert the time stamp */
641 TGpsDatum wgps; /* week time storage */
642 TNtpDatum dntp;
643 l_fp tofs; /* offset to full-second reftime */
644 /* results of sentence/date/time parsing */
645 u_char sentence; /* sentence tag */
646 int checkres;
647 int warp; /* warp to GPS base date */
648 char * cp;
649 int rc_date, rc_time;
650 u_short rc_dtyp;
651 # ifdef HAVE_PPSAPI
652 int withpps = 0;
653 # endif /* HAVE_PPSAPI */
654
655 /* make sure data has defined pristine state */
656 ZERO(tofs);
657 ZERO(date);
658 ZERO(wgps);
659 ZERO(dntp);
660
661 /*
662 * Read the timecode and timestamp, then initialize field
663 * processing. The <CR><LF> at the NMEA line end is translated
664 * to <LF><LF> by the terminal input routines on most systems,
665 * and this gives us one spurious empty read per record which we
666 * better ignore silently.
667 */
668 checkres = field_init(&rdata, up->lb_buf, up->lb_len);
669 switch (checkres) {
670
671 case CHECK_INVALID:
672 DPRINTF(1, ("%s invalid data: '%s'\n",
673 refnumtoa(&peer->srcadr), up->lb_buf));
674 refclock_report(peer, CEVNT_BADREPLY);
675 return;
676
677 case CHECK_EMPTY:
678 return;
679
680 default:
681 DPRINTF(1, ("%s gpsread: %d '%s'\n",
682 refnumtoa(&peer->srcadr), up->lb_len,
683 up->lb_buf));
684 break;
685 }
686 up->tally.total++;
687
688 /*
689 * --> below this point we have a valid NMEA sentence <--
690 *
691 * Check sentence name. Skip first 2 chars (talker ID) in most
692 * cases, to allow for $GLGGA and $GPGGA etc. Since the name
693 * field has at least 5 chars we can simply shift the field
694 * start.
695 */
696 cp = field_parse(&rdata, 0);
697 if (strncmp(cp + 2, "RMC,", 4) == 0)
698 sentence = NMEA_GPRMC;
699 else if (strncmp(cp + 2, "GGA,", 4) == 0)
700 sentence = NMEA_GPGGA;
701 else if (strncmp(cp + 2, "GLL,", 4) == 0)
702 sentence = NMEA_GPGLL;
703 else if (strncmp(cp + 2, "ZDA,", 4) == 0)
704 sentence = NMEA_GPZDA;
705 else if (strncmp(cp + 2, "ZDG,", 4) == 0)
706 sentence = NMEA_GPZDG;
707 else if (strncmp(cp, "PGRMF,", 6) == 0)
708 sentence = NMEA_PGRMF;
709 else if (strncmp(cp, "PUBX,04,", 8) == 0)
710 sentence = NMEA_PUBX04;
711 else
712 return; /* not something we know about */
713
714 /* Eventually output delay measurement now. */
715 if (peer->ttl & NMEA_DELAYMEAS_MASK) {
716 mprintf_clock_stats(&peer->srcadr, "delay %0.6f %.*s",
717 ldexp(rd_timestamp.l_uf, -32),
718 (int)(strchr(up->lb_buf, ',') - up->lb_buf),
719 up->lb_buf);
720 }
721
722 /* See if I want to process this message type */
723 if ((peer->ttl & NMEA_MESSAGE_MASK) &&
724 !(peer->ttl & sentence_mode[sentence])) {
725 up->tally.filtered++;
726 return;
727 }
728
729 /*
730 * make sure it came in clean
731 *
732 * Apparently, older NMEA specifications (which are expensive)
733 * did not require the checksum for all sentences. $GPMRC is
734 * the only one so far identified which has always been required
735 * to include a checksum.
736 *
737 * Today, most NMEA GPS receivers checksum every sentence. To
738 * preserve its error-detection capabilities with modern GPSes
739 * while allowing operation without checksums on all but $GPMRC,
740 * we keep track of whether we've ever seen a valid checksum on
741 * a given sentence, and if so, reject future instances without
742 * checksum. ('up->cksum_type[NMEA_GPRMC]' is set in
743 * 'nmea_start()' to enforce checksums for $GPRMC right from the
744 * start.)
745 */
746 if (up->cksum_type[sentence] <= (u_char)checkres) {
747 up->cksum_type[sentence] = (u_char)checkres;
748 } else {
749 DPRINTF(1, ("%s checksum missing: '%s'\n",
750 refnumtoa(&peer->srcadr), up->lb_buf));
751 refclock_report(peer, CEVNT_BADREPLY);
752 up->tally.malformed++;
753 return;
754 }
755
756 /*
757 * $GPZDG provides GPS time not UTC, and the two mix poorly.
758 * Once have processed a $GPZDG, do not process any further UTC
759 * sentences (all but $GPZDG currently).
760 */
761 if (sentence == NMEA_GPZDG) {
762 if (!up->gps_time) {
763 msyslog(LOG_INFO,
764 "%s using GPS time as if it were UTC",
765 refnumtoa(&peer->srcadr));
766 up->gps_time = 1;
767 }
768 } else {
769 if (up->gps_time) {
770 up->tally.filtered++;
771 return;
772 }
773 }
774
775 DPRINTF(1, ("%s processing %d bytes, timecode '%s'\n",
776 refnumtoa(&peer->srcadr), up->lb_len, up->lb_buf));
777
778 /*
779 * Grab fields depending on clock string type and possibly wipe
780 * sensitive data from the last timecode.
781 */
782 rc_date = -1; /* assume we have to do day-time mapping */
783 rc_dtyp = DTYP_NONE;
784 switch (sentence) {
785
786 case NMEA_GPRMC:
787 /* Check quality byte, fetch data & time */
788 rc_time = parse_time(&date, &tofs, &rdata, 1);
789 pp->leap = parse_qual(&rdata, 2, 'A', 0);
790 if (up->type_gpsdate <= DTYP_Y2D) {
791 rc_date = parse_date(&date, &rdata, 9, DATE_1_DDMMYY);
792 rc_dtyp = DTYP_Y2D;
793 }
794 if (CLK_FLAG4 & pp->sloppyclockflag)
795 field_wipe(&rdata, 3, 4, 5, 6, -1);
796 break;
797
798 case NMEA_GPGGA:
799 /* Check quality byte, fetch time only */
800 rc_time = parse_time(&date, &tofs, &rdata, 1);
801 pp->leap = parse_qual(&rdata, 6, '0', 1);
802 if (CLK_FLAG4 & pp->sloppyclockflag)
803 field_wipe(&rdata, 2, 4, -1);
804 break;
805
806 case NMEA_GPGLL:
807 /* Check quality byte, fetch time only */
808 rc_time = parse_time(&date, &tofs, &rdata, 5);
809 pp->leap = parse_qual(&rdata, 6, 'A', 0);
810 if (CLK_FLAG4 & pp->sloppyclockflag)
811 field_wipe(&rdata, 1, 3, -1);
812 break;
813
814 case NMEA_GPZDA:
815 /* No quality. Assume best, fetch time & full date */
816 rc_time = parse_time(&date, &tofs, &rdata, 1);
817 if (up->type_gpsdate <= DTYP_Y4D) {
818 rc_date = parse_date(&date, &rdata, 2, DATE_3_DDMMYYYY);
819 rc_dtyp = DTYP_Y4D;
820 }
821 break;
822
823 case NMEA_GPZDG:
824 /* Check quality byte, fetch time & full date */
825 rc_time = parse_time(&date, &tofs, &rdata, 1);
826 pp->leap = parse_qual(&rdata, 4, '0', 1);
827 --tofs.l_ui; /* GPZDG gives *following* second */
828 if (up->type_gpsdate <= DTYP_Y4D) {
829 rc_date = parse_date(&date, &rdata, 2, DATE_3_DDMMYYYY);
830 rc_dtyp = DTYP_Y4D;
831 }
832 break;
833
834 case NMEA_PGRMF:
835 /* get time, qualifier and GPS weektime. */
836 rc_time = parse_time(&date, &tofs, &rdata, 4);
837 if (up->type_gpsdate <= DTYP_W10B) {
838 rc_date = parse_gpsw(&wgps, &rdata, 1, 2, 5);
839 rc_dtyp = DTYP_W10B;
840 }
841 pp->leap = parse_qual(&rdata, 11, '0', 1);
842 if (CLK_FLAG4 & pp->sloppyclockflag)
843 field_wipe(&rdata, 6, 8, -1);
844 break;
845
846 case NMEA_PUBX04:
847 /* PUBX,04 is peculiar. The UTC time-of-week is the *internal*
848 * time base, which is not exactly on par with the fix time.
849 */
850 rc_time = parse_time(&date, &tofs, &rdata, 2);
851 if (up->type_gpsdate <= DTYP_WEXT) {
852 rc_date = parse_gpsw(&wgps, &rdata, 5, 4, -1);
853 rc_dtyp = DTYP_WEXT;
854 }
855 break;
856
857 default:
858 INVARIANT(0); /* Coverity 97123 */
859 return;
860 }
861
862 /* ignore receiver status? [bug 3694] */
863 if (peer->ttl & NMEA_IGNSTATUS_MASK) { /* assume always good? */
864 pp->leap = LEAP_NOWARNING;
865 }
866
867 /* check clock sanity; [bug 2143] */
868 if (pp->leap == LEAP_NOTINSYNC) { /* no good status? */
869 checkres = CEVNT_PROP;
870 up->tally.rejected++;
871 }
872 /* Check sanity of time-of-day. */
873 else if (rc_time == 0) { /* no time or conversion error? */
874 checkres = CEVNT_BADTIME;
875 up->tally.malformed++;
876 }
877 /* Check sanity of date. */
878 else if (rc_date == 0) { /* no date or conversion error? */
879 checkres = CEVNT_BADDATE;
880 up->tally.malformed++;
881 }
882 else {
883 checkres = -1;
884 }
885
886 if (checkres != -1) {
887 refclock_save_lcode(pp, up->lb_buf, up->lb_len);
888 refclock_report(peer, checkres);
889 return;
890 }
891
892 /* See if we can augment the receive time stamp. If not, apply
893 * fudge time 2 to the receive time stamp directly.
894 */
895 # ifdef HAVE_PPSAPI
896 if (up->ppsapi_lit && pp->leap != LEAP_NOTINSYNC)
897 withpps = refclock_ppsaugment(
898 &up->atom, &rd_timestamp,
899 pp->fudgetime2, pp->fudgetime1);
900 else
901 # endif /* HAVE_PPSAPI */
902 rd_timestamp = ntpfp_with_fudge(
903 rd_timestamp, pp->fudgetime2);
904
905 /* set the GPS base date, if possible */
906 warp = !(peer->ttl & NMEA_DATETRUST_MASK);
907 if (rc_dtyp != DTYP_NONE) {
908 DPRINTF(1, ("%s saving date, type=%hu\n",
909 refnumtoa(&peer->srcadr), rc_dtyp));
910 switch (rc_dtyp) {
911 case DTYP_W10B:
912 up->last_gpsdate = gpsntp_from_gpscal_ex(
913 &wgps, (warp = TRUE));
914 break;
915 case DTYP_WEXT:
916 up->last_gpsdate = gpsntp_from_gpscal_ex(
917 &wgps, warp);
918 break;
919 default:
920 up->last_gpsdate = gpsntp_from_calendar_ex(
921 &date, tofs, warp);
922 break;
923 }
924 up->type_gpsdate = rc_dtyp;
925 up->hold_gpsdate = DATE_HOLD;
926 }
927 /* now convert and possibly extend/expand the time stamp. */
928 if (up->hold_gpsdate) { /* time of day, based */
929 dntp = gpsntp_from_daytime2_ex(
930 &date, tofs, &up->last_gpsdate, warp);
931 } else { /* time of day, floating */
932 dntp = gpsntp_from_daytime1_ex(
933 &date, tofs, rd_timestamp, warp);
934 }
935
936 if (debug) {
937 /* debug print time stamp */
938 gpsntp_to_calendar(&date, &dntp);
939 # ifdef HAVE_PPSAPI
940 DPRINTF(1, ("%s effective timecode: %s (%s PPS)\n",
941 refnumtoa(&peer->srcadr),
942 ntpcal_iso8601std(NULL, 0, &date),
943 (withpps ? "with" : "without")));
944 # else /* ?HAVE_PPSAPI */
945 DPRINTF(1, ("%s effective timecode: %s\n",
946 refnumtoa(&peer->srcadr),
947 ntpcal_iso8601std(NULL, 0, &date)));
948 # endif /* !HAVE_PPSAPI */
949 }
950
951 /* Get the reference time stamp from the calendar buffer.
952 * Process the new sample in the median filter and determine the
953 * timecode timestamp, but only if the PPS is not in control.
954 * Discard sentence if reference time did not change.
955 */
956 rd_reftime = ntpfp_from_ntpdatum(&dntp);
957 if (L_ISEQU(&up->last_reftime, &rd_reftime)) {
958 /* Do not touch pp->a_lastcode on purpose! */
959 up->tally.filtered++;
960 return;
961 }
962 up->last_reftime = rd_reftime;
963
964 DPRINTF(1, ("%s using '%s'\n",
965 refnumtoa(&peer->srcadr), up->lb_buf));
966
967 /* Data will be accepted. Update stats & log data. */
968 up->tally.accepted++;
969 refclock_save_lcode(pp, up->lb_buf, up->lb_len);
970 pp->lastrec = rd_timestamp;
971
972 /* If we have PPS augmented receive time, we *must* have a
973 * working PPS source and we must set the flags accordingly.
974 */
975 # ifdef HAVE_PPSAPI
976 if (withpps) {
977 up->ppsapi_gate = TRUE;
978 peer->precision = PPS_PRECISION;
979 if (tabsdiffd(rd_reftime, rd_timestamp) < 0.5) {
980 if ( ! (peer->ttl & NMEA_QUIETPPS_MASK))
981 peer->flags |= FLAG_PPS;
982 DPRINTF(2, ("%s PPS_RELATE_PHASE\n",
983 refnumtoa(&peer->srcadr)));
984 up->tally.pps_used++;
985 } else {
986 DPRINTF(2, ("%s PPS_RELATE_EDGE\n",
987 refnumtoa(&peer->srcadr)));
988 }
989 /* !Note! 'FLAG_PPS' is reset in 'nmea_poll()' */
990 }
991 # endif /* HAVE_PPSAPI */
992 /* Whether the receive time stamp is PPS-augmented or not,
993 * the proper fudge offset is already applied. There's no
994 * residual fudge to process.
995 */
996 refclock_process_offset(pp, rd_reftime, rd_timestamp, 0.0);
997 up->rcvtout = 2;
998 }
999
1000 /*
1001 * -------------------------------------------------------------------
1002 * nmea_receive - receive data from the serial interface
1003 *
1004 * With serial IO only, a single call to 'refclock_gtlin()' to get the
1005 * string would suffice to get the NMEA data. When using NMEAD, this
1006 * does unfortunately no longer hold, since TCP is stream oriented and
1007 * not line oriented, and there's no one to do the line-splitting work
1008 * of the TTY driver in line/cooked mode.
1009 *
1010 * So we have to do this manually here, and we have to live with the
1011 * fact that there could be more than one sentence in a receive buffer.
1012 * Likewise, there can be partial messages on either end. (Strictly
1013 * speaking, a receive buffer could also contain just a single fragment,
1014 * though that's unlikely.)
1015 *
1016 * We deal with that by scanning the input buffer, copying bytes from
1017 * the receive buffer to the assembly buffer as we go and calling the
1018 * record processor every time we hit a CR/LF, provided the resulting
1019 * line is not empty. Any leftovers are kept for the next round.
1020 *
1021 * Note: When used with a serial data stream, there's no change to the
1022 * previous line-oriented input: One line is copied to the buffer and
1023 * processed per call. Only with NMEAD the behavior changes, and the
1024 * timing is badly affected unless a PPS channel is also associated with
1025 * the clock instance. TCP leaves us nothing to improve on here.
1026 * -------------------------------------------------------------------
1027 */
1028 static void
nmea_receive(struct recvbuf * rbufp)1029 nmea_receive(
1030 struct recvbuf * rbufp
1031 )
1032 {
1033 /* declare & init control structure pointers */
1034 struct peer * const peer = rbufp->recv_peer;
1035 struct refclockproc * const pp = peer->procptr;
1036 nmea_unit * const up = (nmea_unit*)pp->unitptr;
1037
1038 const char *sp, *se;
1039 char *dp, *de;
1040
1041 /* paranoia check: */
1042 if (up->lb_len >= sizeof(up->lb_buf))
1043 up->lb_len = 0;
1044
1045 /* pick up last assembly position; leave room for NUL */
1046 dp = up->lb_buf + up->lb_len;
1047 de = up->lb_buf + sizeof(up->lb_buf) - 1;
1048 /* set up input range */
1049 sp = (const char *)rbufp->recv_buffer;
1050 se = sp + rbufp->recv_length;
1051
1052 /* walk over the input data, dropping parity bits and control
1053 * chars as we go, and calling the record processor for each
1054 * complete non-empty line.
1055 */
1056 while (sp != se) {
1057 char ch = (*sp++ & 0x7f);
1058 if (dp == up->lb_buf) {
1059 if (ch == '$')
1060 *dp++ = ch;
1061 } else if (dp > de) {
1062 dp = up->lb_buf;
1063 } else if (ch == '\n' || ch == '\r') {
1064 *dp = '\0';
1065 up->lb_len = (int)(dp - up->lb_buf);
1066 dp = up->lb_buf;
1067 nmea_procrec(peer, rbufp->recv_time);
1068 } else if (ch >= 0x20 && ch < 0x7f) {
1069 *dp++ = ch;
1070 }
1071 }
1072 /* update state to keep for next round */
1073 *dp = '\0';
1074 up->lb_len = (int)(dp - up->lb_buf);
1075 }
1076
1077 /*
1078 * -------------------------------------------------------------------
1079 * nmea_poll - called by the transmit procedure
1080 *
1081 * Does the necessary bookkeeping stuff to keep the reported state of
1082 * the clock in sync with reality.
1083 *
1084 * We go to great pains to avoid changing state here, since there may
1085 * be more than one eavesdropper receiving the same timecode.
1086 * -------------------------------------------------------------------
1087 */
1088 static void
nmea_poll(int unit,struct peer * peer)1089 nmea_poll(
1090 int unit,
1091 struct peer * peer
1092 )
1093 {
1094 struct refclockproc * const pp = peer->procptr;
1095 nmea_unit * const up = (nmea_unit *)pp->unitptr;
1096
1097 /*
1098 * Process median filter samples. If none received, declare a
1099 * timeout and keep going.
1100 */
1101 # ifdef HAVE_PPSAPI
1102 /*
1103 * If we don't have PPS pulses and time stamps, turn PPS down
1104 * for now.
1105 */
1106 if (!up->ppsapi_gate) {
1107 peer->flags &= ~FLAG_PPS;
1108 peer->precision = PRECISION;
1109 } else {
1110 up->ppsapi_gate = FALSE;
1111 }
1112 # endif /* HAVE_PPSAPI */
1113
1114 /*
1115 * If the median filter is empty, claim a timeout. Else process
1116 * the input data and keep the stats going.
1117 */
1118 if (pp->coderecv == pp->codeproc) {
1119 peer->flags &= ~FLAG_PPS;
1120 if (pp->currentstatus < CEVNT_TIMEOUT)
1121 refclock_report(peer, CEVNT_TIMEOUT);
1122 memset(&up->last_gpsdate, 0, sizeof(up->last_gpsdate));
1123 } else {
1124 pp->polls++;
1125 pp->lastref = pp->lastrec;
1126 refclock_receive(peer);
1127 if (pp->currentstatus > CEVNT_NOMINAL)
1128 refclock_report(peer, CEVNT_NOMINAL);
1129 }
1130
1131 /*
1132 * If extended logging is required, write the tally stats to the
1133 * clockstats file; otherwise just do a normal clock stats
1134 * record. Clear the tally stats anyway.
1135 */
1136 if (peer->ttl & NMEA_EXTLOG_MASK) {
1137 /* Log & reset counters with extended logging */
1138 const char *nmea = pp->a_lastcode;
1139 if (*nmea == '\0') nmea = "(none)";
1140 mprintf_clock_stats(
1141 &peer->srcadr, "%s %u %u %u %u %u %u",
1142 nmea,
1143 up->tally.total, up->tally.accepted,
1144 up->tally.rejected, up->tally.malformed,
1145 up->tally.filtered, up->tally.pps_used);
1146 } else {
1147 record_clock_stats(&peer->srcadr, pp->a_lastcode);
1148 }
1149 ZERO(up->tally);
1150 }
1151
1152 #if NMEA_WRITE_SUPPORT
1153 /*
1154 * -------------------------------------------------------------------
1155 * gps_send(fd, cmd, peer) Sends a command to the GPS receiver.
1156 * as in gps_send(fd, "rqts,u", peer);
1157 *
1158 * If 'cmd' starts with a '$' it is assumed that this command is in raw
1159 * format, that is, starts with '$', ends with '<cr><lf>' and that any
1160 * checksum is correctly provided; the command will be send 'as is' in
1161 * that case. Otherwise the function will create the necessary frame
1162 * (start char, chksum, final CRLF) on the fly.
1163 *
1164 * We don't currently send any data, but would like to send RTCM SC104
1165 * messages for differential positioning. It should also give us better
1166 * time. Without a PPS output, we're Just fooling ourselves because of
1167 * the serial code paths
1168 * -------------------------------------------------------------------
1169 */
1170 static void
gps_send(int fd,const char * cmd,struct peer * peer)1171 gps_send(
1172 int fd,
1173 const char * cmd,
1174 struct peer * peer
1175 )
1176 {
1177 /* $...*xy<CR><LF><NUL> add 7 */
1178 char buf[NMEA_PROTO_MAXLEN + 7];
1179 int len;
1180 u_char dcs;
1181 const u_char *beg, *end;
1182
1183 if (*cmd != '$') {
1184 /* get checksum and length */
1185 beg = end = (const u_char*)cmd;
1186 dcs = 0;
1187 while (*end >= ' ' && *end != '*')
1188 dcs ^= *end++;
1189 len = end - beg;
1190 /* format into output buffer with overflow check */
1191 len = snprintf(buf, sizeof(buf), "$%.*s*%02X\r\n",
1192 len, beg, dcs);
1193 if ((size_t)len >= sizeof(buf)) {
1194 DPRINTF(1, ("%s gps_send: buffer overflow for command '%s'\n",
1195 refnumtoa(&peer->srcadr), cmd));
1196 return; /* game over player 1 */
1197 }
1198 cmd = buf;
1199 } else {
1200 len = strlen(cmd);
1201 }
1202
1203 DPRINTF(1, ("%s gps_send: '%.*s'\n", refnumtoa(&peer->srcadr),
1204 len - 2, cmd));
1205
1206 /* send out the whole stuff */
1207 if (refclock_fdwrite(peer, fd, cmd, len) != len)
1208 refclock_report(peer, CEVNT_FAULT);
1209 }
1210 #endif /* NMEA_WRITE_SUPPORT */
1211
1212 /*
1213 * -------------------------------------------------------------------
1214 * helpers for faster field splitting
1215 * -------------------------------------------------------------------
1216 *
1217 * set up a field record, check syntax and verify checksum
1218 *
1219 * format is $XXXXX,1,2,3,4*ML
1220 *
1221 * 8-bit XOR of characters between $ and * noninclusive is transmitted
1222 * in last two chars M and L holding most and least significant nibbles
1223 * in hex representation such as:
1224 *
1225 * $GPGLL,5057.970,N,00146.110,E,142451,A*27
1226 * $GPVTG,089.0,T,,,15.2,N,,*7F
1227 *
1228 * Some other constraints:
1229 * + The field name must be at least 5 upcase characters or digits and
1230 * must start with a character.
1231 * + The checksum (if present) must be uppercase hex digits.
1232 * + The length of a sentence is limited to 80 characters (not including
1233 * the final CR/LF nor the checksum, but including the leading '$')
1234 *
1235 * Return values:
1236 * + CHECK_INVALID
1237 * The data does not form a valid NMEA sentence or a checksum error
1238 * occurred.
1239 * + CHECK_VALID
1240 * The data is a valid NMEA sentence but contains no checksum.
1241 * + CHECK_CSVALID
1242 * The data is a valid NMEA sentence and passed the checksum test.
1243 * -------------------------------------------------------------------
1244 */
1245 static int
field_init(nmea_data * data,char * cptr,int dlen)1246 field_init(
1247 nmea_data * data, /* context structure */
1248 char * cptr, /* start of raw data */
1249 int dlen /* data len, not counting trailing NUL */
1250 )
1251 {
1252 u_char cs_l; /* checksum local computed */
1253 u_char cs_r; /* checksum remote given */
1254 char * eptr; /* buffer end end pointer */
1255 char tmp; /* char buffer */
1256
1257 cs_l = 0;
1258 cs_r = 0;
1259 /* some basic input constraints */
1260 if (dlen < 0)
1261 dlen = 0;
1262 eptr = cptr + dlen;
1263 *eptr = '\0';
1264
1265 /* load data context */
1266 data->base = cptr;
1267 data->cptr = cptr;
1268 data->cidx = 0;
1269 data->blen = dlen;
1270
1271 /* syntax check follows here. check allowed character
1272 * sequences, updating the local computed checksum as we go.
1273 *
1274 * regex equiv: '^\$[A-Z][A-Z0-9]{4,}[^*]*(\*[0-9A-F]{2})?$'
1275 */
1276
1277 /* -*- start character: '^\$' */
1278 if (*cptr == '\0')
1279 return CHECK_EMPTY;
1280 if (*cptr++ != '$')
1281 return CHECK_INVALID;
1282
1283 /* -*- advance context beyond start character */
1284 data->base++;
1285 data->cptr++;
1286 data->blen--;
1287
1288 /* -*- field name: '[A-Z][A-Z0-9]{4,},' */
1289 if (*cptr < 'A' || *cptr > 'Z')
1290 return CHECK_INVALID;
1291 cs_l ^= *cptr++;
1292 while ((*cptr >= 'A' && *cptr <= 'Z') ||
1293 (*cptr >= '0' && *cptr <= '9') )
1294 cs_l ^= *cptr++;
1295 if (*cptr != ',' || (cptr - data->base) < NMEA_PROTO_IDLEN)
1296 return CHECK_INVALID;
1297 cs_l ^= *cptr++;
1298
1299 /* -*- data: '[^*]*' */
1300 while (*cptr && *cptr != '*')
1301 cs_l ^= *cptr++;
1302
1303 /* -*- checksum field: (\*[0-9A-F]{2})?$ */
1304 if (*cptr == '\0')
1305 return CHECK_VALID;
1306 if (*cptr != '*' || cptr != eptr - 3 ||
1307 (cptr - data->base) >= NMEA_PROTO_MAXLEN)
1308 return CHECK_INVALID;
1309
1310 for (cptr++; (tmp = *cptr) != '\0'; cptr++) {
1311 if (tmp >= '0' && tmp <= '9')
1312 cs_r = (cs_r << 4) + (tmp - '0');
1313 else if (tmp >= 'A' && tmp <= 'F')
1314 cs_r = (cs_r << 4) + (tmp - 'A' + 10);
1315 else
1316 break;
1317 }
1318
1319 /* -*- make sure we are at end of string and csum matches */
1320 if (cptr != eptr || cs_l != cs_r)
1321 return CHECK_INVALID;
1322
1323 return CHECK_CSVALID;
1324 }
1325
1326 /*
1327 * -------------------------------------------------------------------
1328 * fetch a data field by index, zero being the name field. If this
1329 * function is called repeatedly with increasing indices, the total load
1330 * is O(n), n being the length of the string; if it is called with
1331 * decreasing indices, the total load is O(n^2). Try not to go backwards
1332 * too often.
1333 * -------------------------------------------------------------------
1334 */
1335 static char *
field_parse(nmea_data * data,int fn)1336 field_parse(
1337 nmea_data * data,
1338 int fn
1339 )
1340 {
1341 char tmp;
1342
1343 if (fn < data->cidx) {
1344 data->cidx = 0;
1345 data->cptr = data->base;
1346 }
1347 while ((fn > data->cidx) && (tmp = *data->cptr) != '\0') {
1348 data->cidx += (tmp == ',');
1349 data->cptr++;
1350 }
1351 return data->cptr;
1352 }
1353
1354 /*
1355 * -------------------------------------------------------------------
1356 * Wipe (that is, overwrite with '_') data fields and the checksum in
1357 * the last timecode. The list of field indices is given as integers
1358 * in a varargs list, preferably in ascending order, in any case
1359 * terminated by a negative field index.
1360 *
1361 * A maximum number of 8 fields can be overwritten at once to guard
1362 * against runaway (that is, unterminated) argument lists.
1363 *
1364 * This function affects what a remote user can see with
1365 *
1366 * ntpq -c clockvar <server>
1367 *
1368 * Note that this also removes the wiped fields from any clockstats
1369 * log. Some NTP operators monitor their NMEA GPS using the change in
1370 * location in clockstats over time as as a proxy for the quality of
1371 * GPS reception and thereby time reported.
1372 * -------------------------------------------------------------------
1373 */
1374 static void
field_wipe(nmea_data * data,...)1375 field_wipe(
1376 nmea_data * data,
1377 ...
1378 )
1379 {
1380 va_list va; /* vararg index list */
1381 int fcnt; /* safeguard against runaway arglist */
1382 int fidx; /* field to nuke, or -1 for checksum */
1383 char * cp; /* overwrite destination */
1384
1385 fcnt = 8;
1386 cp = NULL;
1387 va_start(va, data);
1388 do {
1389 fidx = va_arg(va, int);
1390 if (fidx >= 0 && fidx <= NMEA_PROTO_FIELDS) {
1391 cp = field_parse(data, fidx);
1392 } else {
1393 cp = data->base + data->blen;
1394 if (data->blen >= 3 && cp[-3] == '*')
1395 cp -= 2;
1396 }
1397 for ( ; '\0' != *cp && '*' != *cp && ',' != *cp; cp++)
1398 if ('.' != *cp)
1399 *cp = '_';
1400 } while (fcnt-- && fidx >= 0);
1401 va_end(va);
1402 }
1403
1404 /*
1405 * -------------------------------------------------------------------
1406 * PARSING HELPERS
1407 * -------------------------------------------------------------------
1408 */
1409 typedef unsigned char const UCC;
1410
1411 static char const * const s_eof_chars = ",*\r\n";
1412
1413 #ifdef DEBUG
field_length(UCC * cp,unsigned int nfields)1414 static int field_length(UCC *cp, unsigned int nfields)
1415 {
1416 char const * ep = (char const*)cp;
1417 ep = strpbrk(ep, s_eof_chars);
1418 if (ep && nfields)
1419 while (--nfields && ep && *ep == ',')
1420 ep = strpbrk(ep + 1, s_eof_chars);
1421 return (ep)
1422 ? (int)((UCC*)ep - cp)
1423 : (int)strlen((char const*)cp);
1424 }
1425 #endif /* DEBUG */
1426
1427 /* /[,*\r\n]/ --> skip */
_parse_eof(UCC * cp,UCC ** ep)1428 static int _parse_eof(UCC *cp, UCC ** ep)
1429 {
1430 int rc = (strchr(s_eof_chars, *(char const*)cp) != NULL);
1431 *ep = cp + rc;
1432 return rc;
1433 }
1434
1435 /* /,/ --> skip */
_parse_sep(UCC * cp,UCC ** ep)1436 static int _parse_sep(UCC *cp, UCC ** ep)
1437 {
1438 int rc = (*cp == ',');
1439 *ep = cp + rc;
1440 return rc;
1441 }
1442
1443 /* /[[:digit:]]{2}/ --> uint16_t */
_parse_num2d(UCC * cp,UCC ** ep,uint16_t * into)1444 static int _parse_num2d(UCC *cp, UCC ** ep, uint16_t *into)
1445 {
1446 int rc = FALSE;
1447
1448 if (isdigit(cp[0]) && isdigit(cp[1])) {
1449 *into = (cp[0] - '0') * 10 + (cp[1] - '0');
1450 cp += 2;
1451 rc = TRUE;
1452 }
1453 *ep = cp;
1454 return rc;
1455 }
1456
1457 /* /[[:digit:]]+/ --> uint16_t */
_parse_u16(UCC * cp,UCC ** ep,uint16_t * into,unsigned int ndig)1458 static int _parse_u16(UCC *cp, UCC **ep, uint16_t *into, unsigned int ndig)
1459 {
1460 uint16_t num = 0;
1461 int rc = FALSE;
1462 if (isdigit(*cp) && ndig) {
1463 rc = TRUE;
1464 do
1465 num = (num * 10) + (*cp - '0');
1466 while (isdigit(*++cp) && --ndig);
1467 *into = num;
1468 }
1469 *ep = cp;
1470 return rc;
1471 }
1472
1473 /* /[[:digit:]]+/ --> uint32_t */
_parse_u32(UCC * cp,UCC ** ep,uint32_t * into,unsigned int ndig)1474 static int _parse_u32(UCC *cp, UCC **ep, uint32_t *into, unsigned int ndig)
1475 {
1476 uint32_t num = 0;
1477 int rc = FALSE;
1478 if (isdigit(*cp) && ndig) {
1479 rc = TRUE;
1480 do
1481 num = (num * 10) + (*cp - '0');
1482 while (isdigit(*++cp) && --ndig);
1483 *into = num;
1484 }
1485 *ep = cp;
1486 return rc;
1487 }
1488
1489 /* /(\.[[:digit:]]*)?/ --> l_fp{0, f}
1490 * read fractional seconds, convert to l_fp
1491 *
1492 * Only the first 9 decimal digits are evaluated; any excess is parsed
1493 * away but silently ignored. (--> truncation to 1 nanosecond)
1494 */
_parse_frac(UCC * cp,UCC ** ep,l_fp * into)1495 static int _parse_frac(UCC *cp, UCC **ep, l_fp *into)
1496 {
1497 static const uint32_t powtab[10] = {
1498 0,
1499 100000000, 10000000, 1000000,
1500 100000, 10000, 1000,
1501 100, 10, 1
1502 };
1503
1504 struct timespec ts;
1505 ZERO(ts);
1506 if (*cp == '.') {
1507 uint32_t fval = 0;
1508 UCC * sp = cp + 1;
1509 if (_parse_u32(sp, &cp, &fval, 9))
1510 ts.tv_nsec = fval * powtab[(size_t)(cp - sp)];
1511 while (isdigit(*cp))
1512 ++cp;
1513 }
1514
1515 *ep = cp;
1516 *into = tspec_intv_to_lfp(ts);
1517 return TRUE;
1518 }
1519
1520 /* /[[:digit:]]{6}/ --> time-of-day
1521 * parses a number string representing 'HHMMSS'
1522 */
_parse_time(UCC * cp,UCC ** ep,TCivilDate * into)1523 static int _parse_time(UCC *cp, UCC ** ep, TCivilDate *into)
1524 {
1525 uint16_t s, m, h;
1526 int rc;
1527 UCC * xp = cp;
1528
1529 rc = _parse_num2d(cp, &cp, &h) && (h < 24)
1530 && _parse_num2d(cp, &cp, &m) && (m < 60)
1531 && _parse_num2d(cp, &cp, &s) && (s < 61); /* leap seconds! */
1532
1533 if (rc) {
1534 into->hour = (uint8_t)h;
1535 into->minute = (uint8_t)m;
1536 into->second = (uint8_t)s;
1537 *ep = cp;
1538 } else {
1539 *ep = xp;
1540 DPRINTF(1, ("nmea: invalid time code: '%.*s'\n",
1541 field_length(xp, 1), xp));
1542 }
1543 return rc;
1544 }
1545
1546 /* /[[:digit:]]{6}/ --> civil date
1547 * parses a number string representing 'ddmmyy'
1548 */
_parse_date1(UCC * cp,UCC ** ep,TCivilDate * into)1549 static int _parse_date1(UCC *cp, UCC **ep, TCivilDate *into)
1550 {
1551 unsigned short d, m, y;
1552 int rc;
1553 UCC * xp = cp;
1554
1555 rc = _parse_num2d(cp, &cp, &d) && (d - 1 < 31)
1556 && _parse_num2d(cp, &cp, &m) && (m - 1 < 12)
1557 && _parse_num2d(cp, &cp, &y)
1558 && _parse_eof(cp, ep);
1559 if (rc) {
1560 into->monthday = (uint8_t )d;
1561 into->month = (uint8_t )m;
1562 into->year = (uint16_t)y;
1563 *ep = cp;
1564 } else {
1565 *ep = xp;
1566 DPRINTF(1, ("nmea: invalid date code: '%.*s'\n",
1567 field_length(xp, 1), xp));
1568 }
1569 return rc;
1570 }
1571
1572 /* /[[:digit:]]+,[[:digit:]]+,[[:digit:]]+/ --> civil date
1573 * parses three successive numeric fields as date: day,month,year
1574 */
_parse_date3(UCC * cp,UCC ** ep,TCivilDate * into)1575 static int _parse_date3(UCC *cp, UCC **ep, TCivilDate *into)
1576 {
1577 uint16_t d, m, y;
1578 int rc;
1579 UCC * xp = cp;
1580
1581 rc = _parse_u16(cp, &cp, &d, 2) && (d - 1 < 31)
1582 && _parse_sep(cp, &cp)
1583 && _parse_u16(cp, &cp, &m, 2) && (m - 1 < 12)
1584 && _parse_sep(cp, &cp)
1585 && _parse_u16(cp, &cp, &y, 4) && (y > 1980)
1586 && _parse_eof(cp, ep);
1587 if (rc) {
1588 into->monthday = (uint8_t )d;
1589 into->month = (uint8_t )m;
1590 into->year = (uint16_t)y;
1591 *ep = cp;
1592 } else {
1593 *ep = xp;
1594 DPRINTF(1, ("nmea: invalid date code: '%.*s'\n",
1595 field_length(xp, 3), xp));
1596 }
1597 return rc;
1598 }
1599
1600 /*
1601 * -------------------------------------------------------------------
1602 * Check sync status
1603 *
1604 * If the character at the data field start matches the tag value,
1605 * return LEAP_NOWARNING and LEAP_NOTINSYNC otherwise. If the 'inverted'
1606 * flag is given, just the opposite value is returned. If there is no
1607 * data field (*cp points to the NUL byte) the result is LEAP_NOTINSYNC.
1608 * -------------------------------------------------------------------
1609 */
1610 static u_char
parse_qual(nmea_data * rd,int idx,char tag,int inv)1611 parse_qual(
1612 nmea_data * rd,
1613 int idx,
1614 char tag,
1615 int inv
1616 )
1617 {
1618 static const u_char table[2] = {
1619 LEAP_NOTINSYNC, LEAP_NOWARNING };
1620
1621 char * dp = field_parse(rd, idx);
1622
1623 return table[ *dp && ((*dp == tag) == !inv) ];
1624 }
1625
1626 /*
1627 * -------------------------------------------------------------------
1628 * Parse a time stamp in HHMMSS[.sss] format with error checking.
1629 *
1630 * returns 1 on success, 0 on failure
1631 * -------------------------------------------------------------------
1632 */
1633 static int
parse_time(struct calendar * jd,l_fp * fofs,nmea_data * rd,int idx)1634 parse_time(
1635 struct calendar * jd, /* result calendar pointer */
1636 l_fp * fofs, /* storage for nsec fraction */
1637 nmea_data * rd,
1638 int idx
1639 )
1640 {
1641 UCC * dp = (UCC*)field_parse(rd, idx);
1642
1643 return _parse_time(dp, &dp, jd)
1644 && _parse_frac(dp, &dp, fofs)
1645 && _parse_eof (dp, &dp);
1646 }
1647
1648 /*
1649 * -------------------------------------------------------------------
1650 * Parse a date string from an NMEA sentence. This could either be a
1651 * partial date in DDMMYY format in one field, or DD,MM,YYYY full date
1652 * spec spanning three fields. This function does some extensive error
1653 * checking to make sure the date string was consistent.
1654 *
1655 * returns 1 on success, 0 on failure
1656 * -------------------------------------------------------------------
1657 */
1658 static int
parse_date(struct calendar * jd,nmea_data * rd,int idx,enum date_fmt fmt)1659 parse_date(
1660 struct calendar * jd, /* result pointer */
1661 nmea_data * rd,
1662 int idx,
1663 enum date_fmt fmt
1664 )
1665 {
1666 UCC * dp = (UCC*)field_parse(rd, idx);
1667
1668 switch (fmt) {
1669 case DATE_1_DDMMYY:
1670 return _parse_date1(dp, &dp, jd);
1671 case DATE_3_DDMMYYYY:
1672 return _parse_date3(dp, &dp, jd);
1673 default:
1674 DPRINTF(1, ("nmea: invalid parse format: %d\n", fmt));
1675 break;
1676 }
1677 return FALSE;
1678 }
1679
1680 /*
1681 * -------------------------------------------------------------------
1682 * Parse GPS week time info from an NMEA sentence. This info contains
1683 * the GPS week number, the GPS time-of-week and the leap seconds GPS
1684 * to UTC.
1685 *
1686 * returns 1 on success, 0 on failure
1687 * -------------------------------------------------------------------
1688 */
1689 static int
parse_gpsw(TGpsDatum * wd,nmea_data * rd,int weekidx,int timeidx,int leapidx)1690 parse_gpsw(
1691 TGpsDatum * wd,
1692 nmea_data * rd,
1693 int weekidx,
1694 int timeidx,
1695 int leapidx
1696 )
1697 {
1698 uint32_t secs;
1699 uint16_t week, leap = 0;
1700 l_fp fofs;
1701 int rc;
1702
1703 UCC * dpw = (UCC*)field_parse(rd, weekidx);
1704 UCC * dps = (UCC*)field_parse(rd, timeidx);
1705
1706 rc = _parse_u16 (dpw, &dpw, &week, 5)
1707 && _parse_eof (dpw, &dpw)
1708 && _parse_u32 (dps, &dps, &secs, 9)
1709 && _parse_frac(dps, &dps, &fofs)
1710 && _parse_eof (dps, &dps)
1711 && (secs < 7*SECSPERDAY);
1712 if (rc && leapidx > 0) {
1713 UCC * dpl = (UCC*)field_parse(rd, leapidx);
1714 rc = _parse_u16 (dpl, &dpl, &leap, 5)
1715 && _parse_eof (dpl, &dpl);
1716 }
1717 if (rc) {
1718 fofs.l_ui -= leap;
1719 *wd = gpscal_from_gpsweek(week, secs, fofs);
1720 } else {
1721 DPRINTF(1, ("nmea: parse_gpsw: invalid weektime spec\n"));
1722 }
1723 return rc;
1724 }
1725
1726
1727 #ifdef HAVE_PPSAPI
1728 static double
tabsdiffd(l_fp t1,l_fp t2)1729 tabsdiffd(
1730 l_fp t1,
1731 l_fp t2
1732 )
1733 {
1734 double dd;
1735 L_SUB(&t1, &t2);
1736 LFPTOD(&t1, dd);
1737 return fabs(dd);
1738 }
1739 #endif /* HAVE_PPSAPI */
1740
1741 /*
1742 * ===================================================================
1743 *
1744 * NMEAD support
1745 *
1746 * original nmead support added by Jon Miner (cp_n18@yahoo.com)
1747 *
1748 * See http://home.hiwaay.net/~taylorc/gps/nmea-server/
1749 * for information about nmead
1750 *
1751 * To use this, you need to create a link from /dev/gpsX to
1752 * the server:port where nmead is running. Something like this:
1753 *
1754 * ln -s server:port /dev/gps1
1755 *
1756 * Split into separate function by Juergen Perlinger
1757 * (perlinger-at-ntp-dot-org)
1758 *
1759 * ===================================================================
1760 */
1761 static int
nmead_open(const char * device)1762 nmead_open(
1763 const char * device
1764 )
1765 {
1766 int fd = -1; /* result file descriptor */
1767
1768 # ifdef HAVE_READLINK
1769 char host[80]; /* link target buffer */
1770 char * port; /* port name or number */
1771 int rc; /* result code (several)*/
1772 int sh; /* socket handle */
1773 struct addrinfo ai_hint; /* resolution hint */
1774 struct addrinfo *ai_list; /* resolution result */
1775 struct addrinfo *ai; /* result scan ptr */
1776
1777 fd = -1;
1778
1779 /* try to read as link, make sure no overflow occurs */
1780 rc = readlink(device, host, sizeof(host));
1781 if ((size_t)rc >= sizeof(host))
1782 return fd; /* error / overflow / truncation */
1783 host[rc] = '\0'; /* readlink does not place NUL */
1784
1785 /* get port */
1786 port = strchr(host, ':');
1787 if (!port)
1788 return fd; /* not 'host:port' syntax ? */
1789 *port++ = '\0'; /* put in separator */
1790
1791 /* get address infos and try to open socket
1792 *
1793 * This getaddrinfo() is naughty in ntpd's nonblocking main
1794 * thread, but you have to go out of your wary to use this code
1795 * and typically the blocking is at startup where its impact is
1796 * reduced. The same holds for the 'connect()', as it is
1797 * blocking, too...
1798 */
1799 ZERO(ai_hint);
1800 ai_hint.ai_protocol = IPPROTO_TCP;
1801 ai_hint.ai_socktype = SOCK_STREAM;
1802 if (getaddrinfo(host, port, &ai_hint, &ai_list))
1803 return fd;
1804
1805 for (ai = ai_list; ai && (fd == -1); ai = ai->ai_next) {
1806 sh = socket(ai->ai_family, ai->ai_socktype,
1807 ai->ai_protocol);
1808 if (INVALID_SOCKET == sh)
1809 continue;
1810 rc = connect(sh, ai->ai_addr, ai->ai_addrlen);
1811 if (-1 != rc)
1812 fd = sh;
1813 else
1814 close(sh);
1815 }
1816 freeaddrinfo(ai_list);
1817 if (fd != -1)
1818 make_socket_nonblocking(fd);
1819 # else
1820 fd = -1;
1821 # endif
1822
1823 return fd;
1824 }
1825 #else
1826 NONEMPTY_TRANSLATION_UNIT
1827 #endif /* REFCLOCK && CLOCK_NMEA */
1828