]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
[Bug 2689] ATOM driver processes last PPS pulse at startup, even if it is very old
authorJuergen Perlinger <perlinger@ntp.org>
Sun, 25 Sep 2016 08:58:43 +0000 (10:58 +0200)
committerJuergen Perlinger <perlinger@ntp.org>
Sun, 25 Sep 2016 08:58:43 +0000 (10:58 +0200)
 - make sure PPS source is alive before processing samples
 - improve stability close to the 500ms phase jump by a 400ms phase gate

bk: 57e791c3PvvB5iBjSAO_2_mGyBGEgw

ChangeLog
ntpd/ntp_refclock.c

index 0805467dc6b9b1ce7768a039f6a2d87af37546b9..62c69fd53ae4314c2f6827409672da041a47ee8a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+---
+* [Bug 2689] ATOM driver processes last PPS pulse at startup,
+             even if it is very old <perlinger@ntp.org>
+  - make sure PPS source is alive before processing samples
+  - improve stability close to the 500ms phase jump (phase gate)
+
 ---
 (4.2.8p8) 2016/06/02 Released by Harlan Stenn <stenn@ntp.org>
 
index d25cc2c0df1537e5fd10b348ace65b39b18a19f9..5a6f2df74adf6e2c0204fbe431edbe54cc775256 100644 (file)
@@ -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);
 }