Re: [Linuxptp-devel] [PATCH] Add option to bind raw and UDP sockets to interface

2023-03-14 Thread Vladimir Oltean
On Tue, Mar 14, 2023 at 12:25:18PM -0700, Richard Cochran wrote:
> On Tue, Mar 14, 2023 at 12:38:06PM +0200, Kamil Zaripov wrote:
> > Can you explain the problems you see with timestamping in the interface on 
> > top of a bridge?
> 
> When a MAC joins a bridge, the MAC is no longer avaiable as a network
> interface.  This is how the bridge thing is implemented in Linux.

That is approximately true (by default), but with your permission, some
nuance might help.

The bridge driver has an rx_handler which steals all traffic from the
bridge ports, so it can be processed by sockets opened on the bridge
device itself.

The exception is link-local multicast traffic (this is why L2 PTP works
over sockets opened on bridge ports, or at least with gPTP it does,
where all traffic is in the reserved 01-80-c2-00-00-xx space), but it's
also possible to add netfilter rules to tell the bridge to stop stealing
other traffic flows, such that those remain visible to sockets opened on
the bridge ports rather than on the bridge itself.

I happened to have these commands sitting around in a drawer, tailored
particularly to running PTP over bridge ports. Some adjustments might be
necessary depending on distribution and kernel config options.

# PTP over L2
/sbin/ebtables --table broute --append BROUTING --protocol 0x88F7 --jump DROP

# PTP over IPv4
/sbin/ebtables --table broute --append BROUTING --protocol 0x0800 --ip-protocol 
udp --ip-destination-port 320 --jump DROP
/sbin/ebtables --table broute --append BROUTING --protocol 0x0800 --ip-protocol 
udp --ip-destination-port 319 --jump DROP

# PTP over IPv6
/sbin/ebtables --table broute --append BROUTING --protocol 0x86DD 
--ip6-protocol udp --ip6-destination-port 320 --jump DROP
/sbin/ebtables --table broute --append BROUTING --protocol 0x86DD 
--ip6-protocol udp --ip6-destination-port 319 --jump DROP


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


Re: [Linuxptp-devel] [PATCH] Add option to bind raw and UDP sockets to interface

2023-03-14 Thread Vladimir Oltean
On Tue, Mar 14, 2023 at 12:38:06PM +0200, Kamil Zaripov wrote:
> > On 13 Mar 2023, at 20:35, Richard Cochran  wrote:
> > 
> > "It works for me" is not a strong argument.  This software stack must
> > work for everyone.
> 
> I agree that “It works for me” is not enough to merge this patch.
> 
> > Time stamping on top of a bridge interface won't
> > fly in general, if I'm not mistaken.
> 
> Can you explain the problems you see with timestamping in the interface on 
> top of a bridge?
> 
> From my point of view when you call setsockopt(.., SO_TIMESTAMP**, 
> SOF_TIMESTAMPING_**_HARDWARE)
> it does not matter if any network card on your system support hw timestamping 
> capabilities.
> At this point network card only record all socket option values to the socket 
> structure:
> https://elixir.bootlin.com/linux/latest/source/net/core/sock.c#L895.
> Next during package send we check if socket have appropriate timestamping 
> flags, and if so
> we copy this info to the sk_buff structure:
> https://elixir.bootlin.com/linux/latest/source/include/net/sock.h#L2768.
> At the end after package finally ready to be send in ndo_start_xmit
> https://elixir.bootlin.com/linux/latest/source/include/linux/netdevice.h#L1401
> we either implement required times taping features or not. For example
> igb driver checks if tx_flags in skb_buf have timestamping request
> https://elixir.bootlin.com/linux/latest/source/drivers/net/ethernet/intel/igb/igb_main.c#L6432
> and ask hardware to timestamp frame.
> 
> So I think that it doesn’t matter how complex your network configuration, 
> only think that matters is which network card will actually handle frames.
> 
> But I’m neither linux kernel networking expert nor PTP expert. If I’m wrong 
> please correct me.

What will happen if the bridge floods the frame to 2 bridge ports, and
both supports hardware TX timestamping? How many TX timestamps will be
collected by the kernel, and more importantly, which ones? How many of
those will be delivered to user space? Is ptp4l prepared to process more
than one hardware TX timestamp per sent packet?


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


