From: Harlan Stenn Date: Sat, 14 Apr 2001 20:45:59 +0000 (-0000) Subject: ChangeLog, driver20.htm, ntp_refclock.c, refclock_nmea.c: X-Git-Tag: NTP_4_0_99_M~82 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=22ea43b24bfbaaac8820889e4fcf931685beca34;p=thirdparty%2Fntp.git ChangeLog, driver20.htm, ntp_refclock.c, refclock_nmea.c: * ntpd/refclock_nmea.c: * ntpd/ntp_refclock.c: * html/driver20.htm: PPSAPI patches for NMEA driver. From: John.Hay@icomtek.csir.co.za bk: 3ad8b7074OBYOWQS12rey8kEM6OJbw --- diff --git a/ChangeLog b/ChangeLog index 6508964e6e..49ffb252ab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2001-04-14 Harlan Stenn + * ntpd/refclock_nmea.c: + * ntpd/ntp_refclock.c: + * html/driver20.htm: + PPSAPI patches for NMEA driver. + From: John.Hay@icomtek.csir.co.za + * README.rsa: Describe RSAEuro support, provide alternate rsa.c patch. * configure.in: Check for rsaeuro1, RSAOBJS, RSADIR respectively. diff --git a/html/driver20.htm b/html/driver20.htm index e6a4bd2a83..68ab141cec 100644 --- a/html/driver20.htm +++ b/html/driver20.htm @@ -30,6 +30,8 @@ or better relative to the broadcast signal. However, in most cases the actual accuracy is limited by the precision of the timecode and the latencies of the serial interface and operating system. +

If the Operating System supports the PPSAPI, RFC-2783, it will be used. +

The $GPRMC message that the GPS transmits look like this:

$GPRMC,POS_UTC,POS_STAT,LAT,LAT_REF,LON,LON_REF,SPD,HDG,DATE,MAG_VAR,MAG_REF*CC<cr><lf>
 
@@ -104,13 +106,15 @@ Not used by this driver.
 flag2 0 | 1
 
 
-Not used by this driver.
+Specifies the PPS signal on-time edge: 0 for assert (default), +1 for clear.
flag3 0 | 1
-Not used by this driver.
+Controls the kernel PPS discipline: 0 for disable (default), 1 +for enable.
flag4 0 | 1
diff --git a/ntpd/ntp_refclock.c b/ntpd/ntp_refclock.c index 317f005b7e..7a112e90e8 100644 --- a/ntpd/ntp_refclock.c +++ b/ntpd/ntp_refclock.c @@ -34,22 +34,10 @@ #include #endif /* HAVE_PPSCLOCK_H */ -#ifdef HAVE_PPSAPI -# ifdef HAVE_TIMEPPS_H -# include -# else -# ifdef HAVE_SYS_TIMEPPS_H -# include -# endif -# endif -#endif /* HAVE_PPSAPI */ - #ifdef KERNEL_PLL #include "ntp_syscall.h" #endif /* KERNEL_PLL */ -#undef HAVE_PPSAPI /* !!! !!! !!! !!! fix me */ - /* * Reference clock support is provided here by maintaining the fiction * that the clock is actually a peer. As no packets are exchanged with a @@ -104,11 +92,6 @@ static int refclock_cmpl_fp P((const double *, const double *)); #endif /* QSORT_USES_VOID_P */ static int refclock_sample P((struct refclockproc *)); -#ifdef HAVE_PPSAPI -extern int pps_assert; /* capture edge 1:assert, 0:clear */ -extern int pps_hardpps; /* PPS kernel 1:on, 0:off */ -#endif /* HAVE_PPSAPI */ - /* * refclock_report - note the occurance of an event * @@ -617,14 +600,6 @@ refclock_gtlin( int i; l_fp trtmp, tstmp; char c; -#ifdef TIOCDCDTIMESTAMP - struct timeval dcd_time; -#endif /* TIOCDCDTIMESTAMP */ -#ifdef HAVE_PPSAPI - pps_info_t pi; - struct timespec timeout, *tsp; - double a; -#endif /* HAVE_PPSAPI */ /* * Check for the presence of a timestamp left by the tty_clock @@ -637,58 +612,6 @@ refclock_gtlin( dpend = dpt + rbufp->recv_length; trtmp = rbufp->recv_time; -#ifdef HAVE_PPSAPI - timeout.tv_sec = 0; - timeout.tv_nsec = 0; - if ((rbufp->fd == fdpps) && - (time_pps_fetch(fdpps, PPS_TSFMT_TSPEC, &pi, &timeout) >= 0)) { - if(pps_assert) - tsp = &pi.assert_timestamp; - else - tsp = &pi.clear_timestamp; - a = tsp->tv_nsec; - a /= 1e9; - tstmp.l_uf = a * 4294967296.0; - tstmp.l_ui = tsp->tv_sec; - tstmp.l_ui += JAN_1970; - L_SUB(&trtmp, &tstmp); - if (trtmp.l_ui == 0) { -#ifdef DEBUG - if (debug > 1) { - printf( - "refclock_gtlin: fd %d time_pps_fetch %s", - fdpps, lfptoa(&tstmp, 6)); - printf(" sigio %s\n", lfptoa(&trtmp, 6)); - } -#endif - trtmp = tstmp; - goto gotit; - } else - trtmp = rbufp->recv_time; - } -#endif /* HAVE_PPSAPI */ -#ifdef TIOCDCDTIMESTAMP - if(ioctl(rbufp->fd, TIOCDCDTIMESTAMP, &dcd_time) != -1) { - TVTOTS(&dcd_time, &tstmp); - tstmp.l_ui += JAN_1970; - L_SUB(&trtmp, &tstmp); - if (trtmp.l_ui == 0) { -#ifdef DEBUG - if (debug > 1) { - printf( - "refclock_gtlin: fd %d DCDTIMESTAMP %s", - rbufp->fd, lfptoa(&tstmp, 6)); - printf(" sigio %s\n", lfptoa(&trtmp, 6)); - } -#endif - trtmp = tstmp; - goto gotit; - } else - trtmp = rbufp->recv_time; - } - else - /* XXX fallback to old method if kernel refuses TIOCDCDTIMESTAMP */ -#endif /* TIOCDCDTIMESTAMP */ if (dpend >= dpt + 8) { if (buftvtots(dpend - 8, &tstmp)) { L_SUB(&trtmp, &tstmp); @@ -710,9 +633,6 @@ refclock_gtlin( } } -#if defined(HAVE_PPSAPI) || defined(TIOCDCDTIMESTAMP) -gotit: -#endif /* * Edit timecode to remove control chars. Don't monkey with the * line buffer if the input buffer contains no ASCII printing diff --git a/ntpd/refclock_nmea.c b/ntpd/refclock_nmea.c index 19f8eee15a..87a1513021 100644 --- a/ntpd/refclock_nmea.c +++ b/ntpd/refclock_nmea.c @@ -11,12 +11,23 @@ #include "ntpd.h" #include "ntp_io.h" +#include "ntp_unixtime.h" #include "ntp_refclock.h" #include "ntp_stdlib.h" #include #include +#ifdef HAVE_PPSAPI +# ifdef HAVE_TIMEPPS_H +# include +# else +# ifdef HAVE_SYS_TIMEPPS_H +# include +# endif +# endif +#endif /* HAVE_PPSAPI */ + /* * This driver supports the NMEA GPS Receiver with * @@ -25,6 +36,14 @@ * The receiver used spits out the NMEA sentences for boat navigation. * And you thought it was an information superhighway. Try a raging river * filled with rapids and whirlpools that rip away your data and warp time. + * + * If HAVE_PPSAPI is defined code to use the PPSAPI will be compiled in. + * On startup if initialization of the PPSAPI fails, it will fall back + * to the "normal" timestamps. + * + * The PPSAPI part of the driver understands fudge flag2 and flag3. If + * flag2 is set, it will use the clear edge of the pulse. If flag3 is + * set, kernel hardpps is enabled. */ /* @@ -37,9 +56,11 @@ #endif #define SPEED232 B4800 /* uart speed (4800 bps) */ #define PRECISION (-9) /* precision assumed (about 2 ms) */ -#define DCD_PRECISION (-20) /* precision assumed (about 1 us) */ +#define PPS_PRECISION (-20) /* precision assumed (about 1 us) */ #define REFID "GPS\0" /* reference id */ #define DESCRIPTION "NMEA GPS Clock" /* who we are */ +#define NANOSECOND 1000000000 /* one second (ns) */ +#define RANGEGATE 500000 /* range gate (ns) */ #define LENNMEA 75 /* min timecode length */ @@ -57,6 +78,12 @@ struct nmeaunit { int pollcnt; /* poll message counter */ int polled; /* Hand in a sample? */ l_fp tstamp; /* timestamp of last poll */ +#ifdef HAVE_PPSAPI + struct timespec ts; /* last timestamp */ + pps_params_t pps_params; /* pps parameters */ + pps_info_t pps_info; /* last pps data */ + pps_handle_t handle; /* pps handlebars */ +#endif /* HAVE_PPSAPI */ }; /* @@ -64,6 +91,12 @@ struct nmeaunit { */ static int nmea_start P((int, struct peer *)); static void nmea_shutdown P((int, struct peer *)); +#ifdef HAVE_PPSAPI +static void nmea_control P((int, struct refclockstat *, struct + refclockstat *, struct peer *)); +static int nmea_ppsapi P((struct peer *, int, int)); +static int nmea_pps P((struct nmeaunit *, l_fp *)); +#endif /* HAVE_PPSAPI */ static void nmea_receive P((struct recvbuf *)); static void nmea_poll P((int, struct peer *)); static void gps_send P((int, const char *, struct peer *)); @@ -76,7 +109,11 @@ struct refclock refclock_nmea = { nmea_start, /* start up driver */ nmea_shutdown, /* shut down driver */ nmea_poll, /* transmit poll message */ - noentry, /* handle control */ +#ifdef HAVE_PPSAPI + nmea_control, /* fudge control */ +#else + noentry, /* fudge control */ +#endif /* HAVE_PPSAPI */ noentry, /* initialize driver */ noentry, /* buginfo */ NOFLAGS /* not used */ @@ -128,13 +165,26 @@ nmea_start( /* * Initialize miscellaneous variables */ - peer->precision = DCD_PRECISION; + peer->precision = PRECISION; pp->clockdesc = DESCRIPTION; memcpy((char *)&pp->refid, REFID, 4); up->pollcnt = 2; gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer); +#ifdef HAVE_PPSAPI + /* + * Start the PPSAPI interface if it is there. Default to use + * the assert edge and do not enable the kernel hardpps. + */ + if (time_pps_create(fd, &up->handle) < 0) { + msyslog(LOG_ERR, + "refclock_nmea: time_pps_create failed: %m"); + return (1); + } + return(nmea_ppsapi(peer, 0, 0)); +#else return (1); +#endif /* HAVE_PPSAPI */ } /* @@ -151,10 +201,148 @@ nmea_shutdown( pp = peer->procptr; up = (struct nmeaunit *)pp->unitptr; +#ifdef HAVE_PPSAPI + if (up->handle != 0) + time_pps_destroy(up->handle); +#endif /* HAVE_PPSAPI */ io_closeclock(&pp->io); free(up); } +#ifdef HAVE_PPSAPI +/* + * nmea_control - fudge control + */ +static void +nmea_control( + int unit, /* unit (not used */ + struct refclockstat *in, /* input parameters (not uded) */ + struct refclockstat *out, /* output parameters (not used) */ + struct peer *peer /* peer structure pointer */ + ) +{ + struct refclockproc *pp; + + pp = peer->procptr; + nmea_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2, + pp->sloppyclockflag & CLK_FLAG3); +} + + +/* + * Initialize PPSAPI + */ +int +nmea_ppsapi( + struct peer *peer, /* peer structure pointer */ + int enb_clear, /* clear enable */ + int enb_hardpps /* hardpps enable */ + ) +{ + struct refclockproc *pp; + struct nmeaunit *up; + int capability; + + pp = peer->procptr; + up = (struct nmeaunit *)pp->unitptr; + if (time_pps_getcap(up->handle, &capability) < 0) { + msyslog(LOG_ERR, + "refclock_nmea: time_pps_getcap failed: %m"); + return (0); + } + memset(&up->pps_params, 0, sizeof(pps_params_t)); + if (enb_clear) + up->pps_params.mode = capability & PPS_CAPTURECLEAR; + else + up->pps_params.mode = capability & PPS_CAPTUREASSERT; + if (!up->pps_params.mode) { + msyslog(LOG_ERR, + "refclock_nmea: invalid capture edge %d", + !enb_clear); + return (0); + } + up->pps_params.mode |= PPS_TSFMT_TSPEC; + if (time_pps_setparams(up->handle, &up->pps_params) < 0) { + msyslog(LOG_ERR, + "refclock_nmea: time_pps_setparams failed: %m"); + return (0); + } + if (enb_hardpps) { + if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS, + up->pps_params.mode & ~PPS_TSFMT_TSPEC, + PPS_TSFMT_TSPEC) < 0) { + msyslog(LOG_ERR, + "refclock_nmea: time_pps_kcbind failed: %m"); + return (0); + } + } + peer->precision = PPS_PRECISION; + +#if DEBUG + if (debug) { + time_pps_getparams(up->handle, &up->pps_params); + printf( + "refclock_ppsapi: fd %d capability 0x%x version %d mode 0x%x kern %d\n", + up->handle, capability, up->pps_params.api_version, + up->pps_params.mode, enb_hardpps); + } +#endif + + return (1); +} + +/* + * Get PPSAPI timestamps. + * + * Return 0 on failure and 1 on success. + */ +static int +nmea_pps( + struct nmeaunit *up, + l_fp *tsptr + ) +{ + pps_info_t pps_info; + struct timespec timeout, ts; + double dtemp; + l_fp tstmp; + + /* + * Convert the timespec nanoseconds field to ntp l_fp units. + */ + if (up->handle == -1) + return (0); + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t)); + if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info, + &timeout) < 0) + return (0); + if (up->pps_params.mode & PPS_CAPTUREASSERT) { + if (pps_info.assert_sequence == + up->pps_info.assert_sequence) + return (0); + ts = up->pps_info.assert_timestamp; + } else if (up->pps_params.mode & PPS_CAPTURECLEAR) { + if (pps_info.clear_sequence == + up->pps_info.clear_sequence) + return (0); + ts = up->pps_info.clear_timestamp; + } else { + return (0); + } + if ((up->ts.tv_sec == ts.tv_sec) && (up->ts.tv_nsec == ts.tv_nsec)) + return (0); + up->ts = ts; + + tstmp.l_ui = ts.tv_sec + JAN_1970; + dtemp = ts.tv_nsec * FRAC / 1e9; + tstmp.l_uf = (u_int32)dtemp; + *tsptr = tstmp; + return (1); +} +#endif /* HAVE_PPSAPI */ + /* * nmea_receive - receive data from the serial interface */ @@ -191,6 +379,13 @@ nmea_receive( */ pp->lastrec = up->tstamp = trtmp; up->pollcnt = 2; + +#ifdef HAVE_PPSAPI + /* If the PPSAPI is working, rather use its timestamps. */ + if (nmea_pps(up, &trtmp) == 1) + pp->lastrec = up->tstamp = trtmp; +#endif /* HAVE_PPSAPI */ + #ifdef DEBUG if (debug) printf("nmea: timecode %d %s\n", pp->lencode,