diff options
Diffstat (limited to 'contrib/ntp/ntpd/ntp_refclock.c')
-rw-r--r-- | contrib/ntp/ntpd/ntp_refclock.c | 62 |
1 files changed, 51 insertions, 11 deletions
diff --git a/contrib/ntp/ntpd/ntp_refclock.c b/contrib/ntp/ntpd/ntp_refclock.c index d25cc2c0df15..bc389012ef56 100644 --- a/contrib/ntp/ntpd/ntp_refclock.c +++ b/contrib/ntp/ntpd/ntp_refclock.c @@ -710,7 +710,7 @@ process_refclock_packet( if (rio->io_input == NULL || (*rio->io_input)(rb) != 0) { rio->recvcount++; packets_received++; - handler_pkts++; + handler_pkts++; (*rio->clock_recv)(rb); } } @@ -1208,6 +1208,7 @@ refclock_ppsapi( "refclock_ppsapi: time_pps_create: %m"); return (0); } + ZERO(ap->ts); /* [Bug 2689] defined INIT state */ } return (1); } @@ -1278,7 +1279,7 @@ refclock_pps( struct refclockproc *pp; pps_info_t pps_info; struct timespec timeout; - double dtemp; + double dtemp, dcorr, trash; /* * We require the clock to be synchronized before setting the @@ -1293,15 +1294,14 @@ refclock_pps( if (refclock_params(pp->sloppyclockflag, ap) < 1) return (0); } - timeout.tv_sec = 0; - timeout.tv_nsec = 0; + ZERO(timeout); ZERO(pps_info); if (time_pps_fetch(ap->handle, PPS_TSFMT_TSPEC, &pps_info, &timeout) < 0) { refclock_report(peer, CEVNT_FAULT); return (0); } - timeout = ap->ts; + timeout = ap->ts; /* save old timestamp for check */ if (ap->pps_params.mode & PPS_CAPTUREASSERT) ap->ts = pps_info.assert_timestamp; else if (ap->pps_params.mode & PPS_CAPTURECLEAR) @@ -1309,22 +1309,62 @@ refclock_pps( else return (0); + /* [Bug 2689] Discard the first sample we read -- if the PPS + * source is currently down / disconnected, we have read a + * potentially *very* stale value here. So if our old TS value + * is all-zero, we consider this sample unrealiable and drop it. + * + * Note 1: a better check would compare the PPS time stamp to + * the current system time and drop it if it's more than say 3s + * away. + * + * Note 2: If we ever again get an all-zero PPS sample, the next + * one will be discarded. This can happen every 136yrs and is + * unlikely to be ever observed. + */ + if (0 == (timeout.tv_sec | timeout.tv_nsec)) + return (0); + + /* If the PPS source fails to deliver a new sample between + * polls, it regurgitates the last sample. We do not want to + * process the same sample multiple times. + */ if (0 == memcmp(&timeout, &ap->ts, sizeof(timeout))) return (0); /* - * Convert to signed fraction offset and stuff in median filter. + * Convert to signed fraction offset, apply fudge and properly + * fold the correction into the [-0.5s,0.5s] range. Handle + * excessive fudge times, too. */ - pp->lastrec.l_ui = (u_int32)ap->ts.tv_sec + JAN_1970; dtemp = ap->ts.tv_nsec / 1e9; + dcorr = modf((pp->fudgetime1 - dtemp), &trash); + if (dcorr > 0.5) + dcorr -= 1.0; + else if (dcorr < -0.5) + dcorr += 1.0; + + /* phase gate check: avoid wobbling by +/-1s when too close to + * the switch-over point. We allow +/-400ms max phase deviation. + * The trade-off is clear: The smaller the limit, the less + * sensitive to sampling noise the clock becomes. OTOH the + * system must get into phase gate range by other means for the + * PPS clock to lock in. + */ + if (fabs(dcorr) > 0.4) + return (0); + + /* + * record this time stamp and stuff in median filter + */ + pp->lastrec.l_ui = (u_int32)ap->ts.tv_sec + JAN_1970; pp->lastrec.l_uf = (u_int32)(dtemp * FRAC); - if (dtemp > .5) - dtemp -= 1.; - SAMPLE(-dtemp + pp->fudgetime1); + SAMPLE(dcorr); + #ifdef DEBUG if (debug > 1) printf("refclock_pps: %lu %f %f\n", current_time, - dtemp, pp->fudgetime1); + dcorr, pp->fudgetime1); #endif return (1); } |