The previous patches have established that:

- a PPS sink deals with extts events
- a clock deals with synchronization via a servo loop

Therefore, the code for synchronization should not be part of the
implementation of a PPS sink. Move it to the main ts2phc.c.
This allows it to be used by a PPS source as well (the PHC kind).

Signed-off-by: Vladimir Oltean <olte...@gmail.com>
---
v4->v5:
- Rebase on top of the variable renaming.
v3->v4:
- Use bool for boolean types.
v2->v3:
- None.

 ts2phc.c          |  94 +++++++++++++++++++++-
 ts2phc.h          |   3 +
 ts2phc_pps_sink.c | 199 ++++++++++++++++++++++------------------------
 3 files changed, 190 insertions(+), 106 deletions(-)

diff --git a/ts2phc.c b/ts2phc.c
index 1c577af7768e..f84950947712 100644
--- a/ts2phc.c
+++ b/ts2phc.c
@@ -21,6 +21,9 @@
 #include "ts2phc.h"
 #include "version.h"
 
+#define NS_PER_SEC             1000000000LL
+#define SAMPLE_WEIGHT          1.0
+
 struct interface {
        STAILQ_ENTRY(interface) list;
 };
@@ -154,6 +157,30 @@ static struct servo *ts2phc_servo_create(struct 
ts2phc_private *priv,
        return servo;
 }
 
+void ts2phc_clock_add_tstamp(struct ts2phc_clock *clock, tmv_t t)
+{
+       struct timespec ts = tmv_to_timespec(t);
+
+       pr_debug("adding tstamp %ld.%09ld to clock %s",
+                ts.tv_sec, ts.tv_nsec, clock->name);
+       clock->last_ts = t;
+       clock->is_ts_available = true;
+}
+
+static int ts2phc_clock_get_tstamp(struct ts2phc_clock *clock, tmv_t *ts)
+{
+       if (!clock->is_ts_available)
+               return 0;
+       clock->is_ts_available = false;
+       *ts = clock->last_ts;
+       return 1;
+}
+
+static void ts2phc_clock_flush_tstamp(struct ts2phc_clock *clock)
+{
+       clock->is_ts_available = false;
+}
+
 struct ts2phc_clock *ts2phc_clock_add(struct ts2phc_private *priv,
                                      const char *device)
 {
@@ -303,6 +330,64 @@ static int auto_init_ports(struct ts2phc_private *priv)
        return 0;
 }
 
