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

Reply via email to