From: Harlan Stenn Date: Wed, 22 Apr 2009 06:35:47 +0000 (-0400) Subject: PPS/PPSAPI cleanup from Dave Mills X-Git-Tag: NTP_4_2_5P164~3^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2dd4e48073cbf967741fee0f70012a82c4fee3a0;p=thirdparty%2Fntp.git PPS/PPSAPI cleanup from Dave Mills bk: 49eebac3ZVcoqqI7wOmODLy3w8FqJA --- diff --git a/ChangeLog b/ChangeLog index 3ebfe866a..77f9d1181 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5 @@ +* PPS/PPSAPI cleanup from Dave Mills. +* Documentation updates from Dave Mills. (4.2.5p163) 2009/04/10 Released by Harlan Stenn (4.2.5p162) 2009/04/09 Released by Harlan Stenn * Documentation updates from Dave Mills. diff --git a/html/howto.html b/html/howto.html index dc628eb49..3596e8bb8 100644 --- a/html/howto.html +++ b/html/howto.html @@ -13,15 +13,18 @@

How to Write a Reference Clock Driver

giffrom Pogo, Walt Kelly

You need a little magic.

-

Last update: 16:02 UTC Wednesday, January 02, 2008

-
+

Last update: + 19-Apr-2009 19:24 +

+

Related Links

Table of Contents


Description

@@ -30,18 +33,20 @@

All three timescales run only in Coordinated Universal Time (UTC) 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.

The interface routines in the ntp_refclock.c source file call the following driver routines via a transfer vector:

-
startup -
The association has just been mobilized. The driver may open the device(s) required. -
shutdown -
The association is about to be demobilized. The driver should close all device(s) and free all structures. -
receive -
A timecode string is ready for retrieval using the refclock_gtlin() or refclock_gtraw() routines. -
poll -
Called at poll timeout, by default 64 s. -
timer -
Called once per second.
-

The receive routine retrieves a timecode string via serial or parallel port, PPS signal or other means. It decodes the timecode in days, hours, minutes, seconds and nanoseconds and checks for errors. It provides these data along with the on-time timestamp to the interface routine refclock_process(), which saves the computed offset in a 60-sample circular buffer. On occasion, either by timeout, sample count or call to the poll routine, the driver routine calls refclock_receive() to average the samples and update the system clock.

-

The best way to understand how the clock drivers work is to study one of the drivers already implemented, such as refclock_wwvb.c. The main interface is the refclockproc structure, which contains for most drivers the decoded timecode, on0time timestamp, reference timestamp, exception reports, statistics tallies, etc. The support routines are passed a pointer to the peer structure, which 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. This structure should not be used for new implementations.

+
startup
+
The association has just been mobilized. The driver may allocate a private structure and open the device(s) required.
+ +
shutdown
+
The association is about to be demobilized. The driver should close all device(s) and free private structures.
+
receive
+
A timecode string is ready for retrieval using the refclock_gtlin() or refclock_gtraw() routines and provide clock updates.
+
poll
+
Called at poll timeout, by default 64 s. Ordinarily, the driver will send a poll sequence to the radio as required.
+
timer
+
Called once per second. This can be used for housekeeping functions. In the case with pulse-per-second (PPS) signals, this can be used to process the signals and provide clock updates.
+ +

The receive routine retrieves a timecode string via serial or parallel port, PPS signal or other means. It decodes the timecode in days, hours, minutes, seconds and nanoseconds and checks for errors. It provides these data along with the on-time timestamp to the refclock_process routine, which saves the computed offset in a 60-sample circular buffer. On occasion, either by timeout, sample count or call to the poll routine, the driver calls refclock_receive to process the circular buffer samples and update the system clock.

+

The best way to understand how the clock drivers work is to study one of the drivers already implemented, such as refclock_wwvb.c. The main interface is the refclockproc structure, which contains for most drivers the decoded timecode, on-time timestamp, reference timestamp, exception reports and statistics tallies, etc. The support routines are passed a pointer to the peer structure, which 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. This structure should not be used for new implementations.

Radio and modem reference clocks by convention have addresses of 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 or parallel port or special bus peripheral. The particular device is normally specified by adding a soft link /dev/deviceu to the particular hardware device.

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.

Conventions, Fudge Factors and Flags

@@ -50,34 +55,42 @@

Files Which Need to be Changed

When a new reference clock driver is installed, the following files need to be edited. Note that changes are also necessary to properly integrate the driver in the configuration and makefile scripts, but these are decidedly beyond the scope of this page.

-
./include/ntp.h -
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 REFCLK_xxxx identification code should be recorded in the list opposite its assigned type number. -
./libntp/clocktypes.c -
The ./libntp/clktype array is used by certain display functions. A unique short-form name of the driver should be entered together with its assigned identification code. -
./ntpd/ntp_control.c -
The clocktypes 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 ./include/ntp_control.h header file for the assigned classes. -
./ntpd/refclock_conf.c -
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 refclock_conf 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. - +
./include/ntp.h
+
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 REFCLK_xxxx identification code should be recorded in the list opposite its assigned type number.
+
./libntp/clocktypes.c
+
The ./libntp/clktype array is used by certain display functions. A unique short-form name of the driver should be entered together with its assigned identification code.
+
./ntpd/ntp_control.c
+
The clocktypes 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 ./include/ntp_control.h header file for the assigned classes.
+
./ntpd/refclock_conf.c
+
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 refclock_conf 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.

Interface Routine Overview

-
refclock_newpeer - initialize and start a reference clock -
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. -
refclock_unpeer - shut down a clock -
This routine is used to shut down a clock and return its resources to the system. -
refclock_transmit - simulate the transmit procedure -
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. -
refclock_process - insert a sample in the circular buffer -
This routine saves the offset computed from the on-time timestamp and the days, hours, minutes, seconds and nanoseconds in the circular buffer. 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. -
refclock_receive - simulate the receive and packet procedures - -
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. -
refclock_gtraw, refclock_gtlin - read the buffer and on-time
These routines return the data received from the clock and the on-time timestamp. The refclock_gtraw routine returns a batch of one or more characters returned by the Unix terminal routines in raw mode. The refclock_gtlin routine removes the parity bit and control characters and returns all the characters up to and including the line terminator. Either routine returns the number of characters delivered.
refclock_open - open a serial port for reference clock
This routine opens a serial port for I/O and sets default options. It returns the file descriptor if success and zero if failure. -
refclock_ioctl - set serial port control functions - -
This routine attempts to hide the internal, system-specific details of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD (sgtty) interfaces with varying degrees of success. The routine returns one if success and zero if failure. +
refclock_newpeer - initialize and start a reference clock.
+
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.
+
refclock_unpeer - shut down a clock
+
This routine is used to shut down a clock and return its resources to the system.
+
refclock_transmit - simulate the transmit procedure
+
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.
+
refclock_process - insert a sample in the circular buffer
+
This routine saves the offset computed from the on-time timestamp and the days, hours, minutes, seconds and nanoseconds in the circular buffer. 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.
+
refclock_receive - simulate the receive and packet procedures
+
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.
+
refclock_gtraw, refclock_gtlin - read the buffer and on-time timestamp
+
These routines return the data received from the clock and the on-time timestamp. The refclock_gtraw routine returns a batch of one or more characters returned by the Unix terminal routines in raw mode. The refclock_gtlin routine removes the parity bit and control characters and returns all the characters up to and including the line terminator. Either routine returns the number of characters delivered.
+
refclock_open - open a serial port for reference clock
+
This routine opens a serial port for I/O and sets default options. It returns the file descriptor if success and zero if failure.
+
refclock_ioctl - set serial port control functions
+
This routine attempts to hide the internal, system-specific details of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD (sgtty) interfaces with varying degrees of success. The routine returns one if success and zero if failure.
+
refclock_ppsapi
+
IThis routine initializes the Pulse-per-Second interface (see below).
+
refclock_pps
+
This routine is called once per second to read the latest PPS offset and save it in the circular buffer (see below).
+

Pulse-per-Second Interface

+

When the Pulse-per-Second Appliation Interface (RFC 2783) is present, a compact PPS interface is available to all drivers. See the Mitigation Rules and the Prefer Peer page for further information. To use this ingterface, include the timeppps.h and refclock_atom.h header files and define the refclock_atom structure in the driver private storage. The timepps.h file is specific to each operating system and may not be available for some systems.

+

To use the interface, call refclock_ppsapi from the startup routine passing the device file descriptor and refclock_atom structure pointer. Then, call refclock_pps from the timer routine passing the association pointer and refclock_atom structure pointer. See the refclock_atom.c file for examples and calling sequences. If the PPS signal is valid, the offset sample will be save in the circular buffer and a bit set in the association flags word indicating the sample is valid and tthe driver an be selected as a PPS peer. If this bit is set when the poll routine is called, the driver calls the refclock_receive routine to process the samples in the circular buffer and update the system clock.

+
gif diff --git a/html/prefer.html b/html/prefer.html index 4ec412c9e..44879d853 100644 --- a/html/prefer.html +++ b/html/prefer.html @@ -12,7 +12,7 @@ gif from Alice's Adventures in Wonderland, Lewis Carroll

Listen carefully to what I say; it is very complicated.

Last update: - 08-Apr-2009 2:47 + 19-Apr-2009 17:57 UTC


@@ -36,10 +36,9 @@ UTC

Introduction

-

This page summarizes the criteria for choosing from among a number of potential - sources suitable contributors to the clock discipline process. The criteria are very meticulous, since they have to handle many different scenarios that may be optimized for peculiar circumstances, including some scenarios designed to support planetary and deep space missions.

+

This page summarizes the criteria for choosing from among a number of potential sources suitable contributors to the clock discipline algorithm. The criteria are very meticulous, since they have to handle many different scenarios that may be optimized for peculiar circumstances, including some scenarios designed to support planetary and deep space missions.

-

Recall the suite of NTP data acquisition and grooming algorithms as these algorithms proceed in five phases. Phase one discovers the available sources and mobilizes an association for each candidate found. These candidates can result from explicit configuration, broadcast discover or the pool and manycast autonomous configuration schemes. Phase two grooms the selectable candidates excluding those sources showing one or more of the following errors

+

Recall the suite of NTP data acquisition and grooming algorithms as these algorithms proceed in five phases. Phase one discovers the available sources and mobilizes an association for each candidate found. These candidates can result from explicit configuration, broadcast discovery or the pool and manycast autonomous configuration schemes. Phase two grooms the selectable candidates excluding those sources showing one or more of the following errors

    @@ -53,7 +52,7 @@ UTC

-

Phase three uses an intersection algorithm to select the truechimers from among the candidates, leaving behind the falsetickers. Phase four uses a clustering algorithm to cast off statistically insignificant outliers from the truechimers until a set of survivors not less than the number specified as the minclock option of the tos command, with default 3. Phase five uses a set of mitigation rules to select from among the survivors a system peer from which a set of system statistics can be inherited and passed along to a dependent client population. The system offset developed from these algorithms can discipline the system clock either using the ntpd clock discipline algorithm or enable the kernel to discipline the clock directly, as described on the A Kernel Model for Precision Timekeeping page. Phase five is the topic of this page.

+

Phase three uses an intersection algorithm to select the truechimers from among the candidates, leaving behind the falsetickers. A server or peer configured with the true option is ipso facto a truechimer independent of this algorithm. Phase four uses a clustering algorithm to cast off statistical outliers from the truechimers until a set of survivors not less than the number pecified as the minclock option of the tos command, with default 3. Phase five uses a set of mitigation rules to select from among the survivors a system peer from which a set of system statistics can be inherited and passed along to a dependent client population. The clock offset developed from these algorithms can discipline the system clock either using the ntpd clock discipline algorithm or enable the kernel to discipline the system clock directly, as described on the A Kernel Model for Precision Timekeeping page. Phase five is the topic of this page.

Peer Classification

