summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/ntpd/refclock_atom.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ntp/ntpd/refclock_atom.c')
-rw-r--r--contrib/ntp/ntpd/refclock_atom.c608
1 files changed, 307 insertions, 301 deletions
diff --git a/contrib/ntp/ntpd/refclock_atom.c b/contrib/ntp/ntpd/refclock_atom.c
index 764f6e0..56f86b3 100644
--- a/contrib/ntp/ntpd/refclock_atom.c
+++ b/contrib/ntp/ntpd/refclock_atom.c
@@ -5,8 +5,6 @@
#include <config.h>
#endif
-#if defined(REFCLOCK) && defined(CLOCK_ATOM)
-
#include <stdio.h>
#include <ctype.h>
@@ -16,15 +14,8 @@
#include "ntp_refclock.h"
#include "ntp_stdlib.h"
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-#ifdef HAVE_SYS_TERMIOS_H
-# include <sys/termios.h>
-#endif
-#ifdef HAVE_SYS_PPSCLOCK_H
-# include <sys/ppsclock.h>
-#endif
+#if defined(REFCLOCK) && defined(CLOCK_ATOM)
+
#ifdef HAVE_PPSAPI
# ifdef HAVE_TIMEPPS_H
# include <timepps.h>
@@ -37,120 +28,109 @@
/*
* This driver furnishes an interface for pulse-per-second (PPS) signals
- * produced by a cesium clock, timing receiver or related equipment. It
+ * 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.
*
- * In order for this driver to work, the local clock must be set to
+ * 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
- * itself. The 1-pps signal is connected via a serial port and gadget
- * box consisting of a one-shot flopflop and RS232 level converter.
- * Conntection is either via the carrier detect (DCD) lead or via the
- * receive data (RD) lead. The incidental jitter using the DCD lead is
- * essentially the interrupt latency. The incidental jitter using the RD
- * lead has an additional component due to the line sampling clock. When
- * operated at 38.4 kbps, this arrangement has a worst-case jitter less
- * than 26 us.
+ * itself. There are two ways to connect the PPS signal, normally at TTL
+ * levels, to the computer. One is to shift to EIA levels and connect to
+ * pin 8 (DCD) of a serial port. This requires a level converter and
+ * may require a one-shot flipflop to lengthen the pulse. The other is
+ * to connect the PPS signal directly to pin 10 (ACK) of a PC paralell
+ * port. These methods are architecture dependent.
*
- * There are four ways in which this driver can be used. They are
- * described in decreasing order of merit below. The first way uses the
- * ppsapi STREAMS module and the LDISC_PPS line discipline, while the
- * second way uses the ppsclock STREAMS module and the LDISC_PPS line
- * discipline. Either of these works only for the baseboard serial ports
- * of the Sun SPARC IPC and clones. However, the ppsapi uses the
- * proposed IETF interface expected to become standard for PPS signals.
- * The serial port to be used is specified by the pps command in the
- * configuration file. This driver reads the timestamp directly by a
- * designated ioctl() system call.
+ * Both methods require a modified device driver and kernel interface
+ * compatible with 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
+ * the API with multiple PPS drivers and multiple handles per driver.
*
- * The third way uses the LDISC_CLKPPS line discipline and works for
- * any architecture supporting a serial port. If after a few seconds
- * this driver finds no ppsclock module configured, it attempts to open
- * a serial port device /dev/pps%d, where %d is the unit number, and
- * assign the LDISC_CLKPPS line discipline to it. If the line discipline
- * fails, no harm is done except the accuracy is reduced somewhat. The
- * pulse generator in the gadget box is adjusted to produce a start bit
- * of length 26 usec at 38400 bps. Used with the LDISC_CLKPPS line
- * discipline, this produces an ASCII DEL character ('\377') followed by
- * a timestamp at each seconds epoch.
+ * In many configurations a single port is used for the radio timecode
+ * and PPS signal. In order to provide for this configuration and others
+ * involving dedicated multiple serial/parallel ports, the driver first
+ * attempts to open the device /dev/pps%d, where %d is the unit number.
+ * If this fails, the driver attempts to open the device specified by
+ * the pps configuration command. If a port is to be shared, the pps
+ * command must be placed before the radio device(s) and the radio
+ * device(s) must be placed before the PPS driver(s) in the
+ * configuration file.
*
- * The fourth way involves an auxiliary radio clock driver which calls
- * the PPS driver with a timestamp captured by that driver. This use is
- * documented in the source code for the driver(s) involved. Note that
- * some drivers collect the sample information themselves before calling
- * pps_sample(), and others call knowing only that they are running
- * shortly after an on-time tick and they expect to retrieve the PPS
- * offset, fudge their result, and insert it into the timestream.
+ * This driver normally uses the PLL/FLL clock discipline implemented in
+ * the ntpd code. If kernel support is available, the kernel PLL/FLL
+ * clock discipline is used instead. The default configuration is not to
+ * use the kernel PPS discipline, if present. The kernel PPS discipline
+ * can be enabled using the pps command.
*
* Fudge Factors
*
* There are no special fudge factors other than the generic. The fudge
- * time1 parameter can be used to compensate for miscellaneous UART and
- * OS delays. Allow about 247 us for uart delays at 38400 bps and about
- * 1 ms for STREAMS nonsense with older workstations. Velocities may
- * vary with modern workstations.
+ * time1 parameter can be used to compensate for miscellaneous device
+ * driver and OS delays.
*/
/*
* Interface definitions
*/
#ifdef HAVE_PPSAPI
-extern int pps_assert;
+extern int pps_assert; /* selects rising or falling edge */
+extern int pps_hardpps; /* enables the kernel PPS interface */
+#define DEVICE "/dev/pps%d" /* device name and unit */
#endif /* HAVE_PPSAPI */
-#ifdef TTYCLK
-#define DEVICE "/dev/pps%d" /* device name and unit */
-#ifdef B38400
-#define SPEED232 B38400 /* uart speed (38400 baud) */
-#else
-#define SPEED232 EXTB /* as above */
-#endif
-#endif /* TTYCLK */
#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) */
+#define ASTAGE 8 /* filter stages */
-#define FLAG_TTY 0x01 /* tty_clk heard from */
-#define FLAG_PPS 0x02 /* ppsclock heard from */
-#define FLAG_AUX 0x04 /* auxiliary PPS source */
-
-static struct peer *pps_peer; /* atom driver for auxiliary PPS sources */
-
-#ifdef TTYCLK
-static void atom_receive P((struct recvbuf *));
-#endif /* TTYCLK */
+static struct peer *pps_peer; /* atom driver for PPS sources */
+#ifdef HAVE_PPSAPI
/*
- * Unit control structure
+ * PPS unit control structure
*/
-struct atomunit {
-#ifdef HAVE_PPSAPI
- pps_info_t pps_info; /* pps_info control */
-#endif /* HAVE_PPSAPI */
-#ifdef PPS
- struct ppsclockev ev; /* ppsclock control */
-#endif /* PPS */
- int flags; /* flags that wave */
+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 */
};
+#endif /* HAVE_PPSAPI */
/*
* Function prototypes
*/
static int atom_start P((int, struct peer *));
-static void atom_shutdown P((int, struct peer *));
static void atom_poll P((int, struct peer *));
-#if defined(PPS) || defined(HAVE_PPSAPI)
+#ifdef HAVE_PPSAPI
+static void atom_shutdown P((int, struct peer *));
+static void atom_control P((int, struct refclockstat *, struct
+ refclockstat *, struct peer *));
static int atom_pps P((struct peer *));
-#endif /* PPS || HAVE_PPSAPI */
+static int atom_ppsapi P((struct peer *, int, int));
+#endif /* HAVE_PPSAPI */
/*
* Transfer vector
*/
struct refclock refclock_atom = {
atom_start, /* start up driver */
+#ifdef HAVE_PPSAPI
atom_shutdown, /* shut down driver */
+#else
+ noentry, /* shut down driver */
+#endif /* HAVE_PPSAPI */
atom_poll, /* transmit poll message */
- noentry, /* not used (old atom_control) */
+#ifdef HAVE_PPSAPI
+ atom_control, /* fudge control */
+#else
+ noentry, /* fudge control */
+#endif /* HAVE_PPSAPI */
noentry, /* initialize driver */
noentry, /* not used (old atom_buginfo) */
NOFLAGS /* not used */
@@ -162,74 +142,142 @@ struct refclock refclock_atom = {
*/
static int
atom_start(
- int unit,
- struct peer *peer
+ int unit, /* unit number (not used) */
+ struct peer *peer /* peer structure pointer */
)
{
- register struct atomunit *up;
struct refclockproc *pp;
- int flags;
-#ifdef TTYCLK
- int fd = 0;
- char device[20];
- int ldisc = LDISC_CLKPPS;
-#endif /* TTYCLK */
+#ifdef HAVE_PPSAPI
+ register struct ppsunit *up;
+ char device[80];
+#endif /* HAVE_PPSAPI */
+ /*
+ * Allocate and initialize unit structure
+ */
pps_peer = peer;
- flags = 0;
+ pp = peer->procptr;
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ memcpy((char *)&pp->refid, REFID, 4);
+ peer->burst = ASTAGE;
+ peer->stratum = STRATUM_UNSPEC;
+#ifdef HAVE_PPSAPI
+ up = emalloc(sizeof(struct ppsunit));
+ memset(up, 0, sizeof(struct ppsunit));
+ pp->unitptr = (caddr_t)up;
-#ifdef TTYCLK
-# if defined(SCO5_CLOCK)
- ldisc = LDISC_RAW; /* DCD timestamps without any line discipline */
-# endif
/*
- * Open serial port. Use LDISC_CLKPPS line discipline only
- * if the LDISC_PPS line discipline is not availble,
+ * Open PPS device. If this fails and some driver has already
+ * opened the associated radio device, fdpps has the file
+ * descriptor for it.
*/
-# if defined(PPS) || defined(HAVE_PPSAPI)
- if (fdpps <= 0)
-# endif
- {
- (void)sprintf(device, DEVICE, unit);
- if ((fd = refclock_open(device, SPEED232, ldisc)) != 0)
- flags |= FLAG_TTY;
+ sprintf(device, DEVICE, unit);
+ up->fddev = open(device, O_RDWR, 0777);
+ if (up->fddev <= 0 && fdpps > 0) {
+ strcpy(device, pps_device);
+ up->fddev = fdpps;
+ }
+ if (up->fddev <= 0) {
+ msyslog(LOG_ERR,
+ "refclock_atom: %s: %m", device);
+ return (0);
}
-#endif /* TTYCLK */
/*
- * Allocate and initialize unit structure
+ * Light off the PPSAPI interface. If this PPS device is shared
+ * with the radio device, take the default options from the pps
+ * command. This is for legacy purposes.
*/
- if (!(up = (struct atomunit *)emalloc(sizeof(struct atomunit)))) {
-#ifdef TTYCLK
- if (flags & FLAG_TTY)
- (void) close(fd);
-#endif /* TTYCLK */
+ if (time_pps_create(up->fddev, &up->handle) < 0) {
+ msyslog(LOG_ERR,
+ "refclock_atom: time_pps_create failed: %m");
return (0);
}
- memset((char *)up, 0, sizeof(struct atomunit));
+ return (atom_ppsapi(peer, pps_assert, pps_hardpps));
+#else /* HAVE_PPSAPI */
+ return (1);
+#endif /* HAVE_PPSAPI */
+}
+
+
+#ifdef HAVE_PPSAPI
+/*
+ * atom_control - fudge control
+ */
+static void
+atom_control(
+ int unit, /* unit (not used */
+ struct refclockstat *in, /* input parameters (not uded) */
+ struct refclockstat *out, /* output parameters (not used) */
+ struct peer *peer /* peer structure pointer */
+ )
+{
+ struct refclockproc *pp;
+
pp = peer->procptr;
- pp->unitptr = (caddr_t)up;
-#ifdef TTYCLK
- if (flags & FLAG_TTY) {
- pp->io.clock_recv = atom_receive;
- pp->io.srcclock = (caddr_t)peer;
- pp->io.datalen = 0;
- pp->io.fd = fd;
- if (!io_addclock(&pp->io)) {
- (void) close(fd);
- free(up);
+ atom_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2,
+ pp->sloppyclockflag & CLK_FLAG3);
+}
+
+
+/*
+ * Initialize PPSAPI
+ */
+int
+atom_ppsapi(
+ struct peer *peer, /* peer structure pointer */
+ int enb_clear, /* clear enable */
+ int enb_hardpps /* hardpps enable */
+ )
+{
+ struct refclockproc *pp;
+ register struct ppsunit *up;
+ int capability;
+
+ pp = peer->procptr;
+ up = (struct ppsunit *)pp->unitptr;
+ 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));
+ if (enb_clear)
+ up->pps_params.mode = capability & PPS_CAPTURECLEAR;
+ else
+ up->pps_params.mode = capability & PPS_CAPTUREASSERT;
+ if (!up->pps_params.mode) {
+ msyslog(LOG_ERR,
+ "refclock_atom: invalid capture edge %d",
+ pps_assert);
+ return (0);
+ }
+ up->pps_params.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 (enb_hardpps) {
+ 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);
}
+ pps_enable = 1;
}
-#endif /* TTYCLK */
-
- /*
- * Initialize miscellaneous variables
- */
- peer->precision = PRECISION;
- pp->clockdesc = DESCRIPTION;
- memcpy((char *)&pp->refid, REFID, 4);
- up->flags = flags;
+#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 kern %d\n",
+ up->fddev, capability, up->pps_params.api_version,
+ up->pps_params.mode, enb_hardpps);
+ }
+#endif
return (1);
}
@@ -239,181 +287,122 @@ atom_start(
*/
static void
atom_shutdown(
- int unit,
- struct peer *peer
+ int unit, /* unit number (not used) */
+ struct peer *peer /* peer structure pointer */
)
{
- register struct atomunit *up;
struct refclockproc *pp;
+ register struct ppsunit *up;
pp = peer->procptr;
- up = (struct atomunit *)pp->unitptr;
-#ifdef TTYCLK
- if (up->flags & FLAG_TTY)
- io_closeclock(&pp->io);
-#endif /* TTYCLK */
+ up = (struct ppsunit *)pp->unitptr;
+ if (up->fddev > 0)
+ close(up->fddev);
+ if (up->handle != 0)
+ time_pps_destroy(up->handle);
if (pps_peer == peer)
pps_peer = 0;
free(up);
}
-#if defined(PPS) || defined(HAVE_PPSAPI)
/*
- * atom_pps - receive data from the LDISC_PPS discipline
+ * atom_pps - receive data from the PPSAPI interface
+ *
+ * This routine is called once per second when the PPSAPI interface is
+ * present. 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 int
atom_pps(
- struct peer *peer
+ struct peer *peer /* peer structure pointer */
)
{
- register struct atomunit *up;
+ register struct ppsunit *up;
struct refclockproc *pp;
-#ifdef HAVE_PPSAPI
- struct timespec timeout;
-# ifdef HAVE_TIMESPEC
- struct timespec ts;
-# else
- struct timeval ts;
-# endif /* HAVE_TIMESPEC */
-#endif /* HAVE_PPSAPI */
- l_fp lftmp;
- double doffset;
- int i;
-#if !defined(HAVE_PPSAPI)
- int request =
-# ifdef HAVE_CIOGETEV
- CIOGETEV
-# endif
-# ifdef HAVE_TIOCGPPSEV
- TIOCGPPSEV
-# endif
- ;
-#endif /* HAVE_PPSAPI */
+ pps_info_t pps_info;
+ struct timespec timeout, ts;
+ double dtemp;
/*
- * This routine is called once per second when the LDISC_PPS
- * discipline is present. 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.
- */
- pp = peer->procptr;
- up = (struct atomunit *)pp->unitptr;
-
- /*
- * Convert the timeval to l_fp and save for billboards. Sign-
- * extend the fraction and stash in the buffer. No harm is done
- * if previous data are overwritten. If the discipline comes bum
- * or the data grow stale, just forget it. Round the nanoseconds
- * to microseconds with great care.
+ * 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.
*/
- if (fdpps <= 0)
- return (1);
-#ifdef HAVE_PPSAPI
+ pp = peer->procptr;
+ up = (struct ppsunit *)pp->unitptr;
+ if (up->handle == 0)
+ return (-1);
timeout.tv_sec = 0;
timeout.tv_nsec = 0;
- i = up->pps_info.assert_sequence;
- if (time_pps_fetch(fdpps, PPS_TSFMT_TSPEC, &up->pps_info, &timeout)
- < 0)
- return (2);
- if (i == up->pps_info.assert_sequence)
- return (3);
- if (pps_assert)
+ memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
+ if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info,
+ &timeout) < 0)
+ return (-1);
+ if (up->pps_params.mode & PPS_CAPTUREASSERT) {
+ if (pps_info.assert_sequence ==
+ up->pps_info.assert_sequence)
+ return (1);
ts = up->pps_info.assert_timestamp;
- else
+ } else if (up->pps_params.mode & PPS_CAPTURECLEAR) {
+ if (pps_info.clear_sequence ==
+ up->pps_info.clear_sequence)
+ return (1);
ts = up->pps_info.clear_timestamp;
- pp->lastrec.l_ui = ts.tv_sec + JAN_1970;
- ts.tv_nsec = (ts.tv_nsec + 500) / 1000;
- if (ts.tv_nsec > 1000000) {
- ts.tv_nsec -= 1000000;
- ts.tv_sec++;
+ } else {
+ return (-1);
}
- TVUTOTSF(ts.tv_nsec, pp->lastrec.l_uf);
-#else
- i = up->ev.serial;
- if (ioctl(fdpps, request, (caddr_t)&up->ev) < 0)
- return (2);
- if (i == up->ev.serial)
- return (3);
- pp->lastrec.l_ui = up->ev.tv.tv_sec + JAN_1970;
- TVUTOTSF(up->ev.tv.tv_usec, pp->lastrec.l_uf);
-#endif /* HAVE_PPSAPI */
- up->flags |= FLAG_PPS;
- L_CLR(&lftmp);
- L_ADDF(&lftmp, pp->lastrec.l_f);
- LFPTOD(&lftmp, doffset);
- SAMPLE(-doffset + pp->fudgetime1);
+ if (!((ts.tv_sec == up->ts.tv_sec && ts.tv_nsec -
+ up->ts.tv_nsec > NANOSECOND - RANGEGATE) ||
+ (ts.tv_sec - up->ts.tv_sec == 1 && ts.tv_nsec -
+ up->ts.tv_nsec < RANGEGATE))) {
+ up->ts = ts;
+ return (1);
+ }
+ up->ts = ts;
+ 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);
+#ifdef DEBUG
+ if (debug > 1)
+ printf("atom_pps %f %f\n", dtemp, pp->fudgetime1);
+#endif
return (0);
}
-#endif /* PPS || HAVE_PPSAPI */
-
-#ifdef TTYCLK
-/*
- * atom_receive - receive data from the LDISC_CLK discipline
- */
-static void
-atom_receive(
- struct recvbuf *rbufp
- )
-{
- register struct atomunit *up;
- struct refclockproc *pp;
- struct peer *peer;
- l_fp lftmp;
- double doffset;
-
- /*
- * This routine is called once per second when the serial
- * interface is in use. It snatches the timestamp from the
- * buffer and saves the sign-extended fraction in a circular
- * buffer for processing at the next poll event.
- */
- peer = (struct peer *)rbufp->recv_srcclock;
- pp = peer->procptr;
- up = (struct atomunit *)pp->unitptr;
- pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX,
- &pp->lastrec);
+#endif /* HAVE_PPSAPI */
- /*
- * Save the timestamp for billboards. Sign-extend the fraction
- * and stash in the buffer. No harm is done if previous data are
- * overwritten. Do this only if the ppsclock gizmo is not
- * working.
- */
- if (up->flags & FLAG_PPS)
- return;
- L_CLR(&lftmp);
- L_ADDF(&lftmp, pp->lastrec.l_f);
- LFPTOD(&lftmp, doffset);
- SAMPLE(-doffset + pp->fudgetime1);
-}
-#endif /* TTYCLK */
/*
* pps_sample - receive PPS data from some other clock driver
+ *
+ * This routine is called once per second when the external clock driver
+ * processes PPS information. It processes the PPS timestamp and saves
+ * the sign-extended fraction in a circular buffer for processing at the
+ * next poll event. This works only for a single PPS device.
*/
int
pps_sample(
- l_fp *offset
+ l_fp *offset /* PPS offset */
)
{
register struct peer *peer;
- register struct atomunit *up;
struct refclockproc *pp;
l_fp lftmp;
double doffset;
- /*
- * This routine is called once per second when the external
- * clock driver processes PPS information. It processes the pps
- * timestamp and saves the sign-extended fraction in a circular
- * buffer for processing at the next poll event.
- */
peer = pps_peer;
if (peer == 0) /* nobody home */
- return 1;
+ return (1);
pp = peer->procptr;
- up = (struct atomunit *)pp->unitptr;
/*
* Convert the timeval to l_fp and save for billboards. Sign-
@@ -421,7 +410,6 @@ pps_sample(
* if previous data are overwritten. If the discipline comes bum
* or the data grow stale, just forget it.
*/
- up->flags |= FLAG_AUX;
pp->lastrec = *offset;
L_CLR(&lftmp);
L_ADDF(&lftmp, pp->lastrec.l_f);
@@ -432,63 +420,81 @@ pps_sample(
/*
* atom_poll - called by the transmit procedure
+ *
+ * This routine is called once per second when in burst mode to save PPS
+ * sample offsets in the median filter. At the end of the burst period
+ * the samples are processed as a heap and the clock filter updated.
*/
static void
atom_poll(
- int unit,
- struct peer *peer
+ int unit, /* unit number (not used) */
+ struct peer *peer /* peer structure pointer */
)
{
-#if defined(PPS) || defined(HAVE_PPSAPI)
- register struct atomunit *up;
-#endif /* PPS || HAVE_PPSAPI */
struct refclockproc *pp;
+#ifdef HAVE_PPSAPI
+ int err;
+#endif /* HAVE_PPSAPI */
/*
- * Accumulate samples in the median filter. At the end of each
- * poll interval, do a little bookeeping and process the
- * samples.
+ * Accumulate samples in the median filter. If a noise sample,
+ * return with no prejudice; if a protocol error, get mean;
+ * otherwise, cool. At the end of each poll interval, do a
+ * little bookeeping and process the surviving samples.
*/
pp = peer->procptr;
-#if defined(PPS) || defined(HAVE_PPSAPI)
- up = (struct atomunit *)pp->unitptr;
- if (!(up->flags & !(FLAG_AUX | FLAG_TTY))) {
- int err;
-
- err = atom_pps(peer);
- if (err > 0) {
- refclock_report(peer, CEVNT_FAULT);
- return;
- }
- }
-#endif /* PPS || HAVE_PPSAPI */
pp->polls++;
- if (peer->burst > 0)
- return;
- if (pp->coderecv == pp->codeproc) {
- refclock_report(peer, CEVNT_TIMEOUT);
+#ifdef HAVE_PPSAPI
+ err = atom_pps(peer);
+ if (err < 0) {
+ refclock_report(peer, CEVNT_FAULT);
return;
}
+#endif /* HAVE_PPSAPI */
/*
- * Valid time (leap bits zero) is returned only if the prefer
- * peer has survived the intersection algorithm and within
- * clock_max of local time and not too long ago. This ensures
- * the pps time is within +-0.5 s of the local time and the
- * seconds numbering is unambiguous.
+ * Valid time is returned only if the prefer peer has survived
+ * the intersection algorithm and within clock_max of local time
+ * and not too long ago. This ensures the PPS time is within
+ * +-0.5 s of the local time and the seconds numbering is
+ * unambiguous. Note that the leap bits are set no-warning on
+ * the first valid update and the stratum is set at the prefer
+ * peer.
*/
- if (pps_update) {
- pp->leap = LEAP_NOWARNING;
- } else {
- pp->leap = LEAP_NOTINSYNC;
+ if (peer->burst > 0)
+ return;
+ peer->stratum = STRATUM_UNSPEC;
+ if (pp->codeproc == pp->coderecv) {
+ refclock_report(peer, CEVNT_TIMEOUT);
+ peer->burst = ASTAGE;
+ return;
+
+ } else if (!sys_prefer) {
+ pp->codeproc = pp->coderecv;
+ peer->burst = ASTAGE;
+ return;
+
+ } else if (fabs(sys_prefer->offset) > clock_max) {
+ pp->codeproc = pp->coderecv;
+ peer->burst = ASTAGE;
return;
}
- pp->variance = 0;
- record_clock_stats(&peer->srcadr, pp->a_lastcode);
+ peer->stratum = sys_prefer->stratum;
+ if (peer->stratum <= 1)
+ peer->refid = pp->refid;
+ else
+ peer->refid = peer->srcadr.sin_addr.s_addr;
+ pp->leap = LEAP_NOWARNING;
refclock_receive(peer);
- peer->burst = MAXSTAGE;
+ peer->burst = ASTAGE;
}
-
#else
int refclock_atom_bs;
+int
+pps_sample(
+ l_fp *offset /* PPS offset */
+ )
+{
+ return 1;
+}
#endif /* REFCLOCK */
OpenPOWER on IntegriCloud