Add new time stamp processing modes to return raw delay and offset based
on the raw delay instead of the long-term filtered delay, and to return
also a weight of the sample. The weight is set to the ratio between the
two delays. This gives smaller weight to samples where the sync and/or
delay messages were delayed significantly in the network and possibly
include a large error.

Signed-off-by: Miroslav Lichvar <mlich...@redhat.com>
---
 clock.c     |  5 +++--
 config.c    | 24 ++++++++++++++++++++++++
 config.h    |  1 +
 default.cfg |  1 +
 ds.h        |  2 ++
 gPTP.cfg    |  1 +
 port.c      |  3 ++-
 ptp4l.8     |  8 ++++++++
 ptp4l.c     |  1 +
 tsproc.c    | 51 ++++++++++++++++++++++++++++++++++++++++++++++-----
 tsproc.h    | 17 +++++++++++++++--
 11 files changed, 104 insertions(+), 10 deletions(-)

diff --git a/clock.c b/clock.c
index 9735fbd..71fda50 100644
--- a/clock.c
+++ b/clock.c
@@ -852,7 +852,8 @@ struct clock *clock_create(int phc_index, struct 
interfaces_head *ifaces,
        }
        c->servo_state = SERVO_UNLOCKED;
        c->servo_type = servo;
-       c->tsproc = tsproc_create(dds->delay_filter, dds->delay_filter_length);
+       c->tsproc = tsproc_create(dds->tsproc_mode, dds->delay_filter,
+                                 dds->delay_filter_length);
        if (!c->tsproc) {
                pr_err("Failed to create time stamp processor");
                return NULL;
@@ -1357,7 +1358,7 @@ enum servo_state clock_synchronize(struct clock *c, tmv_t 
ingress, tmv_t origin)
 
        tsproc_down_ts(c->tsproc, origin, ingress);
 
-       if (tsproc_update_offset(c->tsproc, &c->master_offset))
+       if (tsproc_update_offset(c->tsproc, &c->master_offset, NULL))
                return state;
 
        if (clock_utc_correct(c, ingress))
diff --git a/config.c b/config.c
index ec8c538..ee0f302 100644
--- a/config.c
+++ b/config.c
@@ -203,6 +203,18 @@ static enum parser_result parse_port_setting(const char 
*option,
                else
                        return BAD_VALUE;
 
+       } else if (!strcmp(option, "tsproc_mode")) {
+               if (!strcasecmp("filter", value))
+                       iface->tsproc_mode = TSPROC_FILTER;
+               else if (!strcasecmp("raw", value))
+                       iface->tsproc_mode = TSPROC_RAW;
+               else if (!strcasecmp("filter_weight", value))
+                       iface->tsproc_mode = TSPROC_FILTER_WEIGHT;
+               else if (!strcasecmp("raw_weight", value))
+                       iface->tsproc_mode = TSPROC_RAW_WEIGHT;
+               else
+                       return BAD_VALUE;
+
        } else if (!strcmp(option, "delay_filter")) {
                if (!strcasecmp("moving_average", value))
                        iface->delay_filter = FILTER_MOVING_AVERAGE;
@@ -566,6 +578,18 @@ static enum parser_result parse_global_setting(const char 
*option,
                        return r;
                cfg->dds.time_source = val;
 
+       } else if (!strcmp(option, "tsproc_mode")) {
+               if (!strcasecmp("filter", value))
+                       cfg->dds.tsproc_mode = TSPROC_FILTER;
+               else if (!strcasecmp("raw", value))
+                       cfg->dds.tsproc_mode = TSPROC_RAW;
+               else if (!strcasecmp("filter_weight", value))
+                       cfg->dds.tsproc_mode = TSPROC_FILTER_WEIGHT;
+               else if (!strcasecmp("raw_weight", value))
+                       cfg->dds.tsproc_mode = TSPROC_RAW_WEIGHT;
+               else
+                       return BAD_VALUE;
+
        } else if (!strcmp(option, "delay_filter")) {
                if (!strcasecmp("moving_average", value))
                        cfg->dds.delay_filter = FILTER_MOVING_AVERAGE;
diff --git a/config.h b/config.h
index c870e42..7bff11f 100644
--- a/config.h
+++ b/config.h
@@ -39,6 +39,7 @@ struct interface {
        enum transport_type transport;
        struct port_defaults pod;
        struct sk_ts_info ts_info;
+       enum tsproc_mode tsproc_mode;
        enum filter_type delay_filter;
        int delay_filter_length;
        int boundary_clock_jbod;
diff --git a/default.cfg b/default.cfg
index ec2ce58..b46c0f6 100644
--- a/default.cfg
+++ b/default.cfg
@@ -68,6 +68,7 @@ uds_address           /var/run/ptp4l
 network_transport      UDPv4
 delay_mechanism                E2E
 time_stamping          hardware
+tsproc_mode            filter
 delay_filter           moving_median
 delay_filter_length    10
 egressLatency          0
diff --git a/ds.h b/ds.h
index 8f44c3b..162687a 100644
--- a/ds.h
+++ b/ds.h
@@ -23,6 +23,7 @@
 #include "ddt.h"
 #include "fault.h"
 #include "filter.h"
+#include "tsproc.h"
 
 /* clock data sets */
 
@@ -59,6 +60,7 @@ struct default_ds {
        int sanity_freq_limit;
        int time_source;
        struct clock_description clock_desc;
+       enum tsproc_mode tsproc_mode;
        enum filter_type delay_filter;
        int delay_filter_length;
        int boundary_clock_jbod;
diff --git a/gPTP.cfg b/gPTP.cfg
index d917bd7..34fa238 100644
--- a/gPTP.cfg
+++ b/gPTP.cfg
@@ -67,6 +67,7 @@ uds_address           /var/run/ptp4l
 network_transport      L2
 delay_mechanism                P2P
 time_stamping          hardware
+tsproc_mode            filter
 delay_filter           moving_median
 delay_filter_length    10
 egressLatency          0
diff --git a/port.c b/port.c
index 7bbcffc..3ed5e7b 100644
--- a/port.c
+++ b/port.c
@@ -2534,7 +2534,8 @@ struct port *port_open(int phc_index,
        p->delayMechanism = interface->dm;
        p->versionNumber = PTP_VERSION;
 
-       p->tsproc = tsproc_create(interface->delay_filter,
+       p->tsproc = tsproc_create(interface->tsproc_mode,
+                                 interface->delay_filter,
                                  interface->delay_filter_length);
        if (!p->tsproc) {
                pr_err("Failed to create time stamp processor");
diff --git a/ptp4l.8 b/ptp4l.8
index 0d01f29..fd00ea3 100644
--- a/ptp4l.8
+++ b/ptp4l.8
@@ -197,6 +197,14 @@ greater than this value the port is marked as not 802.1AS 
capable.
 Lower limit for peer delay in nanoseconds. If the estimated peer delay is
 smaller than this value the port is marked as not 802.1AS capable.
 .TP
+.B tsproc_mode
+Select the time stamp processing mode used to calculate offset and delay.
+Possible values are filter, raw, filter_weight, raw_weight. Raw modes perform
+well when the rate of sync messages (logSyncInterval) is similar to the rate of
+delay messages (logMinDelayReqInterval or logMinPdelayReqInterval). Weighting
+is useful with larger network jitters (e.g. software time stamping).
+The default is filter.
+.TP
 .B delay_filter
 Select the algorithm used to filter the measured delay and peer delay. Possible
 values are moving_average and moving_median.
diff --git a/ptp4l.c b/ptp4l.c
index 1294d88..61c5854 100644
--- a/ptp4l.c
+++ b/ptp4l.c
@@ -73,6 +73,7 @@ static struct config cfg_settings = {
                        .userDescription      = { .max_symbols = 128 },
                        .manufacturerIdentity = { 0, 0, 0 },
                },
+               .tsproc_mode = TSPROC_FILTER,
                .delay_filter = FILTER_MOVING_MEDIAN,
                .delay_filter_length = 10,
                .boundary_clock_jbod = 0,
diff --git a/tsproc.c b/tsproc.c
index 37be08a..5026f2e 100644
--- a/tsproc.c
+++ b/tsproc.c
@@ -25,6 +25,10 @@
 #include "print.h"
 
 struct tsproc {
+       /* Processing options */
+       int raw_mode;
+       int weighting;
+
        /* Current ratio between remote and local clock frequency */
        double clock_rate_ratio;
 
@@ -43,7 +47,8 @@ struct tsproc {
        struct filter *delay_filter;
 };
 
-struct tsproc *tsproc_create(enum filter_type delay_filter, int filter_length)
+struct tsproc *tsproc_create(enum tsproc_mode mode,
+                            enum filter_type delay_filter, int filter_length)
 {
        struct tsproc *tsp;
 
@@ -51,6 +56,28 @@ struct tsproc *tsproc_create(enum filter_type delay_filter, 
int filter_length)
        if (!tsp)
                return NULL;
 
+       switch (mode) {
+       case TSPROC_FILTER:
+               tsp->raw_mode = 0;
+               tsp->weighting = 0;
+               break;
+       case TSPROC_RAW:
+               tsp->raw_mode = 1;
+               tsp->weighting = 0;
+               break;
+       case TSPROC_FILTER_WEIGHT:
+               tsp->raw_mode = 0;
+               tsp->weighting = 1;
+               break;
+       case TSPROC_RAW_WEIGHT:
+               tsp->raw_mode = 1;
+               tsp->weighting = 1;
+               break;
+       default:
+               free(tsp);
+               return NULL;
+       }
+
        tsp->delay_filter = filter_create(delay_filter, filter_length);
        if (!tsp->delay_filter) {
                free(tsp);
@@ -128,24 +155,38 @@ int tsproc_update_delay(struct tsproc *tsp, tmv_t *delay)
                 tsp->filtered_delay, raw_delay);
 
        if (delay)
-               *delay = tsp->filtered_delay;
+               *delay = tsp->raw_mode ? raw_delay : tsp->filtered_delay;
 
        return 0;
 }
 
-int tsproc_update_offset(struct tsproc *tsp, tmv_t *offset)
+int tsproc_update_offset(struct tsproc *tsp, tmv_t *offset, double *weight)
 {
-       tmv_t delay;
+       tmv_t delay, raw_delay = 0;
 
        if (tmv_is_zero(tsp->t1) || tmv_is_zero(tsp->t2) ||
            tmv_is_zero(tsp->t3) || tmv_is_zero(tsp->t4))
                return -1;
 
-       delay = tsp->filtered_delay;
+       if (tsp->raw_mode || tsp->weighting)
+               raw_delay = get_raw_delay(tsp);
+
+       delay = tsp->raw_mode ? raw_delay : tsp->filtered_delay;
 
        /* offset = t2 - t1 - delay */
        *offset = tmv_sub(tmv_sub(tsp->t2, tsp->t1), delay);
 
+       if (!weight)
+               return 0;
+
+       if (tsp->weighting && tsp->filtered_delay > 0 && raw_delay > 0) {
+               *weight = (double)tsp->filtered_delay / raw_delay;
+               if (*weight > 1.0)
+                       *weight = 1.0;
+       } else {
+               *weight = 1.0;
+       }
+
        return 0;
 }
 
diff --git a/tsproc.h b/tsproc.h
index 6b0b1b5..fdb35a8 100644
--- a/tsproc.h
+++ b/tsproc.h
@@ -26,12 +26,24 @@
 struct tsproc;
 
 /**
+ * Defines the available modes.
+ */
+enum tsproc_mode {
+       TSPROC_FILTER,
+       TSPROC_RAW,
+       TSPROC_FILTER_WEIGHT,
+       TSPROC_RAW_WEIGHT,
+};
+
+/**
  * Create a new instance of the time stamp processor.
+ * @param mode           Time stamp processing mode.
  * @param delay_filter   Type of the filter that will be applied to delay.
  * @param filter_length  Length of the filter.
  * @return               A pointer to a new tsproc on success, NULL otherwise.
  */
-struct tsproc *tsproc_create(enum filter_type delay_filter, int filter_length);
+struct tsproc *tsproc_create(enum tsproc_mode mode,
+                            enum filter_type delay_filter, int filter_length);
 
 /**
  * Destroy a time stamp processor.
@@ -82,9 +94,10 @@ int tsproc_update_delay(struct tsproc *tsp, tmv_t *delay);
  * Update offset in a time stamp processor using new measurements.
  * @param tsp    Pointer obtained via @ref tsproc_create().
  * @param offset A pointer to store the new offset.
+ * @param weight A pointer to store the weight of the sample, may be NULL.
  * @return       0 on success, -1 when missing a measurement.
  */
-int tsproc_update_offset(struct tsproc *tsp, tmv_t *offset);
+int tsproc_update_offset(struct tsproc *tsp, tmv_t *offset, double *weight);
 
 /**
  * Reset a time stamp processor.
-- 
2.1.0


------------------------------------------------------------------------------
Dive into the World of Parallel Programming The Go Parallel Website, sponsored
by Intel and developed in partnership with Slashdot Media, is your hub for all
things parallel software development, from weekly thought leadership blogs to
news, videos, case studies, tutorials and more. Take a look and join the 
conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to