+static void ts2phc_synchronize_clocks(struct ts2phc_private *priv)
+{
+       struct timespec source_ts;
+       tmv_t source_tmv;
+       struct ts2phc_clock *c;
+       int valid, err;
+
+       err = ts2phc_pps_source_getppstime(priv->src, &source_ts);
+       if (err < 0) {
+               pr_err("source ts not valid");
+               return;
+       }
+       if (source_ts.tv_nsec > NS_PER_SEC / 2)
+               source_ts.tv_sec++;
+       source_ts.tv_nsec = 0;
+
+       source_tmv = timespec_to_tmv(source_ts);
+
+       LIST_FOREACH(c, &priv->clocks, list) {
+               int64_t offset;
+               double adj;
+               tmv_t ts;
+
+               valid = ts2phc_clock_get_tstamp(c, &ts);
+               if (!valid) {
+                       pr_debug("%s timestamp not valid, skipping", c->name);
+                       continue;
+               }
+
+               offset = tmv_to_nanoseconds(tmv_sub(ts, source_tmv));
+
+               if (c->no_adj) {
+                       pr_info("%s offset %10" PRId64, c->name,
+                               offset);
+                       continue;
+               }
+
+               adj = servo_sample(c->servo, offset, tmv_to_nanoseconds(ts),
+                                  SAMPLE_WEIGHT, &c->servo_state);
+
+               pr_info("%s offset %10" PRId64 " s%d freq %+7.0f",
+                       c->name, offset, c->servo_state, adj);
+
+               switch (c->servo_state) {
+               case SERVO_UNLOCKED:
+                       break;
+               case SERVO_JUMP:
+                       clockadj_set_freq(c->clkid, -adj);
+                       clockadj_step(c->clkid, -offset);
+                       break;
+               case SERVO_LOCKED:
+               case SERVO_LOCKED_STABLE:
+                       clockadj_set_freq(c->clkid, -adj);
+                       break;
+               }
+       }
+}
+
 static void usage(char *progname)
 {
        fprintf(stderr,
@@ -501,11 +586,18 @@ int main(int argc, char *argv[])
        }
 
        while (is_running()) {
+               struct ts2phc_clock *c;
+
+               LIST_FOREACH(c, &priv.clocks, list)
+                       ts2phc_clock_flush_tstamp(c);
+
                err = ts2phc_pps_sink_poll(&priv);
-               if (err) {
+               if (err < 0) {
                        pr_err("poll failed");
                        break;
                }
+               if (err > 0)
+                       ts2phc_synchronize_clocks(&priv);
        }
 
        ts2phc_cleanup(&priv);
diff --git a/ts2phc.h b/ts2phc.h
index 1fab09dbf130..f52a2f3d3cae 100644
--- a/ts2phc.h
+++ b/ts2phc.h
@@ -27,6 +27,8 @@ struct ts2phc_clock {
        enum servo_state servo_state;
        char *name;
        bool no_adj;
+       bool is_ts_available;
+       tmv_t last_ts;
 };
 
 struct ts2phc_port {
@@ -50,6 +52,7 @@ struct ts2phc_private {
 struct ts2phc_clock *ts2phc_clock_add(struct ts2phc_private *priv,
                                      const char *device);
 void ts2phc_clock_destroy(struct ts2phc_clock *clock);
+void ts2phc_clock_add_tstamp(struct ts2phc_clock *clock, tmv_t ts);
 
 #include "ts2phc_pps_source.h"
 #include "ts2phc_pps_sink.h"
diff --git a/ts2phc_pps_sink.c b/ts2phc_pps_sink.c
index 69cc97179e36..92bb8dd47107 100644
--- a/ts2phc_pps_sink.c
+++ b/ts2phc_pps_sink.c
@@ -24,42 +24,29 @@
 #include "ts2phc.h"
 #include "util.h"
 
-#define NS_PER_SEC             1000000000LL
-#define SAMPLE_WEIGHT          1.0
-
 struct ts2phc_pps_sink {
        char *name;
        STAILQ_ENTRY(ts2phc_pps_sink) list;
        struct ptp_pin_desc pin_desc;
        unsigned int polarity;
-       int32_t correction;
+       tmv_t correction;
        uint32_t ignore_lower;
        uint32_t ignore_upper;
        struct ts2phc_clock *clock;
-       int no_adj;
 };
 
 struct ts2phc_sink_array {
        struct ts2phc_pps_sink **sink;
+       int *collected_events;
        struct pollfd *pfd;
 };
 
-struct ts2phc_source_timestamp {
-       struct timespec ts;
-       bool valid;
-};
-
 enum extts_result {
        EXTTS_ERROR     = -1,
        EXTTS_OK        = 0,
        EXTTS_IGNORE    = 1,
 };
 
-static enum extts_result
-ts2phc_pps_sink_offset(struct ts2phc_pps_sink *sink,
-                      struct ts2phc_source_timestamp ts,
-                      int64_t *offset, uint64_t *local_ts);
-
 static int ts2phc_pps_sink_array_create(struct ts2phc_private *priv)
 {
        struct ts2phc_sink_array *polling_array;
@@ -86,6 +73,15 @@ static int ts2phc_pps_sink_array_create(struct 
ts2phc_private *priv)
                polling_array->sink = NULL;
                return -1;
        }
+       polling_array->collected_events = malloc(priv->n_sinks * sizeof(int));
+       if (!polling_array->collected_events) {
+               pr_err("low memory");
+               free(polling_array->sink);
+               free(polling_array->pfd);
+               polling_array->pfd = NULL;
+               polling_array->sink = NULL;
+               return -1;
+       }
        i = 0;
        STAILQ_FOREACH(sink, &priv->sinks, list) {
                polling_array->sink[i] = sink;
@@ -107,8 +103,12 @@ static void ts2phc_pps_sink_array_destroy(struct 
ts2phc_private *priv)
 {
        struct ts2phc_sink_array *polling_array = priv->polling_array;
 
+       if (!polling_array)
+               return;
+
        free(polling_array->sink);
        free(polling_array->pfd);
+       free(polling_array->collected_events);
        free(polling_array);
        priv->polling_array = NULL;
 }
@@ -153,6 +153,7 @@ static struct ts2phc_pps_sink 
*ts2phc_pps_sink_create(struct ts2phc_private *pri
        struct ptp_extts_request extts;
        struct ts2phc_pps_sink *sink;
        int err, pulsewidth;
+       int32_t correction;
 
        sink = calloc(1, sizeof(*sink));
        if (!sink) {
@@ -169,7 +170,8 @@ static struct ts2phc_pps_sink 
*ts2phc_pps_sink_create(struct ts2phc_private *pri
        sink->pin_desc.func = PTP_PF_EXTTS;
        sink->pin_desc.chan = config_get_int(cfg, device, "ts2phc.channel");
        sink->polarity = config_get_int(cfg, device, "ts2phc.extts_polarity");
-       sink->correction = config_get_int(cfg, device, 
"ts2phc.extts_correction");
+       correction = config_get_int(cfg, device, "ts2phc.extts_correction");
+       sink->correction = nanoseconds_to_tmv(correction);
 
        pulsewidth = config_get_int(cfg, device, "ts2phc.pulsewidth");
        pulsewidth /= 2;
@@ -234,71 +236,32 @@ static void ts2phc_pps_sink_destroy(struct 
ts2phc_pps_sink *sink)
        free(sink);
 }
 
-static int ts2phc_pps_sink_event(struct ts2phc_pps_sink *sink,
-                                struct ts2phc_source_timestamp source_ts)
+static enum extts_result ts2phc_pps_sink_event(struct ts2phc_private *priv,
+                                              struct ts2phc_pps_sink *sink)
 {
-       enum extts_result result;
-       uint64_t extts_ts;
-       int64_t offset;
-       double adj;
-
-       result = ts2phc_pps_sink_offset(sink, source_ts, &offset, &extts_ts);
-       switch (result) {
-       case EXTTS_ERROR:
-               return -1;
-       case EXTTS_OK:
-               break;
-       case EXTTS_IGNORE:
-               return 0;
-       }
-
-       if (sink->no_adj) {
-               pr_info("%s source offset %10" PRId64, sink->name, offset);
-               return 0;
-       }
-
-       adj = servo_sample(sink->clock->servo, offset, extts_ts,
-                          SAMPLE_WEIGHT, &sink->clock->servo_state);
-
-       pr_info("%s source offset %10" PRId64 " s%d freq %+7.0f",
-               sink->name, offset, sink->clock->servo_state, adj);
-
-       switch (sink->clock->servo_state) {
-       case SERVO_UNLOCKED:
-               break;
-       case SERVO_JUMP:
-               clockadj_set_freq(sink->clock->clkid, -adj);
-               clockadj_step(sink->clock->clkid, -offset);
-               break;
-       case SERVO_LOCKED:
-       case SERVO_LOCKED_STABLE:
-               clockadj_set_freq(sink->clock->clkid, -adj);
-               break;
-       }
-       return 0;
-}
-
-static enum extts_result
-ts2phc_pps_sink_offset(struct ts2phc_pps_sink *sink,
-                      struct ts2phc_source_timestamp src,
-                      int64_t *offset, uint64_t *local_ts)
-{
-       struct timespec source_ts = src.ts;
+       enum extts_result result = EXTTS_OK;
        struct ptp_extts_event event;
-       uint64_t event_ns, source_ns;
-       int cnt;
+       struct timespec source_ts;
+       int err, cnt;
+       tmv_t ts;
 
        cnt = read(CLOCKID_TO_FD(sink->clock->clkid), &event, sizeof(event));
        if (cnt != sizeof(event)) {
                pr_err("read extts event failed: %m");
-               return EXTTS_ERROR;
+               result = EXTTS_ERROR;
+               goto out;
        }
        if (event.index != sink->pin_desc.chan) {
                pr_err("extts on unexpected channel");
-               return EXTTS_ERROR;
+               result = EXTTS_ERROR;
+               goto out;
+       }
+
+       err = ts2phc_pps_source_getppstime(priv->src, &source_ts);
+       if (err < 0) {
+               pr_debug("source ts not valid");
+               return 0;
        }
-       event_ns = event.t.sec * NS_PER_SEC;
-       event_ns += event.t.nsec;
 
        if (sink->polarity == (PTP_RISING_EDGE | PTP_FALLING_EDGE) &&
            source_ts.tv_nsec > sink->ignore_lower &&
@@ -308,20 +271,17 @@ ts2phc_pps_sink_offset(struct ts2phc_pps_sink *sink,
                 sink->name, event.index, event.t.sec, event.t.nsec,
                 (int64_t) source_ts.tv_sec, source_ts.tv_nsec);
 
-               return EXTTS_IGNORE;
-       }
-       if (source_ts.tv_nsec > 500000000) {
-               source_ts.tv_sec++;
+               result = EXTTS_IGNORE;
+               goto out;
        }
-       source_ns = source_ts.tv_sec * NS_PER_SEC;
-       *offset = event_ns + sink->correction - source_ns;
-       *local_ts = event_ns + sink->correction;
 
-       pr_debug("%s extts index %u at %lld.%09u corr %d src %" PRIi64
-                ".%ld diff %" PRId64,
-                sink->name, event.index, event.t.sec, event.t.nsec,
-                sink->correction,
-                (int64_t) source_ts.tv_sec, source_ts.tv_nsec, *offset);
+out:
+       if (result == EXTTS_ERROR || result == EXTTS_IGNORE)
+               return result;
+
+       ts = pct_to_tmv(event.t);
+       ts = tmv_add(ts, sink->correction);
+       ts2phc_clock_add_tstamp(sink->clock, ts);
 
        return EXTTS_OK;
 }
@@ -397,35 +357,64 @@ void ts2phc_pps_sink_cleanup(struct ts2phc_private *priv)
 int ts2phc_pps_sink_poll(struct ts2phc_private *priv)
 {
        struct ts2phc_sink_array *polling_array = priv->polling_array;
-       struct ts2phc_source_timestamp source_ts;
+       bool all_sinks_have_events = false;
+       bool ignore_any = false;
        unsigned int i;
-       int cnt, err;
+       int cnt;
+
+       for (i = 0; i < priv->n_sinks; i++)
+               polling_array->collected_events[i] = 0;
+
+       while (!all_sinks_have_events) {
+               struct ts2phc_pps_sink *sink;
 
-       cnt = poll(polling_array->pfd, priv->n_sinks, 2000);
-       if (cnt < 0) {
-               if (EINTR == errno) {
+               cnt = poll(polling_array->pfd, priv->n_sinks, 2000);
+               if (cnt < 0) {
+                       if (errno == -EINTR) {
+                               return 0;
+                       } else {
+                               pr_emerg("poll failed");
+                               return -1;
+                       }
+               } else if (!cnt) {
+                       pr_debug("poll returns zero, no events");
                        return 0;
-               } else {
-                       pr_emerg("poll failed");
-                       return -1;
                }
-       } else if (!cnt) {
-               pr_debug("poll returns zero, no events");
-               return 0;
-       }
 
-       err = ts2phc_pps_source_getppstime(priv->src, &source_ts.ts);
-       source_ts.valid = err ? false : true;
+               for (i = 0; i < priv->n_sinks; i++) {
+                       if (polling_array->pfd[i].revents & (POLLIN|POLLPRI)) {
+                               enum extts_result result;
+
+                               sink = polling_array->sink[i];
+
+                               result = ts2phc_pps_sink_event(priv, sink);
+                               if (result == EXTTS_ERROR)
+                                       return -EIO;
+                               if (result == EXTTS_IGNORE)
+                                       ignore_any = true;
+
+                               /*
+                                * Collect the events anyway, even if we'll
+                                * ignore this source edge anyway. We don't
+                                * want sink events from different edges
+                                * to pile up and mix.
+                                */
+                               polling_array->collected_events[i]++;
+                       }
+               }
 
-       if (!source_ts.valid) {
-               pr_debug("ignoring invalid source time stamp");
-               return 0;
-       }
+               all_sinks_have_events = true;
 
-       for (i = 0; i < priv->n_sinks; i++) {
-               if (polling_array->pfd[i].revents & (POLLIN|POLLPRI)) {
-                       ts2phc_pps_sink_event(polling_array->sink[i], 
source_ts);
+               for (i = 0; i < priv->n_sinks; i++) {
+                       if (!polling_array->collected_events[i]) {
+                               all_sinks_have_events = false;
+                               break;
+                       }
                }
        }
-       return 0;
+
+       if (ignore_any)
+               return 0;
+
+       return 1;
 }
-- 
2.25.1



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

Reply via email to