Obfuscate RCS ID matching so that CVS doesn't expand it.
[netbsd-mini2440.git] / dist / ntp / ntpd / refclock_nmea.c
blob6c74bbfe9638a53df9ea3377777761d9da468829
1 /* $NetBSD: refclock_nmea.c,v 1.4 2007/01/06 19:45:23 kardel Exp $ */
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 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
12 #if defined(REFCLOCK) && defined(CLOCK_NMEA)
14 #include <stdio.h>
15 #include <ctype.h>
16 #include <sys/socket.h>
18 #include "ntpd.h"
19 #include "ntp_io.h"
20 #include "ntp_unixtime.h"
21 #include "ntp_refclock.h"
22 #include "ntp_stdlib.h"
24 #ifdef HAVE_PPSAPI
25 # include "ppsapi_timepps.h"
26 #endif /* HAVE_PPSAPI */
28 #ifdef SYS_WINNT
29 extern int async_write(int, const void *, unsigned int);
30 #undef write
31 #define write(fd, data, octets) async_write(fd, data, octets)
32 #endif
35 * This driver supports the NMEA GPS Receiver with
37 * Protype was refclock_trak.c, Thanks a lot.
39 * The receiver used spits out the NMEA sentences for boat navigation.
40 * And you thought it was an information superhighway. Try a raging river
41 * filled with rapids and whirlpools that rip away your data and warp time.
43 * If HAVE_PPSAPI is defined code to use the PPSAPI will be compiled in.
44 * On startup if initialization of the PPSAPI fails, it will fall back
45 * to the "normal" timestamps.
47 * The PPSAPI part of the driver understands fudge flag2 and flag3. If
48 * flag2 is set, it will use the clear edge of the pulse. If flag3 is
49 * set, kernel hardpps is enabled.
51 * GPS sentences other than RMC (the default) may be enabled by setting
52 * the relevent bits of 'mode' in the server configuration line
53 * server 127.127.20.x mode X
55 * bit 0 - enables RMC (1)
56 * bit 1 - enables GGA (2)
57 * bit 2 - enables GLL (4)
58 * multiple sentences may be selected
62 * Definitions
64 #ifdef SYS_WINNT
65 # define DEVICE "COM%d:" /* COM 1 - 3 supported */
66 #else
67 # define DEVICE "/dev/gps%d" /* name of radio device */
68 #endif
69 #define SPEED232 B4800 /* uart speed (4800 bps) */
70 #define PRECISION (-9) /* precision assumed (about 2 ms) */
71 #define PPS_PRECISION (-20) /* precision assumed (about 1 us) */
72 #define REFID "GPS\0" /* reference id */
73 #define DESCRIPTION "NMEA GPS Clock" /* who we are */
74 #define NANOSECOND 1000000000 /* one second (ns) */
75 #define RANGEGATE 500000 /* range gate (ns) */
77 #define LENNMEA 75 /* min timecode length */
80 * Tables to compute the ddd of year form icky dd/mm timecode. Viva la
81 * leap.
83 static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
84 static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
87 * Unit control structure
89 struct nmeaunit {
90 int pollcnt; /* poll message counter */
91 int polled; /* Hand in a sample? */
92 l_fp tstamp; /* timestamp of last poll */
93 #ifdef HAVE_PPSAPI
94 struct timespec ts; /* last timestamp */
95 pps_params_t pps_params; /* pps parameters */
96 pps_info_t pps_info; /* last pps data */
97 pps_handle_t handle; /* pps handlebars */
98 #endif /* HAVE_PPSAPI */
102 * Function prototypes
104 static int nmea_start P((int, struct peer *));
105 static void nmea_shutdown P((int, struct peer *));
106 #ifdef HAVE_PPSAPI
107 static void nmea_control P((int, struct refclockstat *, struct
108 refclockstat *, struct peer *));
109 static int nmea_ppsapi P((struct peer *, int, int));
110 static int nmea_pps P((struct nmeaunit *, l_fp *));
111 #endif /* HAVE_PPSAPI */
112 static void nmea_receive P((struct recvbuf *));
113 static void nmea_poll P((int, struct peer *));
114 static void gps_send P((int, const char *, struct peer *));
115 static char *field_parse P((char *, int));
118 * Transfer vector
120 struct refclock refclock_nmea = {
121 nmea_start, /* start up driver */
122 nmea_shutdown, /* shut down driver */
123 nmea_poll, /* transmit poll message */
124 #ifdef HAVE_PPSAPI
125 nmea_control, /* fudge control */
126 #else
127 noentry, /* fudge control */
128 #endif /* HAVE_PPSAPI */
129 noentry, /* initialize driver */
130 noentry, /* buginfo */
131 NOFLAGS /* not used */
135 * nmea_start - open the GPS devices and initialize data for processing
137 static int
138 nmea_start(
139 int unit,
140 struct peer *peer
143 register struct nmeaunit *up;
144 struct refclockproc *pp;
145 int fd;
146 char device[20];
149 * Open serial port. Use CLK line discipline, if available.
151 (void)sprintf(device, DEVICE, unit);
153 fd = refclock_open(device, SPEED232, LDISC_CLK);
154 if (fd <= 0) {
155 #ifdef HAVE_READLINK
156 /* nmead support added by Jon Miner (cp_n18@yahoo.com)
158 * See http://home.hiwaay.net/~taylorc/gps/nmea-server/
159 * for information about nmead
161 * To use this, you need to create a link from /dev/gpsX to
162 * the server:port where nmead is running. Something like this:
164 * ln -s server:port /dev/gps1
166 char buffer[80];
167 char *nmea_host;
168 int nmea_port;
169 int len;
170 struct hostent *he;
171 struct protoent *p;
172 struct sockaddr_in so_addr;
174 if ((len = readlink(device,buffer,sizeof(buffer))) == -1)
175 return(0);
176 buffer[len] = 0;
178 if ((nmea_host = strtok(buffer,":")) == NULL)
179 return(0);
181 nmea_port = atoi(strtok(NULL,":"));
183 if ((he = gethostbyname(nmea_host)) == NULL)
184 return(0);
185 if ((p = getprotobyname("ip")) == NULL)
186 return(0);
187 so_addr.sin_family = AF_INET;
188 so_addr.sin_port = htons(nmea_port);
189 so_addr.sin_addr = *((struct in_addr *) he->h_addr);
191 if ((fd = socket(PF_INET,SOCK_STREAM,p->p_proto)) == -1)
192 return(0);
193 if (connect(fd,(struct sockaddr *)&so_addr,SOCKLEN(&so_addr)) == -1) {
194 close(fd);
195 return (0);
197 #else
198 return (0);
199 #endif
203 * Allocate and initialize unit structure
205 up = (struct nmeaunit *)emalloc(sizeof(struct nmeaunit));
206 if (up == NULL) {
207 (void) close(fd);
208 return (0);
210 memset((char *)up, 0, sizeof(struct nmeaunit));
211 pp = peer->procptr;
212 pp->io.clock_recv = nmea_receive;
213 pp->io.srcclock = (caddr_t)peer;
214 pp->io.datalen = 0;
215 pp->io.fd = fd;
216 if (!io_addclock(&pp->io)) {
217 (void) close(fd);
218 free(up);
219 return (0);
221 pp->unitptr = (caddr_t)up;
224 * Initialize miscellaneous variables
226 peer->precision = PRECISION;
227 pp->clockdesc = DESCRIPTION;
228 memcpy((char *)&pp->refid, REFID, 4);
229 up->pollcnt = 2;
230 gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer);
232 #ifdef HAVE_PPSAPI
234 * Start the PPSAPI interface if it is there. Default to use
235 * the assert edge and do not enable the kernel hardpps.
237 if (time_pps_create(fd, &up->handle) < 0) {
238 up->handle = 0;
239 msyslog(LOG_ERR,
240 "refclock_nmea: time_pps_create failed: %m");
241 return (1);
243 return(nmea_ppsapi(peer, 0, 0));
244 #else
245 return (1);
246 #endif /* HAVE_PPSAPI */
250 * nmea_shutdown - shut down a GPS clock
252 static void
253 nmea_shutdown(
254 int unit,
255 struct peer *peer
258 register struct nmeaunit *up;
259 struct refclockproc *pp;
261 pp = peer->procptr;
262 up = (struct nmeaunit *)pp->unitptr;
263 #ifdef HAVE_PPSAPI
264 if (up->handle != 0)
265 time_pps_destroy(up->handle);
266 #endif /* HAVE_PPSAPI */
267 io_closeclock(&pp->io);
268 free(up);
271 #ifdef HAVE_PPSAPI
273 * nmea_control - fudge control
275 static void
276 nmea_control(
277 int unit, /* unit (not used */
278 struct refclockstat *in, /* input parameters (not uded) */
279 struct refclockstat *out, /* output parameters (not used) */
280 struct peer *peer /* peer structure pointer */
283 struct refclockproc *pp;
285 pp = peer->procptr;
286 nmea_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2,
287 pp->sloppyclockflag & CLK_FLAG3);
292 * Initialize PPSAPI
295 nmea_ppsapi(
296 struct peer *peer, /* peer structure pointer */
297 int enb_clear, /* clear enable */
298 int enb_hardpps /* hardpps enable */
301 struct refclockproc *pp;
302 struct nmeaunit *up;
303 int capability;
305 pp = peer->procptr;
306 up = (struct nmeaunit *)pp->unitptr;
307 if (time_pps_getcap(up->handle, &capability) < 0) {
308 msyslog(LOG_ERR,
309 "refclock_nmea: time_pps_getcap failed: %m");
310 return (0);
312 memset(&up->pps_params, 0, sizeof(pps_params_t));
313 if (enb_clear)
314 up->pps_params.mode = capability & PPS_CAPTURECLEAR;
315 else
316 up->pps_params.mode = capability & PPS_CAPTUREASSERT;
317 if (!up->pps_params.mode) {
318 msyslog(LOG_ERR,
319 "refclock_nmea: invalid capture edge %d",
320 !enb_clear);
321 return (0);
323 up->pps_params.mode |= PPS_TSFMT_TSPEC;
324 if (time_pps_setparams(up->handle, &up->pps_params) < 0) {
325 msyslog(LOG_ERR,
326 "refclock_nmea: time_pps_setparams failed: %m");
327 return (0);
329 if (enb_hardpps) {
330 if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS,
331 up->pps_params.mode & ~PPS_TSFMT_TSPEC,
332 PPS_TSFMT_TSPEC) < 0) {
333 msyslog(LOG_ERR,
334 "refclock_nmea: time_pps_kcbind failed: %m");
335 return (0);
337 pps_enable = 1;
339 peer->precision = PPS_PRECISION;
341 #if DEBUG
342 if (debug) {
343 time_pps_getparams(up->handle, &up->pps_params);
344 printf(
345 "refclock_ppsapi: capability 0x%x version %d mode 0x%x kern %d\n",
346 capability, up->pps_params.api_version,
347 up->pps_params.mode, enb_hardpps);
349 #endif
351 return (1);
355 * Get PPSAPI timestamps.
357 * Return 0 on failure and 1 on success.
359 static int
360 nmea_pps(
361 struct nmeaunit *up,
362 l_fp *tsptr
365 pps_info_t pps_info;
366 struct timespec timeout, ts;
367 double dtemp;
368 l_fp tstmp;
371 * Convert the timespec nanoseconds field to ntp l_fp units.
373 if (up->handle == 0)
374 return (0);
375 timeout.tv_sec = 0;
376 timeout.tv_nsec = 0;
377 memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
378 if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info,
379 &timeout) < 0)
380 return (0);
381 if (up->pps_params.mode & PPS_CAPTUREASSERT) {
382 if (pps_info.assert_sequence ==
383 up->pps_info.assert_sequence)
384 return (0);
385 ts = up->pps_info.assert_timestamp;
386 } else if (up->pps_params.mode & PPS_CAPTURECLEAR) {
387 if (pps_info.clear_sequence ==
388 up->pps_info.clear_sequence)
389 return (0);
390 ts = up->pps_info.clear_timestamp;
391 } else {
392 return (0);
394 if ((up->ts.tv_sec == ts.tv_sec) && (up->ts.tv_nsec == ts.tv_nsec))
395 return (0);
396 up->ts = ts;
398 tstmp.l_ui = ts.tv_sec + JAN_1970;
399 dtemp = ts.tv_nsec * FRAC / 1e9;
400 tstmp.l_uf = (u_int32)dtemp;
401 *tsptr = tstmp;
402 return (1);
404 #endif /* HAVE_PPSAPI */
407 * nmea_receive - receive data from the serial interface
409 static void
410 nmea_receive(
411 struct recvbuf *rbufp
414 register struct nmeaunit *up;
415 struct refclockproc *pp;
416 struct peer *peer;
417 int month, day;
418 int i;
419 char *cp, *dp;
420 int cmdtype;
421 /* Use these variables to hold data until we decide its worth keeping */
422 char rd_lastcode[BMAX];
423 l_fp rd_tmp;
424 u_short rd_lencode;
427 * Initialize pointers and read the timecode and timestamp
429 peer = (struct peer *)rbufp->recv_srcclock;
430 pp = peer->procptr;
431 up = (struct nmeaunit *)pp->unitptr;
432 rd_lencode = (u_short)refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
435 * There is a case that a <CR><LF> gives back a "blank" line
437 if (rd_lencode == 0)
438 return;
440 #ifdef DEBUG
441 if (debug)
442 printf("nmea: gpsread %d %s\n", rd_lencode,
443 rd_lastcode);
444 #endif
447 * We check the timecode format and decode its contents. The
448 * we only care about a few of them. The most important being
449 * the $GPRMC format
450 * $GPRMC,hhmmss,a,fddmm.xx,n,dddmmm.xx,w,zz.z,yyy.,ddmmyy,dd,v*CC
451 * For Magellan (ColorTrak) GLL probably datum (order of sentences)
452 * also mode (0,1,2,3) select sentence ANY/ALL, RMC, GGA, GLL
453 * $GPGLL,3513.8385,S,14900.7851,E,232420.594,A*21
454 * $GPGGA,232420.59,3513.8385,S,14900.7851,E,1,05,3.4,00519,M,,,,*3F
455 * $GPRMB,...
456 * $GPRMC,232418.19,A,3513.8386,S,14900.7853,E,00.0,000.0,121199,12.,E*77
457 * $GPAPB,...
458 * $GPGSA,...
459 * $GPGSV,...
460 * $GPGSV,...
462 #define GPXXX 0
463 #define GPRMC 1
464 #define GPGGA 2
465 #define GPGLL 4
466 cp = rd_lastcode;
467 cmdtype=0;
468 if(strncmp(cp,"$GPRMC",6)==0) {
469 cmdtype=GPRMC;
471 else if(strncmp(cp,"$GPGGA",6)==0) {
472 cmdtype=GPGGA;
474 else if(strncmp(cp,"$GPGLL",6)==0) {
475 cmdtype=GPGLL;
477 else if(strncmp(cp,"$GPXXX",6)==0) {
478 cmdtype=GPXXX;
480 else
481 return;
484 /* See if I want to process this message type */
485 if ( ((peer->ttl == 0) && (cmdtype != GPRMC))
486 || ((peer->ttl != 0) && !(cmdtype & peer->ttl)) )
487 return;
489 pp->lencode = rd_lencode;
490 strcpy(pp->a_lastcode,rd_lastcode);
491 cp = pp->a_lastcode;
493 pp->lastrec = up->tstamp = rd_tmp;
494 up->pollcnt = 2;
496 #ifdef DEBUG
497 if (debug)
498 printf("nmea: timecode %d %s\n", pp->lencode,
499 pp->a_lastcode);
500 #endif
503 /* Grab field depending on clock string type */
504 switch( cmdtype ) {
505 case GPRMC:
507 * Test for synchronization. Check for quality byte.
509 dp = field_parse(cp,2);
510 if( dp[0] != 'A')
511 pp->leap = LEAP_NOTINSYNC;
512 else
513 pp->leap = LEAP_NOWARNING;
515 /* Now point at the time field */
516 dp = field_parse(cp,1);
517 break;
520 case GPGGA:
522 * Test for synchronization. Check for quality byte.
524 dp = field_parse(cp,6);
525 if( dp[0] == '0')
526 pp->leap = LEAP_NOTINSYNC;
527 else
528 pp->leap = LEAP_NOWARNING;
530 /* Now point at the time field */
531 dp = field_parse(cp,1);
532 break;
535 case GPGLL:
537 * Test for synchronization. Check for quality byte.
539 dp = field_parse(cp,6);
540 if( dp[0] != 'A')
541 pp->leap = LEAP_NOTINSYNC;
542 else
543 pp->leap = LEAP_NOWARNING;
545 /* Now point at the time field */
546 dp = field_parse(cp,5);
547 break;
550 case GPXXX:
551 return;
552 default:
553 return;
558 * Check time code format of NMEA
561 if( !isdigit((int)dp[0]) ||
562 !isdigit((int)dp[1]) ||
563 !isdigit((int)dp[2]) ||
564 !isdigit((int)dp[3]) ||
565 !isdigit((int)dp[4]) ||
566 !isdigit((int)dp[5])
568 refclock_report(peer, CEVNT_BADREPLY);
569 return;
574 * Convert time and check values.
576 pp->hour = ((dp[0] - '0') * 10) + dp[1] - '0';
577 pp->minute = ((dp[2] - '0') * 10) + dp[3] - '0';
578 pp->second = ((dp[4] - '0') * 10) + dp[5] - '0';
579 /* Default to 0 milliseconds, if decimal convert milliseconds in
580 one, two or three digits
582 pp->nsec = 0;
583 if (dp[6] == '.') {
584 if (isdigit((int)dp[7])) {
585 pp->nsec = (dp[7] - '0') * 100000000;
586 if (isdigit((int)dp[8])) {
587 pp->nsec += (dp[8] - '0') * 10000000;
588 if (isdigit((int)dp[9])) {
589 pp->nsec += (dp[9] - '0') * 1000000;
595 if (pp->hour > 23 || pp->minute > 59 || pp->second > 59
596 || pp->nsec > 1000000000) {
597 refclock_report(peer, CEVNT_BADTIME);
598 return;
603 * Convert date and check values.
605 if (cmdtype==GPRMC) {
606 dp = field_parse(cp,9);
607 day = dp[0] - '0';
608 day = (day * 10) + dp[1] - '0';
609 month = dp[2] - '0';
610 month = (month * 10) + dp[3] - '0';
611 pp->year = dp[4] - '0';
612 pp->year = (pp->year * 10) + dp[5] - '0';
614 else {
615 /* only time */
616 time_t tt = time(NULL);
617 struct tm * t = gmtime(&tt);
618 day = t->tm_mday;
619 month = t->tm_mon + 1;
620 pp->year= t->tm_year;
623 if (month < 1 || month > 12 || day < 1) {
624 refclock_report(peer, CEVNT_BADTIME);
625 return;
628 /* Hmmmm this will be a nono for 2100,2200,2300 but I don't think I'll be here */
629 /* good thing that 2000 is a leap year */
630 /* pp->year will be 00-99 if read from GPS, 00-> (years since 1900) from tm_year */
631 if (pp->year % 4) {
632 if (day > day1tab[month - 1]) {
633 refclock_report(peer, CEVNT_BADTIME);
634 return;
636 for (i = 0; i < month - 1; i++)
637 day += day1tab[i];
638 } else {
639 if (day > day2tab[month - 1]) {
640 refclock_report(peer, CEVNT_BADTIME);
641 return;
643 for (i = 0; i < month - 1; i++)
644 day += day2tab[i];
646 pp->day = day;
649 #ifdef HAVE_PPSAPI
651 * If the PPSAPI is working, rather use its timestamps.
652 * assume that the PPS occurs on the second so blow any msec
654 if (nmea_pps(up, &rd_tmp) == 1) {
655 pp->lastrec = up->tstamp = rd_tmp;
656 pp->nsec = 0;
658 #endif /* HAVE_PPSAPI */
661 * Process the new sample in the median filter and determine the
662 * reference clock offset and dispersion. We use lastrec as both
663 * the reference time and receive time, in order to avoid being
664 * cute, like setting the reference time later than the receive
665 * time, which may cause a paranoid protocol module to chuck out
666 * the data.
669 if (!refclock_process(pp)) {
670 refclock_report(peer, CEVNT_BADTIME);
671 return;
677 * Only go on if we had been polled.
679 if (!up->polled)
680 return;
681 up->polled = 0;
682 pp->lastref = pp->lastrec;
683 refclock_receive(peer);
685 /* If we get here - what we got from the clock is OK, so say so */
686 refclock_report(peer, CEVNT_NOMINAL);
688 record_clock_stats(&peer->srcadr, pp->a_lastcode);
693 * nmea_poll - called by the transmit procedure
695 * We go to great pains to avoid changing state here, since there may be
696 * more than one eavesdropper receiving the same timecode.
698 static void
699 nmea_poll(
700 int unit,
701 struct peer *peer
704 register struct nmeaunit *up;
705 struct refclockproc *pp;
707 pp = peer->procptr;
708 up = (struct nmeaunit *)pp->unitptr;
709 if (up->pollcnt == 0)
710 refclock_report(peer, CEVNT_TIMEOUT);
711 else
712 up->pollcnt--;
713 pp->polls++;
714 up->polled = 1;
717 * usually nmea_receive can get a timestamp every second
720 gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer);
725 * gps_send(fd,cmd, peer) Sends a command to the GPS receiver.
726 * as gps_send(fd,"rqts,u\r", peer);
728 * We don't currently send any data, but would like to send
729 * RTCM SC104 messages for differential positioning. It should
730 * also give us better time. Without a PPS output, we're
731 * Just fooling ourselves because of the serial code paths
734 static void
735 gps_send(
736 int fd,
737 const char *cmd,
738 struct peer *peer
742 if (write(fd, cmd, strlen(cmd)) == -1) {
743 refclock_report(peer, CEVNT_FAULT);
747 static char *
748 field_parse(
749 char *cp,
750 int fn
753 char *tp;
754 int i = fn;
756 for (tp = cp; *tp != '\0'; tp++) {
757 if (*tp == ',')
758 i--;
759 if (i == 0)
760 break;
762 return (++tp);
764 #else
765 int refclock_nmea_bs;
766 #endif /* REFCLOCK */