### Line Disciplines and Streams Modules

#### Description

Most radio and modem clocks used for a primary (stratum-1) NTP server utilize serial ports operating at speeds of 9600 baud or greater. The timing jitter contributed by the serial port hardware and software driver can accumulate to several milliseconds on a typical Unix workstation. In order to reduce these errors, a set of special line disciplines and stream modules can be configured in the Unix kernel. These routines intercept special characters or signals provided by the radio or modem clock and save a local timestamp for later processing.

The routines can be compiled in the kernel in older BSD-derived systems, or installed as System V streams modules and either compiled in the kernel or dynamically loaded when required. In either case, they require minor changes in some kernel files and in the NTP daemon `ntpd`. The streams modules can be pushed and popped from the streams stack using conventional System V streams program primitives. Note that not all Unix kernels support line disciplines and of those that do, not all support System V streams. The disciplines here are known to work correctly with SunOS 4.x kernels, but have not been tested for other kernels.

There are two line disciplines and a special streams module included in the distribution. Support for each in `ntpd` is enabled by adding flags to the `DEFS_LOCAL` line of the `ntpd` configuration file `./Config.local`. This can be done automatically by the autoconfiguration build procedures, or can be inserted/deleted after the process has completed.

`tty_clk`
  This routine intercepts characters received from the serial port and passes unchanged all except a set of designated characters to the generic serial port discipline. For each of the exception characters, the character is inserted in the receiver buffer followed by a local timestamp in Unix `timeval` format. Both `select()` and `SIGIO` are supported by the routine. The `-DTTYCLK` flag is used to compile support for this discipline in `ntpd`. This flag is automatically included if the `clkdefs.h` file is found in the `/usr/include/sys` directory, or it can be added (or deleted) manually. This module must be configured in the kernel during the kernel build process, as described in the `README` file in the `./kernel` directory.

`tty_chu`
  This routine is a special purpose line discipline for receiving a special timecode broadcast by Canadian time and frequency standard station CHU. The radio signal is first demodulated by the 300-baud modem included in the gadget box, then processed by the discipline and finally processed by the CHU modem driver (type 7) described in the Reference Clock Drivers page. This discipline should be used in raw mode. The `-DCHUCLK` flag is used to compile support for this discipline in `ntpd`. This flag is automatically included if the `chudefs.h` file is found in the `/usr/include/sys` directory, or it can be added (or deleted) manually. This module must be configured in the kernel during the kernel build process, as described in the `README` file in the `./kernel` directory.

`ppsclock`
  This routine is a special purpose streams module which monitors the state of the data carrier detect (DCD) modem interface signal. It is normally used in connection with a pulse-per-second (PPS) signal generated by some radio clocks, which requires a hardware level converter/pulse generator, such as described in the Gadget Box PPS Level Converter and CHU Modem page. For each positive-going edge of the DCD signal, the `ppsclock` module captures a timestamp in Unix `timeval` format for later retrieval using a special `ioctl()` system call. The `-DPPS` flag is used to compile support for this module in `ntpd`. This flag is automatically included if the `ppsclock.h` file is found in the `/sys/sys` directory, or it can be added (or deleted) manually. This module must also be configured in the kernel during the kernel build process, as described in the `README` file in the `./kernel` directory.

There are two versions of both the `tty_clk` and `chu_clk` programs. The `tty_clk.c` and `chu_clk.c` are designed for use with older BSD systems and are compiled in the kernel. The `tty_clk_STREAMS.c` and `chu_clk_STREAMS.c` are designed for use with System V streams, in which case they can be either compiled in the kernel or dynamically loaded. Since these programs are small, unobtrusive, and do nothing unless specifically enabled by an application program, it probably doesn't matter which version is chosen. Instructions on how to configure and build a kernel supporting either or both of these line disciplines is in the `README` file in the `./kernel` directory.

#### How to Use the `tty_clk` Line Discipline

The tty_clk line discipline defines a new `ioctl()`, `CLK_SETSTR`, which takes a pointer to a string of no more than 32 characters. Until the first `CLK_SETSTR` is performed, the discipline will simply pass through characters. Once it is passed a string by `CLK_SETSTR`, any character in that string will be immediately followed by a timestamp in Unix `timeval` format. You can change the string whenever you want by doing another `CLK_SETSTR`. The character must be an exact, 8 bit match. The character '\000' cannot, be used, as it is the string terminator. Passing an empty string to `CLK_SETSTR` turns off timestamping. Passing `NULL` will produce undefined results.

#### How to Use the `tty_chu` Line Discipline

The tty_chu line discipline translates data received from the CHU modem and returns `chucode` structures, as defined in chudefs.h, and expected by the Scratchbuilt CHU Receiver reference clock driver. Depending on the settings of `PEDANTIC` and `ANAL_RETENTIVE` used when compiling the kernel, some checking of the data may or may not be necessary.

#### How to Use the `ppsclock` Stream Module

The ppsclock streams module implements an `ioctl() CIOGETEV`, which takes a pointer to the structure

    struct ppsclockev {
         struct timeval tv;
         u_int serial;
    };

The ppsclock module is pushed on the streams stack of the serial port connected to the PPS signal. The port must be configured for local operation, rather than remote (modem) operation. At each positive-going edge of the DCD signal, the routine latches the current local timestamp and increments a counter. At each `CIOGETEV ioctl()` call, the current values of the timestamp and counter are returned in the `ppsclockev` structure.

#### TIOCDCDTIMESTAMP timestamping

On FreeBSD 2.2 and later systems the TIOCDCDTIMESTAMP ioctl is used to read the timestamp when the DCD serial go active. To use this the PPS signal must be tied to the serial port DCD signal through the appropriate level converters and pulse stretch circuitry if necessary. This enhances the accuracy of the driver to a few microseconds. Using FreeBSD 2.2 the measured delay between activation of the PPS signal and the time the timestamp is made on a 66MHz 486DX2 is 19us and on a 100MHz Pentium is 6us. The driver does NOT compensate for this.

The TIOCDCDTIMESTAMP timestamping ioctl() is used automatically on FreeBSD systems if available. It is integrated into the refclock_gtlin() function so any driver using it will benefit from the enhanced accuracy.