source: trunk/third/xntp/html/howto.htm @ 16192

Revision 16192, 15.0 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16191, which included commits to RCS files with non-trunk default branches.
Line 
1<html><head><title>
2How to Write a Reference Clock Driver
3</title></head><body><h3>
4How to Write a Reference Clock Driver
5</h3>
6
7<img align=left src=pic/pogo4.gif><a href=http://www.eecis.udel.edu/~mills/pictures.htm>from <i>Pogo</i>, Walt Kelly</a>
8
9<p>You need a little magic.
10<br clear=left><hr>
11
12<h4>Description</h4>
13
14<p>Reference clock support maintains the fiction that the clock is
15actually an ordinary peer in the NTP tradition, but operating at a
16synthetic stratum of zero. The entire suite of algorithms used to filter
17the received data, select the best clocks or peers and combine them to
18produce a local clock correction operate just like ordinary NTP peers.
19In this way, defective clocks can be detected and removed from the peer
20population. As no packets are exchanged with a reference clock; however,
21the transmit, receive and packet procedures are replaced with separate
22code to simulate them.
23
24<p>Radio and modem reference clocks by convention have addresses in the
25form <tt>127.127.<i>t</i>.<i>u</i></tt>, where <i>t</i> is the clock
26type and <i>u</i> in the range 0-3 is used to distinguish multiple
27instances of clocks of the same type. Most clocks require a serial port
28or special bus peripheral. The particular device is normally specified
29by adding a soft link <tt>/dev/device<i>d</i>d</tt> to the particular
30hardware device involved, where <tt><i>d</i></tt> corresponds to the
31unit number.
32
33<p>The best way to understand how the clock drivers work is to study the
34<tt>ntp_refclock.c</tt> module and one of the drivers already
35implemented, such as <tt>refclock_wwvb.c</tt>. Routines
36<tt>refclock_transmit()</tt> and <tt>refclock_receive()</tt> maintain
37the peer variables in a state analogous to a network peer and pass
38received data on through the clock filters. Routines
39<tt>refclock_peer()</tt> and <tt>refclock_unpeer()</tt> are called to
40initialize and terminate reference clock associations, should this ever
41be necessary. A set of utility routines is included to open serial
42devices, process sample data, edit input lines to extract embedded
43timestamps and to perform various debugging functions.
44
45<p>The main interface used by these routines is the
46<tt>refclockproc</tt> structure, which contains for most drivers the
47decimal equivalents of the year, day, month, hour, second and
48millisecond/microsecond decoded from the ASCII timecode. Additional
49information includes the receive timestamp, exception report, statistics
50tallies, etc. The support routines are passed a pointer to the
51<tt>peer</tt> structure, which is used for all peer-specific processing
52and contains a pointer to the <tt>refclockproc</tt> structure, which in
53turn contains a pointer to the unit structure, if used. For legacy
54purposes, a table <tt>typeunit[type][unit]</tt> contains the peer
55structure pointer for each configured clock type and unit.
56
57<p>The reference clock interface supports auxiliary functions to support
58in-stream timestamping, pulse-per-second (PPS) interfacing and precision
59time kernel support. In most cases the drivers do not need to be aware
60of them, since they are detected at autoconfigure time and loaded
61automatically when the device is opened. These include the
62<tt>tty_clk</tt> and <tt>ppsclock</tt> STREAMS modules and
63<tt>ppsapi</tt> PPS interface described in the <a href="ldisc.htm">Line
64Disciplines and Streams Modules</a> page. The <tt>tty_clk</tt> module
65reduces latency errors due to the operating system and serial port code
66in slower systems. The <tt>ppsclock</tt> module is an interface for the
67PPS signal provided by some radios. The <tt>ppsapi</tt> PPS interface
68replaces the <tt>ppsclock</tt> STREAMS module and is expected to become
69the IETF standard cross-platform interface for PPS signals. In either
70case, the PPS signal can be connected via a level converter/pulse
71generator described in the <a href = "gadget.htm"> Gadget Box PPS Level
72Converter and CHU Modem</a> page.
73
74<p>By convention, reference clock drivers are named in the form
75<tt>refclock_<i>xxxx</i>.c</tt>, where <i>xxxx</i> is a unique
76string. Each driver is assigned a unique type number, long-form driver
77name, short-form driver name, and device name. The existing assignments
78are in the <a href="refclock.htm"> Reference Clock Drivers</a> page
79and its dependencies. All drivers supported by the particular hardware
80and operating system are automatically detected in the autoconfigure
81phase and conditionally compiled. They are configured when the daemon is
82started according to the configuration file, as described in the <a
83href="config.htm"> Configuration Options </a> page.
84
85<p>The standard clock driver interface includes a set of common support
86routines some of which do such things as start and stop the device, open
87the serial port, and establish special functions such as PPS signal
88support. Other routines read and write data to the device and process
89time values. Most drivers need only a little customizing code to, for
90instance, transform idiosyncratic timecode formats to standard form,
91poll the device as necessary, and handle exception conditions. A
92standard interface is available for remote debugging and monitoring
93programs, such as <tt>ntpq</tt> and <tt>ntpdc</tt>, as well as
94the <tt>filegen</tt> facility, which can be used to record device
95status on a continuous basis.
96
97<p>The general organization of a typical clock driver includes a
98receive-interrupt routine to read a timecode from the I/O buffer and
99convert to internal format, generally in days, hours, minutes, seconds
100and fraction. Some timecode formats include provisions for leap-second
101warning and determine the clock hardware and software health. The
102interrupt routine then calls <tt>refclock_process()</tt> with these data
103and the timestamp captured at the on-time character of the timecode.
104This routine saves each sample as received in a circular buffer, which
105can store from a few up to 60 samples, in cases where the timecodes
106arrive one per second.
107
108<p>The <tt>refclock_transmit()</tt> routine in the interface is called
109by the system at intervals defined by the poll interval in the peer
110structure, generally 64 s. This routine in turn calls the transmit poll
111routine in the driver. In the intended design, the driver calls the
112<tt>refclock_receive()</tt> to process the offset samples that have
113accumulated since the last poll and produce the final offset and
114variance. The samples are processed by recursively discarding median
115outlyers until about 60 percent of samples remain, then averaging the
116surviving samples. When a reference clock must be explicitly polled to
117produce a timecode, the driver can reset the poll interval so that the
118poll routine is called a specified number of times at 1-s intervals.
119
120<p>The interface code and this documentation have been developed over
121some time and required not a little hard work converting old drivers,
122etc. Should you find success writing a driver for a new radio or modem
123service, please consider contributing it to the common good. Send the
124driver file itself and patches for the other files to Dave Mills
125(mills@udel.edu).
126
127<h4>Conventions, Fudge Factors and Flags</h4>
128
129<p>Most drivers support manual or automatic calibration for systematic
130offset bias using values encoded in the <tt>fudge</tt> configuration
131command. By convention, the <tt>time1</tt> value defines the calibration
132offset in seconds. For those drivers that support statistics collection
133using the <tt>filegen</tt> utility and the <tt>clockstats</tt> file, the
134<tt>flag4</tt> switch enables the utility. When a PPS signal is
135available, a special automatic calibration facility is provided. If the
136<tt>flag1</tt> switch is set and the PPS signal is actively disciplining
137the system time, the calibration value is automatically adjusted to
138maintain a residual offset of zero. Should the PPS signal or the prefer
139peer fail, the adjustment is frozen and the remaining drivers continue
140to discipline the system clock with a minimum of residual error.
141
142<h4>Files Which Need to be Changed</h4>
143
144<p>A new reference clock implementation needs to supply, in addition to
145the driver itself, several changes to existing files.
146
147<dl>
148
149<dt><tt>./include/ntp.h</tt>
150<dd>The reference clock type defines are used in many places. Each
151driver is assigned a unique type number. Unused numbers are clearly
152marked in the list. A unique <tt>REFCLK_<i>xxxx</i></tt>
153identification code should be recorded in the list opposite its assigned
154type number.
155
156<p><dt><tt>./libntp/clocktypes.c</tt>
157<dd>The <tt>./libntp/clktype</tt> array is used by certain display
158functions. A unique short-form name of the driver should be entered
159together with its assigned identification code.
160
161<p><dt><tt>./ntpd/ntp_control.c</tt>
162<dd>The <tt>clocktypes</tt> array is used for certain control
163message displays functions. It should be initialized with the reference
164clock class assigned to the driver, as per the NTP specification
165RFC-1305. See the <tt>./include/ntp_control.h</tt> header file for
166the assigned classes.
167
168<p><dt><tt>./ntpd/refclock_conf.c</tt>
169<dd>This file contains a list of external structure definitions which
170are conditionally defined. A new set of entries should be installed
171similar to those already in the table. The <tt>refclock_conf</tt>
172array is a set of pointers to transfer vectors in the individual
173drivers. The external name of the transfer vector should be initialized
174in correspondence with the type number.
175
176<p><dt><tt>./acconfig.h</tt>
177<dd>This is a configuration file used by the autoconfigure scheme. Add
178two lines in the form:
179
180<p><pre>
181  /* Define if we have a FOO clock */
182  #undef FOO
183</pre>
184
185<p>where FOO is the define used to cause the driver to be included in
186the distribution.
187
188<p><dt><tt>./configure.in</tt>
189<dd>This is a configuration file used by the autoconfigure scheme. Add
190lines similar to the following:
191
192<p><pre>
193  AC_MSG_CHECKING(FOO clock_description)
194  AC_ARG_ENABLE(FOO, [  --enable-FOO        clock_description],
195      [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
196  if test "$ntp_ok" = "yes"; then
197      ntp_refclock=yes
198      AC_DEFINE(FOO)
199  fi
200  AC_MSG_RESULT($ntp_ok)
201</pre>
202
203<p>(Note that <tt>$ntp_eac</tt> is the value from <tt>--
204{dis,en}able-all-clocks</tt> for non-PARSE clocks and
205<tt>$ntp_eacp</tt> is the value from <tt>--{dis,en}able-parse-
206clocks</tt> for PARSE clocks. See the documentation on the autoconf
207and automake tools from the GNU distributions.)
208
209<p><dt><tt>./ntpd/Makefile.am</tt>
210<dd><p>This is the makefile prototype used by the autoconfigure scheme.
211Add the driver file name to the entries already in the
212<tt>ntpd_SOURCES</tt> list.
213
214<p>Patches to <tt>automake-1.0</tt> are required for the
215autoconfigure scripts to work properly. The file <tt>automake-
2161.0.patches</tt> can be used for this purpose.
217
218<p><dt><tt>./ntpd/Makefile.am</tt>
219<dd>Do the following sequence of commands:
220
221<p><pre>
222  automake
223  autoconf
224  autoheader
225  configure
226</pre>
227
228<p>or simply run <tt>make</tt>, which will do this command sequence
229automatically.
230
231</dl>
232
233<p><h4>Interface Routine Overview</h4>
234
235<dl>
236
237<dt><tt>refclock_newpeer</tt> - initialize and start a reference
238clock
239<dd>This routine allocates and initializes the interface structure which
240supports a reference clock in the form of an ordinary NTP peer. A
241driver-specific support routine completes the initialization, if used.
242Default peer variables which identify the clock and establish its
243reference ID and stratum are set here. It returns one if success and
244zero if the clock address is invalid or already running, insufficient
245resources are available or the driver declares a bum rap.
246<p><dt><tt>refclock_unpeer</tt> - shut down a clock
247<dd>This routine is used to shut down a clock and return its resources
248to the system.
249
250<p><dt><tt>refclock_transmit</tt> - simulate the transmit procedure
251<dd>This routine implements the NTP transmit procedure for a reference
252clock. This provides a mechanism to call the driver at the NTP poll
253interval, as well as provides a reachability mechanism to detect a
254broken radio or other madness.
255
256<p><dt><tt>refclock_sample</tt> - process a pile of samples from the
257clock
258<dd>This routine converts the timecode in the form days, hours, minutes,
259seconds, milliseconds/microseconds to internal timestamp format. It then
260calculates the difference from the receive timestamp and assembles the
261samples in a shift register. It implements a recursive median filter to
262suppress spikes in the data, as well as determine a rough dispersion
263estimate. A configuration constant time adjustment
264<tt>fudgetime1</tt> can be added to the final offset to compensate
265for various systematic errors. The routine returns one if success and
266zero if failure due to invalid timecode data or very noisy offsets.
267
268<p>Note that no provision is included for the year, as provided by some
269(but not all) radio clocks. Ordinarily, the year is implicit in the Unix
270file system and hardware/software clock support, so this is ordinarily
271not a problem. Nevertheless, the absence of the year should be
272considered more a bug than a feature and may be supported in future.
273
274<p><dt><tt>refclock_receive</tt> - simulate the receive and packet
275procedures
276<dd>This routine simulates the NTP receive and packet procedures for a
277reference clock. This provides a mechanism in which the ordinary NTP
278filter, selection and combining algorithms can be used to suppress
279misbehaving radios and to mitigate between them when more than one is
280available for backup.
281
282<p><dt><tt>refclock_gtlin</tt> - groom next input line and extract
283timestamp
284<dd>This routine processes the timecode received from the clock and
285removes the parity bit and control characters. If a timestamp is present
286in the timecode, as produced by the <tt>tty_clk</tt> line
287discipline/streams module, it returns that as the timestamp; otherwise,
288it returns the buffer timestamp. The routine return code is the number
289of characters in the line.
290
291<p><dt><tt>refclock_open</tt> - open serial port for reference clock
292<dd>This routine opens a serial port for I/O and sets default options.
293It returns the file descriptor if success and zero if failure.
294
295<p><dt><tt>refclock_ioctl</tt> - set serial port control functions
296<dd>This routine attempts to hide the internal, system-specific details
297of serial ports. It can handle POSIX (<tt>termios</tt>), SYSV
298(<tt>termio</tt>) and BSD (<tt>sgtty</tt>) interfaces with
299varying degrees of success. The routine sets up the <tt>tty_clk,
300chu_clk</tt> and <tt>ppsclock</tt> streams module/line discipline,
301if compiled in the daemon and requested in the call. The routine returns
302one if success and zero if failure.
303
304<p><dt><tt>refclock_control</tt> - set and/or return clock values
305<dd>This routine is used mainly for debugging. It returns designated
306values from the interface structure that can be displayed using ntpdc
307and the clockstat command. It can also be used to initialize
308configuration variables, such as <tt>fudgetimes, fudgevalues,</tt>
309reference ID and stratum.
310
311<p><dt><tt>refclock_buginfo</tt> - return debugging info
312<dd>This routine is used mainly for debugging. It returns designated
313values from the interface structure that can be displayed using
314<tt>ntpdc</tt> and the <tt>clkbug</tt> command.
315
316</dl>
317
318<hr><a href=index.htm><img align=left src=pic/home.gif></a><address><a
319href=mailto:mills@udel.edu> David L. Mills &lt;mills@udel.edu&gt;</a>
320</address></a></body></html>
Note: See TracBrowser for help on using the repository browser.