270 lines
12 KiB
HTML
270 lines
12 KiB
HTML
<!-- $NetBSD: howto.html,v 1.1 1998/12/30 20:20:35 mcr Exp $ -->
|
|
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML Strict//EN">
|
|
<html><head><title>
|
|
How to Write a Reference Clock Driver
|
|
</title></head><body><h3>
|
|
How to Write a Reference Clock Driver
|
|
</h3><hr>
|
|
|
|
<p><h4>Description</h4>
|
|
|
|
<p>Reference clock support maintains the fiction that the clock is
|
|
actually an ordinary peer in the NTP tradition, but operating at a
|
|
synthetic stratum of zero. The entire suite of algorithms used to filter
|
|
the received data, select the best clocks or peers and combine them to
|
|
produce a local clock correction are operative as with ordinary NTP
|
|
peers. In this way, defective clocks can be detected and removed from
|
|
the peer population. As no packets are exchanged with a reference clock,
|
|
however, we replace the transmit, receive and packet procedures with
|
|
separate code to simulate them.
|
|
|
|
<p>Radio and modem reference clocks by convention have addresses in the
|
|
form <code>127.127.<i>t</i>.<i>u</i>,</code>, where <i>t</i> is the
|
|
clock type and <i>u</i> in the range 0-3 is used to distinguish multiple
|
|
instances of clocks of the same type. Most clocks require a serial port
|
|
or special bus peripheral. The particular device is normally specified
|
|
by adding a soft link <code>/dev/device<i>d</i>d</code> to the
|
|
particular hardware device involved, where <code><i>d</i></code>
|
|
corresponds to the unit number.
|
|
|
|
<p>The best way to understand how the clock drivers work is to study the
|
|
<code>ntp_refclock.c</code> module and one of the drivers already
|
|
implemented, such as <code>refclock_wwvb.c</code>. Routines
|
|
<code>refclock_transmit()</code> and <code>refclock_receive()</code>
|
|
maintain the peer variables in a state analogous to an actual peer and
|
|
pass received data on through the clock filters. Routines
|
|
<code>refclock_peer()</code> and <code>refclock_unpeer()</code> are
|
|
called to initialize and terminate reference clock associations, should
|
|
this ever be necessary. A set of utility routines is included to open
|
|
serial devices, process sample data, edit input lines to extract
|
|
embedded timestamps and to perform various debugging functions.
|
|
|
|
<p>The main interface used by these routines is the
|
|
<code>refclockproc</code> structure, which contains for most drivers the
|
|
decimal equivalents of the year, day, month, hour, second and
|
|
millisecond/microsecond decoded from the ASCII timecode. Additional
|
|
information includes the receive timestamp, exception report, statistics
|
|
tallies, etc. In addition, there may be a driver-specific unit structure
|
|
used for local control of the device. The support routines are passed a
|
|
pointer to the <code>peer</code> structure, which is used for all peer-
|
|
specific processing and contains a pointer to the
|
|
<code>refclockproc</code> structure, which in turn contains a pointer to
|
|
the unit structure, if used. A table <code>typeunit[type][unit]</code>
|
|
contains the peer structure pointer for each configured clock type and
|
|
unit.
|
|
|
|
<p>Many drivers support the <code>tty_clk</code> and/or
|
|
<code>ppsclock</code> line disciplines or streams modules described in
|
|
the included in the <a href="ldisc.html">Line Disciplines and Streams
|
|
Modules</a> page. The <code>tty_clk</code> module reduces latency errors
|
|
due to the operating system and serial port code in slower systems. The
|
|
<code>ppsclock</code> module is an interface for the PPS signal provided
|
|
by some radios. It can be connected via a level converter/pulse
|
|
generator described in the <a href = "gadget.html"> Gadget Box PPS Level
|
|
Converter and CHU Modem </a> page.
|
|
|
|
<p>By convention, reference clock drivers are named in the form
|
|
<code>refclock_<i>xxxx</i>.c</code>, where <i>xxxx</i> is a unique
|
|
string. Each driver is assigned a unique type number, long-form driver
|
|
name, short-form driver name, and device name. The existing assignments
|
|
are in the <a href = "refclock.html"> Reference Clock Drivers </a> page
|
|
and its dependencies. Drivers are conditionally compiled using a unique
|
|
flag string in the <code>CLOCKDEFS</code> line described in the <a href
|
|
= "config.html"> Configuration Options </a> page.
|
|
|
|
<p>The standard clock driver interface includes a set of common support
|
|
routines some of which do such things as start and stop the device, open
|
|
the serial port, and establish special functions such as PPS signal
|
|
support. Other routines read and write data to the device and process
|
|
time values. Most drivers need only a little customizing code to, for
|
|
instance, transform idiosyncratic timecode formats to standard form,
|
|
poll the device as necessary, and handle exception conditions. A
|
|
standard interface is available for remote debugging and monitoring
|
|
programs, such as <code>ntpq</code> and <code>xntpdc</code>, as well as
|
|
the <code>filegen</code> facility, which can be used to record device
|
|
status on a continuous basis.
|
|
|
|
<p>The interface code and this documentation have been developed over
|
|
some time and required not a little hard work converting old drivers,
|
|
etc. Should you find success writing a driver for a new radio or modem
|
|
service, please consider contributing it to the common good. Send the
|
|
driver file itself and patches for the other files to Dave Mills
|
|
(mills@udel.edu).
|
|
|
|
<p><h4>Files Which Need to be Changed</h4>
|
|
|
|
<p>A new reference clock implementation needs to supply, in addition to
|
|
the driver itself, several changes to existing files.
|
|
|
|
<dl>
|
|
|
|
<dt><code>./include/ntp.h</code>
|
|
<dd>The reference clock type defines are used in many places. Each
|
|
driver is assigned a unique type number. Unused numbers are clearly
|
|
marked in the list. A unique <code>REFCLK_<i>xxxx</i></code>
|
|
identification code should be recorded in the list opposite its assigned
|
|
type number.
|
|
|
|
<p><dt><code>./libntp/clocktypes.c</code>
|
|
<dd>The <code>./libntp/clktype</code> array is used by certain display
|
|
functions. A unique short-form name of the driver should be entered
|
|
together with its assigned identification code.
|
|
|
|
<p><dt><code>./xntpd/ntp_control.c</code>
|
|
<dd>The <code>clocktypes</code> array is used for certain control
|
|
message displays functions. It should be initialized with the reference
|
|
clock class assigned to the driver, as per the NTP specification
|
|
RFC-1305. See the <code>./include/ntp_control.h</code> header file for
|
|
the assigned classes.
|
|
|
|
<p><dt><code>./xntpd/refclock_conf.c</code>
|
|
<dd>This file contains a list of external structure definitions which
|
|
are conditionally defined. A new set of entries should be installed
|
|
similar to those already in the table. The <code>refclock_conf</code>
|
|
array is a set of pointers to transfer vectors in the individual
|
|
drivers. The external name of the transfer vector should be initialized
|
|
in correspondence with the type number.
|
|
|
|
<p><dt><code>./acconfig.h</code>
|
|
<dd>This is a configuration file used by the autoconfigure scheme. Add
|
|
two lines in the form:
|
|
|
|
<p><pre>
|
|
/* Define if we have a FOO clock */
|
|
#undef FOO
|
|
</pre>
|
|
|
|
<p>where FOO is the define used to cause the driver to be included in
|
|
the distribution.
|
|
|
|
<p><dt><code>./configure.in</code>
|
|
<dd>This is a configuration file used by the autoconfigure scheme. Add
|
|
lines similar to the following:
|
|
|
|
<p><pre>
|
|
AC_MSG_CHECKING(FOO clock_description)
|
|
AC_ARG_ENABLE(FOO, [ --enable-FOO clock_description],
|
|
[ntp_ok=$enableval], [ntp_ok=$ntp_eac])
|
|
if test "$ntp_ok" = "yes"; then
|
|
ntp_refclock=yes
|
|
AC_DEFINE(FOO)
|
|
fi
|
|
AC_MSG_RESULT($ntp_ok)
|
|
</pre>
|
|
|
|
<p>(Note that <code>$ntp_eac</code> is the value from <code>--
|
|
{dis,en}able-all-clocks</code> for non-PARSE clocks and
|
|
<code>$ntp_eacp</code> is the value from <code>--{dis,en}able-parse-
|
|
clocks</code> for PARSE clocks. See the documentation on the autoconf
|
|
and automake tools from the GNU distributions.)
|
|
|
|
<p><dt><code>./xntpd/Makefile.am</code>
|
|
<dd><p>This is the makefile prototype used by the autoconfigure scheme.
|
|
Add the driver file name to the entries already in the
|
|
<code>xntpd_SOURCES</code> list.
|
|
|
|
<p>Patches to <code>automake-1.0</code> are required for the
|
|
autoconfigure scripts to work properly. The file <code>automake-
|
|
1.0.patches</code> can be used for this purpose.
|
|
|
|
<p><dt><code>./xntpd/Makefile.am</code>
|
|
<dd>Do the following sequence of commands:
|
|
|
|
<p><pre>
|
|
automake
|
|
autoconf
|
|
autoheader
|
|
configure
|
|
</pre>
|
|
|
|
<p>or simply run <code>make</code>, which will do this command sequence
|
|
automatically.
|
|
|
|
</dl>
|
|
|
|
<p><h4>Interface Routine Overview</h4>
|
|
|
|
<dl>
|
|
|
|
<dt><code>refclock_newpeer</code> - initialize and start a reference
|
|
clock
|
|
<dd>This routine allocates and initializes the interface structure which
|
|
supports a reference clock in the form of an ordinary NTP peer. A
|
|
driver-specific support routine completes the initialization, if used.
|
|
Default peer variables which identify the clock and establish its
|
|
reference ID and stratum are set here. It returns one if success and
|
|
zero if the clock address is invalid or already running, insufficient
|
|
resources are available or the driver declares a bum rap.
|
|
<p><dt><code>refclock_unpeer</code> - shut down a clock
|
|
<dd>This routine is used to shut down a clock and return its resources
|
|
to the system.
|
|
|
|
<p><dt><code>refclock_transmit</code> - simulate the transmit procedure
|
|
<dd>This routine implements the NTP transmit procedure for a reference
|
|
clock. This provides a mechanism to call the driver at the NTP poll
|
|
interval, as well as provides a reachability mechanism to detect a
|
|
broken radio or other madness.
|
|
|
|
<p><dt><code>refclock_sample</code> - process a pile of samples from the
|
|
clock
|
|
<dd>This routine converts the timecode in the form days, hours, minutes,
|
|
seconds, milliseconds/microseconds to internal timestamp format. It then
|
|
calculates the difference from the receive timestamp and assembles the
|
|
samples in a shift register. It implements a recursive median filter to
|
|
suppress spikes in the data, as well as determine a rough dispersion
|
|
estimate. A configuration constant time adjustment
|
|
<code>fudgetime1</code> can be added to the final offset to compensate
|
|
for various systematic errors. The routine returns one if success and
|
|
zero if failure due to invalid timecode data or very noisy offsets.
|
|
|
|
<p>Note that no provision is included for the year, as provided by some
|
|
(but not all) radio clocks. Ordinarily, the year is implicit in the Unix
|
|
file system and hardware/software clock support, so this is ordinarily
|
|
not a problem. Nevertheless, the absence of the year should be
|
|
considered more a bug than a feature and may be supported in future.
|
|
|
|
<p><dt><code>refclock_receive</code> - simulate the receive and packet
|
|
procedures
|
|
<dd>This routine simulates the NTP receive and packet procedures for a
|
|
reference clock. This provides a mechanism in which the ordinary NTP
|
|
filter, selection and combining algorithms can be used to suppress
|
|
misbehaving radios and to mitigate between them when more than one is
|
|
available for backup.
|
|
|
|
<p><dt><code>refclock_gtlin</code> - groom next input line and extract
|
|
timestamp
|
|
<dd>This routine processes the timecode received from the clock and
|
|
removes the parity bit and control characters. If a timestamp is present
|
|
in the timecode, as produced by the <code>tty_clk</code> line
|
|
discipline/streams module, it returns that as the timestamp; otherwise,
|
|
it returns the buffer timestamp. The routine return code is the number
|
|
of characters in the line.
|
|
|
|
<p><dt><code>refclock_open</code> - open serial port for reference clock
|
|
<dd>This routine opens a serial port for I/O and sets default options.
|
|
It returns the file descriptor if success and zero if failure.
|
|
|
|
<p><dt><code>refclock_ioctl</code> - set serial port control functions
|
|
<dd>This routine attempts to hide the internal, system-specific details
|
|
of serial ports. It can handle POSIX (<code>termios</code>), SYSV
|
|
(<code>termio</code>) and BSD (<code>sgtty</code>) interfaces with
|
|
varying degrees of success. The routine sets up the <code>tty_clk,
|
|
chu_clk</code> and <code>ppsclock</code> streams module/line discipline,
|
|
if compiled in the daemon and requested in the call. The routine returns
|
|
one if success and zero if failure.
|
|
|
|
<p><dt><code>refclock_control</code> - set and/or return clock values
|
|
<dd>This routine is used mainly for debugging. It returns designated
|
|
values from the interface structure that can be displayed using xntpdc
|
|
and the clockstat command. It can also be used to initialize
|
|
configuration variables, such as <code>fudgetimes, fudgevalues,</code>
|
|
reference ID and stratum.
|
|
<p><dt><code>refclock_buginfo</code> - return debugging info
|
|
<dd>This routine is used mainly for debugging. It returns designated
|
|
values from the interface structure that can be displayed using
|
|
<code>xntpdc</code> and the <code>clkbug</code> command.
|
|
|
|
</dl>
|
|
|
|
<hr><address>David L. Mills (mills@udel.edu)</address></body></html>
|