Re: [Linuxptp-devel] [PATCH] Add option to bind raw and UDP sockets to interface

2023-03-14 Thread Erez
On Tue, 14 Mar 2023 at 20:27, Richard Cochran 
wrote:

> On Tue, Mar 14, 2023 at 12:38:06PM +0200, Kamil Zaripov wrote:
> > Can you explain the problems you see with timestamping in the interface
> on top of a bridge?
>
> When a MAC joins a bridge, the MAC is no longer avaiable as a network
> interface.  This is how the bridge thing is implemented in Linux.
>

There are also other options for creating bridges, i.e. like using the dsa
driver.
But the overall result is the same.
With the dsa, you can only access the "host interface" not the external
ports.

Erez


> Thanks,
> Richard
>
>
> ___
> Linuxptp-devel mailing list
> Linuxptp-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
>
___
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel


Re: [Linuxptp-devel] [PATCH] Add option to bind raw and UDP sockets to interface

2023-03-14 Thread Richard Cochran
On Tue, Mar 14, 2023 at 12:38:06PM +0200, Kamil Zaripov wrote:
> Can you explain the problems you see with timestamping in the interface on 
> top of a bridge?

When a MAC joins a bridge, the MAC is no longer avaiable as a network
interface.  This is how the bridge thing is implemented in Linux.

Thanks,
Richard


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


Re: [Linuxptp-devel] [PATCH] Return 1 from port_is_ieee8021as if asCapable true

2023-03-14 Thread Richard Cochran
On Tue, Mar 14, 2023 at 07:42:19PM +0100, Andrew Zaborowski wrote:
> On Tue, 7 Mar 2023 at 16:35, Richard Cochran  wrote:
> > On Tue, Mar 07, 2023 at 04:21:52PM +0100, Andrew Zaborowski wrote:
> > > The (minor) problem this attempts to solve, and I didn't state that,
> > > is the confusing semantics and reduced utility of port_is_ieee8021as
> > > if one relies on the name.
> >
> > So there is no bug.  Just the code is confusing, right?  Then you must
> > ensure that the patch does not actually change the program's behavior.
> 
> Whether it's a bug depends on what users expect from asCapable=true.
> Or if it has any users in the first place, but it is present in some
> of the shipped config files.

IIRc the whole (and only) point of asCapable=1 is too circumvent the
normal port qualification logic in 802.1as, just for the "automotive"
profile.
 
> With asCapable=true your PdelayReq messages have their
> header.logMessageInterval set to 0x7f.  802.1AS says it should be set
> to the value of currentLogPdelayReqInterval.
> currentLogPdelayReqInterval of 0x7f means that no PdelayReqs should be
> sent, so in theory no PdelayReq with the value of 0x7f should go out.

But the automotive profile doesn't care about this.

Thanks,
Richard


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


Re: [Linuxptp-devel] [PATCH] Return 1 from port_is_ieee8021as if asCapable true

2023-03-14 Thread Andrew Zaborowski
On Tue, 7 Mar 2023 at 16:35, Richard Cochran  wrote:
> On Tue, Mar 07, 2023 at 04:21:52PM +0100, Andrew Zaborowski wrote:
> > The (minor) problem this attempts to solve, and I didn't state that,
> > is the confusing semantics and reduced utility of port_is_ieee8021as
> > if one relies on the name.
>
> So there is no bug.  Just the code is confusing, right?  Then you must
> ensure that the patch does not actually change the program's behavior.

Whether it's a bug depends on what users expect from asCapable=true.
Or if it has any users in the first place, but it is present in some
of the shipped config files.

With asCapable=true your PdelayReq messages have their
header.logMessageInterval set to 0x7f.  802.1AS says it should be set
to the value of currentLogPdelayReqInterval.
currentLogPdelayReqInterval of 0x7f means that no PdelayReqs should be
sent, so in theory no PdelayReq with the value of 0x7f should go out.
But this can worked around outside port_is_ieee8021as.

If there are users of asCapable=true, such change is more likely to
make their setup compliant than non-compliant -- that's a better
wording than "more compliant". This is assuming that none of their
other settings break relevant specs.

Best regards


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


Re: [Linuxptp-devel] [PATCH] Add option to bind raw and UDP sockets to interface

2023-03-14 Thread Kamil Zaripov

> On 13 Mar 2023, at 20:35, Richard Cochran  wrote:
> 
> "It works for me" is not a strong argument.  This software stack must
> work for everyone.
> 

I agree that “It works for me” is not enough to merge this patch.

> Time stamping on top of a bridge interface won't
> fly in general, if I'm not mistaken.


Can you explain the problems you see with timestamping in the interface on top 
of a bridge?

From my point of view when you call setsockopt(.., SO_TIMESTAMP**, 
SOF_TIMESTAMPING_**_HARDWARE) it does not matter if any network card on your 
system support hw timestamping capabilities. At this point network card only 
record all socket option values to the socket structure: 
https://elixir.bootlin.com/linux/latest/source/net/core/sock.c#L895 
. Next 
during package send we check if socket have appropriate timestamping flags, and 
if so we copy this info to the sk_buff structure: 
https://elixir.bootlin.com/linux/latest/source/include/net/sock.h#L2768 
. At 
the end after package finally ready to be send in ndo_start_xmit 
https://elixir.bootlin.com/linux/latest/source/include/linux/netdevice.h#L1401 

 we either implement required times taping features or not. For example igb 
driver checks if tx_flags in skb_buf have timestamping request 
https://elixir.bootlin.com/linux/latest/source/drivers/net/ethernet/intel/igb/igb_main.c#L6432
 

 and ask hardware to timestamp frame.

So I think that it doesn’t matter how complex your network configuration, only 
think that matters is which network card will actually handle frames.

But I’m neither linux kernel networking expert nor PTP expert. If I’m wrong 
please correct me.

Regards,
Zaripov Kamil___
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel


[Linuxptp-devel] [PATCH 4/4] Added 'systemd_pidfile'-option to allow ts2phc to be run as systemd 1pps2phc.service with lock detection.

2023-03-14 Thread Jürgen Appel via Linuxptp-devel
Please ignore/delete my previous email with identical subject,
 line wrapping ruined the formatting.

Purpose of this patch:

Locking to an external 1pps pulse with ts2phc is typically done
to assign traceability to a PHC clock, such that then this clock can be 
used to time stamp other events with a high precision and known accuracy.

This requires that the user only uses the PHC, when it is stably locked 
to the external pulse. This patch adds the 
   --systemd_pidfile=/run/ts2phc.pid config option, allowing to use ts2phc
as an forking-type deamon in a systemd.service.

When specified together with
   --servo_offset_threshold=x, ts2phc will run until the servo enters its
SERVO_LOCKED_STABLE (s3) state. It then forks, detaches the child and writes
the pid of the child into the pidfile and quits the main process. This enables
us to have other systemd.service to only start after the PHC lock is valid, and
by using BindsTo inother services, they even can be linked to stop (and later 
automatically restart) when the PHC is not locked stably. A typical 
application would be a traceable NTP server or grandmaster clock.

Signed-off-by: Jürgen Appel 
---
 1pps2phc.service | 42 ++
 config.c |  1 +
 servo.c  |  4 
 ts2phc.c | 45 -
 ts2phc.h |  2 ++
 5 files changed, 93 insertions(+), 1 deletion(-)
 create mode 100644 1pps2phc.service

