Dear devel, On Tuesday, 7 March 2023 15:26:48 CET, I wrote:
> 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. Now, that the edge detection is independent of the system time, there is still a problem with the 'generic' driver, as the TOD we lock to is still determined by CLOCK_REALTIME. The appended patch creates an alternative to "generic" named "extpps" that strictly makes a phc follow the 1pps pulses, independent of the system time. As a nice side-effect this eliminates completely the need for offsets, leap-second tables, etc. within ts2phc and restricts it more precisely to what it claims to do: "Synchronizes one or more PTP Hardware Clocks using external time stamps." After the user has set the PHC approximately to the intended time and offset: phc_ctl /dev/ptp3 -- set adjust $(grep -v '^#' /usr/share/zoneinfo/leap-seconds.list | tail -1 | awk '{ print $2 }') ts2phc will keep the phc locked, no matter what happens to the system time. This allows locking different PHCs to different time domains, even if those clocks drift more than a second away. Using separate 1PPs inputs I now can make different PHCs lock simultaneously to '1PPs' pulses with periods 1010 ms and 1020 ms and when using a stable 1PPs. I noticed that the servo.c -code has a SERVO_LOCKED_STABLE state that is not used. Are there any plans with that? Lock-detection in combination with with sd_noify (https://www.freedesktop.org/software/systemd/man/sd_notify.html) would sound very useful to me. Cheers, Jürgen > ======================================= 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 0000000..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 <richardcoch...@gmail.com> + * @note SPDX-License-Identifier: GPL-2.0+ + */ +#include <stdlib.h> +#include <time.h> + +#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 = + container_of(src, struct ts2phc_extpps_pps_source, pps_source); + + free(s); +} + +static int ts2phc_extpps_pps_source_getppstime(struct ts2phc_pps_source *src, + struct timespec *ts) +{ + ts->tv_sec = 0; + ts->tv_nsec = 0; + return 0; +} + +struct ts2phc_clock *ts2phc_extpps_pps_source_get_clock(struct ts2phc_pps_source *src) +{ + return NULL; +} + + +struct ts2phc_pps_source *ts2phc_extpps_pps_source_create(struct ts2phc_private *priv, + const char *dev) +{ + struct ts2phc_extpps_pps_source *s; + + s = calloc(1, sizeof(*s)); + if (!s) { + return NULL; + } + s->pps_source.destroy = ts2phc_extpps_pps_source_destroy; + s->pps_source.getppstime = ts2phc_extpps_pps_source_getppstime; + + return &s->pps_source; +} diff --git a/ts2phc_extpps_pps_source.h b/ts2phc_extpps_pps_source.h new file mode 100644 index 0000000..1a57cd6 --- /dev/null +++ b/ts2phc_extpps_pps_source.h @@ -0,0 +1,15 @@ +/** + * @file ts2phc_extpps_pps_source.h + * @note Copyright (C) 2019 Richard Cochran <richardcoch...@gmail.com> + * @note SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef HAVE_TS2PHC_EXTPPS_PPS_SOURCE_H +#define HAVE_TS2PHC_EXTPPS_PPS_SOURCE_H + +#include "ts2phc.h" +#include "ts2phc_pps_source.h" + +struct ts2phc_pps_source *ts2phc_extpps_pps_source_create(struct ts2phc_private *priv, + const char *dev); + +#endif diff --git a/ts2phc_pps_source.c b/ts2phc_pps_source.c index c333f65..be98567 100644 --- a/ts2phc_pps_source.c +++ b/ts2phc_pps_source.c @@ -5,6 +5,7 @@ */ #include "ts2phc.h" #include "ts2phc_generic_pps_source.h" +#include "ts2phc_extpps_pps_source.h" #include "ts2phc_nmea_pps_source.h" #include "ts2phc_phc_pps_source.h" #include "ts2phc_pps_source_private.h" @@ -19,6 +20,9 @@ struct ts2phc_pps_source *ts2phc_pps_source_create(struct ts2phc_private *priv, case TS2PHC_PPS_SOURCE_GENERIC: src = ts2phc_generic_pps_source_create(priv, dev); break; + case TS2PHC_PPS_SOURCE_EXTPPS: + src = ts2phc_extpps_pps_source_create(priv, dev); + break; case TS2PHC_PPS_SOURCE_NMEA: src = ts2phc_nmea_pps_source_create(priv, dev); break; diff --git a/ts2phc_pps_source.h b/ts2phc_pps_source.h index 293c693..519fc02 100644 --- a/ts2phc_pps_source.h +++ b/ts2phc_pps_source.h @@ -21,6 +21,7 @@ struct ts2phc_pps_source; */ enum ts2phc_pps_source_type { TS2PHC_PPS_SOURCE_GENERIC, + TS2PHC_PPS_SOURCE_EXTPPS, TS2PHC_PPS_SOURCE_NMEA, TS2PHC_PPS_SOURCE_PHC, }; > ======================================= _______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel