Annotation of embedaddon/ntp/ntpd/refclock_atom.c, revision 1.1.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>