[RQ8.12] ResponseSPDU shall be built by the SafetyProvider by copying RequestSPDU.MonitoringNumber and the RequestSPDU.SafetyConsumerID into the ResponseSPDU. After this, SPDU_ID, Flags, and the SafetyData shall be updated. Finally, ResponseSPDU.CRC shall be calculated and appended.


Figure 19 – Overview of task for SafetyProvider

For the ResponseSPDU.Flags, see Clause For the calculation of the SPDU_ID, see Clause For the calculation of CRC, see Clause

[RQ8.13] The SPDU_ID_1-3 shall be calculated according to Figure 20 and Table 27.


Figure 20 – Calculation of the SPDU_ID

Table 27 – Presentation of the SPDU_ID

SPDU_ID_1 := SafetyBaseID (bytes 0…3) XOR SafetyProviderLevel_ID

SPDU_ID_2 := SafetyBaseID (bytes 4…7) XOR SafetyStructureSignature

SPDU_ID_3 := SafetyBaseID (bytes 8…11) XOR SafetyBaseID (bytes 12…15) XOR SafetyProviderID

NOTE: In case of a mismatch between expected SPDU_ID and actual SPDU_ID, the following rules can be used for diagnostic purposes:

  • If all of SPDU_ID1, SPDU_ID2, and SPDU_ID3 differ, there is a mismatching SafetyBaseID.
  • If SPDU_ID3 differs, but SPDU_ID1 and SPDU_ID2 do not, there is a mismatching SafetyProviderID.
  • If SPDU_ID2 differs, but SPDU_ID1 and SPDU_ID3 do not, the structure or identifier of the safety data do not match.
  • If SPDU_ID3 differs, but SPDU_ID1 and SPDU_ID2 do not, the SafetyProviderLevel does not match.

By using these rules, there is a very low probability (<10-9) that a mismatching SafetyBaseID will be misinterpreted. From a practical view, this probability can be ignored.

Table 28 – Coding for the SafetyProviderLevel_ID


Value of SafetyProviderLevel_ID

Up to SIL1Up to SIL2Up to SIL3Up to SIL4


[RQ8.14] Exactly one of the values provided in Table 28 shall be used as constant code value for SafetyProviderLevel_ID. They were chosen in such a way that the hamming distance becomes maximal (hamming distance of 21).

[RQ8.15] Measures shall be taken to avoid that a SafetyProvider is erroneously using a code-value belonging to a SIL that is higher than the SIL it is capable of. For instance, a SafetyProvider capable of SIL1-3 should not be able to accidently use the value 0xAB47F33B used for SIL4. One way to achieve this is to avoid that this constant appears in the source code of the SafetyProvider at all.

The SafetyProviderLevel is independent to the SIL capability of the provided SafetyData, see Clause 7.3.3.

SafetyStructureSignature is used to check the number, data types and order of application data transmitted in SafetyData. If the SafetyConsumer is expecting anything different than what the SafetyProvider actually provides, SafetyStructureSignature will differ, allowing the SafetyConsumer to enable fail-safe substitute values.

In addition, also the identifier of the structure type (StructureIdentifier) is taken into account when calculating SafetyStructureSignature. This ensures that the SafetyProvider and SafetyConsumer are using the same identifier for the structure type, effectively avoiding any confusion.

For instance, if a SafetyProvider defines a structure with identifier “vec3D_m” comprising three floats containing a three-dimensional vector in the metric system, this structure could not be used by a SafetyConsumer expecting a structure of type “vec3D_in” where the vector components are given in inch, or even at a SafetyConsumer expecting a structure of type “orientation”, containing three floats to define an orientation using Euler angles.

[RQ8.16] StructureSignature shall be calculated as CRC32-signature (polynomial: 0x F4ACFB13, see Annex B.1) over StructureIdentifier (encoding: UTF-8), StructureSignatureVersion and the sequence of the DataType IDs. After each datatype ID, a 16-bit zero-value (0x0000) shall be inserted.

The terminating zero of StructureIdentifier shall not be considered when calculating the CRC.

[RQ8.17] StructureIdentifier shall be visible in the OPC UA information model for diagnostic purposes, but shall not be evaluated by the SafetyConsumer during runtime.

[RQ8.18] For version V1.0 of the specification, the value for StructureSignatureVersion shall be 0x0001.


StructureIdentifier, e.g. “foo” = 0x66,0x6f,0x6f

StructureSignatureVersion:= 0x0001

1. DataType Int16: (Id = 0x0004), // see Clause 6.4

2. DataType Boolean: (Id = 0x0001),

3. DataType Float32: (Id =0x000A)

StructureSignature := CRC32(0x66,0x6f,0x6f, 0x00,0x01,0x00,0x00, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x0A)

NOTE: The insertion of 0x0000 values before the DataType ID, allows for introducing arrays in later version of OPC UA Safety.

The DataType ID can be found at the DataType or at the derived DataType.

The OPC UA Information model supports not only built-in DataTypes, but also allows for DataTypes derived from built-in DataTypes. In case of derived DataTypes, the Data Structure CRC uses the ID of a built-in DataType (which is found at the end of the tree).

Example: the base type "enumeration" is derived from the DataType Int32 (ID=6); therefore, an ID of 6 is used whenever the DataType “enumeration” is used in SafetyData.

In this version of the specification, arrays are not supported. Instead, multiple variables of the same type are used.

The SafetyProvider calculates the CRC signature (ResponseSPDU.CRC) and sends it to the SafetyConsumer as part of SPDU. This enables the SafetyConsumer to check the correctness of the SPDU including the SafetyData, Flags, MNR, SafetyConsumerID and SPDU_ID by recalculating the CRC signature (CRC_calc).

[RQ8.19] The generator polynomial 0x F4ACFB13 shall be used for the 32-Bit CRC signature.

[RQ8.20] If SafetyData is longer than one byte (e.g. UInt16, Int16, Float32), it shall be decoded and encoded using big-endian order in which the least significant byte appears last in the incremental memory address stream.

[RQ8.21] The calculation sequence shall begin with the highest memory address (n) of the SafetyData counting back to the lowest memory address (0) and then include also the STrailer beginning with the highest memory address.

Figure 21 shows the calculation sequence of the CRC_SPDU using an example SafetyData with the following fields:

Boolean var1


Int16 var3


Int32 var5

The STrailer and SafetyData have a total length of 34 bytes. The calculation of ResponseSPDU.CRC (SafetyProvider) or CRC_calc (SafetyConsumer) is done in reverse order, i.e. starts at byte 33 and ends at byte 0.


Figure 21 – Calculation of the CRCr

For devices where the SafetyData remains at the same value for a longer period of time, it is a viable optimization to store the calculated CRC over the SafetyData and take – in case the SafetyData hasn’t changed, this stored CRC as start value for the CRC calculation of the STrailer.

Note: On the SafetyConsumer, CRC_calc is calculated using data received in the ResponseSPDU, and not from expected values.