You need a little magic.
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 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.
Radio and modem reference clocks by convention have addresses in the form 127.127.t.u, where t is the clock type and u 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 /dev/devicedd to the particular hardware device involved, where d corresponds to the unit number.
The best way to understand how the clock drivers work is to study the ntp_refclock.c module and one of the drivers already implemented, such as refclock_wwvb.c. Routines refclock_transmit() and refclock_receive() maintain the peer variables in a state analogous to a network peer and pass received data on through the clock filters. Routines refclock_peer() and refclock_unpeer() 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.
The main interface used by these routines is the refclockproc 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. The support routines are passed a pointer to the peer structure, which is used for all peer-specific processing and contains a pointer to the refclockproc structure, which in turn contains a pointer to the unit structure, if used. For legacy purposes, a table typeunit[type][unit] contains the peer structure pointer for each configured clock type and unit.
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 tty_clk and ppsclock STREAMS modules and ppsapi PPS interface described in the Line Disciplines and Streams Modules page. The tty_clk module reduces latency errors due to the operating system and serial port code in slower systems. The ppsclock module is an interface for the PPS signal provided by some radios. The ppsapi PPS interface replaces the ppsclock 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 Gadget Box PPS Level Converter and CHU Modem page.
By convention, reference clock drivers are named in the form refclock_xxxx.c, where xxxx 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 Reference Clock Drivers 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 Configuration Options page.
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 ntpq and ntpdc, as well as the filegen facility, which can be used to record device status on a continuous basis.
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 refclock_process() 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.
The refclock_transmit() 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 refclock_receive() 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.
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).
Most drivers support manual or automatic calibration for systematic offset bias using values encoded in the fudge configuration command. By convention, the time1 value defines the calibration offset in seconds. For those drivers that support statistics collection using the filegen utility and the clockstats file, the flag4 switch enables the utility. When a PPS signal is available, a special automatic calibration facility is provided. If the flag1 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.
A new reference clock implementation needs to supply, in addition to the driver itself, several changes to existing files.
/* Define if we have a FOO clock */ #undef FOO
where FOO is the define used to cause the driver to be included in the distribution.
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)
(Note that $ntp_eac is the value from -- {dis,en}able-all-clocks for non-PARSE clocks and $ntp_eacp is the value from --{dis,en}able-parse- clocks for PARSE clocks. See the documentation on the autoconf and automake tools from the GNU distributions.)
This is the makefile prototype used by the autoconfigure scheme. Add the driver file name to the entries already in the ntpd_SOURCES list.
Patches to automake-1.0 are required for the autoconfigure scripts to work properly. The file automake- 1.0.patches can be used for this purpose.
automake autoconf autoheader configure
or simply run make, which will do this command sequence automatically.
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.