]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
Zyfer GPStarplus driver (From Harlan Stenn)
authorHarlan Stenn <stenn@ntp.org>
Tue, 19 Feb 2002 17:52:08 +0000 (12:52 -0500)
committerHarlan Stenn <stenn@ntp.org>
Tue, 19 Feb 2002 17:52:08 +0000 (12:52 -0500)
debug cleanup in loopfilter.

bk: 3c7290c8oB-kZ7Yn-jQM2IcJCYi57w

configure.in
html/driver42.html [new file with mode: 0644]
include/ntp.h
libntp/clocktypes.c
ntpd/Makefile.am
ntpd/ntp_control.c
ntpd/ntp_loopfilter.c
ntpd/refclock_conf.c
ntpd/refclock_zyfer.c [new file with mode: 0644]

index 5519c5d25a02c064c5b5e9ca4a2ed32549c2f670..11b38146206fac1ebd5a9cbcc0a39f7d3ed8e706 100644 (file)
@@ -2068,6 +2068,16 @@ if test "$ntp_ok" = "yes"; then
 fi
 AC_MSG_RESULT($ntp_ok)
 
+AC_MSG_CHECKING(for Zyfer receiver)
+AC_ARG_ENABLE(ZYFER,
+    AC_HELP_STRING([--enable-ZYFER], [+ Zyfer GPStarplus receiver]),
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_ZYFER, 1, [Zyfer GPStarplus])
+fi
+AC_MSG_RESULT($ntp_ok)
+
 AC_MSG_CHECKING(for default inclusion of all suitable PARSE clocks)
 AC_ARG_ENABLE(parse-clocks,    [  --enable-parse-clocks   - include all suitable PARSE clocks:],
     [ntp_eapc=$enableval],
diff --git a/html/driver42.html b/html/driver42.html
new file mode 100644 (file)
index 0000000..3622b84
--- /dev/null
@@ -0,0 +1,39 @@
+<HTML>
+<HEAD>
+   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+   <META NAME="GENERATOR" CONTENT="Mozilla/4.01 [en] (Win95; I) [Netscape]">
+   <TITLE>Zyfer GPStarplus Receiver</TITLE>
+</HEAD>
+<BODY>
+
+<H3>Zyfer GPStarplus Receiver</H3>
+
+<HR>
+<H4>Synopsis</H4>
+Address: 127.127.42.<I>u</I>
+<BR>Reference ID: <TT>GPS</TT>
+<BR>Driver ID: <TT>Zyfer GPStarplus</TT>
+<BR>Serial Port: <TT>/dev/zyfer<I>u</I></TT>; 9600 baud, 8-bits, no parity
+<BR>Features: <TT>(none)</TT>
+
+<H4>Description</H4>
+This driver supports the <a href="http://www.zyfer.com/">Zyfer GPStarplus</a>
+receiver.
+
+<p>The receiver has a DB15 port on the back which has input TxD and RxD
+lines for configuration and control, and a separate TxD line for the
+once-per-second timestamp.
+
+<p>Additionally, there are BNC connectors on the back for things like PPS
+and IRIG output.
+
+</DL>
+Additional Information
+
+<P><A HREF="refclock.htm">Reference Clock Drivers</A>&nbsp;
+<HR>
+<ADDRESS>
+Harlan Stenn (stenn@whimsy.udel.edu)</ADDRESS>
+
+</BODY>
+</HTML>
index eaf9228e108b3f1492ced33d48442706ce75c1e1..5881df180f1e4afe26d27c446d1dab88b93d7bb0 100644 (file)
@@ -458,7 +458,8 @@ struct peer {
 #define REFCLK_HOPF_SERIAL     38      /* hopf DCF77/GPS serial line receiver  */
 #define REFCLK_HOPF_PCI                39      /* hopf DCF77/GPS PCI receiver  */
 #define REFCLK_JJY             40      /* JJY receiver  */
-#define REFCLK_MAX             40      /* Grow as needed... */
+#define REFCLK_ZYFER           41      /* Zyfer GPStarplus receiver  */
+#define REFCLK_MAX             41      /* Grow as needed... */
 
 /*
  * We tell reference clocks from real peers by giving the reference
index 69250aa5a1015a5191769734fc640a26a5c6593a..3e767ce910213cf1e2e8a38319f51f2d11b1b73c 100644 (file)
@@ -92,6 +92,8 @@ struct clktype clktypes[] = {
          "HOPF_P"},
        { REFCLK_JJY,   "JJY receiver (40)",
          "JJY" },
+       { REFCLK_ZYFER, "Zyfer GPStarplus receiver (41)",
+         "GPS_ZYFER" },
        { -1,                   "", "" }
 };
 
index 531da470064894726fa57db33915e54d58f0a544..f6552ca46ac1c1e416a52cbb82b430ea30412a7e 100644 (file)
@@ -30,13 +30,14 @@ ntpd_SOURCES = cmd_args.c jupiter.h map_vme.c ntp_config.c ntp_control.c \
        refclock_as2201.c refclock_atom.c refclock_bancomm.c \
        refclock_chronolog.c refclock_chu.c refclock_conf.c refclock_datum.c \
        refclock_dumbclock.c refclock_fg.c refclock_gpsvme.c refclock_heath.c \
-       refclock_hopfser.c refclock_hopfpci.c \
-       refclock_hpgps.c refclock_irig.c refclock_jjy.c refclock_jupiter.c refclock_leitch.c \
+       refclock_hopfser.c refclock_hopfpci.c refclock_hpgps.c \
+       refclock_irig.c refclock_jjy.c refclock_jupiter.c refclock_leitch.c \
        refclock_local.c refclock_msfees.c refclock_mx4200.c refclock_nmea.c \
        refclock_oncore.c refclock_palisade.c refclock_palisade.h \
        refclock_parse.c refclock_pcf.c refclock_pst.c refclock_ptbacts.c \
        refclock_shm.c refclock_tpro.c refclock_trak.c refclock_true.c \
-       refclock_ulink.c refclock_usno.c refclock_wwv.c refclock_wwvb.c
+       refclock_ulink.c refclock_usno.c refclock_wwv.c refclock_wwvb.c \
+       refclock_zyfer.c
 
 $(PROGRAMS): $(LDADD)
 
index a423d9a89f93fa15478751202e7e6e7f7d4189a0..771d76be44af7233ebcb31a4456abbb42b4e89b4 100644 (file)
@@ -396,6 +396,7 @@ static u_char clocktypes[] = {
        CTL_SST_TS_UHF,         /* REFCLK_HOPF_SERIAL (38) */
        CTL_SST_TS_UHF,         /* REFCLK_HOPF_PCI (39) */
        CTL_SST_TS_LF,          /* REFCLK_JJY (40) */
+       CTL_SST_TS_UHF,         /* REFCLK_ZYFER (41) */
 };
 
 
index b88c255db739e562400141d1a0f39f3464ecce6a..21085aaab5a63c756b50dab2b47e230fddd7ffd3 100644 (file)
@@ -695,8 +695,8 @@ local_clock(
        if (debug)
                printf(
                    "local_clock: mu %.0f noi %.3f stb %.3f pol %d cnt %d\n",
-                   mu, sys_jitter * 1e6 / mu, clock_stability * 1e6,
-                   sys_poll, tc_counter);
+                   mu, sys_jitter * 1e6, clock_stability * 1e6, sys_poll,
+                   tc_counter);
 #endif /* DEBUG */
        return (retval);
 }
