This commit adds functionality to increase the sync and pdelay request intervals once gptp synchronization has been achieved. This is useful while running Automotive Profile where the network is usually static.
Here, we are assuming that the gPTP synchronization is achieved whenever the last 'n' offsets calculated using the Sync messages are below a certain threshold. Both, the number of offsets to consider and the offset threshold are configurable. Four new config options have been added to provide this functionality: - offset_threshold: All the offset values being considered should be below this value. - num_offset_values: number of previously received offset values to consider. - operLogSyncInterval: slave will ask the master to switch to this interval for sending sync messages when the timer expires. - operLogPdelayReqInterval: the slave will set this interval for pdelay request messages when the timer expires. Signed-off-by: Vedang Patel <vedang.pa...@intel.com> --- clock.c | 4 ++++ config.c | 4 ++++ configs/automotive-slave.cfg | 4 ++++ configs/default.cfg | 2 ++ designated_fsm.c | 18 +++++++++++++- port.c | 57 ++++++++++++++++++++++++++++++++++++++++---- port_private.h | 7 +++++- ptp4l.8 | 30 +++++++++++++++++++++++ 8 files changed, 120 insertions(+), 6 deletions(-) diff --git a/clock.c b/clock.c index 79e8f2b9d0b2..b4955b1fad34 100644 --- a/clock.c +++ b/clock.c @@ -1796,6 +1796,10 @@ static void handle_state_decision_event(struct clock *c) clock_update_slave(c); event = EV_RS_SLAVE; break; + /* This is a special case only applicable when BMCA == 'noop'. */ + case PS_UNCALIBRATED: + event = EV_NONE; + break; default: event = EV_FAULT_DETECTED; break; diff --git a/config.c b/config.c index 6775f66d94c6..e006597adaed 100644 --- a/config.c +++ b/config.c @@ -263,7 +263,11 @@ struct config_item config_tab[] = { PORT_ITEM_INT("net_sync_monitor", 0, 0, 1), PORT_ITEM_ENU("network_transport", TRANS_UDP_IPV4, nw_trans_enu), GLOB_ITEM_INT("ntpshm_segment", 0, INT_MIN, INT_MAX), + PORT_ITEM_INT("num_offset_values", 10, 0, INT_MAX), + PORT_ITEM_INT("offset_threshold", 0, 0, INT_MAX), GLOB_ITEM_INT("offsetScaledLogVariance", 0xffff, 0, UINT16_MAX), + PORT_ITEM_INT("operLogSyncInterval", 0, INT8_MIN, INT8_MAX), + PORT_ITEM_INT("operLogPdelayReqInterval", 0, INT8_MIN, INT8_MAX), PORT_ITEM_INT("path_trace_enabled", 0, 0, 1), GLOB_ITEM_DBL("pi_integral_const", 0.0, 0.0, DBL_MAX), GLOB_ITEM_DBL("pi_integral_exponent", 0.4, -DBL_MAX, DBL_MAX), diff --git a/configs/automotive-slave.cfg b/configs/automotive-slave.cfg index fc8d0c909acd..99b037935f51 100644 --- a/configs/automotive-slave.cfg +++ b/configs/automotive-slave.cfg @@ -32,3 +32,7 @@ ignore_source_id 1 # Required to quickly correct Time Jumps in master step_threshold 1 ignore_interval_update_req 1 +operLogSyncInterval 0 +operLogPdelayReqInterval 2 +offset_threshold 30 +num_offset_values 10 diff --git a/configs/default.cfg b/configs/default.cfg index 13b30de0c32a..f922fd011804 100644 --- a/configs/default.cfg +++ b/configs/default.cfg @@ -23,8 +23,10 @@ maxStepsRemoved 255 # logAnnounceInterval 1 logSyncInterval 0 +operLogSyncInterval 0 logMinDelayReqInterval 0 logMinPdelayReqInterval 0 +operLogPdelayReqInterval 0 announceReceiptTimeout 3 syncReceiptTimeout 0 delayAsymmetry 0 diff --git a/designated_fsm.c b/designated_fsm.c index d19158b0b8a1..18b472f0e717 100644 --- a/designated_fsm.c +++ b/designated_fsm.c @@ -77,7 +77,7 @@ enum port_state designated_slave_fsm(enum port_state state, next = PS_FAULTY; break; case EV_INIT_COMPLETE: - next = PS_SLAVE; + next = PS_UNCALIBRATED; break; default: break; @@ -90,11 +90,27 @@ enum port_state designated_slave_fsm(enum port_state state, } break; + case PS_UNCALIBRATED: + switch (event) { + case EV_FAULT_DETECTED: + next = PS_FAULTY; + break; + case EV_RS_SLAVE: + next = PS_SLAVE; + break; + default: + break; + } + break; + case PS_SLAVE: switch (event) { case EV_FAULT_DETECTED: next = PS_FAULTY; break; + case EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES: + next = PS_UNCALIBRATED; + break; default: break; } diff --git a/port.c b/port.c index 81e340938fc9..f5d5b0d10e3c 100644 --- a/port.c +++ b/port.c @@ -1602,8 +1602,10 @@ int port_initialize(struct port *p) p->localPriority = config_get_int(cfg, p->name, "G.8275.portDS.localPriority"); p->logSyncInterval = config_get_int(cfg, p->name, "logSyncInterval"); p->initialLogSyncInterval = p->logSyncInterval; + p->operLogSyncInterval = config_get_int(cfg, p->name, "operLogSyncInterval"); p->logMinPdelayReqInterval = config_get_int(cfg, p->name, "logMinPdelayReqInterval"); p->logPdelayReqInterval = p->logMinPdelayReqInterval; + p->operLogPdelayReqInterval = config_get_int(cfg, p->name, "operLogPdelayReqInterval"); p->neighborPropDelayThresh = config_get_int(cfg, p->name, "neighborPropDelayThresh"); p->min_neighbor_prop_delay = config_get_int(cfg, p->name, "min_neighbor_prop_delay"); p->ignore_interval_update_req = config_get_int(cfg, p->name, "ignore_interval_update_req"); @@ -2196,6 +2198,22 @@ void process_pdelay_resp_fup(struct port *p, struct ptp_message *m) port_peer_delay(p); } +int check_offset_threshold(struct port *p) +{ + int64_t offset = tmv_to_nanoseconds(clock_master_offset(p->clock)); + + + if (p->offset_threshold && p->curr_offset_values && offset != 0) { + if (abs(offset) < p->offset_threshold) { + p->curr_offset_values--; + } else { + p->curr_offset_values = p->num_offset_values; + } + return p->curr_offset_values ? 0 : 1; + } + return 0; +} + enum fsm_event process_sync(struct port *p, struct ptp_message *m) { enum syfu_event event; @@ -2242,6 +2260,18 @@ enum fsm_event process_sync(struct port *p, struct ptp_message *m) } port_syfufsm(p, event, m); + /* + * If the master resets before the slave notices, there will be a + * descrepency in the interval. Slave should transition to + * PS_UNCALIBRATED to fix this. + */ + if (p->offset_threshold && + m->header.logMessageInterval < p->logSyncInterval) { + return EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES; + } else if (check_offset_threshold(p)) { + return EV_RS_SLAVE; + } + return EV_NONE; } @@ -2382,9 +2412,25 @@ static void port_p2p_transition(struct port *p, enum port_state next) case PS_UNCALIBRATED: flush_last_sync(p); flush_peer_delay(p); - /* fall through */ + port_set_announce_tmo(p); + if (p->offset_threshold) { + p->curr_offset_values = p->num_offset_values; + p->logPdelayReqInterval = p->logMinPdelayReqInterval; + p->logSyncInterval = p->initialLogSyncInterval; + port_tx_signaling(p, SIGNAL_NO_CHANGE, + SIGNAL_SET_INITIAL, + SIGNAL_NO_CHANGE); + } + break; case PS_SLAVE: port_set_announce_tmo(p); + if (p->offset_threshold) { + p->logPdelayReqInterval = p->operLogPdelayReqInterval; + p->logSyncInterval = p->operLogSyncInterval; + port_tx_signaling(p, SIGNAL_NO_CHANGE, + p->operLogSyncInterval, + SIGNAL_NO_CHANGE); + } break; }; } @@ -2500,8 +2546,9 @@ static enum fsm_event bc_event(struct port *p, int fd_index) /* * Clear out the event returned by poll(). It is only cleared - * in port_*_transition(). But, when BMCA == 'noop', there is no - * state transition. So, it won't be cleared anywhere else. + * in port_*_transition(). But, when BMCA == 'noop' and + * state == PS_UNCALIBRATED ,there is no state transition. + * So, it won't be cleared anywhere else. */ if (p->bmca == BMCA_NOOP) { port_clr_tmo(p->fda.fd[FD_SYNC_RX_TIMER]); @@ -2604,7 +2651,7 @@ static enum fsm_event bc_event(struct port *p, int fd_index) switch (msg_type(msg)) { case SYNC: - process_sync(p, msg); + event = process_sync(p, msg); break; case DELAY_REQ: if (process_delay_req(p, msg)) @@ -2909,6 +2956,8 @@ struct port *port_open(int phc_index, transport = config_get_int(cfg, interface->name, "network_transport"); p->master_only = config_get_int(cfg, interface->name, "masterOnly"); p->bmca = config_get_int(cfg, interface->name, "BMCA"); + p->offset_threshold = config_get_int(cfg, interface->name, "offset_threshold"); + p->num_offset_values = config_get_int(cfg, interface->name, "num_offset_values"); if (p->bmca == BMCA_NOOP && transport != TRANS_UDS) { if (p->master_only) { diff --git a/port_private.h b/port_private.h index 2182dd3a9151..a1951e0361bd 100644 --- a/port_private.h +++ b/port_private.h @@ -115,9 +115,11 @@ struct port { UInteger8 transportSpecific; UInteger8 localPriority; Integer8 initialLogSyncInterval; + Integer8 operLogSyncInterval; Integer8 logSyncInterval; Enumeration8 delayMechanism; Integer8 logMinPdelayReqInterval; + Integer8 operLogPdelayReqInterval; Integer8 logPdelayReqInterval; UInteger32 neighborPropDelayThresh; int follow_up_info; @@ -145,8 +147,11 @@ struct port { /* unicast service mode */ struct unicast_service *unicast_service; int inhibit_multicast_service; - /* interval update timer */ + /* interval update */ int ignore_interval_update_req; + int offset_threshold; + int num_offset_values; + int curr_offset_values; }; #define portnum(p) (p->portIdentity.portNumber) diff --git a/ptp4l.8 b/ptp4l.8 index c3e26fbbe32f..6cf9c71a255e 100644 --- a/ptp4l.8 +++ b/ptp4l.8 @@ -719,6 +719,36 @@ and the slave does not have any way to know it's identity. The default is 0 .B ignore_interval_update_req Ignore all the incoming signaling requests which request a change in Sync, Announce or Link delay intervals. The default is 0(requests are not ignored). +.TP +.B operLogSyncInterval +The mean time interval between Sync messages. This value is only used by the +slave device when interval_update_timer is enabled. Slave will send this +interval to the master to switch to. This is done via a signaling message after +interval_update_timer expires. It's specified as a power of two in seconds. The +default value is 0 (1 second). +.TP +.B operLogPdelayReqInterval +The mean time interval between Pdelay Request messages. This value is only used +by the slave device when interval_update_timer is enabled. Slave will switch to +the interval specified by this config option after the interval_update_timer +expires. It's specified as a power of two in seconds. The default value is 0 (1 +second). +.TP +.B num_offset_values +The number of offset values calculated in previously received Sync messages to +consider when adjusting the Sync and Pdelay request intervals. More information +provided in the description of 'offset_threshold'. The default value is 10. +.TP +.B offset_threshold +This value is used by the slave for adjusting the intervals for Sync and Pdelay +request messages. The slave will check the last 'num_offset_values' offsets and +if all those offsets are less than the offset_threshold, it will adjust both +the intervals. The Sync interval is adjusted via the signaling mechanism and +the pdelay request interval is just adjusted locally. The new values to use for +sync message intervals and pdelay request intervals can be indicated by +operLogSyncInterval and operLogPdelayReqInterval respectively. This mechanism +is currently only supported when BMCA == 'noop'. The default +value of offset_threshold is 0 (disabled). .SH UNICAST DISCOVERY OPTIONS -- 2.7.3 _______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel