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 are a mere approximation. 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 PPS sinks to report an extts event first, 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> --- 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 | 45 ++++++++++++++++++++++++++++++++++++- 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, 64 insertions(+), 1 deletion(-) diff --git a/ts2phc.c b/ts2phc.c index 0968ef28ca73..25c8bb3a5fa6 100644 --- a/ts2phc.c +++ b/ts2phc.c @@ -482,6 +482,42 @@ 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 + * a precise perout timestamp, we'll have to use this crude + * approximation. + */ + 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, @@ -702,8 +738,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 4a4bfb2569b9..d9e00f3b525d 100644 --- a/ts2phc_phc_pps_source.c +++ b/ts2phc_phc_pps_source.c @@ -83,6 +83,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) { @@ -94,6 +102,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 2a3300aaaf19..53aaf207f566 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.25.1 _______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel