Now that we are registering a clock even for the PPS source when it supports that (i.e. when it is a PHC), introduce a new API to retrieve its clock in order to add timestamps to it.
The timestamps of periodic output transitions are not really known. We configure the kernel to emit periodic output and then never hear back from that PHC again. We just assume that it emits periodic output as promised, and that each pulse is emitted at the beginning of each second. We rely on the kernel to wake us up when PPS sinks have an extts event to report, and we know who generated that - the PPS source, of course. So then we proceed to read the PPS source's PHC time, and round that to what is the most plausible integer second in its time base. We believe that to be the 'timestamp'. This is fed into the servo algorithm. The PHC PPS source can be synchronized to the extts events of a PHC slave, when in automatic mode. Signed-off-by: Vladimir Oltean <olte...@gmail.com> --- v5->v6: - eliminate use of offensive word "approximation" v4->v5: - rebase on top of data structure renames v3->v4: Add one more paragraph to commit message. v2->v3: Implement ts2phc_master_get_clock() as part of ts2phc_master.c instead of ts2phc_phc_master.c. ts2phc.c | 49 ++++++++++++++++++++++++++++++++++++- ts2phc_phc_pps_source.c | 9 +++++++ ts2phc_pps_source.c | 8 ++++++ ts2phc_pps_source.h | 2 ++ ts2phc_pps_source_private.h | 1 + 5 files changed, 68 insertions(+), 1 deletion(-) diff --git a/ts2phc.c b/ts2phc.c index 4d23a5dcdf5a..5f0acc31dd47 100644 --- a/ts2phc.c +++ b/ts2phc.c @@ -473,6 +473,46 @@ static void ts2phc_synchronize_clocks(struct ts2phc_private *priv, int autocfg) } } +static int ts2phc_collect_pps_source_tstamp(struct ts2phc_private *priv) +{ + struct ts2phc_clock *pps_src_clock; + struct timespec source_ts; + int err; + + pps_src_clock = ts2phc_pps_source_get_clock(priv->src); + /* + * PPS source isn't a PHC (it may be a generic or a GPS PPS source), + * don't error out, just don't do anything. If it doesn't have a PHC, + * there is nothing to synchronize, which is the only point of + * collecting its perout timestamp in the first place. + */ + if (!pps_src_clock) + return 0; + + err = ts2phc_pps_source_getppstime(priv->src, &source_ts); + if (err < 0) { + pr_err("source ts not valid"); + return err; + } + + /* + * As long as the kernel doesn't support a proper API for reporting + * back a precise perout timestamp, we'll have to implicitly assume + * assumption that the current time on the PPS source is still within + * +/- half a second of the past perout output edge, and hence, we can + * deduce the timestamp (actually only seconds part, nanoseconds are by + * construction zero) of this edge at the emitter based on the + * emitter's current time. + */ + if (source_ts.tv_nsec > NS_PER_SEC / 2) + source_ts.tv_sec++; + source_ts.tv_nsec = 0; + + ts2phc_clock_add_tstamp(pps_src_clock, timespec_to_tmv(source_ts)); + + return 0; +} + static void usage(char *progname) { fprintf(stderr, @@ -693,8 +733,15 @@ int main(int argc, char *argv[]) pr_err("poll failed"); break; } - if (err > 0) + if (err > 0) { + err = ts2phc_collect_pps_source_tstamp(&priv); + if (err) { + pr_err("failed to collect PPS source tstamp"); + break; + } + ts2phc_synchronize_clocks(&priv, autocfg); + } } ts2phc_cleanup(&priv); diff --git a/ts2phc_phc_pps_source.c b/ts2phc_phc_pps_source.c index 92273f4fc14d..f2a9c6196a45 100644 --- a/ts2phc_phc_pps_source.c +++ b/ts2phc_phc_pps_source.c @@ -82,6 +82,14 @@ static int ts2phc_phc_pps_source_getppstime(struct ts2phc_pps_source *src, return clock_gettime(s->clock->clkid, ts); } +struct ts2phc_clock *ts2phc_phc_pps_source_get_clock(struct ts2phc_pps_source *src) +{ + struct ts2phc_phc_pps_source *s = + container_of(src, struct ts2phc_phc_pps_source, pps_source); + + return s->clock; +} + struct ts2phc_pps_source *ts2phc_phc_pps_source_create(struct ts2phc_private *priv, const char *dev) { @@ -93,6 +101,7 @@ struct ts2phc_pps_source *ts2phc_phc_pps_source_create(struct ts2phc_private *pr } s->pps_source.destroy = ts2phc_phc_pps_source_destroy; s->pps_source.getppstime = ts2phc_phc_pps_source_getppstime; + s->pps_source.get_clock = ts2phc_phc_pps_source_get_clock; s->clock = ts2phc_clock_add(priv, dev); if (!s->clock) { diff --git a/ts2phc_pps_source.c b/ts2phc_pps_source.c index b4a912ff0043..c333f652b864 100644 --- a/ts2phc_pps_source.c +++ b/ts2phc_pps_source.c @@ -38,3 +38,11 @@ int ts2phc_pps_source_getppstime(struct ts2phc_pps_source *src, struct timespec { return src->getppstime(src, ts); } + +struct ts2phc_clock *ts2phc_pps_source_get_clock(struct ts2phc_pps_source *src) +{ + if (src->get_clock) + return src->get_clock(src); + + return NULL; +} diff --git a/ts2phc_pps_source.h b/ts2phc_pps_source.h index 349c44ed0618..293c69335287 100644 --- a/ts2phc_pps_source.h +++ b/ts2phc_pps_source.h @@ -51,4 +51,6 @@ void ts2phc_pps_source_destroy(struct ts2phc_pps_source *src); */ int ts2phc_pps_source_getppstime(struct ts2phc_pps_source *src, struct timespec *ts); +struct ts2phc_clock *ts2phc_pps_source_get_clock(struct ts2phc_pps_source *src); + #endif diff --git a/ts2phc_pps_source_private.h b/ts2phc_pps_source_private.h index 6472df6d5e0b..99e6a78d915c 100644 --- a/ts2phc_pps_source_private.h +++ b/ts2phc_pps_source_private.h @@ -15,6 +15,7 @@ struct ts2phc_pps_source { void (*destroy)(struct ts2phc_pps_source *src); int (*getppstime)(struct ts2phc_pps_source *src, struct timespec *ts); + struct ts2phc_clock *(*get_clock)(struct ts2phc_pps_source *src); }; #endif -- 2.34.1 _______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel