]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
ChangeLog, driver20.htm, ntp_refclock.c, refclock_nmea.c:
authorHarlan Stenn <stenn@ntp.org>
Sat, 14 Apr 2001 20:45:59 +0000 (20:45 -0000)
committerHarlan Stenn <stenn@ntp.org>
Sat, 14 Apr 2001 20:45:59 +0000 (20:45 -0000)
  * 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

ChangeLog
html/driver20.htm
ntpd/ntp_refclock.c
ntpd/refclock_nmea.c

index 6508964e6e67207e0feeff5d2983aed82f05e445..49ffb252ab0eb4819a1e73ce6a56bbd048326b4e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2001-04-14  Harlan Stenn  <stenn@whimsy.udel.edu>
 
+       * 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. 
index e6a4bd2a83d11c4982e2d4295a9b6cad1ec953eb..68ab141cecf914c6ef19759b0aa24a04abd19e86 100644 (file)
@@ -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.
 
+<P>If the Operating System supports the PPSAPI, RFC-2783, it will be used.
+
 <P>The $GPRMC message that the GPS transmits look like this:
 <PRE>$GPRMC,POS_UTC,POS_STAT,LAT,LAT_REF,LON,LON_REF,SPD,HDG,DATE,MAG_VAR,MAG_REF*CC&lt;cr>&lt;lf>
 
@@ -104,13 +106,15 @@ Not used by this driver.</DD>
 <TT>flag2 0 | 1</TT></DT>
 
 <DD>
-Not used by this driver.</DD>
+Specifies the PPS signal on-time edge: 0 for assert (default),
+1 for clear.</DD>
 
 <DT>
 <TT>flag3 0 | 1</TT></DT>
 
 <DD>
-Not used by this driver.</DD>
+Controls the kernel PPS discipline: 0 for disable (default), 1
+for enable.</DD>
 
 <DT>
 <TT>flag4 0 | 1</TT></DT>
index 317f005b7ea9daa51464c438b720f943b1f1ea7c..7a112e90e85ac1418431d55a0642765ea6b205e2 100644 (file)
 #include <sys/ppsclock.h>
 #endif /* HAVE_PPSCLOCK_H */
 
-#ifdef HAVE_PPSAPI
-# ifdef HAVE_TIMEPPS_H
-#  include <timepps.h>
-# else
-#  ifdef HAVE_SYS_TIMEPPS_H
-#   include <sys/timepps.h>
-#  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
index 19f8eee15a05943d8d0d7332b5dba99a75304a2c..87a15130216a0d0ea42baa8c934720d80595506c 100644 (file)
 
 #include "ntpd.h"
 #include "ntp_io.h"
+#include "ntp_unixtime.h"
 #include "ntp_refclock.h"
 #include "ntp_stdlib.h"
 
 #include <stdio.h>
 #include <ctype.h>
 
+#ifdef HAVE_PPSAPI
+# ifdef HAVE_TIMEPPS_H
+#  include <timepps.h>
+# else
+#  ifdef HAVE_SYS_TIMEPPS_H
+#   include <sys/timepps.h>
+#  endif
+# endif
+#endif /* HAVE_PPSAPI */
+
 /*
  * This driver supports the NMEA GPS Receiver with
  *
  * 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.
  */
 
 /*
 #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,