diff --git a/1pps2phc.service b/1pps2phc.service
new file mode 100644
index 000..00e5fda
--- /dev/null
+++ b/1pps2phc.service
@@ -0,0 +1,42 @@
+[Unit]
+
+# This example unit file shows how to configure a systemd-service that keeps
+# ptp3 locked to an external 100ms-hardware-1PPS pulse connected to ptp3.SDP0
+  
+Description=Lock phc3 to 1pps
+
+After=network.target
+
+# This service roughly sets the PHC clock to within 1 s of the intended offset
+After=initializePHC.service
+
+# Optional: As soon as we are locked, we want to use chrony to use /dev/ptp3 
as time source
+# Add the line "BindsTo=1pps2phc.service" to the [Unit] section in 
+# chrony's chrony.service configuration, and you are guaranteed that 
+# chrony is only running as long as your PHC is actually locked and is 
restarted when lock is lost.
+#Wants=chrony.service
+
+[Service]
+Type=forking
+PIDFile=/run/ts2phc_1pps%i.pid
+
+# We start up ts2phc and give the process up to 3 minutes to lock to within 
100 ns 
+TimeoutStartSec=180
+ExecStart=/usr/local/sbin/ts2phc -l 5 -c eth3 -s extpps \
+ --ts2phc.extts_correction=-35 \
+ --ts2phc.pin_index=0 \
+ --ts2phc.channel=0 \
+ --ts2phc.extts_polarity=both \
+ --ts2phc.pulsewidth=1 \
+ --message_tag=1pps \
+ --servo_offset_threshold=100 \
+ --systemd_pidfile=/run/ts2phc_1pps%i.pid
+
+Restart=on-failure
+
+# Optional: Enable an external Hardware-1PPS-output on ptp3.SDP1 as long as 
the lock is stable 
+ExecStartPost=/usr/local/sbin/testptp -d /dev/ptp3 -i 0 -L 1,2 -p 10
+ExecStopPost=/usr/local/sbin/testptp -d /dev/ptp3 -i 0 -L 1,0
+
+[Install]
+WantedBy=multi-user.target
diff --git a/config.c b/config.c
index cb4421f..76a1056 100644
--- a/config.c
+++ b/config.c
@@ -329,6 +329,7 @@ struct config_item config_tab[] = {
GLOB_ITEM_INT("socket_priority", 0, 0, 15),
GLOB_ITEM_DBL("step_threshold", 0.0, 0.0, DBL_MAX),
GLOB_ITEM_INT("step_window", 0, 0, INT_MAX),
+   GLOB_ITEM_STR("systemd_pidfile", NULL),
GLOB_ITEM_INT("summary_interval", 0, INT_MIN, INT_MAX),
PORT_ITEM_INT("syncReceiptTimeout", 0, 0, UINT8_MAX),
GLOB_ITEM_INT("tc_spanning_tree", 0, 0, 1),
diff --git a/servo.c b/servo.c
index ea171cd..85fe665 100644
--- a/servo.c
+++ b/servo.c
@@ -107,6 +107,10 @@ static int check_offset_threshold(struct servo *s, int64_t 
offset)
if (s->curr_offset_values)
s->curr_offset_values--;
} else {
+   if (! s->curr_offset_values) {
+   // lock became unstable after having been stable
+   pr_info("servo got unlocked");
+   }
s->curr_offset_values = s->num_offset_values;
}
return s->curr_offset_values ? 0 : 1;
diff --git a/ts2phc.c b/ts2phc.c
index 6a8cad9..13bf474 100644
--- a/ts2phc.c
+++ b/ts2phc.c
@@ -436,6 +436,9 @@ static void ts2phc_synchronize_clocks(struct ts2phc_private 
*priv, int autocfg)
struct ts2phc_clock *c;
int valid, err;
 
