From: Harlan Stenn Date: Tue, 19 Feb 2002 17:52:08 +0000 (-0500) Subject: Zyfer GPStarplus driver (From Harlan Stenn) X-Git-Tag: NTP_4_1_1_A~5^2^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ba6959fac9bb5cea84cb42e77e7861f4ed7182e9;p=thirdparty%2Fntp.git Zyfer GPStarplus driver (From Harlan Stenn) debug cleanup in loopfilter. bk: 3c7290c8oB-kZ7Yn-jQM2IcJCYi57w --- diff --git a/configure.in b/configure.in index 5519c5d25a..11b3814620 100644 --- a/configure.in +++ b/configure.in @@ -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 index 0000000000..3622b84b3f --- /dev/null +++ b/html/driver42.html @@ -0,0 +1,39 @@ + + + + + Zyfer GPStarplus Receiver + + + +

Zyfer GPStarplus Receiver

+ +
+

Synopsis

+Address: 127.127.42.u +
Reference ID: GPS +
Driver ID: Zyfer GPStarplus +
Serial Port: /dev/zyferu; 9600 baud, 8-bits, no parity +
Features: (none) + +

Description

+This driver supports the Zyfer GPStarplus +receiver. + +

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. + +

Additionally, there are BNC connectors on the back for things like PPS +and IRIG output. + + +Additional Information + +

Reference Clock Drivers  +


+
+Harlan Stenn (stenn@whimsy.udel.edu)
+ + + diff --git a/include/ntp.h b/include/ntp.h index eaf9228e10..5881df180f 100644 --- a/include/ntp.h +++ b/include/ntp.h @@ -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 diff --git a/libntp/clocktypes.c b/libntp/clocktypes.c index 69250aa5a1..3e767ce910 100644 --- a/libntp/clocktypes.c +++ b/libntp/clocktypes.c @@ -92,6 +92,8 @@ struct clktype clktypes[] = { "HOPF_P"}, { REFCLK_JJY, "JJY receiver (40)", "JJY" }, + { REFCLK_ZYFER, "Zyfer GPStarplus receiver (41)", + "GPS_ZYFER" }, { -1, "", "" } }; diff --git a/ntpd/Makefile.am b/ntpd/Makefile.am index 531da47006..f6552ca46a 100644 --- a/ntpd/Makefile.am +++ b/ntpd/Makefile.am @@ -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) diff --git a/ntpd/ntp_control.c b/ntpd/ntp_control.c index a423d9a89f..771d76be44 100644 --- a/ntpd/ntp_control.c +++ b/ntpd/ntp_control.c @@ -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) */ }; diff --git a/ntpd/ntp_loopfilter.c b/ntpd/ntp_loopfilter.c index b88c255db7..21085aaab5 100644 --- a/ntpd/ntp_loopfilter.c +++ b/ntpd/ntp_loopfilter.c @@ -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); } diff --git a/ntpd/refclock_conf.c b/ntpd/refclock_conf.c index 2c8b1beb3f..efe1f823d6 100644 --- a/ntpd/refclock_conf.c +++ b/ntpd/refclock_conf.c @@ -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 index 0000000000..ea9b25bafd --- /dev/null +++ b/ntpd/refclock_zyfer.c @@ -0,0 +1,336 @@ +/* + * refclock_zyfer - clock driver for the Zyfer GPSTarplus Clock + * + * Harlan Stenn, Jan 2002 + */ + +#ifdef HAVE_CONFIG_H +#include +#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 +#include + +#ifdef HAVE_SYS_TERMIOS_H +# include +#endif +#ifdef HAVE_SYS_PPSCLOCK_H +# include +#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 */