3 * refclock_atom - clock driver for 1-pps signals
14 #include "ntp_unixtime.h"
15 #include "ntp_refclock.h"
16 #include "ntp_stdlib.h"
18 #if defined(REFCLOCK) && defined(CLOCK_ATOM)
21 # ifdef HAVE_TIMEPPS_H
24 # ifdef HAVE_SYS_TIMEPPS_H
25 # include <sys/timepps.h>
28 #endif /* HAVE_PPSAPI */
31 * This driver furnishes an interface for pulse-per-second (PPS) signals
32 * produced by a cesium clock, timing receiver or related equipment. It
33 * can be used to remove accumulated jitter and retime a secondary
34 * server when synchronized to a primary server over a congested, wide-
35 * area network and before redistributing the time to local clients.
37 * Before this driver becomes active, the local clock must be set to
38 * within +-500 ms by another means, such as a radio clock or NTP
39 * itself. There are two ways to connect the PPS signal, normally at TTL
40 * levels, to the computer. One is to shift to EIA levels and connect to
41 * pin 8 (DCD) of a serial port. This requires a level converter and
42 * may require a one-shot flipflop to lengthen the pulse. The other is
43 * to connect the PPS signal directly to pin 10 (ACK) of a PC paralell
44 * port. These methods are architecture dependent.
46 * Both methods require a modified device driver and kernel interface
47 * compatible with the Pulse-per-Second API for Unix-like Operating
48 * Systems, Version 1.0, RFC-2783 (PPSAPI). Implementations are
49 * available for FreeBSD, Linux, SunOS, Solaris and Alpha. However, at
50 * present only the Alpha implementation provides the full generality of
51 * the API with multiple PPS drivers and multiple handles per driver.
53 * In many configurations a single port is used for the radio timecode
54 * and PPS signal. In order to provide for this configuration and others
55 * involving dedicated multiple serial/parallel ports, the driver first
56 * attempts to open the device /dev/pps%d, where %d is the unit number.
57 * If this fails, the driver attempts to open the device specified by
58 * the pps configuration command. If a port is to be shared, the pps
59 * command must be placed before the radio device(s) and the radio
60 * device(s) must be placed before the PPS driver(s) in the
63 * This driver normally uses the PLL/FLL clock discipline implemented in
64 * the ntpd code. If kernel support is available, the kernel PLL/FLL
65 * clock discipline is used instead. The default configuration is not to
66 * use the kernel PPS discipline, if present. The kernel PPS discipline
67 * can be enabled using the pps command.
71 * There are no special fudge factors other than the generic. The fudge
72 * time1 parameter can be used to compensate for miscellaneous device
73 * driver and OS delays.
76 * Interface definitions
79 #define DEVICE "/dev/pps%d" /* device name and unit */
80 #endif /* HAVE_PPSAPI */
82 #define PRECISION (-20) /* precision assumed (about 1 us) */
83 #define REFID "PPS\0" /* reference ID */
84 #define DESCRIPTION "PPS Clock Discipline" /* WRU */
85 #define NANOSECOND 1000000000 /* one second (ns) */
86 #define RANGEGATE 500000 /* range gate (ns) */
87 #define ASTAGE 8 /* filter stages */
89 static struct peer *pps_peer; /* atom driver for PPS sources */
93 * PPS unit control structure
96 struct timespec ts; /* last timestamp */
97 int fddev; /* pps device descriptor */
98 pps_params_t pps_params; /* pps parameters */
99 pps_info_t pps_info; /* last pps data */
100 pps_handle_t handle; /* pps handlebars */
102 #endif /* HAVE_PPSAPI */
105 * Function prototypes
107 static int atom_start P((int, struct peer *));
108 static void atom_poll P((int, struct peer *));
110 static void atom_shutdown P((int, struct peer *));
111 static void atom_control P((int, struct refclockstat *, struct
112 refclockstat *, struct peer *));
113 static int atom_pps P((struct peer *));
114 static int atom_ppsapi P((struct peer *, int, int));
115 #endif /* HAVE_PPSAPI */
120 struct refclock refclock_atom = {
121 atom_start, /* start up driver */
123 atom_shutdown, /* shut down driver */
125 noentry, /* shut down driver */
126 #endif /* HAVE_PPSAPI */
127 atom_poll, /* transmit poll message */
129 atom_control, /* fudge control */
131 noentry, /* fudge control */
132 #endif /* HAVE_PPSAPI */
133 noentry, /* initialize driver */
134 noentry, /* not used (old atom_buginfo) */
135 NOFLAGS /* not used */
140 * atom_start - initialize data for processing
144 int unit, /* unit number (not used) */
145 struct peer *peer /* peer structure pointer */
148 struct refclockproc *pp;
150 register struct ppsunit *up;
152 #endif /* HAVE_PPSAPI */
155 * Allocate and initialize unit structure
159 peer->precision = PRECISION;
160 pp->clockdesc = DESCRIPTION;
161 pp->stratum = STRATUM_UNSPEC;
162 memcpy((char *)&pp->refid, REFID, 4);
163 peer->burst = ASTAGE;
165 up = emalloc(sizeof(struct ppsunit));
166 memset(up, 0, sizeof(struct ppsunit));
167 pp->unitptr = (caddr_t)up;
170 * Open PPS device. If this fails and some driver has already
171 * opened the associated radio device, fdpps has the file
174 sprintf(device, DEVICE, unit);
175 up->fddev = open(device, O_RDWR, 0777);
176 if (up->fddev <= 0 && fdpps > 0) {
177 strcpy(device, pps_device);
180 if (up->fddev <= 0) {
182 "refclock_atom: %s: %m", device);
187 * Light off the PPSAPI interface. If this PPS device is shared
188 * with the radio device, take the default options from the pps
189 * command. This is for legacy purposes.
191 if (time_pps_create(up->fddev, &up->handle) < 0) {
193 "refclock_atom: time_pps_create failed: %m");
196 return (atom_ppsapi(peer, 0, 0));
197 #else /* HAVE_PPSAPI */
199 #endif /* HAVE_PPSAPI */
205 * atom_control - fudge control
209 int unit, /* unit (not used */
210 struct refclockstat *in, /* input parameters (not uded) */
211 struct refclockstat *out, /* output parameters (not used) */
212 struct peer *peer /* peer structure pointer */
215 struct refclockproc *pp;
218 atom_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2,
219 pp->sloppyclockflag & CLK_FLAG3);
228 struct peer *peer, /* peer structure pointer */
229 int enb_clear, /* clear enable */
230 int enb_hardpps /* hardpps enable */
233 struct refclockproc *pp;
234 register struct ppsunit *up;
238 up = (struct ppsunit *)pp->unitptr;
239 if (time_pps_getcap(up->handle, &capability) < 0) {
241 "refclock_atom: time_pps_getcap failed: %m");
244 memset(&up->pps_params, 0, sizeof(pps_params_t));
246 up->pps_params.mode = capability & PPS_CAPTURECLEAR;
248 up->pps_params.mode = capability & PPS_CAPTUREASSERT;
249 if (!up->pps_params.mode) {
251 "refclock_atom: invalid capture edge %d",
255 up->pps_params.mode |= PPS_TSFMT_TSPEC;
256 if (time_pps_setparams(up->handle, &up->pps_params) < 0) {
258 "refclock_atom: time_pps_setparams failed: %m");
262 if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS,
263 up->pps_params.mode & ~PPS_TSFMT_TSPEC,
264 PPS_TSFMT_TSPEC) < 0) {
266 "refclock_atom: time_pps_kcbind failed: %m");
273 time_pps_getparams(up->handle, &up->pps_params);
275 "refclock_ppsapi: fd %d capability 0x%x version %d mode 0x%x kern %d\n",
276 up->fddev, capability, up->pps_params.api_version,
277 up->pps_params.mode, enb_hardpps);
285 * atom_shutdown - shut down the clock
289 int unit, /* unit number (not used) */
290 struct peer *peer /* peer structure pointer */
293 struct refclockproc *pp;
294 register struct ppsunit *up;
297 up = (struct ppsunit *)pp->unitptr;
301 time_pps_destroy(up->handle);
302 if (pps_peer == peer)
309 * atom_pps - receive data from the PPSAPI interface
311 * This routine is called once per second when the PPSAPI interface is
312 * present. It snatches the PPS timestamp from the kernel and saves the
313 * sign-extended fraction in a circular buffer for processing at the
318 struct peer *peer /* peer structure pointer */
321 register struct ppsunit *up;
322 struct refclockproc *pp;
324 struct timespec timeout, ts;
328 * Convert the timespec nanoseconds field to signed double and
329 * save in the median filter. for billboards. No harm is done if
330 * previous data are overwritten. If the discipline comes bum or
331 * the data grow stale, just forget it. A range gate rejects new
332 * samples if less than a jiggle time from the next second.
335 up = (struct ppsunit *)pp->unitptr;
340 memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
341 if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info,
344 if (up->pps_params.mode & PPS_CAPTUREASSERT) {
345 if (pps_info.assert_sequence ==
346 up->pps_info.assert_sequence)
348 ts = up->pps_info.assert_timestamp;
349 } else if (up->pps_params.mode & PPS_CAPTURECLEAR) {
350 if (pps_info.clear_sequence ==
351 up->pps_info.clear_sequence)
353 ts = up->pps_info.clear_timestamp;
357 if (!((ts.tv_sec == up->ts.tv_sec && ts.tv_nsec -
358 up->ts.tv_nsec > NANOSECOND - RANGEGATE) ||
359 (ts.tv_sec - up->ts.tv_sec == 1 && ts.tv_nsec -
360 up->ts.tv_nsec < RANGEGATE))) {
365 pp->lastrec.l_ui = ts.tv_sec + JAN_1970;
366 dtemp = ts.tv_nsec * FRAC / 1e9;
369 pp->lastrec.l_uf = (u_int32)dtemp;
370 if (ts.tv_nsec > NANOSECOND / 2)
371 ts.tv_nsec -= NANOSECOND;
372 dtemp = -(double)ts.tv_nsec / NANOSECOND;
373 SAMPLE(dtemp + pp->fudgetime1);
376 printf("atom_pps %f %f\n", dtemp, pp->fudgetime1);
380 #endif /* HAVE_PPSAPI */
384 * pps_sample - receive PPS data from some other clock driver
386 * This routine is called once per second when the external clock driver
387 * processes PPS information. It processes the PPS timestamp and saves
388 * the sign-extended fraction in a circular buffer for processing at the
389 * next poll event. This works only for a single PPS device.
393 l_fp *offset /* PPS offset */
396 register struct peer *peer;
397 struct refclockproc *pp;
402 if (peer == 0) /* nobody home */
407 * Convert the timeval to l_fp and save for billboards. Sign-
408 * extend the fraction and stash in the buffer. No harm is done
409 * if previous data are overwritten. If the discipline comes bum
410 * or the data grow stale, just forget it.
412 pp->lastrec = *offset;
414 L_ADDF(&lftmp, pp->lastrec.l_f);
415 LFPTOD(&lftmp, doffset);
416 SAMPLE(-doffset + pp->fudgetime1);
421 * atom_poll - called by the transmit procedure
423 * This routine is called once per second when in burst mode to save PPS
424 * sample offsets in the median filter. At the end of the burst period
425 * the samples are processed as a heap and the clock filter updated.
429 int unit, /* unit number (not used) */
430 struct peer *peer /* peer structure pointer */
433 struct refclockproc *pp;
436 #endif /* HAVE_PPSAPI */
439 * Accumulate samples in the median filter. If a noise sample,
440 * return with no prejudice; if a protocol error, get mean;
441 * otherwise, cool. At the end of each poll interval, do a
442 * little bookeeping and process the surviving samples.
447 err = atom_pps(peer);
449 refclock_report(peer, CEVNT_FAULT);
452 #endif /* HAVE_PPSAPI */
455 * Valid time is returned only if the prefer peer has survived
456 * the intersection algorithm and within clock_max of local time
457 * and not too long ago. This ensures the PPS time is within
458 * +-0.5 s of the local time and the seconds numbering is
459 * unambiguous. Note that the leap bits are set no-warning on
460 * the first valid update and the stratum is set at the prefer
461 * peer, unless overriden by a fudge command.
465 peer->leap = LEAP_NOTINSYNC;
466 if (pp->codeproc == pp->coderecv) {
467 refclock_report(peer, CEVNT_TIMEOUT);
468 peer->burst = ASTAGE;
471 } else if (sys_prefer == NULL) {
472 pp->codeproc = pp->coderecv;
473 peer->burst = ASTAGE;
476 } else if (fabs(sys_prefer->offset) > clock_max) {
477 pp->codeproc = pp->coderecv;
478 peer->burst = ASTAGE;
481 pp->leap = LEAP_NOWARNING;
482 if (pp->stratum >= STRATUM_UNSPEC)
483 peer->stratum = sys_prefer->stratum;
485 peer->stratum = pp->stratum;
486 if (peer->stratum == STRATUM_REFCLOCK || peer->stratum ==
488 peer->refid = pp->refid;
490 peer->refid = addr2refid(&sys_prefer->srcadr);
491 pp->lastref = pp->lastrec;
492 refclock_receive(peer);
493 peer->burst = ASTAGE;
496 int refclock_atom_bs;
499 l_fp *offset /* PPS offset */
504 #endif /* REFCLOCK */