Annotation of embedaddon/ntp/ntpd/refclock_atom.c, revision 1.1
1.1 ! misho 1: /*
! 2: * refclock_atom - clock driver for 1-pps signals
! 3: */
! 4: #ifdef HAVE_CONFIG_H
! 5: #include <config.h>
! 6: #endif
! 7:
! 8: #include <stdio.h>
! 9: #include <ctype.h>
! 10:
! 11: #include "ntpd.h"
! 12: #include "ntp_io.h"
! 13: #include "ntp_unixtime.h"
! 14: #include "ntp_refclock.h"
! 15: #include "ntp_stdlib.h"
! 16:
! 17: /*
! 18: * This driver requires the PPSAPI interface (RFC 2783)
! 19: */
! 20: #if defined(REFCLOCK) && defined(CLOCK_ATOM) && defined(HAVE_PPSAPI)
! 21: #include "ppsapi_timepps.h"
! 22: #include "refclock_atom.h"
! 23:
! 24: /*
! 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.
! 31: *
! 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.
! 40: *
! 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.
! 48: *
! 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
! 54: * available.
! 55: *
! 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.
! 65: *
! 66: * Fudge Factors
! 67: *
! 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.
! 75: */
! 76: /*
! 77: * Interface definitions
! 78: */
! 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 */
! 83:
! 84: /*
! 85: * PPS unit control structure
! 86: */
! 87: struct ppsunit {
! 88: struct refclock_atom atom; /* atom structure pointer */
! 89: int fddev; /* file descriptor */
! 90: };
! 91:
! 92: /*
! 93: * Function prototypes
! 94: */
! 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 *);
! 99:
! 100: /*
! 101: * Transfer vector
! 102: */
! 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 */
! 111: };
! 112:
! 113:
! 114: /*
! 115: * atom_start - initialize data for processing
! 116: */
! 117: static int
! 118: atom_start(
! 119: int unit, /* unit number (not used) */
! 120: struct peer *peer /* peer structure pointer */
! 121: )
! 122: {
! 123: struct refclockproc *pp;
! 124: struct ppsunit *up;
! 125: char device[80];
! 126:
! 127: /*
! 128: * Allocate and initialize unit structure
! 129: */
! 130: pp = peer->procptr;
! 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));
! 137: pp->unitptr = (caddr_t)up;
! 138:
! 139: /*
! 140: * Open PPS device. This can be any serial or parallel port and
! 141: * not necessarily the port used for the associated radio.
! 142: */
! 143: snprintf(device, sizeof(device), DEVICE, unit);
! 144: up->fddev = tty_open(device, O_RDWR, 0777);
! 145: if (up->fddev <= 0) {
! 146: msyslog(LOG_ERR,
! 147: "refclock_atom: %s: %m", device);
! 148: return (0);
! 149: }
! 150:
! 151: /*
! 152: * Light up the PPSAPI interface.
! 153: */
! 154: return (refclock_ppsapi(up->fddev, &up->atom));
! 155: }
! 156:
! 157:
! 158: /*
! 159: * atom_shutdown - shut down the clock
! 160: */
! 161: static void
! 162: atom_shutdown(
! 163: int unit, /* unit number (not used) */
! 164: struct peer *peer /* peer structure pointer */
! 165: )
! 166: {
! 167: struct refclockproc *pp;
! 168: struct ppsunit *up;
! 169:
! 170: pp = peer->procptr;
! 171: up = (struct ppsunit *)pp->unitptr;
! 172: if (up->fddev > 0)
! 173: close(up->fddev);
! 174: free(up);
! 175: }
! 176:
! 177: /*
! 178: * atom_timer - called once per second
! 179: */
! 180: void
! 181: atom_timer(
! 182: int unit, /* unit pointer (not used) */
! 183: struct peer *peer /* peer structure pointer */
! 184: )
! 185: {
! 186: struct ppsunit *up;
! 187: struct refclockproc *pp;
! 188: char tbuf[80];
! 189:
! 190: pp = peer->procptr;
! 191: up = (struct ppsunit *)pp->unitptr;
! 192: if (refclock_pps(peer, &up->atom, pp->sloppyclockflag) <= 0)
! 193: return;
! 194:
! 195: peer->flags |= FLAG_PPS;
! 196:
! 197: /*
! 198: * If flag4 is lit, record each second offset to clockstats.
! 199: * That's so we can make awesome Allan deviation plots.
! 200: */
! 201: if (pp->sloppyclockflag & CLK_FLAG4) {
! 202: snprintf(tbuf, sizeof(tbuf), "%.9f",
! 203: pp->filter[pp->coderecv]);
! 204: record_clock_stats(&peer->srcadr, tbuf);
! 205: }
! 206: }
! 207:
! 208:
! 209: /*
! 210: * atom_poll - called by the transmit procedure
! 211: */
! 212: static void
! 213: atom_poll(
! 214: int unit, /* unit number (not used) */
! 215: struct peer *peer /* peer structure pointer */
! 216: )
! 217: {
! 218: struct refclockproc *pp;
! 219:
! 220: /*
! 221: * Don't wiggle the clock until some other driver has numbered
! 222: * the seconds.
! 223: */
! 224: if (sys_leap == LEAP_NOTINSYNC)
! 225: return;
! 226:
! 227: pp = peer->procptr;
! 228: pp->polls++;
! 229: if (pp->codeproc == pp->coderecv) {
! 230: peer->flags &= ~FLAG_PPS;
! 231: refclock_report(peer, CEVNT_TIMEOUT);
! 232: return;
! 233: }
! 234: pp->lastref = pp->lastrec;
! 235: refclock_receive(peer);
! 236: }
! 237: #else
! 238: int refclock_atom_bs;
! 239: #endif /* REFCLOCK */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>