8 Safety communication layer protocol ToC Previous Next

8.1 SafetyProvider and SafetyConsumer ToC Previous Next

8.1.2 OPC UA Safety behavior ToC Previous Next

8.1.2.1 General ToC

The two SCL-services “SafetyProvider” and “SafetyConsumer” are specified using state diagrams.

8.1.2.2 SafetyProvider/-Consumer Sequence diagram ToC

Figure 15 shows the sequence of request and response with SafetyData and the timeouts for OPC UA Safety.

readme_files/image017.png NOTE: Transmission errors are handled within the OPC UA stack (e.g. when using client/server over TCP) and do not have to be corrected or re-transmitted by OPC UA Safety.

Figure 15 – Sequence diagram for OPC UA Safety

The SafetyConsumerTimeout is the watchdog time checked in the SafetyConsumer. The watchdog is restarted whenever a new RequestSPDU is generated (transitions T14 and T26 of the SafetyConsumer). If an appropriate ResponseSPDU is received in time, and the checks for data integrity, authenticity, and timeliness are all valid, the timer will not expire before it is restarted.

Otherwise, the watchdog timer expires, and the SafetyConsumer triggers a safe reaction. To duly check its timer, the SafetyConsumer is executed cyclically, with period ConsumerCycleTime. ConsumerCycleTime is expected to be smaller than SafetyConsumerTimeout.

The ConsumerCycleTime is the maximum time for the cyclic update of the SafetyConsumer. It is the timeframe from one call of the SafetyConsumer to the next call of the SafetyConsumer. The implementation and error reaction of ConsumerCycleTime is not part of OPC UA Safety; it is vendor specific.

8.1.2.3 SafetyProvider state diagram ToC

[RQ8.10] Figure 16 shows a simplified representation of the state diagram of the SafetyProvider. The exact behavior is described in Table 21, Table 22, and Table 23. The SafetyProvider shall implement that behavior. It is not required to literally follow the entries given in the tables, if the behavior does not change.

readme_files/image018.png Figure 16 – Simplified representation of the state diagram for the SafetyProvider

Graphical representation Type Description
readme_files/image019.png    
Activity State Within these interruptible “activity” states the SafetyProvider waits for new inputs.  
readme_files/image020.png    
Action State Within these non-interruptible “action” states events like new request is deferred until the next “activity” state is reached, see [1].  

The transitions are fired in case of an event, for example receiving a SPDU. In case of several possible transitions, so-called guard conditions (refer to […] in UML diagrams) define which transition to fire

The diagram consists of activity and action states. Activity states are surrounded by bold lines, action states are surrounded by thin lines. While activity states may be interruptible by new events, action states are not. External events occurring while the state machine is in an action state, are deferred until the next activity state is reached.

Table 20 – Symbols used for state machines.

INTERNAL ITEMS TYPE DEFINITION
RequestSPDU_i Variable Local Memory for RequestSPDU (required to react on changes).
<Get RequestSPDU> Macro Instruction to take the whole RequestSPDU from the OPC UA Mapper.
<Set ResponseSPDU> Macro Instruction to transfer the whole ResponseSPDU to the OPC UA Mapper
<build ResponseSPDU> Macro Take the MNR and the SafetyConsumerID of the received RequestSPDU. Add the SPDU_ID_1, SPDU_ID_2, SPDU_ID_3, Flags, and SafetyData, as well as the calculated CRC.
See Clause 8.1.3.1

Table 22 – States of SafetyProvider instance

STATE NAME STATE DESCRIPTION
Initialization // Initial state
SAPI.SafetyData:= 0 SAPI.MonitoringNumber:= 0 SAPI.SafetyConsumerID:= 0
RequestSPDU_i:= 0
S1_WaitForRequest // waiting on next RequestSPDU from SafetyConsumer
<Get RequestSPDU>
S2_PrepareSPDU ResponseSPDU.Flags.ActivateFSV := SAPI.ActivateFSV ResponseSPDU.Flags.OperatorAckProvider := SAPI.OperatorAckProvider Response.Flags.TestModeActivated := SAPI.EnableTestMode
<build ResponseSPDU> // see Clause 8.1.3.1
TRAN-SITION SOURCE STATE TARGET STATE GUARD CONDITION ACTIVITY
T1 Init 1 -  
T2
1
2 // RequestSPDU received
<Get RequestSPDU>
When: [RequestSPDU_i<> RequestSPDU]
// Process Request
RequestSPDU_i:= RequestSPDU
SAPI.MonitoringNumber:= RequestSPDU.MonitoringNumber
SAPI.SafetyConsumerID := RequestSPDU.SafetyConsumerID
T3 2 1 // SPDU is prepared
-
<Set ResponseSPDU>

8.1.2.4 SafetyConsumer state diagram ToC

[RQ8.11] Figure 17 shows a simplified representation of the state diagram of the SafetyConsumer. The exact behavior is described in Table 24, Table 25, and Table 26. The SafetyConsumer shall implement that behavior. It is not required to literally follow the entries given in the tables, if the behavior does not change.

readme_files/image021.png Figure 17 – Principle state diagram for SafetyConsumer

Table 24 – SafetyConsumer driver internal items

INTERNAL ITEMS TYPE DEFINITION
Constants    
MNR_min := 0x100 UInt32 // 0x100 is the start value for MNR, also used after wrap-around.
// The values 0…0xFF are reserved for future use.
Variables    
FaultReqOA_i Boolean Local memory for errors which request operator acknowledgment.
MNR_i UInt32 Local Monitoring Number (MNR).
prevMNR_i UInt32 Local memory for previous MNR
SafetyProviderID_i UInt32 Local memory for SafetyProviderID in use.
CRCCheck_i Boolean Local variable used to store the result of the CRC-check.
SPDUCheck_i Boolean Local variable used to store the result of the additional SPDU-checks.
SPDU_ID_1_i UInt32 Local variable to store the expected SPDU_ID_1
SPDU_ID_2_i UInt32 Local variable to store the expected SPDU_ID_2
SPDU_ID_3_i UInt32 Local variable to store the expected SPDU_ID_3
Timers    
ConsumerTimer Timer This timer is used to check whether the next valid ResponseSPDU has arrived on time. It is initialized using the parameter SPI.SafetyConsumerTimeOut.
ErrorIntervalTimer Timer This timer is initialized using the parameter SPI.SafetyErrorIntervalLimit.
See Table 17, Clause 7.4.2, and Clause 11.4 for more information.
Macros <…><…>    
<risingEdge x> Macro // detection of a rising edge:
If   x==true && tmp==false Then result:= true Else result := false Endif
tmp := x
<Get ResponseSPDU> Macro Instruction to take the whole ResponseSPDU from the OPC UA Mapper.
<Use FSV> Macro SafetyData is set to binary 0
SAPI.FSV_Activated := 1
RequestSPDU.Flags.FSV_Activated := 1

NOTE: If a safety application prefers different fail-safe values than binary 0, this can be implemented in the safety application by querying SAPI.FSV_Activated.
<Use SafetyData> Macro SAPI.SafetyData is set to ResponseSPDU.SafetyData
SAPI.FSV_Activated := 0
RequestSPDU.Flags.FSV_Activated := 0
RequestSPDU.Flags.CommunicationError:=0
<Set RequestSPDU> Macro Instruction to transfer the whole RequestSPDU to the OPC UA Mapper
<(Re)Start ConsumerTimer> Macro Restarts the consumer timer.
<(Re)Start ErrorIntervalTimer> Macro Restarts the error interval timer.
<ConsumerTimer expired?> Macro Yields “true” if the timer is running longer than SPI.SafetyConsumerTimeOut since last restart, “false” otherwise.
<ErrorIntervalTimer expired?> Macro Yields “true” if the timer is running longer than SPI.SafetyErrorIntervalLimit since last restart, “false” otherwise.
<Build RequestSPDU> Macro RequestSPDU.SafetyConsumerID := SPI.SafetyConsumerID
RequestSPDU.MonitoringNumber := MNR_i
<Calc SPDU_ID_i> Macro uint128 BaseID
uint32 ProviderID
const uint32 SafetyProviderLevel_ID := … // see Clause 8.1.3.3
If(SAPI.SafetyBaseID == 0) then BaseID := SPI.SafetyBaseID Else BaseID := SAPI.SafetyBaseID
Endif   If(SAPI.SafetyProviderID == 0) then ProviderID := SPI.SafetyProviderID Else ProviderID := SAPI.SafetyProviderID
Endif
SPDU_ID_1_i := BaseID (bytes 0…3) XOR SafetyProviderLevel_ID
SPDU_ID_2_i := BaseID (bytes 4…7) XOR SPI.SafetyStructureSignature
SPDU_ID_3_i := BaseID (bytes 8…11) XOR BaseID (bytes 12…15) XOR ProviderID
// see Clause 8.1.3.2 for clarification
<Set Diag(ID, Boolean permanent)> Macro // ID is the identifier for the type of diagnostic output, see Table 29 // permanent is used to indicate a permanent error. // Only one diagnostic message is created for multiple permanent // errors in sequence
If(RequestSPDU.Flags.CommunicationError == 0) Then <do vendor-specific function for diagnostic output using ID> Else //do nothing Endif

RequestSPDU.Flags.CommunicationError:= permanent
// Note: See for possible values for “ID” and their codes.
External Event    
Restart Cycle Event The external call of SafetyConsumer can be interpreted as event “Restart Cycle”

Note: A macro is a shorthand representation for operations described in the according definition.

Table 25 – SafetyConsumer driver states

STATE NAME STATE DESCRIPTION
Initialization // Initial state of the SafetyConsumer driver instance.
<Use FSV> SAPI.OperatorAckRequested := 0 RequestSPDU.Flags.OperatorAckRequested :=0 SAPI.OperatorAckProvider := 0 FaultReqOA_i :=0 SAPI.TestModeActivated := 0 RequestSPDU.Flags.CommunicationError:= 0
S11_Wait for (Re)Start // Safety Layer is waiting (Re)Start
S12_initialize MNR // Use previous MNR if known // or random MNR within the allowed range (e.g. after cold start), see Clause 11.2.
MNR_i := (previous MNR_i if known) or (random MNR)
MNR_i := max(MNR_i, MNR_min)
S13_PrepareRequest // Build RequestSPDU and send (done in T16)
S14_WaitForChangedSPDU // Safety Layer is waiting on next ResponseSPDU from SafetyProvider
S15_CRCCheckSPDU // Check CRC

uint32 CRC_calc CRCCheck_i := (CRC_calc == ResponseSPDU.CRC)
// see Clause 8.1.3.5 on how to calculate CRC_calc
S16_CheckResponseSPDU // Check SafetyConsumerID and SPDU_ID and MNR (see T22, T23, T24)

SPDUCheck_i := ResponseSPDU.SPDU_ID_1== SPDU_ID_1_i && ResponseSPDU.SPDU_ID_2== SPDU_ID_2_i && ResponseSPDU.SPDU_ID_3== SPDU_ID_3_i && ResponseSPDU.SafetyConsumerID== SPI.SafetyConsumerID && ResponseSPDU.MNR==MNR_i
S17_Error SAPI.TestModeActivated := 0
S18_ProvideSafetyData // Provide SafetyData to the application program

Table 26 – SafetyConsumer driver transitions

TRANSITION SOURCE STATE TARGET STATE GUARD CONDITION ACTIVITY        
T12 Init S11 -          
T13 S11 S12
//Start
[SAPI.Enable==1]
<(Re)Start ErrorIntervalTimer> <calc SPDU_ID> // see Clause 8.1.3.2 for clarification        
T14 S12 S13 // MNR initialized <(Re)Start ConsumerTimer>        
T15 S18 S11 // Termination
[SAPI.Enable==0]
<Use FSV>        
T16 S13 S14 // Build Request SPDU and send
prevMNR_i := MNR_i,
If   MNR_i== 0xFFFFFFFFF Then MNR_i := MNR_min, Else
MNR_i := MNR_i + 1 Endif
<Build RequestSPDU>
<Set RequestSPDU>
       
T17 S14 S15 // New ResponseSPDU received
<Get ResponseSPDU>
[ResponseSPDU.MNR<>prevMNR_i]
-        
T18 S14 S17 // WDTimeout
[<ConsumerTimer expired?>]
<Set Diag(CommErrTO,1)> <use FSV>
If SPI.SafetyOperatorAckNecessary == 1 Then FaultReqOA_i := 1 Else // do nothing Endif
       