index 2c8b1beb3fa26462e2e6ba0ce0d167ac9074d03d..efe1f823d6ff21c5d2b6e061b6e72eb52393204a 100644 (file)
@@ -246,6 +246,12 @@ extern     struct refclock refclock_jjy;
 #define        refclock_jjy refclock_none
 #endif
 
+#ifdef CLOCK_ZYFER
+extern struct refclock refclock_zyfer;
+#else
+#define        refclock_zyfer refclock_none
+#endif
+
 /*
  * Order is clock_start(), clock_shutdown(), clock_poll(),
  * clock_control(), clock_init(), clock_buginfo, clock_flags;
@@ -293,7 +299,8 @@ struct refclock *refclock_conf[] = {
        &refclock_fg,           /* 37 REFCLOCK_FG */
        &refclock_hopfser,      /* 38 REFCLK_HOPF_SERIAL */
        &refclock_hopfpci,      /* 39 REFCLK_HOPF_PCI */
-       &refclock_jjy           /* 40 REFCLK_JJY */
+       &refclock_jjy,          /* 40 REFCLK_JJY */
+       &refclock_zyfer         /* 41 REFCLK_ZYFER */
 };
 
 u_char num_refclock_conf = sizeof(refclock_conf)/sizeof(struct refclock *);
diff --git a/ntpd/refclock_zyfer.c b/ntpd/refclock_zyfer.c
new file mode 100644 (file)
index 0000000..ea9b25b
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * refclock_zyfer - clock driver for the Zyfer GPSTarplus Clock
+ *
+ * Harlan Stenn, Jan 2002
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(REFCLOCK) && defined(CLOCK_ZYFER)
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_stdlib.h"
+#include "ntp_unixtime.h"
+
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef HAVE_SYS_TERMIOS_H
+# include <sys/termios.h>
+#endif
+#ifdef HAVE_SYS_PPSCLOCK_H
+# include <sys/ppsclock.h>
+#endif
+
+/*
+ * This driver provides support for the TOD serial port of a Zyfer GPStarplus.
+ * This clock also provides PPS as well as IRIG outputs.
+ * Precision is limited by the serial driver, etc.
+ *
+ * If I was really brave I'd hack/generalize the serial driver to deal
+ * with arbitrary on-time characters.  This clock *begins* the stream with
+ * `!`, the on-time character, and the string is *not* EOL-terminated.
+ *
+ * Configure the beast for 9600, 8N1.  While I see leap-second stuff
+ * in the documentation, the published specs on the TOD format only show
+ * the seconds going to '59'.  I see no leap warning in the TOD format.
+ *
+ * The clock sends the following message once per second:
+ *
+ *     !TIME,2002,017,07,59,32,2,4,1
+ *           YYYY DDD HH MM SS m T O
+ *
+ *     !               On-time character
+ *     YYYY            Year
+ *     DDD     001-366 Day of Year
+ *     HH      00-23   Hour
+ *     MM      00-59   Minute
+ *     SS      00-59   Second (probably 00-60)
+ *     m       1-5     Time Mode:
+ *                     1 = GPS time
+ *                     2 = UTC time
+ *                     3 = LGPS time (Local GPS)
+ *                     4 = LUTC time (Local UTC)
+ *                     5 = Manual time
+ *     T       4-9     Time Figure Of Merit:
+ *                     4         x <= 1us
+ *                     5   1us < x <= 10 us
+ *                     6  10us < x <= 100us
+ *                     7 100us < x <= 1ms
+ *                     8   1ms < x <= 10ms
+ *                     9  10ms < x
+ *     O       0-4     Operation Mode:
+ *                     0 Warm-up
+ *                     1 Time Locked
+ *                     2 Coasting
+ *                     3 Recovering
+ *                     4 Manual
+ *
+ */
+
+/*
+ * Interface definitions
+ */
+#define        DEVICE          "/dev/zyfer%d" /* device name and unit */
+#define        SPEED232        B9600   /* uart speed (9600 baud) */
+#define        PRECISION       (-20)   /* precision assumed (about 1 us) */
+#define        REFID           "GPS\0" /* reference ID */
+#define        DESCRIPTION     "Zyfer GPStarplus" /* WRU */
+
+#define        LENZYFER        29      /* timecode length */
+
+/*
+ * Unit control structure
+ */
+struct zyferunit {
+       u_char  Rcvbuf[LENZYFER + 1];
+       u_char  polled;         /* poll message flag */
+       int     pollcnt;
+       l_fp    tstamp;         /* timestamp of last poll */
+       int     Rcvptr;
+};
+
+/*
+ * Function prototypes
+ */
+static int     zyfer_start     P((int, struct peer *));
+static void    zyfer_shutdown  P((int, struct peer *));
+static void    zyfer_receive   P((struct recvbuf *));
+static void    zyfer_poll      P((int, struct peer *));
+
+/*
+ * Transfer vector
+ */
+struct refclock refclock_zyfer = {
+       zyfer_start,            /* start up driver */
+       zyfer_shutdown,         /* shut down driver */
+       zyfer_poll,             /* transmit poll message */
+       noentry,                /* not used (old zyfer_control) */
+       noentry,                /* initialize driver (not used) */
+       noentry,                /* not used (old zyfer_buginfo) */
+       NOFLAGS                 /* not used */
+};
+
+
+/*
+ * zyfer_start - open the devices and initialize data for processing
+ */
+static int
+zyfer_start(
+       int unit,
+       struct peer *peer
+       )
+{
+       register struct zyferunit *up;
+       struct refclockproc *pp;
+       int fd;
+       char device[20];
+
+       /*
+        * Open serial port.
+        * Something like LDISC_ACTS that looked for ! would be nice...
+        */
+       (void)sprintf(device, DEVICE, unit);
+       if ( !(fd = refclock_open(device, SPEED232, LDISC_RAW)) )
+           return (0);
+
+       msyslog(LOG_NOTICE, "zyfer(%d) fd: %d dev <%s>", unit, fd, device);
+
+       /*
+        * Allocate and initialize unit structure
+        */
+       if (!(up = (struct zyferunit *)
+             emalloc(sizeof(struct zyferunit)))) {
+               (void) close(fd);
+               return (0);
+       }
+       memset((char *)up, 0, sizeof(struct zyferunit));
+       pp = peer->procptr;
+       pp->io.clock_recv = zyfer_receive;
+       pp->io.srcclock = (caddr_t)peer;
+       pp->io.datalen = 0;
+       pp->io.fd = fd;
+       if (!io_addclock(&pp->io)) {
+               (void) close(fd);
+               free(up);
+               return (0);
+       }
+       pp->unitptr = (caddr_t)up;
+
+       /*
+        * Initialize miscellaneous variables
+        */
+       peer->precision = PRECISION;
+       pp->clockdesc = DESCRIPTION;
+       memcpy((char *)&pp->refid, REFID, 4);
+       up->pollcnt = 2;
+       up->polled = 0;         /* May not be needed... */
+
+       return (1);
+}
+
+
+/*
+ * zyfer_shutdown - shut down the clock
+ */
+static void
+zyfer_shutdown(
+       int unit,
+       struct peer *peer
+       )
+{
+       register struct zyferunit *up;
+       struct refclockproc *pp;
+
+       pp = peer->procptr;
+       up = (struct zyferunit *)pp->unitptr;
+       io_closeclock(&pp->io);
+       free(up);
+}
+
+
+/*
+ * zyfer_receive - receive data from the serial interface
+ */
+static void
+zyfer_receive(
+       struct recvbuf *rbufp
+       )
+{
+       register struct zyferunit *up;
+       struct refclockproc *pp;
+       struct peer *peer;
+       int tmode;              /* Time mode */
+       int tfom;               /* Time Figure Of Merit */
+       int omode;              /* Operation mode */
+       u_char *p;
+
+       peer = (struct peer *)rbufp->recv_srcclock;
+       pp = peer->procptr;
+       up = (struct zyferunit *)pp->unitptr;
+       p = (u_char *) &rbufp->recv_space;
+       /*
+        * If lencode is 0:
+        * - if *rbufp->recv_space is !
+        * - - call refclock_gtlin to get things going
+        * - else flush
+        * else stuff it on the end of lastcode
+        * If we don't have LENZYFER bytes
+        * - wait for more data
+        * Crack the beast, and if it's OK, process it.
+        *
+        * We use refclock_getlin() because we might use LDISC_CLK.
+        *
+        * Under FreeBSD, we get the ! followed by two 14-byte packets.
+        */
+
+       if (pp->lencode >= LENZYFER)
+               pp->lencode = 0;
+
+       if (!pp->lencode) {
+               if (*p == '!')
+                       pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode,
+                                                    BMAX, &pp->lastrec);
+               else
+                       return;
+       } else {
+               memcpy(pp->a_lastcode + pp->lencode, p, rbufp->recv_length);
+               pp->lencode += rbufp->recv_length;
+               pp->a_lastcode[pp->lencode] = '\0';
+       }
+
+       if (pp->lencode < LENZYFER)
+               return;
+
+       record_clock_stats(&peer->srcadr, pp->a_lastcode);
+
+       /*
+        * We get down to business, check the timecode format and decode
+        * its contents. If the timecode has invalid length or is not in
+        * proper format, we declare bad format and exit.
+        */
+
+       if (pp->lencode != LENZYFER) {
+               refclock_report(peer, CEVNT_BADTIME);
+               return;
+       }
+
+       /*
+        * Timecode sample: "!TIME,2002,017,07,59,32,2,4,1"
+        */
+       if (sscanf(pp->a_lastcode, "!TIME,%4d,%3d,%2d,%2d,%2d,%d,%d,%d",
+                  &pp->year, &pp->day, &pp->hour, &pp->minute, &pp->second,
+                  &tmode, &tfom, &omode) != 8) {
+               refclock_report(peer, CEVNT_BADREPLY);
+               return;
+       }
+
+       if (tmode != 2) {
+               refclock_report(peer, CEVNT_BADTIME);
+               return;
+       }
+
+       /* Should we make sure tfom is 4? */
+
+       if (omode != 1) {
+               pp->leap = LEAP_NOTINSYNC;
+               return;
+       }
+#ifdef PPS
+       if(ioctl(fdpps,request,(caddr_t) &ppsev) >=0) {
+               ppsev.tv.tv_sec += (u_int32) JAN_1970;
+               TVTOTS(&ppsev.tv,&up->tstamp);
+       }
+       /* record the last ppsclock event time stamp */
+       pp->lastrec = up->tstamp;
+#endif /* PPS */
+       if (!refclock_process(pp)) {
+               refclock_report(peer, CEVNT_BADTIME);
+               return;
+        }
+
+       /*
+        * Good place for record_clock_stats()
+        */
+       up->pollcnt = 2;
+
+       if (up->polled) {
+               up->polled = 0;
+               refclock_receive(peer);
+       }
+}
+
+
+/*
+ * zyfer_poll - called by the transmit procedure
+ */
+static void
+zyfer_poll(
+       int unit,
+       struct peer *peer
+       )
+{
+       register struct zyferunit *up;
+       struct refclockproc *pp;
+
+       /*
+        * We don't really do anything here, except arm the receiving
+        * side to capture a sample and check for timeouts.
+        */
+       pp = peer->procptr;
+       up = (struct zyferunit *)pp->unitptr;
+       if (!up->pollcnt)
+               refclock_report(peer, CEVNT_TIMEOUT);
+       else
+               up->pollcnt--;
+       pp->polls++;
+       up->polled = 1;
+}
+
+#else
+int refclock_zyfer_bs;
+#endif /* REFCLOCK */