+   pid_t pid;
+   FILE *pid_file;
+
if (autocfg) {
if (!priv->ref_clock) {
pr_debug("no reference clock, skipping");
@@ -499

[Linuxptp-devel] [PATCH 2/4] Add 'extpps' source to lock PHC to nearest whole second, ignoring CLOCK_REALTIME and leap-seconds

2023-03-14 Thread Jürgen Appel via Linuxptp-devel
Please ignore/delete my previous email with identical subject,
 line wrapping ruined the formatting.

Purpose of this patch: 
* A new pps-source named 'extpps' is added with similar function 
  as the 'generic' interface. Whereas the 'generic' interface is
  dependent on that no other process (like, e.g. an NTP server) 
  fiddles with the system clock too much and that the system clock
  and the PHC stays in a fixed phase relationship, the extpps pulse
  restricts its action strictly to the documented program purpose 
  "Synchronizes one or more PTP Hardware Clocks using external 
  time stamps" irrespective of what the system clock does (i.e. 
  it will still keep working even with jumps, leapsmear, and drifts
  between CLOCK_REALTIME and the source PHC).

Signed-off-by: Jürgen Appel 
---
 makefile   |  5 ++--
 ts2phc.c   | 16 ++--
 ts2phc_extpps_pps_source.c | 51 ++
 ts2phc_extpps_pps_source.h | 15 +++
 ts2phc_pps_source.c|  4 +++
 ts2phc_pps_source.h|  1 +
 6 files changed, 88 insertions(+), 4 deletions(-)
 create mode 100644 ts2phc_extpps_pps_source.c
 create mode 100644 ts2phc_extpps_pps_source.h

diff --git a/makefile b/makefile
index 3e3b8b3..5192a0f 100644
--- a/makefile
+++ b/makefile
@@ -26,8 +26,9 @@ PRG   = ptp4l hwstamp_ctl nsm phc2sys phc_ctl pmc timemaster 
ts2phc tz2alt
 FILTERS= filter.o mave.o mmedian.o
 SERVOS = linreg.o ntpshm.o nullf.o pi.o refclock_sock.o servo.o
 TRANSP = raw.o transport.o udp.o udp6.o uds.o
-TS2PHC = ts2phc.o lstab.o nmea.o serial.o sock.o ts2phc_generic_pps_source.o \
- ts2phc_nmea_pps_source.o ts2phc_phc_pps_source.o ts2phc_pps_sink.o 
ts2phc_pps_source.o
+TS2PHC = ts2phc.o lstab.o nmea.o serial.o sock.o  ts2phc_extpps_pps_source.o \
+ ts2phc_generic_pps_source.o ts2phc_nmea_pps_source.o ts2phc_phc_pps_source.o \
+ ts2phc_pps_sink.o ts2phc_pps_source.o
 OBJ= bmc.o clock.o clockadj.o clockcheck.o config.o designated_fsm.o \
  e2e_tc.o fault.o $(FILTERS) fsm.o hash.o interface.o monitor.o msg.o phc.o \
  port.o port_signaling.o pqueue.o print.o ptp4l.o p2p_tc.o rtnl.o $(SERVOS) \
diff --git a/ts2phc.c b/ts2phc.c
index 4393059..6a8cad9 100644
--- a/ts2phc.c
+++ b/ts2phc.c
@@ -467,7 +467,14 @@ static void ts2phc_synchronize_clocks(struct 
ts2phc_private *priv, int autocfg)
continue;
}
 
-   offset = tmv_to_nanoseconds(tmv_sub(ts, source_tmv));
+   if (source_tmv.ns)
+ offset = tmv_to_nanoseconds(tmv_sub(ts, source_tmv));
+   else {
+ /* no source timestamp => lock ts.ns to nearest whole second 
*/
+ offset = tmv_to_nanoseconds(ts) % NS_PER_SEC;
+ if (offset > NS_PER_SEC/2)
+   offset -= NS_PER_SEC;
+   };
 