T19 S15 S13 // When CRC err and SafetyErrorIntervalTimer expired [(crcCheck_i == 0
) && <ErrorIntervalTimer expired?>]
<(Re)Start ErrorIntervalTimer> <Set Diag(CRCerrIgn,0)>        
T20 S15 S17 // When CRC err and SafetyErrorIntervalTimer not expired
[(crcCheck_i == 0
) && not <ErrorIntervalTimer expired?>]
<(Re)Start ErrorIntervalTimer> <Set Diag(CRCerrOA,1)> <use FSV>
FaultReqOA_i:= 1
       
T21 S15 S16 // When CRCCheckOK
[crcCheck_i == 1
]
-        
T22 S16 S18 // SPDU OK
[SPDUCheck_i==1]
// For clarification, refer to Figure 18

// indicate OA from provider
SAPI.OperatorAckProvider := ResponseSPDU.Flags.OperatorAckProvider

// OA requested due to edge at ActivateFSV?
If   (<risingEdge ResponseSPDU.Flags.ActivateFSV>&& SPI.SafetyOperatorAckNecessary == 1) Then FaultReqOA_i:=1; <Set Diag(FSV_Requested,1)> Else // do nothing
Endif
// Set Flags if OA requested:
If   FaultReqOA_i==1 Then SAPI.OperatorAckRequested:= 1, RequestSPDU.Flags.OperatorAckRequested:=1, FaultReqOA_i:= 0 Else //do nothing Endif
// Reset flags after OA:
If   (<risingEdge SAPI.OperatorAckConsumer >) Then SAPI.OperatorAckRequested:=0, RequestSPDU.Flags.OperatorAckRequested:=0 Else // do nothing Endif If SAPI.OperatorAckRequested==1
  ResponseSPDU.ActivateFSV==1 Then <use FSV> Else <use SafetyData> Endif

// Notify safety application that SafetyProvider is in test mode:
SAPI.TestModeActivated:= ResponseSPDU.Flags.TestModeActivated
   
T23 S16 S13 // SPDU NOK and SafetyErrorIntervalTimer expired [SPDUCheck_i == 0 && <ErrorIntervalTimer expired?>] <(Re)Start ErrorIntervalTimer>, // Send diagnostic message according the // detected error:
If   ResponseSPDU.SafetyConsumerID<> SPI.SafetyConsumerID Then <Set Diag(CoIDerrIgn,0)> Else If ResponseSPDU.MNR<>MNR_i Then <Set Diag(MNRerrIgn,0)> Else //do nothing EndIf If ResponseSPDU.SPDU_ID_1<> SPDU_ID_1_i
  ResponseSPDU.SPDU_ID_2<> SPDU_ID_2_i   ResponseSPDU.SPDU_ID_3<> SPDU_ID_3_i Then <Set Diag(SD_IDerrIgn,0)> Else // do nothing Endif Endif
T24 S16 S17 // SPDU NOK and SafetyErrorIntervalTimer not expired
   [SPDUCheck_i == 0 && not <ErrorIntervalTimer expired?>]
<(Re)Start ErrorIntervalTimer> // Send diagnostic message according the // detected error:
If   ResponseSPDU.SafetyConsumerID<> SPI.SafetyConsumerID Then <Set Diag(CoIDerrIgn,1)> Else If ResponseSPDU.MNR<>MNR_i Then <Set Diag(MNRerrIgn,1)> Else //do nothing Endif If ResponseSPDU.SPDU_ID_1<> SPDU_ID_1_i
  ResponseSPDU.SPDU_ID_2<> SPDU_ID_2_i   ResponseSPDU.SPDU_ID_3<> SPDU_ID_3_i Then <Set Diag(SD_IDerrIgn,1)> <use FSV> Else //do nothing Endif Endif
FaultReqOA_i:= 1
T25 S17 S18 // SPDU NOK
-
         
T26 S18 S13 // Restart Cycle
[SAPI.Enable==1]
<(Re)Start ConsumerTimer>        

8.1.2.5 SafetyConsumer sequence diagram for OA (informative) ToC

Figure 18 shows the sequence after a second ResponseSPDU error was detected before the timer SafetyErrorIntervalTimer stops.

readme_files/image022.png Figure 18 – Sequence diagram for OA

After the error is gone the sequence follows the logic of T22 in Table 26.

Previous Next