diff options
Diffstat (limited to 'html/howto.htm')
-rw-r--r-- | html/howto.htm | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/html/howto.htm b/html/howto.htm new file mode 100644 index 0000000..6e08242 --- /dev/null +++ b/html/howto.htm @@ -0,0 +1,320 @@ +<html><head><title> +How to Write a Reference Clock Driver +</title></head><body><h3> +How to Write a Reference Clock Driver +</h3> + +<img align=left src=pic/pogo4.gif><a href=http://www.eecis.udel.edu/~mills/pictures.htm>from <i>Pogo</i>, Walt Kelly</a> + +<p>You need a little magic. +<br clear=left><hr> + +<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 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>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 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>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> 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 +<tt>refclockproc</tt> 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 +<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. + +<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> and <tt>ppsclock</tt> STREAMS modules and +<tt>ppsapi</tt> PPS interface described in the <a href="ldisc.htm">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>ppsclock</tt> module is an interface for the +PPS signal provided by some radios. 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 = "gadget.htm"> Gadget Box PPS Level +Converter and CHU Modem</a> page. + +<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.htm"> 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.htm"> 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 <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>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>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>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). + +<h4>Conventions, Fudge Factors and Flags</h4> + +<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. + +<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><tt>./include/ntp.h</tt> +<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. + +<p><dt><tt>./libntp/clocktypes.c</tt> +<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. + +<p><dt><tt>./ntpd/ntp_control.c</tt> +<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. + +<p><dt><tt>./ntpd/refclock_conf.c</tt> +<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. + +<p><dt><tt>./acconfig.h</tt> +<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><tt>./configure.in</tt> +<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 <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.) + +<p><dt><tt>./ntpd/Makefile.am</tt> +<dd><p>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. + +<p>Patches to <tt>automake-1.0</tt> are required for the +autoconfigure scripts to work properly. The file <tt>automake- +1.0.patches</tt> can be used for this purpose. + +<p><dt><tt>./ntpd/Makefile.am</tt> +<dd>Do the following sequence of commands: + +<p><pre> + automake + autoconf + autoheader + configure +</pre> + +<p>or simply run <tt>make</tt>, which will do this command sequence +automatically. + +</dl> + +<p><h4>Interface Routine Overview</h4> + +<dl> + +<dt><tt>refclock_newpeer</tt> - 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><tt>refclock_unpeer</tt> - shut down a clock +<dd>This routine is used to shut down a clock and return its resources +to the system. + +<p><dt><tt>refclock_transmit</tt> - 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><tt>refclock_sample</tt> - 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 +<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. + +<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><tt>refclock_receive</tt> - 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><tt>refclock_gtlin</tt> - 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 <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. + +<p><dt><tt>refclock_open</tt> - 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><tt>refclock_ioctl</tt> - set serial port control functions +<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. + +<p><dt><tt>refclock_control</tt> - 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 ntpdc +and the clockstat command. It can also be used to initialize +configuration variables, such as <tt>fudgetimes, fudgevalues,</tt> +reference ID and stratum. + +<p><dt><tt>refclock_buginfo</tt> - return debugging info +<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. + +</dl> + +<hr><a href=index.htm><img align=left src=pic/home.gif></a><address><a +href=mailto:mills@udel.edu> David L. Mills <mills@udel.edu></a> +</address></a></body></html> |