@@ -61,11 +60,11 @@ UTC

    -
  1. A remote server or peer is classified simply as a server. All others are classified as a device driver of one kind or another. In general, one or more sources of either or both types will be configured in each installation.
  2. +
  3. An association configured for a remote server or peer is classified simply as a server. All other associations are classified as a device driver of one kind or another. In general, one or more sources of either or both types will be configured in each installation.
  4. -
  5. If all sources have been lost and the orphan stratum specified by the orphan option of the tos command, a pseudo-source called the orphan parent is created. Dependent orphan children will see the orphan parent as if synchronized to a primary server at the orphan stratum.
  6. +
  7. If all sources have been lost and the orphan stratum has been specified by the orphan option of the tos command, a pseudo-source called the orphan parent is created with offset and jitter both zero. Dependent orphan children will see the orphan parent as if synchronized to a server at the orphan stratum.If the only survivor is the orphan parent, it becomes the system peer and its clock offset and jitter are inherited by the corresponding system variables. Note that by design all the orphan children having the same set of orphan parents will select the same parent.
  8. -
  9. When the PPS Clock Discipline driver (type 22) is configured, it is designated the PPS driver. This driver provides precision clock discipline only within +-0.5 s, so is always associated with another source or sources that provide the seconds numbering function.
  10. +
  11. When a device driver has been configured for pulse-per-second (PPS) signals and PPS signals are being received, it is designated the PPS driver. Note that the Pulse-per-Second driver (type 22) is often used as a PPS driver, but any driver can be operated as a PPS driver as well. The PPS driver provides precision clock discipline only within +-0.5 s, so is always associated with another source or sources that provide the seconds numbering function.
  12. When the Undisciplined Local Clock driver (type 1) is configured, it is designated the local driver. This driver is used either as a backup source (stratum greater than zero) should all sources fail, or as the primary source (stratum zero) in cases where the kernel time is disciplined by some other means of synchronization, such as the NIST lockclock scheme, or another synchronization protocol such as the Digital Time Synchronization Service (DTSS).
  13. @@ -75,27 +74,41 @@ UTC

    The prefer Peer

    -

    The mitigation rules are designed to provide an intelligent selection of the system peer from among the survivors of different types. When used with the server or peer commands, the prefer option designates one or more survivors as preferred over all others. While the rules do not forbid it, it is usually not useful to designate more than one source as preferred; however, if more than one source is so designated, they are used in the order specified in the configuration file; that is, if the first one becomes unselectable, the second one is used and so forth. This order of priority is also applicable to multiple modem drivers and even multiple local drivers, although that would not normally be useful.

    +

    The mitigation rules are designed to provide an intelligent selection of the system peer from among the survivors of different types. When used with the server or peer commands, the prefer option designates one or more survivors as preferred over all others. While the rules do not forbid it, it is usually not useful to designate more than one source as preferred; however, if more than one source is so designated, they are used in the order specified in the configuration file; that is, if the first one becomes unselectable, the second one is considered and so forth. This order of priority is also applicable to multiple PPS drivers, multiple modem drivers and even multiple local drivers, although that would not normally be useful.

    -

    The prefer scheme works on the set of truechimers produced by the intersection algorithms. Ordinarily, any one of them can in principle provide correct time; however, due to various latency variations, not all can provide the most accurate and stable time. The clustering algorithm, which is invoked at this point, operates in one or more rounds to cast off the statistically least significant to the current ensemble until no more than the minclock option of the tos command are left.

    +

    The clustering algorithm works on the set of truechimers produced by the intersection algorithms. Ordinarily, any one of them can in principle provide correct time; however, due to various latency variations, not all can provide the most accurate and stable time. The clustering algorithm, processes the truechimers in one or more rounds to cast off a statistical outlier until no more than the minclock option of the tos command are left. The default for this option is 3.

    -

    In the prefer scheme the clustering algorithm is modified so that the prefer peer is never discarded; on the contrary, its potential removal becomes a rounds-termination condition. However, the prefer peer can still be discarded by the intersection algorithm as a falseticker. To avoid this, it is usually wise to increase the mindist option of the tos command from the default .005 s to something like .05 s. s.

    +

    In the prefer scheme the clustering algorithm is modified so that the prefer peer is never discarded; on the contrary, its potential removal becomes a rounds-termination condition. However, the prefer peer can still be discarded by the intersection algorithm as a falseticker. To avoid this, it is usually wise to increase the mindist option of the tos command from the default .005 s to something like .05 s.

    -

    Along with this behavior, the clock selection procedures are modified so that the combining algorithm is not used when a prefer peer is present. Instead, the offset of the prefer peer is used exclusively as the synchronization source. In the usual case involving a radio clock and a flock of remote stratum-1 peers, and with the radio clock designated a prefer peer, the result is that the high quality radio time disciplines the server clock as long as the radio itself remains operational and with valid time, as determined from the remote peers, sanity checks and intersection algorithm.

    +

    Ordinarily, the combining algorithm computes a weighted average of the survivor offsets to produce the final osynchronization sourcem. However, if a prefer peer is among the survivors, the combining algorithm is not used. Instead, the offset of the prefer peer is used exclusively as the finalsynchronization source. In the common case involving a radio clock and a flock of remote backup servers, and with the radio clock designated a prefer peer, the result is that the radio clock normally disciplines the system clock as long as the radio itself remains operational. However, if the radio fails or becomes a falseticker, the averaged backup sources continue to discipline the system clock.

    Mitigation Rules

    -

    As the selection algorithm scans the associations for selectable candidates, the modem driver, local driver and PPS driver, are segregated for later, but only if not designated a prefer peer. If so designated, a driver is included among the selectable candidate population along with the others. In addition if orphan servers are found the parent with the lowest distnace is segregated for later; the others are discarded. Here, distance is defined as the IPv4 address of the first four octets of the hashed IPv6 address. The resulting candidates, including the first prefer peer found, are processed by the intersection and clustering algorithms to yield a possibly empty set of survivors. The clustering algorithm ranks the survivors by synchronization distance and designates the survivor with the lowest distance as the potential system peer.

    +

    As the selection algorithm scans the associations for selectable candidates, the modem driver and local driver are segregated for later, but only if not designated a prefer peer. If so designated, a driver is included among the candidate population. In addition, if orphan parents are found the parent with the lowest metric is segregated for later; the others are discarded. For this purpose the metric is defined as the four-octet IPv4 address or the first four octets of the hashed IPv6 address. The resulting candidates, including any prefer peers found, are processed by the intersection to produce a possibly empty set of truechimers. The clustering algorithm ranks the truechimers first by stratum then by synchronization distance and designates the survivor with the lowest distance as the potential system peer.

    + +

    If one or more truechimers support a pulse-per-second (PPS) signal and the PPS signal is operating correcly, it is designated a PPS driver. If more than one PPS diver are found, only the first one is used. The PPS driver is not included in the combining algorithm and is mitigated separately.

    + +

    At this point we have the following contributors to the system clock discipline:

    + +
      + +
    • (potential) system peer, if there are survivors;
    • +
    • orphan parent, if present;
    • +
    • local driver and zero offset, if present;
    • +
    • modem driver and modem offset, if present;
    • +
    • prefer peer and offset, if present;
    • +
    • PPS driver and offset, if present.
    • +

    The mitigation algorithm proceeds in three steps in turn.

      -
    1. If there are no survivors, the modem driver becomes the only survivor if there is one. If not, the orphan parent becomes the only survivor if there is one. If not, the local driver becomes the only survivor if there is one. If the number of survivors at this point is less than the minsane option of the tos command, the algorithm is terminated and the system variables remain unchanged. Note that minsane is by default 1, but can set at any value including 0.
    2. +
    3. If there are no survivors, the modem driver becomes the only survivor if there is one. If not, the local driver becomes the only survivor if there is one. If not, the orphan parent becomes the only survivor if there is one. If the number of survivors at this point is less than the minsane option of the tos command, the algorithm is terminated and the system variables remain unchanged. Note that minsane is by default 1, but can be set at any value including 0.
    4. -
    5. If the only survivor is the orphan parent, it becomes the system peer and its clock offset and jitter are inherited by the corresponding system variables. Note that by design all the orphan children sharing the same set of potential orphan parents will select the same parent. Otherwise, if the prefer peer is among the survivors, it becomes the system peer and its clock offset and jitter are inherited by the corresponding system variables. If not, the combining algorithm computes these variables from the survivor population.
    6. +
    7. If the prefer peer is among the survivors, it becomes the system peer and its clock offset and jitter are inherited by the corresponding system variables. Otherwise, the combining algorithm computes these variables from the survivor population.
    8. -
    9. If there is a PPS driver and the system clock offset produced in step two is less than 0.4 s, the PPS driver is selectable and operation continues in two contingencies. If there is a prefer peer, or if overridden by the flag1 option of the fudge command for the PPS driver, the PPS driver becomes the system peer and its offset and jitter are inherited by the system variables.
    10. +
    11. If there is a PPS driver and the system clock offset at this point is less than 0.4 s, and if there is a prefer peer among the survivors or if the PPS peer is designated as a prefer peer, the PPS driver becomes the system peer and its offset and jitter are inherited by the system variables, thus overriding any variables already computed. Note that a PPS driver is present only if PPS signals are actually being received and enabled by the associated driver.
    @@ -103,24 +116,18 @@ UTC

    The minsane Option

    -

    The minsane option of the tos command, the prefer option of the server and peer commands and the flag1 option of the fudge command for the PPS driver can be used in conjunction with the mitigation rules to provide many useful configurations. The minsane option specifies the minimum number of survivors required to synchronized the system clock. The prefer option designates the prefer peer. The flag1 option enables the PPS driver even if no prefer peer is available.

    +

    The minsane option of the tos command, the prefer option of the server and peer commands and the flag options of the fudge command for the PPS driver can be used with the mitigation rules to provide many useful configurations. The minsane option specifies the minimum number of survivors required to synchronized the system clock. The prefer option designates the prefer peer. The driver-dependent flag options enable the PPS driver for various conditions.

    + +

    A common scenario is a GPS driver with PPS signal and designated the prefer peer. If the serial timecode from the GPS receiver is within 0.4 s of the PPS signal, the GPS driver is designated the PPS driver and the PPS signal disciplines the system clock. If no GPS satellites are in view, or if the PPS signal is disconnected, the GPS driver stops updating the ntpd daemon and so eventually becomes unreachable and replaced by other sources..

    -

    In the intended mode of operation, a GPS clock driver is configured along with the PPS driver and the GPS driver set as the prefer peer. If the serial timecode of the GPS driver is within 0.4 s of the PPS driver, the PPS driver disciplines the system clock. If no GPS satellites are in view, or if the antenna is disconnected, this condition is visible to the GPS driver, which then indicates this by ceasing updates to the ntpd daemon. The result is that the GPS driver becomes unreachable and in turn the PPS driver is disabled. This is the preferred behavior, as the holdover stability of the PPS signal from the GPS receiver is no better than the system clock stability.

    +

    Whether or not the GPS driver disables the PPS signal when unreachable is +at the discretion of the driver. Ordinarily, the PPS signal would be disabled in this case; however, in some cases, such as when the GPS receiver has a precision holdover oscillator, the driver may elect to continue PPS operation.

    -

    As in the above scenario, if the minsane option is set to 0 and there is a prefer peer, it can be used in the same manner. However, this would normally disable the PPS driver if the prefer peer were to become unavailable. This behavior can be altered with the flag1 option for the PPS driver. In the default case (dim) the behavior is as above; if lit, the prefer peer is disregarded and the PPS driver is enabled no matter what the state of the prefer peer or if there is no designated prefer peer.

    +

    If the minsane option is set to 0 and there is a prefer peer, it can be used in the same manner. However, this would normally disable the PPS driver if the prefer peer were to become unselectable. This behavior can be altered with the flag1 option for the PPS driver. In the default case (dim) the behavior is as above; if lit, the prefer peer is disregarded and the PPS driver is enabled no matter what the state of the prefer peer or if there is no designated prefer peer.

    -

    A scenario where the latter behavior can be most useful is for a planetary - orbiter fleet, for instance in the vicinity of Mars, where contact between - orbiters is only one or two times per Sol (Mars day). These orbiters have a - precise timing reference based on a Ultra Stable Oscillator (USO) with accuracy - in the order of a Cesium oscillator. A PPS signal is derived from the USO and - can be disciplined from Earth on rare occasion or from another orbiter via NTP. - In the above scenario the PPS signal disciplines the spacecraft clock between - NTP updates.

    +

    A scenario where the latter behavior can be most useful is for a planetary orbiter fleet, for instance in the vicinity of Mars, where contact between orbiters is only one or two times per Sol (Mars day). These orbiters have a precise timing reference based on a Ultra Stable Oscillator (USO) with accuracy in the order of a Cesium oscillator. A PPS signal is derived from the USO and can be disciplined from Earth on rare occasion or from another orbiter via NTP. In the above scenario the PPS signal disciplines the spacecraft clock between NTP updates.

    -

    In a similar scenario a PPS signal can be used to discipline the clock between - updates produced by the modem driver. This would provide precise synchronization - without needing the Internet at all.

    +

    In a similar scenario a PPS signal can be used to discipline the clock between updates produced by the modem driver. This would provide precise synchronization without needing the Internet at all.


    diff --git a/include/Makefile.am b/include/Makefile.am index 30ff0874c..25fab8b75 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -58,6 +58,7 @@ noinst_HEADERS = \ parse.h \ parse_conf.h \ recvbuff.h \ + refclock_atom.h \ timepps-SCO.h \ timepps-Solaris.h \ timepps-SunOS.h \ diff --git a/include/ntp.h b/include/ntp.h index 55d772076..8bb6df126 100644 --- a/include/ntp.h +++ b/include/ntp.h @@ -445,8 +445,9 @@ struct peer { #define FLAG_XLEAVE 0x1000 /* interleaved protocol */ #define FLAG_XB 0x2000 /* interleaved broadcast */ #define FLAG_XBOGUS 0x4000 /* interleaved bogus packet */ +#define FLAG_PPS 0x8000 /* steered by PPS */ #ifdef OPENSSL -#define FLAG_ASSOC 0x8000 /* autokey request */ +#define FLAG_ASSOC 0x10000 /* autokey request */ #endif /* OPENSSL */ /* diff --git a/include/ntpd.h b/include/ntpd.h index b61bcad09..0becc5f83 100644 --- a/include/ntpd.h +++ b/include/ntpd.h @@ -11,7 +11,6 @@ #include "ntp_refclock.h" #include "recvbuff.h" - /* ntp_config.c */ #define TAI_1972 10 /* initial TAI offset (s) */ diff --git a/include/refclock_atom.h b/include/refclock_atom.h new file mode 100644 index 000000000..9afce0207 --- /dev/null +++ b/include/refclock_atom.h @@ -0,0 +1,15 @@ +/* + * Definitions for the atom driver and its friends + */ +#define NANOSECOND 1000000000 /* one second (ns) */ +#define RANGEGATE 500000 /* range gate (ns) */ + +struct refclock_atom { + pps_handle_t handle; + pps_params_t pps_params; + struct timespec ts; +}; + +extern int refclock_ppsapi(int, struct refclock_atom *); +extern int refclock_params(int, struct refclock_atom *); +extern int refclock_pps(struct peer *, struct refclock_atom *, int); diff --git a/ntpd/ntp_proto.c b/ntpd/ntp_proto.c index 7fae54144..513d67e98 100644 --- a/ntpd/ntp_proto.c +++ b/ntpd/ntp_proto.c @@ -2166,7 +2166,7 @@ clock_select(void) double high, low; double seljitter; double synch[NTP_MAXASSOC], error[NTP_MAXASSOC]; - double orphdist = 1e10;; + double orphdist = 1e10; struct peer *osys_peer = NULL; struct peer *sys_prefer = NULL; /* prefer peer */ struct peer *typesystem = NULL; @@ -2243,7 +2243,8 @@ clock_select(void) /* * If this is an orphan, choose the one with - * the least distance. + * the lowest metric defined as the IPv4 address + * or the first 64 bits of the hashed IPv6 address. */ if (peer->stratum == sys_orphan) { double ftemp; @@ -2266,12 +2267,6 @@ clock_select(void) !(peer->flags & FLAG_PREFER)) typelocal = peer; continue; - - case REFCLK_ATOM_PPS: - if (typepps == NULL && - !(peer->flags & FLAG_PREFER)) - typepps = peer; - continue; case REFCLK_ACTS: if (typeacts == NULL && @@ -2421,6 +2416,18 @@ clock_select(void) high) && !(peer->flags & FLAG_TRUE)) continue; + + /* + * Elegible PPS peers must survive the intersection + * algorithm. Use the first one found, but don't + * include any of them in the cluster population. + */ + if (peer->flags & FLAG_PPS) { + if (typepps == NULL) + typepps = peer; + continue; + } + /* * The metric is the scaled root distance plus the peer * stratum. For compliance with the specification, both @@ -2451,17 +2458,13 @@ clock_select(void) /* * If no survivors remain at this point, check if the modem - * driver, orphan server or local driver have been found. If - * so, nominate the first one found as the only survivor. + * driver, local driver or orphan parent in that order. If so, + * nominate the first one found as the only survivor. * Otherwise, give up and leave the island to the rats. */ if (nlist == 0) { error[0] = 0; synch[0] = 0; - if (typeorphan != NULL) { - peer_list[0] = typeorphan; - nlist = 1; - } #ifdef REFCLOCK if (typeacts != NULL) { peer_list[0] = typeacts; @@ -2471,6 +2474,10 @@ clock_select(void) nlist = 1; } #endif /* REFCLOCK */ + if (typeorphan != NULL) { + peer_list[0] = typeorphan; + nlist = 1; + } } /* @@ -2616,22 +2623,14 @@ clock_select(void) /* * If a PPS driver is lit and the combined offset is less than * 0.4 s, select the driver as the PPS peer and use its offset - * and jitter. - */ - if (typepps != NULL && fabs(sys_offset < 0.4)) { - struct refclockproc *pp; - - /* - * If flag1 is dim, PPS is enabled only if the prefer - * peer has survived the intersection algorithm and - * numbers the seconds. Otherwise, some other means - * must be provided to number the seconds. - */ - pp = typepps->procptr; - if (!(pp->sloppyclockflag & CLK_FLAG1) && sys_prefer == - NULL) - return; - + * and jitter. However, if this is the atom driver, use it only + * if there is a prefer peer or there are no survivors and none + * are required. + */ + if (typepps != NULL && fabs(sys_offset < 0.4) && + (typepps->refclktype != REFCLK_ATOM_PPS || + (typepps->refclktype == REFCLK_ATOM_PPS && (sys_prefer != + NULL || (typesystem == NULL && sys_minsane == 0))))) { typesystem = typepps; typesystem->status = CTL_PST_SEL_PPS; sys_offset = typesystem->offset; @@ -2725,7 +2724,7 @@ peer_xmit( struct pkt xpkt; /* transmit packet */ int sendlen, authlen; keyid_t xkeyid = 0; /* transmit key ID */ - l_fp xmt_tx, xmt_ty;; + l_fp xmt_tx, xmt_ty; if (!peer->dstadr) /* drop peers without interface */ return; diff --git a/ntpd/ntp_refclock.c b/ntpd/ntp_refclock.c index 7785f4404..c04813361 100644 --- a/ntpd/ntp_refclock.c +++ b/ntpd/ntp_refclock.c @@ -34,6 +34,11 @@ #include "ntp_syscall.h" #endif /* KERNEL_PLL */ +#ifdef HAVE_PPSAPI +#include "ppsapi_timepps.h" +#include "refclock_atom.h" +#endif /* HAVE_PPSAPI */ + /* * Reference clock support is provided here by maintaining the fiction * that the clock is actually a peer. As no packets are exchanged with a @@ -73,6 +78,7 @@ #ifdef PPS int fdpps; /* ppsclock legacy */ #endif /* PPS */ + int cal_enable; /* enable refclock calibrate */ /* @@ -1195,4 +1201,154 @@ refclock_buginfo( (refclock_conf[clktype]->clock_buginfo)(unit, bug, peer); } + +#ifdef HAVE_PPSAPI +/* + * refclock_ppsapi - initialize/update ppsapi + * + * This routine is called after the fudge command to open the PPSAPI + * interface for later parameter setting after the fudge command. + */ +int +refclock_ppsapi( + int fddev, /* fd device */ + struct refclock_atom *ap /* atom structure pointer */ + ) +{ + if (ap->handle == NULL) { + if (time_pps_create(fddev, &ap->handle) < 0) { + msyslog(LOG_ERR, + "refclock_atom: time_pps_create failed: %m"); + return (errno); + } + } + return (1); +} + + +/* + * refclock_params - set ppsapi parameters + * + * This routine is called to set the PPSAPI parameters after the fudge + * command. + */ +int +refclock_params( + int mode, /* mode bits */ + struct refclock_atom *ap /* atom structure pointer */ + ) +{ + memset(&ap->pps_params, 0, sizeof(pps_params_t)); + ap->pps_params.api_version = PPS_API_VERS_1; + + /* + * Solaris serial ports provide PPS pulse capture only on the + * assert edge. FreeBSD serial ports provide capture on the + * clear edge, while FreeBSD parallel ports provide capture + * on the assert edge. Your mileage may vary. + */ + if (mode & CLK_FLAG2) + ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTURECLEAR; + else + ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTUREASSERT; + if (time_pps_setparams(ap->handle, &ap->pps_params) < 0) { + msyslog(LOG_ERR, + "refclock_ppsapi: time_pps_setparams failed: %m"); + return (errno); + } + + /* + * If flag3 is lit, select the kernel PPS. + */ + if (mode & CLK_FLAG3) { + if (time_pps_kcbind(ap->handle, PPS_KC_HARDPPS, + ap->pps_params.mode & ~PPS_TSFMT_TSPEC, + PPS_TSFMT_TSPEC) < 0) { + if (errno != EOPNOTSUPP) { + msyslog(LOG_ERR, + "refclock_ppsapi: time_pps_kcbind failed: %m"); + return (errno); + } + } + pps_enable = 1; + } + return (1); +} + + +/* + * refclock_pps - called once per second + * + * This routine is called once per second. It snatches the PPS + * timestamp from the kernel and saves the sign-extended fraction in + * a circular buffer for processing at the next poll event. + */ +int +refclock_pps( + struct peer *peer, /* peer structure pointer */ + struct refclock_atom *ap, /* atom structure pointer */ + int mode /* mode bits */ + ) +{ + struct refclockproc *pp; + pps_info_t pps_info; + struct timespec timeout; + double dtemp; + + /* + * We require the clock to be synchronized before setting the + * parameters. When the parameters have been set, fetch the + * most recent PPS timestamp. + */ + pp = peer->procptr; + if (ap->handle == NULL) + return (0); + + if (ap->pps_params.mode == 0 && sys_leap != LEAP_NOTINSYNC) { + if (refclock_params(pp->sloppyclockflag, ap) < 1) + return (0); + } + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + memset(&pps_info, 0, sizeof(pps_info_t)); + if (time_pps_fetch(ap->handle, PPS_TSFMT_TSPEC, &pps_info, + &timeout) < 0) { + refclock_report(peer, CEVNT_FAULT); + return (errno); + } + timeout = ap->ts; + if (ap->pps_params.mode & PPS_CAPTUREASSERT) + ap->ts = pps_info.assert_timestamp; + else if (ap->pps_params.mode & PPS_CAPTURECLEAR) + ap->ts = pps_info.clear_timestamp; + else + return (0); + + /* + * There can be zero, one or two PPS pulses between polls, + * depending on the poll interval relative to the PPS interval. + * The pulse must be newer and within the range gate relative + * to the last pulse. + */ + if (ap->ts.tv_sec <= timeout.tv_sec || abs(ap->ts.tv_nsec - + timeout.tv_nsec) > RANGEGATE) + return (0); + + /* + * Convert to signed fraction offset and stuff in median filter. + */ + pp->lastrec.l_ui = ap->ts.tv_sec + JAN_1970; + dtemp = ap->ts.tv_nsec / 1e9; + pp->lastrec.l_uf = (u_int32)(dtemp * FRAC); + if (dtemp > .5) + dtemp -= 1.; + SAMPLE(-(dtemp + pp->fudgetime1)); +#ifdef DEBUG + if (debug > 1) + printf("refclock_pps: %lu %f %f\n", current_time, + dtemp, pp->fudgetime1); +#endif + return (1); +} +#endif /* HAVE_PPSAPI */ #endif /* REFCLOCK */ diff --git a/ntpd/ntp_request.c b/ntpd/ntp_request.c index 48dbd3ab8..0b7ec1fe6 100644 --- a/ntpd/ntp_request.c +++ b/ntpd/ntp_request.c @@ -1607,7 +1607,13 @@ do_unconf( #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR peeraddr.ss_len = SOCKLEN(&peeraddr); #endif +#if 1 peer_unconfig(&peeraddr, (struct interface *)0, -1); +#else + /* We might be able to get rid of the peeraddr stuff */ + peer_clear(peer, "GONE"); + unpeer(peer); +#endif cp = (struct conf_unpeer *) ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize)); } diff --git a/ntpd/refclock_atom.c b/ntpd/refclock_atom.c index c3b278ca8..c519f2d74 100644 --- a/ntpd/refclock_atom.c +++ b/ntpd/refclock_atom.c @@ -18,15 +18,14 @@ * This driver requires the PPSAPI interface (RFC 2783) */ #if defined(REFCLOCK) && defined(CLOCK_ATOM) && defined(HAVE_PPSAPI) - -# include "ppsapi_timepps.h" +#include "ppsapi_timepps.h" +#include "refclock_atom.h" /* * This driver furnishes an interface for pulse-per-second (PPS) signals * produced by a cesium clock, timing receiver or related equipment. It - * can be used to remove accumulated jitter and retime a secondary - * server when synchronized to a primary server over a congested, wide- - * area network and before redistributing the time to local clients. + * can be used to remove accumulated jitter over a congested link and + * retime a server before redistributing the time to clients. * * Before this driver becomes active, the local clock must be set to * within +-500 ms by another means, such as a radio clock or NTP @@ -37,11 +36,10 @@ * to connect the PPS signal directly to pin 10 (ACK) of a PC paralell * port. These methods are architecture dependent. * - * Both methods require a modified device driver and kernel interface - * compatible with the Pulse-per-Second API for Unix-like Operating + * This driver requires the Pulse-per-Second API for Unix-like Operating * Systems, Version 1.0, RFC-2783 (PPSAPI). Implementations are - * available for FreeBSD, Linux, SunOS, Solaris and Alpha. However, at - * present only the Alpha implementation provides the full generality of + * available for FreeBSD, Linux, SunOS, Solaris and Tru64. However, at + * present only the Tru64 implementation provides the full generality of * the API with multiple PPS drivers and multiple handles per driver. If * the PPSAPI is normally implemented in the /usr/include/sys/timepps.h * header file and kernel support specific to each operating system. @@ -57,11 +55,13 @@ * * If flag1 is dim (default) the PPS is active only if a prefer peer is * preset; if lit the PPS is active as long as the system clock offset is - * synchronized and within 0.4 s. If flag2 is dim (default), the on-time - * epoch is the assert edge of the PPS signal; if lit, the on-time epoch - * is the clear edge. If flag3 is dim (default), the kernel PPS support - * is disabled; if lit it is enabled. The time1 parameter can be used to - * compensate for miscellaneous device driver and OS delays. + * synchronized and within 0.4 s. If flag2 is dim (default), the the PPS + * signal is enabled; if lit, the PPS signal is disabled. This would not + * make sense with this driver, but it might make sense if the PPSAPI + * was enabled by another driver. If flag3 is dim (default), the kernel + * PPS support is disabled; if lit it is enabled. The time1 parameter + * can be used to compensate for miscellaneous device driver and OS + * delays. */ /* * Interface definitions @@ -70,28 +70,22 @@ #define PRECISION (-20) /* precision assumed (about 1 us) */ #define REFID "PPS\0" /* reference ID */ #define DESCRIPTION "PPS Clock Discipline" /* WRU */ -#define NANOSECOND 1000000000 /* one second (ns) */ -#define RANGEGATE 500000 /* range gate (ns) */ /* * PPS unit control structure */ struct ppsunit { - struct timespec ts; /* last timestamp */ - int fddev; /* pps device descriptor */ - pps_params_t pps_params; /* pps parameters */ - pps_info_t pps_info; /* last pps data */ - pps_handle_t handle; /* pps handlebars */ + struct refclock_atom atom; /* atom structure pointer */ + int fddev; /* file descriptor */ }; /* * Function prototypes */ static int atom_start (int, struct peer *); -static void atom_poll (int, struct peer *); static void atom_shutdown (int, struct peer *); +static void atom_poll (int, struct peer *); static void atom_timer (int, struct peer *); -static int atom_ppsapi (struct peer *, int); /* * Transfer vector @@ -117,9 +111,8 @@ atom_start( ) { struct refclockproc *pp; - register struct ppsunit *up; + struct ppsunit *up; char device[80]; - int mode; /* * Allocate and initialize unit structure @@ -146,18 +139,9 @@ atom_start( } /* - * Light off the PPSAPI interface. + * Light up the PPSAPI interface. */ - if (time_pps_create(up->fddev, &up->handle) < 0) { - msyslog(LOG_ERR, - "refclock_atom: time_pps_create failed: %m"); - return (0); - } - if (pp->sloppyclockflag & CLK_FLAG2) - mode = PPS_CAPTURECLEAR; - else - mode = PPS_CAPTUREASSERT; - return (atom_ppsapi(peer, mode)); + return (refclock_ppsapi(up->fddev, &up->atom)); } @@ -171,173 +155,43 @@ atom_shutdown( ) { struct refclockproc *pp; - register struct ppsunit *up; + struct ppsunit *up; pp = peer->procptr; up = (struct ppsunit *)pp->unitptr; if (up->fddev > 0) close(up->fddev); - if (up->handle != 0) - time_pps_destroy(up->handle); free(up); } - -/* - * Initialize PPSAPI - */ -int -atom_ppsapi( - struct peer *peer, /* peer structure pointer */ - int mode /* mode */ - ) -{ - struct refclockproc *pp; - register struct ppsunit *up; - int capability; - - pp = peer->procptr; - up = (struct ppsunit *)pp->unitptr; - if (up->handle == 0) - return (0); - - if (time_pps_getcap(up->handle, &capability) < 0) { - msyslog(LOG_ERR, - "refclock_atom: time_pps_getcap failed: %m"); - return (0); - } - memset(&up->pps_params, 0, sizeof(pps_params_t)); - up->pps_params.api_version = PPS_API_VERS_1; - up->pps_params.mode = mode | PPS_TSFMT_TSPEC; - if (time_pps_setparams(up->handle, &up->pps_params) < 0) { - msyslog(LOG_ERR, - "refclock_atom: time_pps_setparams failed: %m"); - return (0); - } - if (pp->sloppyclockflag & CLK_FLAG3) { - if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS, - up->pps_params.mode & ~PPS_TSFMT_TSPEC, - PPS_TSFMT_TSPEC) < 0) { - msyslog(LOG_ERR, - "refclock_atom: time_pps_kcbind failed: %m"); - return (0); - } - } -#if DEBUG - if (debug) { - time_pps_getparams(up->handle, &up->pps_params); - printf( - "refclock_ppsapi: fd %d capability 0x%x version %d mode 0x%x\n", - up->fddev, capability, up->pps_params.api_version, - up->pps_params.mode); - } -#endif - return (1); -} - - /* * atom_timer - called once per second - * - * This routine is called once per second. It snatches the PPS - * timestamp from the kernel and saves the sign-extended fraction in - * a circular buffer for processing at the next poll event. */ -static void +void atom_timer( - int unit, /* unit number (not used) */ + int unit, /* unit pointer (not used) */ struct peer *peer /* peer structure pointer */ ) { - register struct ppsunit *up; + struct ppsunit *up; struct refclockproc *pp; - pps_info_t pps_info; - struct timespec timeout, ts; - long sec, nsec; - double dtemp; - char tbuf[80]; /* monitor buffer */ + char tbuf[80]; - /* - * Convert the timespec nanoseconds field to signed double and - * save in the median filter. for billboards. No harm is done if - * previous data are overwritten. If the discipline comes bum or - * the data grow stale, just forget it. A range gate rejects new - * samples if less than a jiggle time from the next second. - */ pp = peer->procptr; up = (struct ppsunit *)pp->unitptr; - if (up->handle == 0) + if (refclock_pps(peer, &up->atom, pp->sloppyclockflag) <= 0) return; - timeout.tv_sec = 0; - timeout.tv_nsec = 0; - memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t)); - if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info, - &timeout) < 0) { - refclock_report(peer, CEVNT_FAULT); - return; - } - if (up->pps_params.mode & PPS_CAPTUREASSERT) { - ts = up->pps_info.assert_timestamp; - } else if (up->pps_params.mode & PPS_CAPTURECLEAR) { - ts = up->pps_info.clear_timestamp; - } else { - refclock_report(peer, CEVNT_FAULT); - return; - } + peer->flags |= FLAG_PPS; /* - * There can be zero, one or two PPS seconds between polls. If - * zero, either the poll clock is slightly faster than the PPS - * clock or the PPS clock has died. If the PPS clock advanced - * once between polls, we make sure the fraction time difference - * since the last sample is within the range gate of 5 ms (500 - * PPM). If the PPS clock advanced twice since the last poll, - * the poll bracketed more than one second and the first second - * was lost to a slip. Since the interval since the last sample - * found is now two seconds, just widen the range gate. If the - * PPS clock advanced three or more times, either the signal has - * failed for a number of seconds or we have runts, in which - * case just ignore them. - * * If flag4 is lit, record each second offset to clockstats. * That's so we can make awesome Allan deviation plots. */ - sec = ts.tv_sec - up->ts.tv_sec; - nsec = ts.tv_nsec - up->ts.tv_nsec; - up->ts = ts; - if (nsec < 0) { - sec --; - nsec += NANOSECOND; - } else if (nsec >= NANOSECOND) { - sec++; - nsec -= NANOSECOND; - } - if (sec * NANOSECOND + nsec > NANOSECOND + RANGEGATE) - return; - - else if (sec * NANOSECOND + nsec < NANOSECOND - RANGEGATE) - return; - - pp->lastrec.l_ui = ts.tv_sec + JAN_1970; - dtemp = ts.tv_nsec * FRAC / 1e9; - if (dtemp >= FRAC) - pp->lastrec.l_ui++; - pp->lastrec.l_uf = (u_int32)dtemp; - if (ts.tv_nsec > NANOSECOND / 2) - ts.tv_nsec -= NANOSECOND; - dtemp = -(double)ts.tv_nsec / NANOSECOND; - SAMPLE(dtemp + pp->fudgetime1); - if (pp->sloppyclockflag & CLK_FLAG4){ - sprintf(tbuf, "%.9f", dtemp); + if (pp->sloppyclockflag & CLK_FLAG4) { + sprintf(tbuf, "%.9f", pp->filter[pp->coderecv]); record_clock_stats(&peer->srcadr, tbuf); } -#ifdef DEBUG - if (debug > 1) - printf("atom_timer: %lu %f %f\n", current_time, - dtemp, pp->fudgetime1); -#endif - return; } @@ -351,19 +205,21 @@ atom_poll( ) { struct refclockproc *pp; + + /* + * Don't wiggle the clock until some other driver has numbered + * the seconds. + */ + if (sys_leap == LEAP_NOTINSYNC) + return; + pp = peer->procptr; pp->polls++; - if (pp->sloppyclockflag & CLK_FLAG3) - pps_enable = 1; - else - pps_enable = 0; if (pp->codeproc == pp->coderecv) { + peer->flags &= ~FLAG_PPS; refclock_report(peer, CEVNT_TIMEOUT); return; } - if (sys_leap == LEAP_NOTINSYNC) - return; - pp->lastref = pp->lastrec; refclock_receive(peer); } diff --git a/ntpd/refclock_wwvb.c b/ntpd/refclock_wwvb.c index 6eef142e4..bcbed4da4 100644 --- a/ntpd/refclock_wwvb.c +++ b/ntpd/refclock_wwvb.c @@ -17,6 +17,11 @@ #include #include +#ifdef HAVE_PPSAPI +#include "ppsapi_timepps.h" +#include "refclock_atom.h" +#endif /* HAVE_PPSAPI */ + /* * This driver supports the Spectracom Model 8170 and Netclock/2 WWVB * Synchronized Clocks and the Netclock/GPS Master Clock. Both the WWVB @@ -113,6 +118,9 @@ * WWVB unit control structure */ struct wwvbunit { +#ifdef HAVE_PPSAPI + struct refclock_atom atom; /* PPSAPI structure */ +#endif /* HAVE_PPSAPI */ l_fp laststamp; /* last receive timestamp */ u_char lasthour; /* last hour (for monitor) */ u_char linect; /* count ignored lines (for monitor */ @@ -189,7 +197,14 @@ wwvb_start( peer->precision = PRECISION; pp->clockdesc = DESCRIPTION; memcpy((char *)&pp->refid, REFID, 4); +#ifdef HAVE_PPSAPI + /* + * Light up the PPSAPI interface. + */ + return (refclock_ppsapi(fd, &up->atom)); +#else /* HAVE_PPSAPI */ return (1); +#endif /* HAVE_PPSAPI */ } @@ -368,8 +383,13 @@ wwvb_receive( /* * Process the new sample in the median filter and determine the - * timecode timestamp. + * timecode timestamp, but only if the PPS is not in control. */ +#ifdef HAVE_PPSAPI + if (peer->flags & FLAG_PPS) + return; + +#endif /* HAVE_PPSAPI */ if (!refclock_process(pp)) refclock_report(peer, CEVNT_BADTIME); } @@ -403,6 +423,12 @@ wwvb_timer( pollchar = 'T'; if (write(pp->io.fd, &pollchar, 1) != 1) refclock_report(peer, CEVNT_FAULT); +#ifdef HAVE_PPSAPI + if (pp->sloppyclockflag & CLK_FLAG1) { + if (refclock_pps(peer, &up->atom, pp->sloppyclockflag) > 0) + peer->flags |= FLAG_PPS; + } +#endif /* HAVE_PPSAPI */ } @@ -440,6 +466,9 @@ wwvb_poll( * timeout and keep going. */ if (pp->coderecv == pp->codeproc) { +#ifdef HAE_PPSAPI + peer->flags &= ~FLAG_PPS; +#endif /* HAVE_PPSAPI */ refclock_report(peer, CEVNT_TIMEOUT); return; }