2 * refclock_nmea.c - clock driver for an NMEA GPS CLOCK
3 * Michael Petry Jun 20, 1994
4 * based on refclock_heathn.c
10 #if defined(SYS_WINNT)
12 #define close closesocket
15 #if defined(REFCLOCK) && defined(CLOCK_NMEA)
22 #include "ntp_unixtime.h"
23 #include "ntp_refclock.h"
24 #include "ntp_stdlib.h"
27 # include "ppsapi_timepps.h"
28 #endif /* HAVE_PPSAPI */
31 * This driver supports the NMEA GPS Receiver with
33 * Protype was refclock_trak.c, Thanks a lot.
35 * The receiver used spits out the NMEA sentences for boat navigation.
36 * And you thought it was an information superhighway. Try a raging river
37 * filled with rapids and whirlpools that rip away your data and warp time.
39 * If HAVE_PPSAPI is defined code to use the PPSAPI will be compiled in.
40 * On startup if initialization of the PPSAPI fails, it will fall back
41 * to the "normal" timestamps.
43 * The PPSAPI part of the driver understands fudge flag2 and flag3. If
44 * flag2 is set, it will use the clear edge of the pulse. If flag3 is
45 * set, kernel hardpps is enabled.
47 * GPS sentences other than RMC (the default) may be enabled by setting
48 * the relevent bits of 'mode' in the server configuration line
49 * server 127.127.20.x mode X
51 * bit 0 - enables RMC (1)
52 * bit 1 - enables GGA (2)
53 * bit 2 - enables GLL (4)
54 * multiple sentences may be selected
61 # define DEVICE "COM%d:" /* COM 1 - 3 supported */
63 # define DEVICE "/dev/gps%d" /* name of radio device */
65 #define SPEED232 B4800 /* uart speed (4800 bps) */
66 #define PRECISION (-9) /* precision assumed (about 2 ms) */
67 #define PPS_PRECISION (-20) /* precision assumed (about 1 us) */
68 #define REFID "GPS\0" /* reference id */
69 #define DESCRIPTION "NMEA GPS Clock" /* who we are */
70 #define NANOSECOND 1000000000 /* one second (ns) */
71 #define RANGEGATE 500000 /* range gate (ns) */
73 #define LENNMEA 75 /* min timecode length */
76 * Tables to compute the ddd of year form icky dd/mm timecode. Viva la
79 static int day1tab
[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
80 static int day2tab
[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
83 * Unit control structure
86 int pollcnt
; /* poll message counter */
87 int polled
; /* Hand in a sample? */
88 l_fp tstamp
; /* timestamp of last poll */
90 struct timespec ts
; /* last timestamp */
91 pps_params_t pps_params
; /* pps parameters */
92 pps_info_t pps_info
; /* last pps data */
93 pps_handle_t handle
; /* pps handlebars */
94 #endif /* HAVE_PPSAPI */
100 static int nmea_start
P((int, struct peer
*));
101 static void nmea_shutdown
P((int, struct peer
*));
103 static void nmea_control
P((int, struct refclockstat
*, struct
104 refclockstat
*, struct peer
*));
105 static int nmea_ppsapi
P((struct peer
*, int, int));
106 static int nmea_pps
P((struct nmeaunit
*, l_fp
*));
107 #endif /* HAVE_PPSAPI */
108 static void nmea_receive
P((struct recvbuf
*));
109 static void nmea_poll
P((int, struct peer
*));
110 static void gps_send
P((int, const char *, struct peer
*));
111 static char *field_parse
P((char *, int));
116 struct refclock refclock_nmea
= {
117 nmea_start
, /* start up driver */
118 nmea_shutdown
, /* shut down driver */
119 nmea_poll
, /* transmit poll message */
121 nmea_control
, /* fudge control */
123 noentry
, /* fudge control */
124 #endif /* HAVE_PPSAPI */
125 noentry
, /* initialize driver */
126 noentry
, /* buginfo */
127 NOFLAGS
/* not used */
131 * nmea_start - open the GPS devices and initialize data for processing
139 register struct nmeaunit
*up
;
140 struct refclockproc
*pp
;
145 * Open serial port. Use CLK line discipline, if available.
147 (void)sprintf(device
, DEVICE
, unit
);
149 fd
= refclock_open(device
, SPEED232
, LDISC_CLK
);
152 /* nmead support added by Jon Miner (cp_n18@yahoo.com)
154 * See http://home.hiwaay.net/~taylorc/gps/nmea-server/
155 * for information about nmead
157 * To use this, you need to create a link from /dev/gpsX to
158 * the server:port where nmead is running. Something like this:
160 * ln -s server:port /dev/gps1
168 struct sockaddr_in so_addr
;
170 if ((len
= readlink(device
,buffer
,sizeof(buffer
))) == -1)
174 if ((nmea_host
= strtok(buffer
,":")) == NULL
)
177 nmea_port
= atoi(strtok(NULL
,":"));
179 if ((he
= gethostbyname(nmea_host
)) == NULL
)
181 if ((p
= getprotobyname("ip")) == NULL
)
183 so_addr
.sin_family
= AF_INET
;
184 so_addr
.sin_port
= htons(nmea_port
);
185 so_addr
.sin_addr
= *((struct in_addr
*) he
->h_addr
);
187 if ((fd
= socket(PF_INET
,SOCK_STREAM
,p
->p_proto
)) == -1)
189 if (connect(fd
,(struct sockaddr
*)&so_addr
,SOCKLEN(&so_addr
)) == -1) {
199 * Allocate and initialize unit structure
201 up
= (struct nmeaunit
*)emalloc(sizeof(struct nmeaunit
));
206 memset((char *)up
, 0, sizeof(struct nmeaunit
));
208 pp
->io
.clock_recv
= nmea_receive
;
209 pp
->io
.srcclock
= (caddr_t
)peer
;
212 if (!io_addclock(&pp
->io
)) {
217 pp
->unitptr
= (caddr_t
)up
;
220 * Initialize miscellaneous variables
222 peer
->precision
= PRECISION
;
223 pp
->clockdesc
= DESCRIPTION
;
224 memcpy((char *)&pp
->refid
, REFID
, 4);
226 gps_send(pp
->io
.fd
,"$PMOTG,RMC,0000*1D\r\n", peer
);
230 * Start the PPSAPI interface if it is there. Default to use
231 * the assert edge and do not enable the kernel hardpps.
233 if (time_pps_create(fd
, &up
->handle
) < 0) {
236 "refclock_nmea: time_pps_create failed: %m");
239 return(nmea_ppsapi(peer
, 0, 0));
242 #endif /* HAVE_PPSAPI */
246 * nmea_shutdown - shut down a GPS clock
254 register struct nmeaunit
*up
;
255 struct refclockproc
*pp
;
258 up
= (struct nmeaunit
*)pp
->unitptr
;
261 time_pps_destroy(up
->handle
);
262 #endif /* HAVE_PPSAPI */
263 io_closeclock(&pp
->io
);
269 * nmea_control - fudge control
273 int unit
, /* unit (not used */
274 struct refclockstat
*in
, /* input parameters (not uded) */
275 struct refclockstat
*out
, /* output parameters (not used) */
276 struct peer
*peer
/* peer structure pointer */
279 struct refclockproc
*pp
;
282 nmea_ppsapi(peer
, pp
->sloppyclockflag
& CLK_FLAG2
,
283 pp
->sloppyclockflag
& CLK_FLAG3
);
292 struct peer
*peer
, /* peer structure pointer */
293 int enb_clear
, /* clear enable */
294 int enb_hardpps
/* hardpps enable */
297 struct refclockproc
*pp
;
302 up
= (struct nmeaunit
*)pp
->unitptr
;
303 if (time_pps_getcap(up
->handle
, &capability
) < 0) {
305 "refclock_nmea: time_pps_getcap failed: %m");
308 memset(&up
->pps_params
, 0, sizeof(pps_params_t
));
310 up
->pps_params
.mode
= capability
& PPS_CAPTURECLEAR
;
312 up
->pps_params
.mode
= capability
& PPS_CAPTUREASSERT
;
313 if (!up
->pps_params
.mode
) {
315 "refclock_nmea: invalid capture edge %d",
319 up
->pps_params
.mode
|= PPS_TSFMT_TSPEC
;
320 if (time_pps_setparams(up
->handle
, &up
->pps_params
) < 0) {
322 "refclock_nmea: time_pps_setparams failed: %m");
326 if (time_pps_kcbind(up
->handle
, PPS_KC_HARDPPS
,
327 up
->pps_params
.mode
& ~PPS_TSFMT_TSPEC
,
328 PPS_TSFMT_TSPEC
) < 0) {
330 "refclock_nmea: time_pps_kcbind failed: %m");
335 peer
->precision
= PPS_PRECISION
;
339 time_pps_getparams(up
->handle
, &up
->pps_params
);
341 "refclock_ppsapi: capability 0x%x version %d mode 0x%x kern %d\n",
342 capability
, up
->pps_params
.api_version
,
343 up
->pps_params
.mode
, enb_hardpps
);
351 * Get PPSAPI timestamps.
353 * Return 0 on failure and 1 on success.
362 struct timespec timeout
, ts
;
367 * Convert the timespec nanoseconds field to ntp l_fp units.
373 memcpy(&pps_info
, &up
->pps_info
, sizeof(pps_info_t
));
374 if (time_pps_fetch(up
->handle
, PPS_TSFMT_TSPEC
, &up
->pps_info
,
377 if (up
->pps_params
.mode
& PPS_CAPTUREASSERT
) {
378 if (pps_info
.assert_sequence
==
379 up
->pps_info
.assert_sequence
)
381 ts
= up
->pps_info
.assert_timestamp
;
382 } else if (up
->pps_params
.mode
& PPS_CAPTURECLEAR
) {
383 if (pps_info
.clear_sequence
==
384 up
->pps_info
.clear_sequence
)
386 ts
= up
->pps_info
.clear_timestamp
;
390 if ((up
->ts
.tv_sec
== ts
.tv_sec
) && (up
->ts
.tv_nsec
== ts
.tv_nsec
))
394 tstmp
.l_ui
= ts
.tv_sec
+ JAN_1970
;
395 dtemp
= ts
.tv_nsec
* FRAC
/ 1e9
;
396 tstmp
.l_uf
= (u_int32
)dtemp
;
400 #endif /* HAVE_PPSAPI */
403 * nmea_receive - receive data from the serial interface
407 struct recvbuf
*rbufp
410 register struct nmeaunit
*up
;
411 struct refclockproc
*pp
;
417 /* Use these variables to hold data until we decide its worth keeping */
418 char rd_lastcode
[BMAX
];
423 * Initialize pointers and read the timecode and timestamp
425 peer
= (struct peer
*)rbufp
->recv_srcclock
;
427 up
= (struct nmeaunit
*)pp
->unitptr
;
428 rd_lencode
= (u_short
)refclock_gtlin(rbufp
, rd_lastcode
, BMAX
, &rd_tmp
);
431 * There is a case that a <CR><LF> gives back a "blank" line
438 printf("nmea: gpsread %d %s\n", rd_lencode
,
443 * We check the timecode format and decode its contents. The
444 * we only care about a few of them. The most important being
446 * $GPRMC,hhmmss,a,fddmm.xx,n,dddmmm.xx,w,zz.z,yyy.,ddmmyy,dd,v*CC
447 * For Magellan (ColorTrak) GLL probably datum (order of sentences)
448 * also mode (0,1,2,3) select sentence ANY/ALL, RMC, GGA, GLL
449 * $GPGLL,3513.8385,S,14900.7851,E,232420.594,A*21
450 * $GPGGA,232420.59,3513.8385,S,14900.7851,E,1,05,3.4,00519,M,,,,*3F
452 * $GPRMC,232418.19,A,3513.8386,S,14900.7853,E,00.0,000.0,121199,12.,E*77
464 if(strncmp(cp
,"$GPRMC",6)==0) {
467 else if(strncmp(cp
,"$GPGGA",6)==0) {
470 else if(strncmp(cp
,"$GPGLL",6)==0) {
473 else if(strncmp(cp
,"$GPXXX",6)==0) {
480 /* See if I want to process this message type */
481 if ( ((peer
->ttl
== 0) && (cmdtype
!= GPRMC
))
482 || ((peer
->ttl
!= 0) && !(cmdtype
& peer
->ttl
)) )
485 pp
->lencode
= rd_lencode
;
486 strcpy(pp
->a_lastcode
,rd_lastcode
);
489 pp
->lastrec
= up
->tstamp
= rd_tmp
;
494 printf("nmea: timecode %d %s\n", pp
->lencode
,
499 /* Grab field depending on clock string type */
503 * Test for synchronization. Check for quality byte.
505 dp
= field_parse(cp
,2);
507 pp
->leap
= LEAP_NOTINSYNC
;
509 pp
->leap
= LEAP_NOWARNING
;
511 /* Now point at the time field */
512 dp
= field_parse(cp
,1);
518 * Test for synchronization. Check for quality byte.
520 dp
= field_parse(cp
,6);
522 pp
->leap
= LEAP_NOTINSYNC
;
524 pp
->leap
= LEAP_NOWARNING
;
526 /* Now point at the time field */
527 dp
= field_parse(cp
,1);
533 * Test for synchronization. Check for quality byte.
535 dp
= field_parse(cp
,6);
537 pp
->leap
= LEAP_NOTINSYNC
;
539 pp
->leap
= LEAP_NOWARNING
;
541 /* Now point at the time field */
542 dp
= field_parse(cp
,5);
554 * Check time code format of NMEA
557 if( !isdigit((int)dp
[0]) ||
558 !isdigit((int)dp
[1]) ||
559 !isdigit((int)dp
[2]) ||
560 !isdigit((int)dp
[3]) ||
561 !isdigit((int)dp
[4]) ||
564 refclock_report(peer
, CEVNT_BADREPLY
);
570 * Convert time and check values.
572 pp
->hour
= ((dp
[0] - '0') * 10) + dp
[1] - '0';
573 pp
->minute
= ((dp
[2] - '0') * 10) + dp
[3] - '0';
574 pp
->second
= ((dp
[4] - '0') * 10) + dp
[5] - '0';
575 /* Default to 0 milliseconds, if decimal convert milliseconds in
576 one, two or three digits
580 if (isdigit((int)dp
[7])) {
581 pp
->nsec
= (dp
[7] - '0') * 100000000;
582 if (isdigit((int)dp
[8])) {
583 pp
->nsec
+= (dp
[8] - '0') * 10000000;
584 if (isdigit((int)dp
[9])) {
585 pp
->nsec
+= (dp
[9] - '0') * 1000000;
591 if (pp
->hour
> 23 || pp
->minute
> 59 || pp
->second
> 59
592 || pp
->nsec
> 1000000000) {
593 refclock_report(peer
, CEVNT_BADTIME
);
599 * Convert date and check values.
601 if (cmdtype
==GPRMC
) {
602 dp
= field_parse(cp
,9);
604 day
= (day
* 10) + dp
[1] - '0';
606 month
= (month
* 10) + dp
[3] - '0';
607 pp
->year
= dp
[4] - '0';
608 pp
->year
= (pp
->year
* 10) + dp
[5] - '0';
612 time_t tt
= time(NULL
);
613 struct tm
* t
= gmtime(&tt
);
615 month
= t
->tm_mon
+ 1;
616 pp
->year
= t
->tm_year
;
619 if (month
< 1 || month
> 12 || day
< 1) {
620 refclock_report(peer
, CEVNT_BADTIME
);
624 /* Hmmmm this will be a nono for 2100,2200,2300 but I don't think I'll be here */
625 /* good thing that 2000 is a leap year */
626 /* pp->year will be 00-99 if read from GPS, 00-> (years since 1900) from tm_year */
628 if (day
> day1tab
[month
- 1]) {
629 refclock_report(peer
, CEVNT_BADTIME
);
632 for (i
= 0; i
< month
- 1; i
++)
635 if (day
> day2tab
[month
- 1]) {
636 refclock_report(peer
, CEVNT_BADTIME
);
639 for (i
= 0; i
< month
- 1; i
++)
647 * If the PPSAPI is working, rather use its timestamps.
648 * assume that the PPS occurs on the second so blow any msec
650 if (nmea_pps(up
, &rd_tmp
) == 1) {
651 pp
->lastrec
= up
->tstamp
= rd_tmp
;
654 #endif /* HAVE_PPSAPI */
657 * Process the new sample in the median filter and determine the
658 * reference clock offset and dispersion. We use lastrec as both
659 * the reference time and receive time, in order to avoid being
660 * cute, like setting the reference time later than the receive
661 * time, which may cause a paranoid protocol module to chuck out
665 if (!refclock_process(pp
)) {
666 refclock_report(peer
, CEVNT_BADTIME
);
673 * Only go on if we had been polled.
678 pp
->lastref
= pp
->lastrec
;
679 refclock_receive(peer
);
681 /* If we get here - what we got from the clock is OK, so say so */
682 refclock_report(peer
, CEVNT_NOMINAL
);
684 record_clock_stats(&peer
->srcadr
, pp
->a_lastcode
);
689 * nmea_poll - called by the transmit procedure
691 * We go to great pains to avoid changing state here, since there may be
692 * more than one eavesdropper receiving the same timecode.
700 register struct nmeaunit
*up
;
701 struct refclockproc
*pp
;
704 up
= (struct nmeaunit
*)pp
->unitptr
;
705 if (up
->pollcnt
== 0)
706 refclock_report(peer
, CEVNT_TIMEOUT
);
713 * usually nmea_receive can get a timestamp every second
716 gps_send(pp
->io
.fd
,"$PMOTG,RMC,0000*1D\r\n", peer
);
721 * gps_send(fd,cmd, peer) Sends a command to the GPS receiver.
722 * as gps_send(fd,"rqts,u\r", peer);
724 * We don't currently send any data, but would like to send
725 * RTCM SC104 messages for differential positioning. It should
726 * also give us better time. Without a PPS output, we're
727 * Just fooling ourselves because of the serial code paths
738 if (write(fd
, cmd
, strlen(cmd
)) == -1) {
739 refclock_report(peer
, CEVNT_FAULT
);
752 for (tp
= cp
; *tp
!= '\0'; tp
++) {
761 int refclock_nmea_bs
;
762 #endif /* REFCLOCK */