Dear linuxptp-devel,

thanks for providing my with this nice program, allowing me to lock my PHC
to an external SDP-input on my i211 NICs. :-)

As many of you might recall, this particular NIC does not discriminate
between rising and falling edges, and in ts2phc_pps_sink.c there already
exists code to partly cope with this problem.

When a -ts2phc.pulsewidth=tau is specified, only transitions happening with a
timestamp within an interval of ±tau/2 with respect to CLOCK_REALTIME are
retained, other transitions are ignored. 

But this requires 
a) CLOCK_REALTIME to be stable and never to make jumps anywhere close to tau/2
b) the external 1PPS-pulse to be aligned to CLOCK-REALTIME 
   within tau/2 for the lock to work.

Whereas the NIC can cope with pulses as short as 1ms reliably, it's unfeasible
to get the clocks aligned with sufficient precision to start with, and other
events fiddling with the system time (such as restarting an NTP server)
easily can throw the lock off balance and lead to locking of the wrong
edge of the 1PPS-pulse. Also, this can 'kick' the pulse outside the ±tau 
detection window completely, which leaves the clock unlocked potentially
for a long time. 

I therefore suggest to change the edge-detection to use the pulse-width:
Unless pulsewidth=NS_PER_SEC/2, from the time-interval relative to the
previous event the edge can be determined uniquely, making involvement 
of the system time into acquiring a lock of the PHC unnecessary,
completely avoid locking on the wrong edge and increase the capturing range.


=======================================
diff --git a/ts2phc_pps_sink.c b/ts2phc_pps_sink.c
index d25bc89..4ca46d3 100644
--- a/ts2phc_pps_sink.c
+++ b/ts2phc_pps_sink.c
@@ -30,8 +30,8 @@ struct ts2phc_pps_sink {
        struct ptp_pin_desc pin_desc;
        unsigned int polarity;
        tmv_t correction;
-       uint32_t ignore_lower;
-       uint32_t ignore_upper;
+       int pulsewidth;
+       tmv_t last;
        struct ts2phc_clock *clock;
 };
 
@@ -175,9 +175,8 @@ static struct ts2phc_pps_sink 
*ts2phc_pps_sink_create(struct ts2phc_private *pri
        sink->correction = nanoseconds_to_tmv(correction);
 
        pulsewidth = config_get_int(cfg, device, "ts2phc.pulsewidth");
-       pulsewidth /= 2;
-       sink->ignore_upper = 1000000000 - pulsewidth;
-       sink->ignore_lower = pulsewidth;
+       sink->pulsewidth = pulsewidth;
+       sink->last.ns = 0;
 
        sink->clock = ts2phc_clock_add(priv, device);
        if (!sink->clock) {
@@ -238,15 +237,36 @@ static void ts2phc_pps_sink_destroy(struct 
ts2phc_pps_sink *sink)
 
 static bool ts2phc_pps_sink_ignore(struct ts2phc_private *priv,
                                   struct ts2phc_pps_sink *sink,
+                                  struct ptp_extts_event event,
                                   struct timespec source_ts)
 {
-       tmv_t source_tmv = timespec_to_tmv(source_ts);
-
-       source_tmv = tmv_sub(source_tmv, priv->perout_phase);
-       source_ts = tmv_to_timespec(source_tmv);
-
-       return source_ts.tv_nsec > sink->ignore_lower &&
-              source_ts.tv_nsec < sink->ignore_upper;
+       tmv_t event_tmv, source_tmv, dt;
+
+       if (sink->pulsewidth == NS_PER_SEC/2) {
+               // 1pps has exactly 50% duty cycle: discriminate edges
+               // by CLOCK_REALTIME timestamp, requires CLOCK_REALTIME
+               // to be approximately correct and stable
+               source_tmv = timespec_to_tmv(source_ts);
+               source_tmv = tmv_sub(source_tmv, priv->perout_phase);
+               source_ts = tmv_to_timespec(source_tmv);
+
+               return (source_ts.tv_nsec > NS_PER_SEC/4) &&
+                 (source_ts.tv_nsec < NS_PER_SEC/4*3);
+       } else {
+               // use pulse-width to discriminate rising/falling edges,
+               // does not require CLOCK_REALTIME to run correctly,
+               // tolerates jumps there
+               event_tmv = pct_to_tmv(event.t);
+               if (sink->last.ns) {
+                       dt = tmv_sub(event_tmv, sink->last);
+                       sink->last = event_tmv;
+                       return ((dt.ns < (NS_PER_SEC / 2)) ^
+                               (sink->pulsewidth > (NS_PER_SEC / 2)));
+               } else { // ignore first event
+                       sink->last = event_tmv;
+                       return true;
+               }
+       }
 }
 
 static enum extts_result ts2phc_pps_sink_event(struct ts2phc_private *priv,
@@ -277,7 +297,7 @@ static enum extts_result ts2phc_pps_sink_event(struct 
ts2phc_private *priv,
        }
 
        if (sink->polarity == (PTP_RISING_EDGE | PTP_FALLING_EDGE) &&
-           ts2phc_pps_sink_ignore(priv, sink, source_ts)) {
+           ts2phc_pps_sink_ignore(priv, sink, event, source_ts)) {
 
                pr_debug("%s SKIP extts index %u at %lld.%09u src %" PRIi64 
".%ld",
                 sink->name, event.index, event.t.sec, event.t.nsec,
====================================
Best regards,
        Jürgen Appel


_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to