2 * refclock_atom - clock driver for 1-pps signals
13 #include "ntp_unixtime.h"
14 #include "ntp_refclock.h"
15 #include "ntp_stdlib.h"
18 * This driver requires the PPSAPI interface (RFC 2783)
20 #if defined(REFCLOCK) && defined(CLOCK_ATOM) && defined(HAVE_PPSAPI)
21 #include "ppsapi_timepps.h"
22 #include "refclock_atom.h"
25 * This driver furnishes an interface for pulse-per-second (PPS) signals
26 * produced by a cesium clock, timing receiver or related equipment. It
27 * can be used to remove accumulated jitter over a congested link and
28 * retime a server before redistributing the time to clients. It can
29 *also be used as a holdover should all other synchronization sources
30 * beconme unreachable.
32 * Before this driver becomes active, the local clock must be set to
33 * within +-0.4 s by another means, such as a radio clock or NTP
34 * itself. There are two ways to connect the PPS signal, normally at TTL
35 * levels, to the computer. One is to shift to EIA levels and connect to
36 * pin 8 (DCD) of a serial port. This requires a level converter and
37 * may require a one-shot flipflop to lengthen the pulse. The other is
38 * to connect the PPS signal directly to pin 10 (ACK) of a PC paralell
39 * port. These methods are architecture dependent.
41 * This driver requires the Pulse-per-Second API for Unix-like Operating
42 * Systems, Version 1.0, RFC-2783 (PPSAPI). Implementations are
43 * available for FreeBSD, Linux, SunOS, Solaris and Tru64. However, at
44 * present only the Tru64 implementation provides the full generality of
45 * the API with multiple PPS drivers and multiple handles per driver. If
46 * the PPSAPI is normally implemented in the /usr/include/sys/timepps.h
47 * header file and kernel support specific to each operating system.
49 * This driver normally uses the PLL/FLL clock discipline implemented in
50 * the ntpd code. Ordinarily, this is the most accurate means, as the
51 * median filter in the driver interface is much larger than in the
52 * kernel. However, if the systemic clock frequency error is large (tens
53 * to hundreds of PPM), it's better to used the kernel support, if
56 * This deriver is subject to the mitigation rules described in the
57 * "mitigation rulse and the prefer peer" page. However, there is an
58 * important difference. If this driver becomes the PPS driver according
59 * to these rules, it is acrive only if (a) a prefer peer other than
60 * this driver is among the survivors or (b) there are no survivors and
61 * the minsane option of the tos command is zero. This is intended to
62 * support space missions where updates from other spacecraft are
63 * infrequent, but a reliable PPS signal, such as from an Ultra Stable
64 * Oscillator (USO) is available.
68 * The PPS timestamp is captured on the rising (assert) edge if flag2 is
69 * dim (default) and on the falling (clear) edge if lit. If flag3 is dim
70 * (default), the kernel PPS support is disabled; if lit it is enabled.
71 * If flag4 is lit, each timesampt is copied to the clockstats file for
72 * later analysis. This can be useful when constructing Allan deviation
73 * plots. The time1 parameter can be used to compensate for
74 * miscellaneous device driver and OS delays.
77 * Interface definitions
79 #define DEVICE "/dev/pps%d" /* device name and unit */
80 #define PRECISION (-20) /* precision assumed (about 1 us) */
81 #define REFID "PPS\0" /* reference ID */
82 #define DESCRIPTION "PPS Clock Discipline" /* WRU */
85 * PPS unit control structure
88 struct refclock_atom atom; /* atom structure pointer */
89 int fddev; /* file descriptor */
95 static int atom_start (int, struct peer *);
96 static void atom_shutdown (int, struct peer *);
97 static void atom_poll (int, struct peer *);
98 static void atom_timer (int, struct peer *);
103 struct refclock refclock_atom = {
104 atom_start, /* start up driver */
105 atom_shutdown, /* shut down driver */
106 atom_poll, /* transmit poll message */
107 noentry, /* control (not used) */
108 noentry, /* initialize driver (not used) */
109 noentry, /* buginfo (not used) */
110 atom_timer, /* called once per second */
115 * atom_start - initialize data for processing
119 int unit, /* unit number (not used) */
120 struct peer *peer /* peer structure pointer */
123 struct refclockproc *pp;
128 * Allocate and initialize unit structure
131 peer->precision = PRECISION;
132 pp->clockdesc = DESCRIPTION;
133 pp->stratum = STRATUM_UNSPEC;
134 memcpy((char *)&pp->refid, REFID, 4);
135 up = emalloc(sizeof(struct ppsunit));
136 memset(up, 0, sizeof(struct ppsunit));
140 * Open PPS device. This can be any serial or parallel port and
141 * not necessarily the port used for the associated radio.
143 snprintf(device, sizeof(device), DEVICE, unit);
144 up->fddev = tty_open(device, O_RDWR, 0777);
145 if (up->fddev <= 0) {
147 "refclock_atom: %s: %m", device);
152 * Light up the PPSAPI interface.
154 return (refclock_ppsapi(up->fddev, &up->atom));
159 * atom_shutdown - shut down the clock
163 int unit, /* unit number (not used) */
164 struct peer *peer /* peer structure pointer */
167 struct refclockproc *pp;
178 * atom_timer - called once per second
182 int unit, /* unit pointer (not used) */
183 struct peer *peer /* peer structure pointer */
187 struct refclockproc *pp;
192 if (refclock_pps(peer, &up->atom, pp->sloppyclockflag) <= 0)
195 peer->flags |= FLAG_PPS;
198 * If flag4 is lit, record each second offset to clockstats.
199 * That's so we can make awesome Allan deviation plots.
201 if (pp->sloppyclockflag & CLK_FLAG4) {
202 snprintf(tbuf, sizeof(tbuf), "%.9f",
203 pp->filter[pp->coderecv]);
204 record_clock_stats(&peer->srcadr, tbuf);
210 * atom_poll - called by the transmit procedure
214 int unit, /* unit number (not used) */
215 struct peer *peer /* peer structure pointer */
218 struct refclockproc *pp;
221 * Don't wiggle the clock until some other driver has numbered
224 if (sys_leap == LEAP_NOTINSYNC)
229 if (pp->codeproc == pp->coderecv) {
230 peer->flags &= ~FLAG_PPS;
231 refclock_report(peer, CEVNT_TIMEOUT);
234 pp->lastref = pp->lastrec;
235 refclock_receive(peer);
238 int refclock_atom_bs;
239 #endif /* REFCLOCK */