xref: /netbsd-src/external/bsd/ntp/dist/ntpd/refclock_nmea.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*	$NetBSD: refclock_nmea.c,v 1.3 2010/12/04 23:08:35 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 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 #if defined(REFCLOCK) && defined(CLOCK_NMEA)
25 
26 #include <sys/stat.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <sys/socket.h>
30 
31 #include "ntpd.h"
32 #include "ntp_io.h"
33 #include "ntp_unixtime.h"
34 #include "ntp_refclock.h"
35 #include "ntp_stdlib.h"
36 
37 #ifdef HAVE_PPSAPI
38 # include "ppsapi_timepps.h"
39 #include "refclock_atom.h"
40 #endif /* HAVE_PPSAPI */
41 
42 #ifdef SYS_WINNT
43 #undef write	/* ports/winnt/include/config.h: #define write _write */
44 extern int async_write(int, const void *, unsigned int);
45 #define write(fd, data, octets)	async_write(fd, data, octets)
46 #endif
47 
48 /*
49  * This driver supports NMEA-compatible GPS receivers
50  *
51  * Prototype was refclock_trak.c, Thanks a lot.
52  *
53  * The receiver used spits out the NMEA sentences for boat navigation.
54  * And you thought it was an information superhighway.  Try a raging river
55  * filled with rapids and whirlpools that rip away your data and warp time.
56  *
57  * If HAVE_PPSAPI is defined code to use the PPSAPI will be compiled in.
58  * On startup if initialization of the PPSAPI fails, it will fall back
59  * to the "normal" timestamps.
60  *
61  * The PPSAPI part of the driver understands fudge flag2 and flag3. If
62  * flag2 is set, it will use the clear edge of the pulse. If flag3 is
63  * set, kernel hardpps is enabled.
64  *
65  * GPS sentences other than RMC (the default) may be enabled by setting
66  * the relevent bits of 'mode' in the server configuration line
67  * server 127.127.20.x mode X
68  *
69  * bit 0 - enables RMC (1)
70  * bit 1 - enables GGA (2)
71  * bit 2 - enables GLL (4)
72  * bit 3 - enables ZDA (8) - Standard Time & Date
73  * bit 3 - enables ZDG (8) - Accord GPS Clock's custom sentence with GPS time
74  *			     very close to standard ZDA
75  *
76  * Multiple sentences may be selected except when ZDG/ZDA is selected.
77  *
78  * bit 4/5/6 - selects the baudrate for serial port :
79  *		0 for 4800 (default)
80  *		1 for 9600
81  *		2 for 19200
82  *		3 for 38400
83  *		4 for 57600
84  *		5 for 115200
85  */
86 #define NMEA_MESSAGE_MASK_OLD    0x07
87 #define NMEA_MESSAGE_MASK_SINGLE 0x08
88 #define NMEA_MESSAGE_MASK        (NMEA_MESSAGE_MASK_OLD | NMEA_MESSAGE_MASK_SINGLE)
89 
90 #define NMEA_BAUDRATE_MASK       0x70
91 #define NMEA_BAUDRATE_SHIFT      4
92 
93 /*
94  * Definitions
95  */
96 #define	DEVICE		"/dev/gps%d"	/* GPS serial device */
97 #define	PPSDEV		"/dev/gpspps%d"	/* PPSAPI device override */
98 #define	SPEED232	B4800	/* uart speed (4800 bps) */
99 #define	PRECISION	(-9)	/* precision assumed (about 2 ms) */
100 #define	PPS_PRECISION	(-20)	/* precision assumed (about 1 us) */
101 #define	REFID		"GPS\0"	/* reference id */
102 #define	DESCRIPTION	"NMEA GPS Clock" /* who we are */
103 #define NANOSECOND	1000000000 /* one second (ns) */
104 #define RANGEGATE	500000	/* range gate (ns) */
105 #ifndef O_NOCTTY
106 #define M_NOCTTY	0
107 #else
108 #define M_NOCTTY	O_NOCTTY
109 #endif
110 #ifndef O_NONBLOCK
111 #define M_NONBLOCK	0
112 #else
113 #define M_NONBLOCK	O_NONBLOCK
114 #endif
115 #define PPSOPENMODE	(O_RDWR | M_NOCTTY | M_NONBLOCK)
116 
117 /*
118  * Unit control structure
119  */
120 struct nmeaunit {
121 #ifdef HAVE_PPSAPI
122 	struct refclock_atom atom; /* PPSAPI structure */
123 	int	ppsapi_tried;	/* attempt PPSAPI once */
124 	int	ppsapi_lit;	/* time_pps_create() worked */
125 	int	ppsapi_fd;	/* fd used with PPSAPI */
126 	int	tcount;		/* timecode sample counter */
127 	int	pcount;		/* PPS sample counter */
128 #endif /* HAVE_PPSAPI */
129 	l_fp	tstamp;		/* timestamp of last poll */
130 	int	gps_time;	/* 0 UTC, 1 GPS time */
131 };
132 
133 /*
134  * Function prototypes
135  */
136 static	int	nmea_start	(int, struct peer *);
137 static	void	nmea_shutdown	(int, struct peer *);
138 static	void	nmea_receive	(struct recvbuf *);
139 static	void	nmea_poll	(int, struct peer *);
140 #ifdef HAVE_PPSAPI
141 static	void	nmea_control	(int, struct refclockstat *,
142 				 struct refclockstat *, struct peer *);
143 static  void	nmea_timer	(int, struct peer *);
144 #define		NMEA_CONTROL	nmea_control
145 #define		NMEA_TIMER	nmea_timer
146 #else
147 #define		NMEA_CONTROL	noentry
148 #define		NMEA_TIMER	noentry
149 #endif /* HAVE_PPSAPI */
150 static	void	gps_send	(int, const char *, struct peer *);
151 static	char *	field_parse	(char *, int);
152 static	int	nmea_checksum_ok(const char *);
153 
154 /*
155  * Transfer vector
156  */
157 struct	refclock refclock_nmea = {
158 	nmea_start,		/* start up driver */
159 	nmea_shutdown,		/* shut down driver */
160 	nmea_poll,		/* transmit poll message */
161 	NMEA_CONTROL,		/* fudge control */
162 	noentry,		/* initialize driver */
163 	noentry,		/* buginfo */
164 	NMEA_TIMER		/* called once per second */
165 };
166 
167 /*
168  * nmea_start - open the GPS devices and initialize data for processing
169  */
170 static int
171 nmea_start(
172 	int unit,
173 	struct peer *peer
174 	)
175 {
176 	register struct nmeaunit *up;
177 	struct refclockproc *pp;
178 	int fd;
179 	char device[20];
180 	int baudrate;
181 	const char *baudtext;
182 
183 	pp = peer->procptr;
184 
185 	/*
186 	 * Open serial port. Use CLK line discipline, if available.
187 	 */
188 	snprintf(device, sizeof(device), DEVICE, unit);
189 
190 	/*
191 	 * Opening the serial port with appropriate baudrate
192 	 * based on the value of bit 4/5/6
193 	 */
194 	switch ((peer->ttl & NMEA_BAUDRATE_MASK) >> NMEA_BAUDRATE_SHIFT) {
195 	    case 0:
196 	    case 6:
197 	    case 7:
198 	    default:
199 		baudrate = SPEED232;
200 		baudtext = "4800";
201 		break;
202 	    case 1:
203 		baudrate = B9600;
204 		baudtext = "9600";
205 		break;
206 	    case 2:
207 		baudrate = B19200;
208 		baudtext = "19200";
209 		break;
210 	    case 3:
211 		baudrate = B38400;
212 		baudtext = "38400";
213 		break;
214 #ifdef B57600
215 	    case 4:
216 		baudrate = B57600;
217 		baudtext = "57600";
218 		break;
219 #endif
220 #ifdef B115200
221 	    case 5:
222 		baudrate = B115200;
223 		baudtext = "115200";
224 		break;
225 #endif
226 	}
227 
228 	fd = refclock_open(device, baudrate, LDISC_CLK);
229 
230 	if (fd <= 0) {
231 #ifdef HAVE_READLINK
232 		/* nmead support added by Jon Miner (cp_n18@yahoo.com)
233 		 *
234 		 * See http://home.hiwaay.net/~taylorc/gps/nmea-server/
235 		 * for information about nmead
236 		 *
237 		 * To use this, you need to create a link from /dev/gpsX to
238 		 * the server:port where nmead is running.  Something like this:
239 		 *
240 		 * ln -s server:port /dev/gps1
241 		 */
242 		char buffer[80];
243 		char *nmea_host, *nmea_tail;
244 		int   nmea_port;
245 		int   len;
246 		struct hostent *he;
247 		struct protoent *p;
248 		struct sockaddr_in so_addr;
249 
250 		if ((len = readlink(device,buffer,sizeof(buffer))) == -1)
251 			return(0);
252 		buffer[len] = 0;
253 
254 		if ((nmea_host = strtok(buffer,":")) == NULL)
255 			return(0);
256 		if ((nmea_tail = strtok(NULL,":")) == NULL)
257 			return(0);
258 
259 		nmea_port = atoi(nmea_tail);
260 
261 		if ((he = gethostbyname(nmea_host)) == NULL)
262 			return(0);
263 		if ((p = getprotobyname("ip")) == NULL)
264 			return(0);
265 		memset(&so_addr, 0, sizeof(so_addr));
266 		so_addr.sin_family = AF_INET;
267 		so_addr.sin_port = htons(nmea_port);
268 		so_addr.sin_addr = *((struct in_addr *) he->h_addr);
269 
270 		if ((fd = socket(PF_INET,SOCK_STREAM,p->p_proto)) == -1)
271 			return(0);
272 		if (connect(fd,(struct sockaddr *)&so_addr, sizeof(so_addr)) == -1) {
273 			close(fd);
274 			return (0);
275 		}
276 #else
277 		pp->io.fd = -1;
278 		return (0);
279 #endif
280 	}
281 
282 	msyslog(LOG_NOTICE, "%s serial %s open at %s bps",
283 		refnumtoa(&peer->srcadr), device, baudtext);
284 
285 	/*
286 	 * Allocate and initialize unit structure
287 	 */
288 	up = emalloc(sizeof(*up));
289 	memset(up, 0, sizeof(*up));
290 	pp->io.clock_recv = nmea_receive;
291 	pp->io.srcclock = (caddr_t)peer;
292 	pp->io.datalen = 0;
293 	pp->io.fd = fd;
294 	if (!io_addclock(&pp->io)) {
295 		pp->io.fd = -1;
296 		close(fd);
297 		free(up);
298 		return (0);
299 	}
300 	pp->unitptr = (caddr_t)up;
301 
302 	/*
303 	 * Initialize miscellaneous variables
304 	 */
305 	peer->precision = PRECISION;
306 	pp->clockdesc = DESCRIPTION;
307 	memcpy(&pp->refid, REFID, 4);
308 
309 	gps_send(fd,"$PMOTG,RMC,0000*1D\r\n", peer);
310 
311 	return (1);
312 }
313 
314 
315 /*
316  * nmea_shutdown - shut down a GPS clock
317  *
318  * NOTE this routine is called after nmea_start() returns failure,
319  * as well as during a normal shutdown due to ntpq :config unpeer.
320  */
321 static void
322 nmea_shutdown(
323 	int unit,
324 	struct peer *peer
325 	)
326 {
327 	register struct nmeaunit *up;
328 	struct refclockproc *pp;
329 
330 	UNUSED_ARG(unit);
331 
332 	pp = peer->procptr;
333 	up = (struct nmeaunit *)pp->unitptr;
334 	if (up != NULL) {
335 #ifdef HAVE_PPSAPI
336 		if (up->ppsapi_lit) {
337 			time_pps_destroy(up->atom.handle);
338 			if (up->ppsapi_fd != pp->io.fd)
339 				close(up->ppsapi_fd);
340 		}
341 #endif
342 		free(up);
343 	}
344 	if (-1 != pp->io.fd)
345 		io_closeclock(&pp->io);
346 }
347 
348 /*
349  * nmea_control - configure fudge params
350  */
351 #ifdef HAVE_PPSAPI
352 static void
353 nmea_control(
354 	int unit,
355 	struct refclockstat *in_st,
356 	struct refclockstat *out_st,
357 	struct peer *peer
358 	)
359 {
360 	char device[32];
361 	register struct nmeaunit *up;
362 	struct refclockproc *pp;
363 	int pps_fd;
364 
365 	UNUSED_ARG(in_st);
366 	UNUSED_ARG(out_st);
367 
368 	pp = peer->procptr;
369 	up = (struct nmeaunit *)pp->unitptr;
370 
371 	if (!(CLK_FLAG1 & pp->sloppyclockflag)) {
372 		if (!up->ppsapi_tried)
373 			return;
374 		up->ppsapi_tried = 0;
375 		if (!up->ppsapi_lit)
376 			return;
377 		peer->flags &= ~FLAG_PPS;
378 		peer->precision = PRECISION;
379 		time_pps_destroy(up->atom.handle);
380 		if (up->ppsapi_fd != pp->io.fd)
381 			close(up->ppsapi_fd);
382 		up->atom.handle = 0;
383 		up->ppsapi_lit = 0;
384 		up->ppsapi_fd = -1;
385 		return;
386 	}
387 
388 	if (up->ppsapi_tried)
389 		return;
390 	/*
391 	 * Light up the PPSAPI interface.
392 	 */
393 	up->ppsapi_tried = 1;
394 
395 	/*
396 	 * if /dev/gpspps$UNIT can be opened that will be used for
397 	 * PPSAPI.  Otherwise, the GPS serial device /dev/gps$UNIT
398 	 * already opened is used for PPSAPI as well.
399 	 */
400 	snprintf(device, sizeof(device), PPSDEV, unit);
401 
402 	pps_fd = open(device, PPSOPENMODE, S_IRUSR | S_IWUSR);
403 
404 	if (-1 == pps_fd)
405 		pps_fd = pp->io.fd;
406 
407 	if (refclock_ppsapi(pps_fd, &up->atom)) {
408 		up->ppsapi_lit = 1;
409 		up->ppsapi_fd = pps_fd;
410 		return;
411 	}
412 
413 	NLOG(NLOG_CLOCKINFO)
414 		msyslog(LOG_WARNING, "%s flag1 1 but PPSAPI fails",
415 			refnumtoa(&peer->srcadr));
416 }
417 #endif	/* HAVE_PPSAPI */
418 
419 
420 /*
421  * nmea_timer - called once per second, fetches PPS
422  *		timestamp and stuffs in median filter.
423  */
424 #ifdef HAVE_PPSAPI
425 static void
426 nmea_timer(
427 	int		unit,
428 	struct peer *	peer
429 	)
430 {
431 	struct nmeaunit *up;
432 	struct refclockproc *pp;
433 
434 	UNUSED_ARG(unit);
435 
436 	pp = peer->procptr;
437 	up = (struct nmeaunit *)pp->unitptr;
438 
439 	if (up->ppsapi_lit &&
440 	    refclock_pps(peer, &up->atom, pp->sloppyclockflag) > 0) {
441 		up->pcount++,
442 		peer->flags |= FLAG_PPS;
443 		peer->precision = PPS_PRECISION;
444 	}
445 }
446 #endif	/* HAVE_PPSAPI */
447 
448 
449 /*
450  * nmea_receive - receive data from the serial interface
451  */
452 static void
453 nmea_receive(
454 	struct recvbuf *rbufp
455 	)
456 {
457 	register struct nmeaunit *up;
458 	struct refclockproc *pp;
459 	struct peer *peer;
460 	int month, day;
461 	char *cp, *dp, *msg;
462 	int cmdtype;
463 	int cmdtypezdg = 0;
464 	/* Use these variables to hold data until we decide its worth keeping */
465 	char	rd_lastcode[BMAX];
466 	l_fp	rd_timestamp;
467 	int	rd_lencode;
468 
469 	/*
470 	 * Initialize pointers and read the timecode and timestamp
471 	 */
472 	peer = rbufp->recv_peer;
473 	pp = peer->procptr;
474 	up = (struct nmeaunit *)pp->unitptr;
475 
476 	rd_lencode = refclock_gtlin(
477 			rbufp,
478 			rd_lastcode,
479 			sizeof(rd_lastcode),
480 			&rd_timestamp);
481 
482 	/*
483 	 * There is a case that a <CR><LF> gives back a "blank" line
484 	 */
485 	if (rd_lencode == 0)
486 		return;
487 
488 	DPRINTF(1, ("nmea: gpsread %d %s\n", rd_lencode, rd_lastcode));
489 
490 	/*
491 	 * We check the timecode format and decode its contents. The
492 	 * we only care about a few of them.  The most important being
493 	 * the $GPRMC format
494 	 * $GPRMC,hhmmss,a,fddmm.xx,n,dddmmm.xx,w,zz.z,yyy.,ddmmyy,dd,v*CC
495 	 * mode (0,1,2,3) selects sentence ANY/ALL, RMC, GGA, GLL, ZDA
496 	 * $GPGLL,3513.8385,S,14900.7851,E,232420.594,A*21
497 	 * $GPGGA,232420.59,3513.8385,S,14900.7851,E,1,05,3.4,00519,M,,,,*3F
498 	 * $GPRMC,232418.19,A,3513.8386,S,14900.7853,E,00.0,000.0,121199,12.,E*77
499 	 *
500 	 * Defining GPZDA to support Standard Time & Date
501 	 * sentence. The sentence has the following format
502 	 *
503 	 *  $--ZDA,HHMMSS.SS,DD,MM,YYYY,TH,TM,*CS<CR><LF>
504 	 *
505 	 *  Apart from the familiar fields,
506 	 *  'TH'    Time zone Hours
507 	 *  'TM'    Time zone Minutes
508 	 *
509 	 * Defining GPZDG to support Accord GPS Clock's custom NMEA
510 	 * sentence. The sentence has the following format
511 	 *
512 	 *  $GPZDG,HHMMSS.S,DD,MM,YYYY,AA.BB,V*CS<CR><LF>
513 	 *
514 	 *  It contains the GPS timestamp valid for next PPS pulse.
515 	 *  Apart from the familiar fields,
516 	 *  'AA.BB' denotes the signal strength( should be < 05.00 )
517 	 *  'V'     denotes the GPS sync status :
518 	 *	   '0' indicates INVALID time,
519 	 *	   '1' indicates accuracy of +/-20 ms
520 	 *	   '2' indicates accuracy of +/-100 ns
521 	 */
522 #define GPXXX		0	/* any/all */
523 #define GPRMC		1
524 #define GPGGA		2
525 #define GPGLL		4
526 #define GPZDG_ZDA	8
527 
528 	cp = rd_lastcode;
529 	cmdtype=0;
530 	if (cp[0] == '$') {
531 		/* Allow for GLGGA and GPGGA etc. */
532 		msg = cp + 3;
533 
534 		if (strncmp(msg, "RMC", 3) == 0)
535 			cmdtype = GPRMC;
536 		else if (strncmp(msg, "GGA", 3) == 0)
537 			cmdtype = GPGGA;
538 		else if (strncmp(msg, "GLL", 3) == 0)
539 			cmdtype = GPGLL;
540 		else if (strncmp(msg, "ZD", 2) == 0) {
541 			cmdtype = GPZDG_ZDA;
542 			if ('G' == msg[2])
543 				cmdtypezdg = 1;
544 			else if ('A' != msg[2])
545 				return;
546 		} else
547 			return;
548 	} else
549 		return;
550 
551 	/* See if I want to process this message type */
552 	if (peer->ttl && !(cmdtype & (peer->ttl & NMEA_MESSAGE_MASK)))
553 		return;
554 
555 	/*
556 	 * $GPZDG provides GPS time not UTC, and the two mix poorly.
557 	 * Once have processed a $GPZDG, do not process any further
558 	 * UTC sentences (all but $GPZDG currently).
559 	 */
560 	if (up->gps_time && !cmdtypezdg)
561 		return;
562 
563 	/* make sure it came in clean */
564 	if (!nmea_checksum_ok(rd_lastcode)) {
565 		refclock_report(peer, CEVNT_BADREPLY);
566 		return;
567 	}
568 
569 	pp->lencode = (u_short) rd_lencode;
570 	memcpy(pp->a_lastcode, rd_lastcode, pp->lencode + 1);
571 	cp = pp->a_lastcode;
572 
573 	up->tstamp = rd_timestamp;
574 	pp->lastrec = up->tstamp;
575 
576 	DPRINTF(1, ("nmea: timecode %d %s\n", pp->lencode, pp->a_lastcode));
577 
578 	/* Grab field depending on clock string type */
579 	switch (cmdtype) {
580 
581 	case GPRMC:
582 		/*
583 		 * Test for synchronization.  Check for quality byte.
584 		 */
585 		dp = field_parse(cp, 2);
586 		if (dp[0] != 'A')
587 			pp->leap = LEAP_NOTINSYNC;
588 		else
589 			pp->leap = LEAP_NOWARNING;
590 
591 		/* Now point at the time field */
592 		dp = field_parse(cp, 1);
593 		break;
594 
595 	case GPGGA:
596 		/*
597 		 * Test for synchronization.  Check for quality byte.
598 		 */
599 		dp = field_parse(cp, 6);
600 		if (dp[0] == '0')
601 			pp->leap = LEAP_NOTINSYNC;
602 		else
603 			pp->leap = LEAP_NOWARNING;
604 
605 		/* Now point at the time field */
606 		dp = field_parse(cp, 1);
607 		break;
608 
609 	case GPGLL:
610 		/*
611 		 * Test for synchronization.  Check for quality byte.
612 		 */
613 		dp = field_parse(cp, 6);
614 		if (dp[0] != 'A')
615 			pp->leap = LEAP_NOTINSYNC;
616 		else
617 			pp->leap = LEAP_NOWARNING;
618 
619 		/* Now point at the time field */
620 		dp = field_parse(cp, 5);
621 		break;
622 
623 	case GPZDG_ZDA:
624 		/*
625 		 * Test for synchronization.  For $GPZDG check for validity of GPS time.
626 		 */
627 		if (cmdtypezdg) {
628 			dp = field_parse(cp, 6);
629 			if (dp[0] == '0')
630 				pp->leap = LEAP_NOTINSYNC;
631 			else
632 				pp->leap = LEAP_NOWARNING;
633 		} else
634 			pp->leap = LEAP_NOWARNING;
635 
636 		/* Now point at the time field */
637 		dp = field_parse(cp, 1);
638 		break;
639 
640 	default:
641 		return;
642 	}
643 
644 	/*
645 	 * Check time code format of NMEA
646 	 */
647 	if (!isdigit((unsigned char)dp[0]) ||
648 	    !isdigit((unsigned char)dp[1]) ||
649 	    !isdigit((unsigned char)dp[2]) ||
650 	    !isdigit((unsigned char)dp[3]) ||
651 	    !isdigit((unsigned char)dp[4]) ||
652 	    !isdigit((unsigned char)dp[5])) {
653 
654 		DPRINTF(1, ("NMEA time code %c%c%c%c%c%c non-numeric",
655 			    dp[0], dp[1], dp[2], dp[3], dp[4], dp[5]));
656 		refclock_report(peer, CEVNT_BADTIME);
657 		return;
658 	}
659 
660 	/*
661 	 * Convert time and check values.
662 	 */
663 	pp->hour = ((dp[0] - '0') * 10) + dp[1] - '0';
664 	pp->minute = ((dp[2] - '0') * 10) + dp[3] -  '0';
665 	pp->second = ((dp[4] - '0') * 10) + dp[5] - '0';
666 	/*
667 	 * Default to 0 milliseconds, if decimal convert milliseconds in
668 	 * one, two or three digits
669 	 */
670 	pp->nsec = 0;
671 	if (dp[6] == '.') {
672 		if (isdigit((unsigned char)dp[7])) {
673 			pp->nsec = (dp[7] - '0') * 100000000;
674 			if (isdigit((unsigned char)dp[8])) {
675 				pp->nsec += (dp[8] - '0') * 10000000;
676 				if (isdigit((unsigned char)dp[9])) {
677 					pp->nsec += (dp[9] - '0') * 1000000;
678 				}
679 			}
680 		}
681 	}
682 
683 	/*
684 	 * Manipulating GPS timestamp in GPZDG as the seconds field
685 	 * is valid for next PPS tick. Just rolling back the second,
686 	 * minute and hour fields appopriately
687 	 */
688 	if (cmdtypezdg) {
689 		if (pp->second == 0) {
690 			pp->second = 59;
691 			if (pp->minute == 0) {
692 				pp->minute = 59;
693 				if (pp->hour == 0)
694 					pp->hour = 23;
695 			}
696 		} else
697 			pp->second -= 1;
698 	}
699 
700 	if (pp->hour > 23 || pp->minute > 59 ||
701 	    pp->second > 59 || pp->nsec > 1000000000) {
702 
703 		DPRINTF(1, ("NMEA hour/min/sec/nsec range %02d:%02d:%02d.%09ld\n",
704 			    pp->hour, pp->minute, pp->second, pp->nsec));
705 		refclock_report(peer, CEVNT_BADTIME);
706 		return;
707 	}
708 
709 	/*
710 	 * Convert date and check values.
711 	 */
712 	if (GPRMC == cmdtype) {
713 
714 		dp = field_parse(cp,9);
715 		day = dp[0] - '0';
716 		day = (day * 10) + dp[1] - '0';
717 		month = dp[2] - '0';
718 		month = (month * 10) + dp[3] - '0';
719 		pp->year = dp[4] - '0';
720 		pp->year = (pp->year * 10) + dp[5] - '0';
721 
722 	} else if (GPZDG_ZDA == cmdtype) {
723 
724 		dp = field_parse(cp, 2);
725 		day = 10 * (dp[0] - '0') + (dp[1] - '0');
726 		dp = field_parse(cp, 3);
727 		month = 10 * (dp[0] - '0') + (dp[1] - '0');
728 		dp = field_parse(cp, 4);
729 		pp->year = /* 1000 * (dp[0] - '0') + 100 * (dp[1] - '0') + */ 10 * (dp[2] - '0') + (dp[3] - '0');
730 
731 	} else {
732 		/* only time */
733 		time_t tt = time(NULL);
734 		struct tm * t = gmtime(&tt);
735 		day = t->tm_mday;
736 		month = t->tm_mon + 1;
737 		pp->year= t->tm_year + 1900;
738 	}
739 
740 	if (month < 1 || month > 12 || day < 1) {
741 		refclock_report(peer, CEVNT_BADDATE);
742 		return;
743 	}
744 
745 	/* pp->year will be 2 or 4 digits if read from GPS, 4 from gmtime */
746 	if (pp->year < 100) {
747 		if (pp->year < 9)	/* year of our line of code is 2009 */
748 			pp->year += 2100;
749 		else
750 			pp->year += 2000;
751 	}
752 
753 	/* pp->year now 4 digits as ymd2yd requires */
754 	day = ymd2yd(pp->year, month, day);
755 	if (-1 == day) {
756 		refclock_report(peer, CEVNT_BADDATE);
757 		return;
758 	}
759 	pp->day = day;
760 
761 	/*
762 	 * If "fudge 127.127.20.__ flag4 1" is configured in ntp.conf,
763 	 * remove the location and checksum from the NMEA sentence
764 	 * recorded as the last timecode and visible to remote users
765 	 * with:
766 	 *
767 	 * ntpq -c clockvar <server>
768 	 *
769 	 * Note that this also removes the location from the clockstats
770 	 * log (if it is enabled).  Some NTP operators monitor their
771 	 * NMEA GPS using the change in location in clockstats over
772 	 * time as as a proxy for the quality of GPS reception and
773 	 * thereby time reported.
774 	 */
775 	if (CLK_FLAG4 & pp->sloppyclockflag) {
776 		/*
777 		 * Start by pointing cp and dp at the fields with
778 		 * longitude and latitude in the last timecode.
779 		 */
780 		switch (cmdtype) {
781 
782 		case GPGLL:
783 			cp = field_parse(pp->a_lastcode, 1);
784 			dp = field_parse(cp, 2);
785 			break;
786 
787 		case GPGGA:
788 			cp = field_parse(pp->a_lastcode, 2);
789 			dp = field_parse(cp, 2);
790 			break;
791 
792 		case GPRMC:
793 			cp = field_parse(pp->a_lastcode, 3);
794 			dp = field_parse(cp, 2);
795 			break;
796 
797 		case GPZDG_ZDA:
798 		default:
799 			cp = dp = NULL;
800 		}
801 
802 		/* Blank the entire latitude & longitude. */
803 		while (cp) {
804 			while (',' != *cp) {
805 				if ('.' != *cp)
806 					*cp = '_';
807 				cp++;
808 			}
809 
810 			/* Longitude at cp then latitude at dp */
811 			if (cp < dp)
812 				cp = dp;
813 			else
814 				cp = NULL;
815 		}
816 
817 		/* Blank the checksum, the last two characters */
818 		if (dp) {
819 			cp = pp->a_lastcode + pp->lencode - 2;
820 			if (0 == cp[2])
821 				cp[0] = cp[1] = '_';
822 		}
823 
824 	}
825 
826 	/*
827 	 * Note if we're only using GPS timescale from now on.
828 	 */
829 	if (cmdtypezdg && !up->gps_time) {
830 		up->gps_time = 1;
831 		NLOG(NLOG_CLOCKINFO)
832 			msyslog(LOG_INFO, "%s using only $GPZDG",
833 				refnumtoa(&peer->srcadr));
834 	}
835 
836 	/*
837 	 * Process the new sample in the median filter and determine the
838 	 * timecode timestamp, but only if the PPS is not in control.
839 	 */
840 #ifdef HAVE_PPSAPI
841 	up->tcount++;
842 	if (peer->flags & FLAG_PPS)
843 		return;
844 #endif /* HAVE_PPSAPI */
845 	if (!refclock_process_f(pp, pp->fudgetime2))
846 		refclock_report(peer, CEVNT_BADTIME);
847 }
848 
849 
850 /*
851  * nmea_poll - called by the transmit procedure
852  *
853  * We go to great pains to avoid changing state here, since there may be
854  * more than one eavesdropper receiving the same timecode.
855  */
856 static void
857 nmea_poll(
858 	int unit,
859 	struct peer *peer
860 	)
861 {
862 	register struct nmeaunit *up;
863 	struct refclockproc *pp;
864 
865 	pp = peer->procptr;
866 	up = (struct nmeaunit *)pp->unitptr;
867 
868 	/*
869 	 * Process median filter samples. If none received, declare a
870 	 * timeout and keep going.
871 	 */
872 #ifdef HAVE_PPSAPI
873 	if (up->pcount == 0) {
874 		peer->flags &= ~FLAG_PPS;
875 		peer->precision = PRECISION;
876 	}
877 	if (up->tcount == 0) {
878 		pp->coderecv = pp->codeproc;
879 		refclock_report(peer, CEVNT_TIMEOUT);
880 		return;
881 	}
882 	up->pcount = up->tcount = 0;
883 #else /* HAVE_PPSAPI */
884 	if (pp->coderecv == pp->codeproc) {
885 		refclock_report(peer, CEVNT_TIMEOUT);
886 		return;
887 	}
888 #endif /* HAVE_PPSAPI */
889 
890 	pp->polls++;
891 	pp->lastref = pp->lastrec;
892 	refclock_receive(peer);
893 	record_clock_stats(&peer->srcadr, pp->a_lastcode);
894 
895 	/*
896 	 * usually nmea_receive can get a timestamp every second,
897 	 * but at least one Motorola unit needs prompting each
898 	 * time.
899 	 */
900 
901 	gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer);
902 }
903 
904 
905 /*
906  *
907  *	gps_send(fd,cmd, peer)  Sends a command to the GPS receiver.
908  *	 as	gps_send(fd,"rqts,u\r", peer);
909  *
910  *	We don't currently send any data, but would like to send
911  *	RTCM SC104 messages for differential positioning. It should
912  *	also give us better time. Without a PPS output, we're
913  *	Just fooling ourselves because of the serial code paths
914  *
915  */
916 static void
917 gps_send(
918 	int fd,
919 	const char *cmd,
920 	struct peer *peer
921 	)
922 {
923 	if (write(fd, cmd, strlen(cmd)) == -1) {
924 		refclock_report(peer, CEVNT_FAULT);
925 	}
926 }
927 
928 
929 static char *
930 field_parse(
931 	char *cp,
932 	int fn
933 	)
934 {
935 	char *tp;
936 	int i = fn;
937 
938 	for (tp = cp; i && *tp; tp++)
939 		if (*tp == ',')
940 			i--;
941 
942 	return tp;
943 }
944 
945 
946 /*
947  * nmea_checksum_ok verifies 8-bit XOR checksum is correct then returns 1
948  *
949  * format is $XXXXX,1,2,3,4*ML
950  *
951  * 8-bit XOR of characters between $ and * noninclusive is transmitted
952  * in last two chars M and L holding most and least significant nibbles
953  * in hex representation such as:
954  *
955  *   $GPGLL,5057.970,N,00146.110,E,142451,A*27
956  *   $GPVTG,089.0,T,,,15.2,N,,*7F
957  */
958 int
959 nmea_checksum_ok(
960 	const char *sentence
961 	)
962 {
963 	u_char my_cs;
964 	u_long input_cs;
965 	const char *p;
966 
967 	my_cs = 0;
968 	p = sentence;
969 
970 	if ('$' != *p++)
971 		return 0;
972 
973 	for ( ; *p && '*' != *p; p++) {
974 
975 		my_cs ^= *p;
976 	}
977 
978 	if ('*' != *p++)
979 		return 0;
980 
981 	if (0 == p[0] || 0 == p[1] || 0 != p[2])
982 		return 0;
983 
984 	if (0 == hextoint(p, &input_cs))
985 		return 0;
986 
987 	if (my_cs != input_cs)
988 		return 0;
989 
990 	return 1;
991 }
992 #else
993 int refclock_nmea_bs;
994 #endif /* REFCLOCK && CLOCK_NMEA */
995