2 * refclock_atom - clock driver for 1-pps signals
13 #include "ntp_unixtime.h"
14 #include "ntp_refclock.h"
15 #include "ntp_stdlib.h"
17 #if defined(REFCLOCK) && defined(CLOCK_ATOM)
20 # include "ppsapi_timepps.h"
21 #endif /* HAVE_PPSAPI */
24 * This driver furnishes an interface for pulse-per-second (PPS) signals
25 * produced by a cesium clock, timing receiver or related equipment. It
26 * can be used to remove accumulated jitter and retime a secondary
27 * server when synchronized to a primary server over a congested, wide-
28 * area network and before redistributing the time to local clients.
30 * Before this driver becomes active, the local clock must be set to
31 * within +-500 ms by another means, such as a radio clock or NTP
32 * itself. There are two ways to connect the PPS signal, normally at TTL
33 * levels, to the computer. One is to shift to EIA levels and connect to
34 * pin 8 (DCD) of a serial port. This requires a level converter and
35 * may require a one-shot flipflop to lengthen the pulse. The other is
36 * to connect the PPS signal directly to pin 10 (ACK) of a PC paralell
37 * port. These methods are architecture dependent.
39 * Both methods require a modified device driver and kernel interface
40 * compatible with the Pulse-per-Second API for Unix-like Operating
41 * Systems, Version 1.0, RFC-2783 (PPSAPI). Implementations are
42 * available for FreeBSD, Linux, SunOS, Solaris and Alpha. However, at
43 * present only the Alpha implementation provides the full generality of
44 * the API with multiple PPS drivers and multiple handles per driver. If
45 * the PPSAPI is normally implemented in the /usr/include/sys/timepps.h
46 * header file and kernel support specific to each operating system.
47 * However, this driver can operate without this interface if means are
48 * proviced to call the pps_sample() routine from another driver. Please
49 * note; if the PPSAPI interface is present, it must be used.
51 * In many configurations a single port is used for the radio timecode
52 * and PPS signal. In order to provide for this configuration and others
53 * involving dedicated multiple serial/parallel ports, the driver first
54 * attempts to open the device /dev/pps%d, where %d is the unit number.
55 * If this fails, the driver attempts to open the device specified by
56 * the pps configuration command. If a port is to be shared, the pps
57 * command must be placed before the radio device(s) and the radio
58 * device(s) must be placed before the PPS driver(s) in the
61 * This driver normally uses the PLL/FLL clock discipline implemented in
62 * the ntpd code. Ordinarily, this is the most accurate means, as the
63 * median filter in the driver interface is much larger than in the
64 * kernel. However, if the systemic clock frequency error is large (tens
65 * to hundreds of PPM), it's better to used the kernel support, if
70 * If flag2 is dim (default), the on-time epoch is the assert edge of
71 * the PPS signal; if lit, the on-time epoch is the clear edge. If flag2
72 * is lit, the assert edge is used; if flag3 is dim (default), the
73 * kernel PPS support is disabled; if lit it is enabled. The time1
74 * parameter can be used to compensate for miscellaneous device driver
78 * Interface definitions
81 #define DEVICE "/dev/pps%d" /* device name and unit */
82 #endif /* HAVE_PPSAPI */
84 #define PRECISION (-20) /* precision assumed (about 1 us) */
85 #define REFID "PPS\0" /* reference ID */
86 #define DESCRIPTION "PPS Clock Discipline" /* WRU */
87 #define NANOSECOND 1000000000 /* one second (ns) */
88 #define RANGEGATE 500000 /* range gate (ns) */
90 static struct peer *pps_peer; /* atom driver for PPS sources */
94 * PPS unit control structure
97 struct timespec ts; /* last timestamp */
98 int fddev; /* pps device descriptor */
99 pps_params_t pps_params; /* pps parameters */
100 pps_info_t pps_info; /* last pps data */
101 pps_handle_t handle; /* pps handlebars */
103 #endif /* HAVE_PPSAPI */
106 * Function prototypes
108 static int atom_start P((int, struct peer *));
109 static void atom_poll P((int, struct peer *));
110 static void atom_shutdown P((int, struct peer *));
112 static void atom_control P((int, struct refclockstat *, struct
113 refclockstat *, struct peer *));
114 static void atom_timer P((int, struct peer *));
115 static int atom_ppsapi P((struct peer *, int));
116 #endif /* HAVE_PPSAPI */
122 struct refclock refclock_atom = {
123 atom_start, /* start up driver */
124 atom_shutdown, /* shut down driver */
125 atom_poll, /* transmit poll message */
126 atom_control, /* fudge control */
127 noentry, /* initialize driver (not used) */
128 noentry, /* buginfo (not used) */
129 atom_timer, /* called once per second */
131 #else /* HAVE_PPSAPI */
132 struct refclock refclock_atom = {
133 atom_start, /* start up driver */
134 atom_shutdown, /* shut down driver */
135 atom_poll, /* transmit poll message */
136 noentry, /* fudge control (not used) */
137 noentry, /* initialize driver (not used) */
138 noentry, /* buginfo (not used) */
139 NOFLAGS /* not used */
141 #endif /* HAVE_PPPSAPI */
145 * atom_start - initialize data for processing
149 int unit, /* unit number (not used) */
150 struct peer *peer /* peer structure pointer */
153 struct refclockproc *pp;
155 register struct ppsunit *up;
158 #endif /* HAVE_PPSAPI */
161 * Allocate and initialize unit structure
165 peer->precision = PRECISION;
166 pp->clockdesc = DESCRIPTION;
167 pp->stratum = STRATUM_UNSPEC;
168 memcpy((char *)&pp->refid, REFID, 4);
170 up = emalloc(sizeof(struct ppsunit));
171 memset(up, 0, sizeof(struct ppsunit));
172 pp->unitptr = (caddr_t)up;
175 * Open PPS device. This can be any serial or parallel port and
176 * not necessarily the port used for the associated radio.
178 sprintf(device, DEVICE, unit);
179 up->fddev = open(device, O_RDWR, 0777);
180 if (up->fddev <= 0) {
182 "refclock_atom: %s: %m", device);
187 * Light off the PPSAPI interface.
189 if (time_pps_create(up->fddev, &up->handle) < 0) {
191 "refclock_atom: time_pps_create failed: %m");
196 * If the mode is nonzero, use that for the time_pps_setparams()
197 * mode; otherwise, PPS_CAPTUREASSERT. Enable kernel PPS if
202 mode = PPS_CAPTUREASSERT;
203 return (atom_ppsapi(peer, mode));
204 #else /* HAVE_PPSAPI */
206 #endif /* HAVE_PPSAPI */
211 * atom_shutdown - shut down the clock
215 int unit, /* unit number (not used) */
216 struct peer *peer /* peer structure pointer */
219 struct refclockproc *pp;
220 register struct ppsunit *up;
223 up = (struct ppsunit *)pp->unitptr;
228 time_pps_destroy(up->handle);
229 #endif /* HAVE_PPSAPI */
230 if (pps_peer == peer)
238 * atom_control - fudge control
242 int unit, /* unit (not used */
243 struct refclockstat *in, /* input parameters (not uded) */
244 struct refclockstat *out, /* output parameters (not used) */
245 struct peer *peer /* peer structure pointer */
248 struct refclockproc *pp;
252 if (peer->ttl != 0) /* all legal modes must be nonzero */
255 if (pp->sloppyclockflag & CLK_FLAG2)
256 mode = PPS_CAPTURECLEAR;
258 mode = PPS_CAPTUREASSERT;
259 atom_ppsapi(peer, mode);
268 struct peer *peer, /* peer structure pointer */
272 struct refclockproc *pp;
273 register struct ppsunit *up;
277 up = (struct ppsunit *)pp->unitptr;
281 if (time_pps_getcap(up->handle, &capability) < 0) {
283 "refclock_atom: time_pps_getcap failed: %m");
286 memset(&up->pps_params, 0, sizeof(pps_params_t));
287 up->pps_params.api_version = PPS_API_VERS_1;
288 up->pps_params.mode = mode | PPS_TSFMT_TSPEC;
289 if (time_pps_setparams(up->handle, &up->pps_params) < 0) {
291 "refclock_atom: time_pps_setparams failed: %m");
294 if (pp->sloppyclockflag & CLK_FLAG3) {
295 if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS,
296 up->pps_params.mode & ~PPS_TSFMT_TSPEC,
297 PPS_TSFMT_TSPEC) < 0) {
299 "refclock_atom: time_pps_kcbind failed: %m");
306 time_pps_getparams(up->handle, &up->pps_params);
308 "refclock_ppsapi: fd %d capability 0x%x version %d mode 0x%x\n",
309 up->fddev, capability, up->pps_params.api_version,
310 up->pps_params.mode);
318 * atom_timer - called once per second
320 * This routine is called once per second when the PPSAPI interface is
321 * present. It snatches the PPS timestamp from the kernel and saves the
322 * sign-extended fraction in a circular buffer for processing at the
327 int unit, /* unit number (not used) */
328 struct peer *peer /* peer structure pointer */
331 register struct ppsunit *up;
332 struct refclockproc *pp;
334 struct timespec timeout, ts;
337 char tbuf[80]; /* monitor buffer */
340 * Convert the timespec nanoseconds field to signed double and
341 * save in the median filter. for billboards. No harm is done if
342 * previous data are overwritten. If the discipline comes bum or
343 * the data grow stale, just forget it. A range gate rejects new
344 * samples if less than a jiggle time from the next second.
347 up = (struct ppsunit *)pp->unitptr;
353 memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
354 if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info,
356 refclock_report(peer, CEVNT_FAULT);
359 if (up->pps_params.mode & PPS_CAPTUREASSERT) {
360 ts = up->pps_info.assert_timestamp;
361 } else if (up->pps_params.mode & PPS_CAPTURECLEAR) {
362 ts = up->pps_info.clear_timestamp;
364 refclock_report(peer, CEVNT_FAULT);
369 * There can be zero, one or two PPS seconds between polls. If
370 * zero, either the poll clock is slightly faster than the PPS
371 * clock or the PPS clock has died. If the PPS clock advanced
372 * once between polls, we make sure the fraction time difference
373 * since the last sample is within the range gate of 5 ms (500
374 * PPM). If the PPS clock advanced twice since the last poll,
375 * the poll bracketed more than one second and the first second
376 * was lost to a slip. Since the interval since the last sample
377 * found is now two seconds, just widen the range gate. If the
378 * PPS clock advanced three or more times, either the signal has
379 * failed for a number of seconds or we have runts, in which
380 * case just ignore them.
382 * If flag4 is lit, record each second offset to clockstats.
383 * That's so we can make awesome Allan deviation plots.
385 sec = ts.tv_sec - up->ts.tv_sec;
386 nsec = ts.tv_nsec - up->ts.tv_nsec;
391 } else if (nsec >= NANOSECOND) {
395 if (sec * NANOSECOND + nsec > NANOSECOND + RANGEGATE)
398 else if (sec * NANOSECOND + nsec < NANOSECOND - RANGEGATE)
401 pp->lastrec.l_ui = ts.tv_sec + JAN_1970;
402 dtemp = ts.tv_nsec * FRAC / 1e9;
405 pp->lastrec.l_uf = (u_int32)dtemp;
406 if (ts.tv_nsec > NANOSECOND / 2)
407 ts.tv_nsec -= NANOSECOND;
408 dtemp = -(double)ts.tv_nsec / NANOSECOND;
409 SAMPLE(dtemp + pp->fudgetime1);
410 if (pp->sloppyclockflag & CLK_FLAG4){
411 sprintf(tbuf, "%.9f", dtemp);
412 record_clock_stats(&peer->srcadr, tbuf);
416 printf("atom_timer: %lu %f %f\n", current_time,
417 dtemp, pp->fudgetime1);
421 #endif /* HAVE_PPSAPI */
425 * pps_sample - receive PPS data from some other clock driver
427 * This routine is called once per second when the external clock driver
428 * processes PPS information. It processes the PPS timestamp and saves
429 * the sign-extended fraction in a circular buffer for processing at the
430 * next poll event. This works only for a single PPS device.
432 * The routine should be used by another configured driver ONLY when
433 * this driver is configured as well and the PPSAPI is NOT in use.
437 l_fp *offset /* PPS offset */
440 register struct peer *peer;
441 struct refclockproc *pp;
452 * Convert the timeval to l_fp and save for billboards. Sign-
453 * extend the fraction and stash in the buffer. No harm is done
454 * if previous data are overwritten. If the discipline comes bum
455 * or the data grow stale, just forget it.
457 pp->lastrec = *offset;
459 L_ADDF(&lftmp, pp->lastrec.l_f);
460 LFPTOD(&lftmp, doffset);
461 SAMPLE(-doffset + pp->fudgetime1);
467 * atom_poll - called by the transmit procedure
471 int unit, /* unit number (not used) */
472 struct peer *peer /* peer structure pointer */
475 struct refclockproc *pp;
480 * Valid time is returned only if the prefer peer has survived
481 * the intersection algorithm and within 0.4 s of local time
482 * and not too long ago. This ensures the PPS time is within
483 * 0.5 s of the local time and the seconds numbering is
484 * unambiguous. Note that the leap bits, stratum and refid are
485 * set from the prefer peer, unless overriden by a fudge
488 if (pp->codeproc == pp->coderecv) {
489 refclock_report(peer, CEVNT_TIMEOUT);
492 } else if (sys_prefer == NULL) {
493 pp->codeproc = pp->coderecv;
496 } else if (fabs(sys_prefer->offset) >= 0.4) {
497 pp->codeproc = pp->coderecv;
500 pp->leap = sys_prefer->leap;
501 if (pp->stratum >= STRATUM_UNSPEC)
502 peer->stratum = sys_prefer->stratum;
504 peer->stratum = pp->stratum;
505 pp->lastref = pp->lastrec;
506 refclock_receive(peer);
509 int refclock_atom_bs;
512 l_fp *offset /* PPS offset */
517 #endif /* REFCLOCK */