diff options
Diffstat (limited to 'contrib/ntp/ntpd/refclock_atom.c')
-rw-r--r-- | contrib/ntp/ntpd/refclock_atom.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/contrib/ntp/ntpd/refclock_atom.c b/contrib/ntp/ntpd/refclock_atom.c new file mode 100644 index 0000000..b3c0d6b --- /dev/null +++ b/contrib/ntp/ntpd/refclock_atom.c @@ -0,0 +1,239 @@ +/* + * refclock_atom - clock driver for 1-pps signals + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <ctype.h> + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +/* + * This driver requires the PPSAPI interface (RFC 2783) + */ +#if defined(REFCLOCK) && defined(CLOCK_ATOM) && defined(HAVE_PPSAPI) +#include "ppsapi_timepps.h" +#include "refclock_atom.h" + +/* + * This driver furnishes an interface for pulse-per-second (PPS) signals + * produced by a cesium clock, timing receiver or related equipment. It + * can be used to remove accumulated jitter over a congested link and + * retime a server before redistributing the time to clients. It can + *also be used as a holdover should all other synchronization sources + * beconme unreachable. + * + * Before this driver becomes active, the local clock must be set to + * within +-0.4 s by another means, such as a radio clock or NTP + * itself. There are two ways to connect the PPS signal, normally at TTL + * levels, to the computer. One is to shift to EIA levels and connect to + * pin 8 (DCD) of a serial port. This requires a level converter and + * may require a one-shot flipflop to lengthen the pulse. The other is + * to connect the PPS signal directly to pin 10 (ACK) of a PC paralell + * port. These methods are architecture dependent. + * + * This driver requires the Pulse-per-Second API for Unix-like Operating + * Systems, Version 1.0, RFC-2783 (PPSAPI). Implementations are + * available for FreeBSD, Linux, SunOS, Solaris and Tru64. However, at + * present only the Tru64 implementation provides the full generality of + * the API with multiple PPS drivers and multiple handles per driver. If + * the PPSAPI is normally implemented in the /usr/include/sys/timepps.h + * header file and kernel support specific to each operating system. + * + * This driver normally uses the PLL/FLL clock discipline implemented in + * the ntpd code. Ordinarily, this is the most accurate means, as the + * median filter in the driver interface is much larger than in the + * kernel. However, if the systemic clock frequency error is large (tens + * to hundreds of PPM), it's better to used the kernel support, if + * available. + * + * This deriver is subject to the mitigation rules described in the + * "mitigation rulse and the prefer peer" page. However, there is an + * important difference. If this driver becomes the PPS driver according + * to these rules, it is acrive only if (a) a prefer peer other than + * this driver is among the survivors or (b) there are no survivors and + * the minsane option of the tos command is zero. This is intended to + * support space missions where updates from other spacecraft are + * infrequent, but a reliable PPS signal, such as from an Ultra Stable + * Oscillator (USO) is available. + * + * Fudge Factors + * + * The PPS timestamp is captured on the rising (assert) edge if flag2 is + * dim (default) and on the falling (clear) edge if lit. If flag3 is dim + * (default), the kernel PPS support is disabled; if lit it is enabled. + * If flag4 is lit, each timesampt is copied to the clockstats file for + * later analysis. This can be useful when constructing Allan deviation + * plots. The time1 parameter can be used to compensate for + * miscellaneous device driver and OS delays. + */ +/* + * Interface definitions + */ +#define DEVICE "/dev/pps%d" /* device name and unit */ +#define PRECISION (-20) /* precision assumed (about 1 us) */ +#define REFID "PPS\0" /* reference ID */ +#define DESCRIPTION "PPS Clock Discipline" /* WRU */ + +/* + * PPS unit control structure + */ +struct ppsunit { + struct refclock_atom atom; /* atom structure pointer */ + int fddev; /* file descriptor */ +}; + +/* + * Function prototypes + */ +static int atom_start (int, struct peer *); +static void atom_shutdown (int, struct peer *); +static void atom_poll (int, struct peer *); +static void atom_timer (int, struct peer *); + +/* + * Transfer vector + */ +struct refclock refclock_atom = { + atom_start, /* start up driver */ + atom_shutdown, /* shut down driver */ + atom_poll, /* transmit poll message */ + noentry, /* control (not used) */ + noentry, /* initialize driver (not used) */ + noentry, /* buginfo (not used) */ + atom_timer, /* called once per second */ +}; + + +/* + * atom_start - initialize data for processing + */ +static int +atom_start( + int unit, /* unit number (not used) */ + struct peer *peer /* peer structure pointer */ + ) +{ + struct refclockproc *pp; + struct ppsunit *up; + char device[80]; + + /* + * Allocate and initialize unit structure + */ + pp = peer->procptr; + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + pp->stratum = STRATUM_UNSPEC; + memcpy((char *)&pp->refid, REFID, 4); + up = emalloc(sizeof(struct ppsunit)); + memset(up, 0, sizeof(struct ppsunit)); + pp->unitptr = up; + + /* + * Open PPS device. This can be any serial or parallel port and + * not necessarily the port used for the associated radio. + */ + snprintf(device, sizeof(device), DEVICE, unit); + up->fddev = tty_open(device, O_RDWR, 0777); + if (up->fddev <= 0) { + msyslog(LOG_ERR, + "refclock_atom: %s: %m", device); + return (0); + } + + /* + * Light up the PPSAPI interface. + */ + return (refclock_ppsapi(up->fddev, &up->atom)); +} + + +/* + * atom_shutdown - shut down the clock + */ +static void +atom_shutdown( + int unit, /* unit number (not used) */ + struct peer *peer /* peer structure pointer */ + ) +{ + struct refclockproc *pp; + struct ppsunit *up; + + pp = peer->procptr; + up = pp->unitptr; + if (up->fddev > 0) + close(up->fddev); + free(up); +} + +/* + * atom_timer - called once per second + */ +void +atom_timer( + int unit, /* unit pointer (not used) */ + struct peer *peer /* peer structure pointer */ + ) +{ + struct ppsunit *up; + struct refclockproc *pp; + char tbuf[80]; + + pp = peer->procptr; + up = pp->unitptr; + if (refclock_pps(peer, &up->atom, pp->sloppyclockflag) <= 0) + return; + + peer->flags |= FLAG_PPS; + + /* + * If flag4 is lit, record each second offset to clockstats. + * That's so we can make awesome Allan deviation plots. + */ + if (pp->sloppyclockflag & CLK_FLAG4) { + snprintf(tbuf, sizeof(tbuf), "%.9f", + pp->filter[pp->coderecv]); + record_clock_stats(&peer->srcadr, tbuf); + } +} + + +/* + * atom_poll - called by the transmit procedure + */ +static void +atom_poll( + int unit, /* unit number (not used) */ + struct peer *peer /* peer structure pointer */ + ) +{ + struct refclockproc *pp; + + /* + * Don't wiggle the clock until some other driver has numbered + * the seconds. + */ + if (sys_leap == LEAP_NOTINSYNC) + return; + + pp = peer->procptr; + pp->polls++; + if (pp->codeproc == pp->coderecv) { + peer->flags &= ~FLAG_PPS; + refclock_report(peer, CEVNT_TIMEOUT); + return; + } + pp->lastref = pp->lastrec; + refclock_receive(peer); +} +#else +int refclock_atom_bs; +#endif /* REFCLOCK */ |