xref: /freebsd/contrib/ntp/html/howto.html (revision 9c2daa00c2315f101948c7144d62af5d5fb515cf)
19c2daa00SOllivier Robert<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
29c2daa00SOllivier Robert
39c2daa00SOllivier Robert<html>
49c2daa00SOllivier Robert
59c2daa00SOllivier Robert    <head>
69c2daa00SOllivier Robert        <meta name="generator" content="HTML Tidy, see www.w3.org">
79c2daa00SOllivier Robert        <title>How to Write a Reference Clock Driver</title>
89c2daa00SOllivier Robert        <link href="scripts/style.css" type="text/css" rel="stylesheet">
99c2daa00SOllivier Robert    </head>
109c2daa00SOllivier Robert
119c2daa00SOllivier Robert    <body>
129c2daa00SOllivier Robert        <h3>How to Write a Reference Clock Driver</h3>
139c2daa00SOllivier Robert        <img src="pic/pogo4.gif" alt="gif" align="left"><a href="http://www.eecis.udel.edu/~mills/pictures.html">from <i>Pogo</i>, Walt Kelly</a>
149c2daa00SOllivier Robert        <p>You need a little magic.</p>
159c2daa00SOllivier Robert        <p>Last update: <csobj format="ShortTime" h="25" locale="00000409" region="0" t="DateTime" w="99">03:11 AM</csobj> UTC <csobj format="LongDate" h="25" locale="00000409" region="0" t="DateTime" w="270">Monday, October 13, 2003</csobj></p>
169c2daa00SOllivier Robert        <br clear="left">
179c2daa00SOllivier Robert        <h4>Related Links</h4>
189c2daa00SOllivier Robert        <script type="text/javascript" language="javascript" src="scripts/links10.txt"></script>
199c2daa00SOllivier Robert        <h4>Table of Contents</h4>
209c2daa00SOllivier Robert        <ul>
219c2daa00SOllivier Robert            <li class="inline"><a href="#desc">Description</a>
229c2daa00SOllivier Robert            <li class="inline"><a href="#file">Files Which Need to be Changed</a>
239c2daa00SOllivier Robert            <li class="inline"><a href="#intf">Interface Routine Overview</a>
249c2daa00SOllivier Robert        </ul>
259c2daa00SOllivier Robert        <hr>
269c2daa00SOllivier Robert        <h4 id="desc">Description</h4>
279c2daa00SOllivier Robert        <p>NTP 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 system clock correction operate just like 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, the transmit, receive and packet procedures are replaced with separate code to simulate them.</p>
289c2daa00SOllivier Robert        <p>It is important to understand how the NTP clock driver interface works. The driver assumes three timescales: standard time maintained by a distant laboratory such as USNO or NIST, reference time maintained by the external radio and the system time maintained by NTP. The radio synchronizes reference time and frequency to standard time via radio, satellite or modem. As the transmission means may not always be reliable, most radios continue to provide clock updates for some time after signal loss using an internal reference oscillator. In such cases the radio may or may not reveal the time since last synchronized and/or the estimated time error.</p>
299c2daa00SOllivier Robert        <p>All three timescales run <i>only</i> in Coordinated Universal Time (UTC), 24-hour format, and are not adjusted for local timezone or standard/daylight time. The local timezone, standard/daylight indicator and year, if provided, are ignored. However, it is important to determine whether a leap second is to be inserted in the UTC timescale in the near future so NTP can insert it in the system timescale at the appropriate epoch.</p>
309c2daa00SOllivier Robert        <p>The NTP clock driver synchronizes the system time and frequency to the radio via serial or parallel port, PPS signal or other means. The driver routinely checks the radio timecode string or status indicators to determine whether it is operating correctly or not. If it is, the driver decodes the radio timecode in days, hours, minutes, seconds and nanoseconds and provides these data with the NTP receive timestamp corresponding to the on-time epoch of the timecode. The driver interface computes the difference between the timecode time and NTP timestamp and saves the difference in a circular buffer for later processing. Once each poll interval, usually 64 s, the driver provides ancillary data including leap bits and last reference time to the interface. The interface processes the circular buffer using a median/trimmed mean algorithm to extract the best estimate and provides this and the ancillary data to the clock filter as with ordinary NTP peers.</p>
319c2daa00SOllivier Robert        <p>The audio drivers are designed to look like a typical external radio in that the reference oscillator is derived from the audio codec oscillator and separate from the system clock oscillator. In the WWV and IRIG drivers, the codec oscillator is disciplined in frequency to the standard timescale via radio or local sources and can be assumed to have the same reliability and accuracy as an external radio. In these cases the driver continues to provide updates to the clock filter even if the WWV or IRIG signals are lost. However, the interface is provided the last reference time when the signals were received and increases the dispersion as expected with an ordinary peer.</p>
329c2daa00SOllivier Robert        <p>The best way to understand how the clock drivers work is to study the <tt>ntp_refclock.c</tt> module and one of the drivers already implemented, such as <tt>refclock_wwvb.c</tt>. Routines <tt>refclock_transmit()</tt> and <tt>refclock_receive()</tt> maintain the peer variables in a state analogous to a network peer and pass received data on through the clock filters. Routines <tt>refclock_peer()</tt> and <tt>refclock_unpeer()</tt> 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>
339c2daa00SOllivier Robert        <p>The main interface used by these routines is the <tt>refclockproc</tt> structure, which contains for most drivers the decimal equivalents of the year, day, month, hour, second and nanosecond decoded from the radio timecode. Additional information includes the receive timestamp, reference timestamp, exception reports, statistics tallies, etc. The support routines are passed a pointer to the <tt>peer</tt> structure, which is used for all peer-specific processing and contains a pointer to the <tt>refclockproc</tt> structure, which in turn contains a pointer to the unit structure, if used. For legacy purposes, a table <tt>typeunit[type][unit]</tt> contains the peer structure pointer for each configured clock type and unit. This structure should not be used for new implementations.</p>
349c2daa00SOllivier Robert        <p>The reference clock interface supports auxiliary functions to support in-stream timestamping, pulse-per-second (PPS) interfacing and precision time kernel support. In most cases the drivers do not need to be aware of them, since they are detected at autoconfigure time and loaded automatically when the device is opened. These include the <tt>tty_clk</tt> STREAMS module and <tt>ppsapi</tt> PPS interface described in the <a href="ldisc.html">Line Disciplines and Streams Modules</a> page. The <tt>tty_clk</tt> module reduces latency errors due to the operating system and serial port code in slower systems. The <tt>ppsapi</tt> PPS interface replaces the <tt>ppsclock</tt> STREAMS module and is expected to become the IETF standard cross-platform interface for PPS signals. In either case, the PPS signal can be connected via a level converter/pulse generator described in the <a href="pps.html">Pulse-per-second (PPS) Signal Interfacing</a> page.</p>
359c2daa00SOllivier Robert        <p>Radio and modem reference clocks by convention have addresses in the form <tt>127.127.<i>t</i>.<i>u</i></tt>, 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 or parallel port or special bus peripheral. The particular device is normally specified by adding a soft link <tt>/dev/device<i>d</i>d</tt> to the particular hardware device involved, where <tt><i>d</i></tt> corresponds to the unit number.</p>
369c2daa00SOllivier Robert        <p>By convention, reference clock drivers are named in the form <tt>refclock_<i>xxxx</i>.c</tt>, 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. All drivers supported by the particular hardware and operating system are automatically detected in the autoconfigure phase and conditionally compiled. They are configured when the daemon is started according to the configuration file, as described in the <a href="config.html">Configuration Options</a> page.</p>
379c2daa00SOllivier Robert        <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 <tt>ntpq</tt> and <tt>ntpdc</tt>, as well as the <tt>filegen</tt> facility, which can be used to record device status on a continuous basis.</p>
389c2daa00SOllivier Robert        <p>The general organization of a typical clock driver includes a receive-interrupt routine to read a timecode from the I/O buffer and convert to internal format, generally in days, hours, minutes, seconds and fraction. Some timecode formats include provisions for leap-second warning and determine the clock hardware and software health. The interrupt routine then calls <tt>refclock_process()</tt> with these data and the timestamp captured at the on-time character of the timecode. This routine saves each sample as received in a circular buffer, which can store from a few up to 60 samples, in cases where the timecodes arrive one per second.</p>
399c2daa00SOllivier Robert        <p>The <tt>refclock_transmit()</tt> routine in the interface is called by the system at intervals defined by the poll interval in the peer structure, generally 64 s. This routine in turn calls the transmit poll routine in the driver. In the intended design, the driver calls the <tt>refclock_receive()</tt> to process the offset samples that have accumulated since the last poll and produce the final offset and variance. The samples are processed by recursively discarding median outlyers until about 60 percent of samples remain, then averaging the surviving samples. When a reference clock must be explicitly polled to produce a timecode, the driver can reset the poll interval so that the poll routine is called a specified number of times at 1-s intervals.</p>
409c2daa00SOllivier Robert        <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>
419c2daa00SOllivier Robert        <h4>Conventions, Fudge Factors and Flags</h4>
429c2daa00SOllivier Robert        <p>Most drivers support manual or automatic calibration for systematic offset bias using values encoded in the <tt>fudge</tt> configuration command. By convention, the <tt>time1</tt> value defines the calibration offset in seconds. For those drivers that support statistics collection using the <tt>filegen</tt> utility and the <tt>clockstats</tt> file, the <tt>flag4</tt> switch enables the utility. When a PPS signal is available, a special automatic calibration facility is provided. If the <tt>flag1</tt> switch is set and the PPS signal is actively disciplining the system time, the calibration value is automatically adjusted to maintain a residual offset of zero. Should the PPS signal or the prefer peer fail, the adjustment is frozen and the remaining drivers continue to discipline the system clock with a minimum of residual error.</p>
439c2daa00SOllivier Robert        <h4 id="file">Files Which Need to be Changed</h4>
449c2daa00SOllivier Robert        <p>A new reference clock implementation needs to supply, in addition to the driver itself, several changes to existing files.</p>
459c2daa00SOllivier Robert        <dl>
469c2daa00SOllivier Robert            <dt><tt>./include/ntp.h</tt>
479c2daa00SOllivier Robert            <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 <tt>REFCLK_<i>xxxx</i></tt> identification code should be recorded in the list opposite its assigned type number.
489c2daa00SOllivier Robert            <dt><tt>./libntp/clocktypes.c</tt>
499c2daa00SOllivier Robert            <dd>The <tt>./libntp/clktype</tt> array is used by certain display functions. A unique short-form name of the driver should be entered together with its assigned identification code.
509c2daa00SOllivier Robert            <dt><tt>./ntpd/ntp_control.c</tt>
519c2daa00SOllivier Robert            <dd>The <tt>clocktypes</tt> 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 <tt>./include/ntp_control.h</tt> header file for the assigned classes.
529c2daa00SOllivier Robert            <dt><tt>./ntpd/refclock_conf.c</tt>
539c2daa00SOllivier Robert            <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 <tt>refclock_conf</tt> 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.
549c2daa00SOllivier Robert            <dt><tt>./configure.in</tt>
559c2daa00SOllivier Robert            <dd>This is a configuration file used by the autoconfigure scheme. Add lines similar to the following:
569c2daa00SOllivier Robert            <pre>
579c2daa00SOllivier Robert  AC_MSG_CHECKING(FOO clock_description)
589c2daa00SOllivier Robert  AC_ARG_ENABLE(FOO,
599c2daa00SOllivier Robert      AC_HELP_STRING([--enable-FOO], [x clock_description]),
609c2daa00SOllivier Robert      [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
619c2daa00SOllivier Robert  if test &quot;$ntp_ok&quot; = &quot;yes&quot;; then
629c2daa00SOllivier Robert      ntp_refclock=yes
639c2daa00SOllivier Robert      AC_DEFINE(CLOCK_FOO, 1, [Foo clock?])
649c2daa00SOllivier Robert  fi
659c2daa00SOllivier Robert  AC_MSG_RESULT($ntp_ok)
669c2daa00SOllivier Robert</pre>
679c2daa00SOllivier Robert            <dd>(Note that <tt>$ntp_eac</tt> is the value from <tt>--{dis,en}able-all-clocks</tt> for non-PARSE clocks and <tt>$ntp_eacp</tt> is the value from <tt>--{dis,en}able-parse-clocks</tt> for PARSE clocks. See the documentation on the autoconf and automake tools from the GNU distributions.)
689c2daa00SOllivier Robert            <dt><tt>./ntpd/Makefile.am</tt>
699c2daa00SOllivier Robert            <dd>This is the makefile prototype used by the autoconfigure scheme. Add the driver file name to the entries already in the <tt>ntpd_SOURCES</tt> list.
709c2daa00SOllivier Robert            <dd>Do the following sequence of commands:
719c2daa00SOllivier Robert            <pre>
729c2daa00SOllivier Robert  autoreconf
739c2daa00SOllivier Robert  configure
749c2daa00SOllivier Robert</pre>
759c2daa00SOllivier Robert            <dd>or simply run <tt>make</tt>, which will do this command sequence automatically.
769c2daa00SOllivier Robert        </dl>
779c2daa00SOllivier Robert        <h4 id="intf">Interface Routine Overview</h4>
789c2daa00SOllivier Robert        <dl>
799c2daa00SOllivier Robert            <dt><tt>refclock_newpeer</tt> - initialize and start a reference clock
809c2daa00SOllivier Robert            <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.
819c2daa00SOllivier Robert            <dt><tt>refclock_unpeer</tt> - shut down a clock
829c2daa00SOllivier Robert            <dd>This routine is used to shut down a clock and return its resources to the system.
839c2daa00SOllivier Robert            <dt><tt>refclock_transmit</tt> - simulate the transmit procedure
849c2daa00SOllivier Robert            <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.
859c2daa00SOllivier Robert            <dt><tt>refclock_sample</tt> - process a pile of samples from the clock
869c2daa00SOllivier Robert            <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 <tt>fudgetime1</tt> 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.
879c2daa00SOllivier Robert            <dd>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.
889c2daa00SOllivier Robert            <dt><tt>refclock_receive</tt> - simulate the receive and packet procedures
899c2daa00SOllivier Robert            <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.
909c2daa00SOllivier Robert            <dt><tt>refclock_gtlin</tt> - groom next input line and extract timestamp
919c2daa00SOllivier Robert            <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 <tt>tty_clk</tt> 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.
929c2daa00SOllivier Robert            <dt><tt>refclock_open</tt> - open serial port for reference clock
939c2daa00SOllivier Robert            <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.
949c2daa00SOllivier Robert            <dt><tt>refclock_ioctl</tt> - set serial port control functions
959c2daa00SOllivier Robert            <dd>This routine attempts to hide the internal, system-specific details of serial ports. It can handle POSIX (<tt>termios</tt>), SYSV (<tt>termio</tt>) and BSD (<tt>sgtty</tt>) interfaces with varying degrees of success. The routine sets up the <tt>tty_clk, chu_clk</tt> and <tt>ppsclock</tt> streams module/line discipline, if compiled in the daemon and requested in the call. The routine returns one if success and zero if failure.
969c2daa00SOllivier Robert            <dt><tt>refclock_control</tt> - set and/or return clock values
979c2daa00SOllivier Robert            <dd>This routine is used mainly for debugging. It returns designated values from the interface structure that can be displayed using ntpdc and the clockstat command. It can also be used to initialize configuration variables, such as <tt>fudgetimes, fudgevalues,</tt> reference ID and stratum.
989c2daa00SOllivier Robert            <dt><tt>refclock_buginfo</tt> - return debugging info
999c2daa00SOllivier Robert            <dd>This routine is used mainly for debugging. It returns designated values from the interface structure that can be displayed using <tt>ntpdc</tt> and the <tt>clkbug</tt> command.
1009c2daa00SOllivier Robert        </dl>
1019c2daa00SOllivier Robert        <hr>
1029c2daa00SOllivier Robert        <center>
1039c2daa00SOllivier Robert            <img src="pic/pogo1a.gif" alt="gif"></center>
1049c2daa00SOllivier Robert        <br>
1059c2daa00SOllivier Robert        <script type="text/javascript" language="javascript" src="scripts/footer.txt"></script>
1069c2daa00SOllivier Robert    </body>
1079c2daa00SOllivier Robert
1089c2daa00SOllivier Robert</html>