if (c->no_adj) {
pr_info("%s offset %10" PRId64, c->name,
@@ -547,7 +554,10 @@ static void usage(char *progname)
" -q do not print messages to the syslog\n"
" -s [dev|name]  source of the PPS signal\n"
"may take any of the following forms:\n"
-   "generic   - an external 1-PPS without ToD 
information\n"
+   "generic   - an external 1-PPS without ToD 
information,\n"
+   "ToD information taken from 
CLOCK_REALTIME\n"
+   "extpps- an external 1-PPS without ToD 
information,\n"
+   "lock PHCs towards nearest 
whole second."
"/dev/ptp0 - a local PTP Hardware Clock 
(PHC)\n"
"eth0  - a local PTP Hardware Clock 
(PHC)\n"
"nmea  - a gps device connected by 
serial port or network\n"
@@ -731,6 +741,8 @@ int main(int argc, char *argv[])
 
if (!strcasecmp(tod_source, "generic")) {
pps_type = TS2PHC_PPS_SOURCE_GENERIC;
+   } else if (!strcasecmp(tod_source, "extpps")) {
+   pps_type = TS2PHC_PPS_SOURCE_EXTPPS;
} else if (!strcasecmp(tod_source, "nmea")) {
pps_type = TS2PHC_PPS_SOURCE_NMEA;
} else {
diff --git a/ts2phc_extpps_pps_source.c b/ts2phc_extpps_pps_source.c
new file mode 100644
index 000..4e1f26d
--- /dev/null
+++ b/ts2phc_extpps_pps_source.c
@@ -0,0 +1,51 @@
+/**
+ * @file ts2phc_extpps_pps_source.c
+ * @note Copyright (C) 2019 Richard Cochran 
+ * @note SPDX-License-Identifier: GPL-2.0+
+ */
+#include 
+#include 
+
+#include "ts2phc_extpps_pps_source.h"
+#include "ts2phc_pps_source_private.h"
+
+struct ts2phc_extpps_pps_source {
+   struct ts2phc_pps_source pps_source;
+};
+
+static void ts2phc_extpps_pps_source_destroy(struct ts2phc_pps_source *src)
+{
+   struct ts2phc_extpps_pps_source *s =
+

[Linuxptp-devel] [PATCH 3/4] SERVO_LOCKED_STABLE behavior fixed.

2023-03-14 Thread Jürgen Appel via Linuxptp-devel
Please ignore/delete my previous email with identical subject,
 line wrapping ruined the formatting.

Purpose of this patch: 
This fixes an issue with transitioning to the transition
of the servo state from SERVO_LOCKED (s2) to 
SERVO_LOCKED_STABLE (s3), which is controlled by the 
servo_offset_threshold=x and servo_num_offset_values=y config option.
The current code switched to SERVO_LOCKED_STABLE as soon as the offset
was y times below x, this patch changes this to switching to 
SERVO_LOCKED_STABLE only after y _consecutive_ offset values being below x,
following the ptp4l-manpage documentation. 

Signed-off-by: Jürgen Appel 
---
 servo.c | 8 ++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/servo.c b/servo.c
index daaa41c..ea171cd 100644
--- a/servo.c
+++ b/servo.c
@@ -103,8 +103,12 @@ static int check_offset_threshold(struct servo *s, int64_t 
offset)
long long int abs_offset = llabs(offset);
 
if (s->offset_threshold) {
-   if (abs_offset < s->offset_threshold && s->curr_offset_values)
-   s->curr_offset_values--;
+   if (abs_offset < s->offset_threshold) {
+   if (s->curr_offset_values)
+   s->curr_offset_values--;
+   } else {
+   s->curr_offset_values = s->num_offset_values;
+   }
return s->curr_offset_values ? 0 : 1;
}
return 0;
-- 
2.34.1




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


[Linuxptp-devel] [PATCH 1/4] use pulsewidth to discriminate edges

2023-03-14 Thread Jürgen Appel via Linuxptp-devel
Please ignore/delete my previous email with identical subject,
 line wrapping ruined the formatting.

Purpose of this patch: 
* For 1pps pulse widths != 500ms, the pulse width allows unambiguous 
  determination of the correct edge on popular devices like i211 and i210 which
  can only time stamp external pulses with  extts_polarity=both. For 500ms 
pulses
  the edge closest to the whole second is chosen.

* Fix error handling: timeout=1500ms
  The old value of 2000 ms would allow a missing pulse undetected if the PHC is 
running a 
  little bit slow.
  A sign orror of EINTR is fixed
  The behavior for missing pulses (cnt==0) is changed to an error such that a 
silent 
  1pps source can be acted upon.

Signed-off-by: Jürgen Appel 
---
 ts2phc_pps_sink.c | 66 +++
 1 file changed, 49 insertions(+), 17 deletions(-)

diff --git a/ts2phc_pps_sink.c b/ts2phc_pps_sink.c
index d25bc89..1e86849 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 = 10 - 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,40 @@ 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 +301,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,
@@ -379,17 +403,25 @@ int ts2phc_pps_sink_poll(struct ts2phc_private *priv)
while (!all_sinks_have_events) {
struct ts2phc_pps_sink *sink;
 
-   cnt = poll(polling_array->pfd, priv->n_sinks, 2000);
+   cnt = poll(polling_array->pfd, priv->n_sinks, 1500);
+   /*
+* timeout =1.5 s ensures that every missing pulse is
+* detected, even if the PHC is running a little
+* bit slow, and that a slightly fast PHC causes
+* no false alarms.
+*/
if (cnt < 0) {
-   if (errno == -EINTR) {
+