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 @@ -25,13 +25,25 @@ /** Opaque type */ 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.