Supported platforms: CODESYS 3.5 SAFETY
This section describes how to review generated code for safety parameters.
Safety parameter implementation consists of non-safety related code (CANopen OD) and safety related code.
This guide focuses mainly on safety related implementation.
Init_CANopen_ODX (PRG)
Verify that the access type G_CANOPEN_OD_ACCESS_SAFEPARAMINDEX is used in each safety parameter OD index initialization. This will prevent write access to the safety parameters from CAN bus, until authentication is done.
Code: |
|
i_ObjectAccess := G_CANOPEN_OD_ACCESS_READWRITE OR G_CANOPEN_OD_ACCESS_SUB0NOWRITE OR G_CANOPEN_OD_ACCESS_SAVE OR G_CANOPEN_OD_ACCESS_SAFEPARAMINDEX,
|
S_ValidateParameters_CANX (PRG)
This program validates safety parameter CRC for each safety parameter OD index.
Verify that the S_ValidateSafetyParameterIndex function is executed for each safety parameter OD index
Verify that the validation datatype corresponds to the OD index datatype (see ParameterDataType for supported types)
Verify that number of subindex matches with the parameter count in the safety parameter OD index
Verify that the parameter given in the i_pData input is the first parameter of the safety parameter OD index (same parameter as used in corresponding OD initialization at Init_CANopen_ODX)
Verify that the used CRC array index matches the safety parameter index list (see below)
The following example definition has 6 safety parameter indexes.
SafetyParameterIndexList has a list of safety parameter OD indexes. The order of CRCs in SafetyParameterIndexCRCs shall match with the SafetyParameterIndexList.
Definition: |
|
/// 16#21FB Table of safety parameter index numbers SafetyParameterIndexList: ARRAY[0..5] OF WORD := [WORD#16#2201, WORD#16#2202, WORD#16#2203, WORD#16#2204, WORD#16#2205, WORD#16#2206]; /// 16#21FC Table of safety parameter index CRCs SafetyParameterIndexCRCs: ARRAY[0..5] OF WORD := [6(WORD#0)]; |
The following is an initialization of 2201h safety parameter index.
Note that G_CAN1_PAR.Joystick_X_Deadband is given as a pointer to the OD index (first parameter in safety parameter index).
Code: |
|
(* 16#2201 *) IF G_CANopen_CAN1_VAR.OD_Error = EPEC_CANopen.Errors.NoError THEN G_CANopen_CAN1_VAR.OD_Error := CANopenODAddLine( i_pOD := ADR(G_CANopen_CAN1.OD),(*Address of Object dictionary where index will be added*) i_Index := 16#2201, i_ObjectCode := EPEC_CANopen.ObjectCode.OD_ARRAY,(*Type of index*) i_NumOfSubids := USINT#7,(*Number of subindexes*) i_TypeSpec := EPEC_CANopen.DataType.Deftype_INTEGER32,(*Index datatype, either user defined or standard CiA 301*) i_ObjectAccess := G_CANOPEN_OD_ACCESS_READWRITE OR G_CANOPEN_OD_ACCESS_SUB0NOWRITE OR G_CANOPEN_OD_ACCESS_SAVE OR G_CANOPEN_OD_ACCESS_SAFEPARAMINDEX, i_Sub0data := USINT#7,(*Value of subindex0 in array or (def)struct*) i_pIndexData := ADR(G_CAN1_PAR.Joystick_X_Deadband), i_itfSDOHandler := DWORD#0 ); END_IF |
The following example validates two of the safety parameter indexes (in S_ValidateParameters_CANX).
Note that the first validation uses a pointer to G_CAN1_PAR.Joystick_X_Deadband (first safety parameter in 2201h).
The array index of SafetyParameterIndexCRCs is 0 which corresponds to 2201h position in SafetyParameterIndexList.
Code: |
failed_index := WORD#0;
S_o_Valid := EPEC_SDV.S_ValidateSafetyParameterIndex( i_pData := ADR(G_CAN1_PAR.Joystick_X_Deadband), i_NumberOfIndices := USINT#7, i_DataType := EPEC_SDV.ParameterDataType.Deftype_INTEGER32, i_pCRC := ADR(G_CAN1_VAR.SafetyParameterIndexCRCs[0]), i_pEventCode := ADR(EC_ParameterValidation), o_ParameterError => sparerror, o_OutputValid => sparvalid );
IF NOT S_o_Valid THEN failed_index := G_CAN1_VAR.SafetyParameterIndexList[0]; END_IF
IF S_o_Valid THEN S_o_Valid := EPEC_SDV.S_ValidateSafetyParameterIndex( i_pData := ADR(G_CAN1_PAR.Joystick_X_DirSwitchDiagDelay), i_NumberOfIndices := USINT#1, i_DataType := EPEC_SDV.ParameterDataType.Deftype_UNSIGNED16, i_pCRC := ADR(G_CAN1_VAR.SafetyParameterIndexCRCs[1]), i_pEventCode := ADR(EC_ParameterValidation), o_ParameterError => sparerror, o_OutputValid => sparvalid ); IF NOT S_o_Valid THEN failed_index := G_CAN1_VAR.SafetyParameterIndexList[1]; END_IF END_IF |
Error code is added to application log only when device description includes SafeErrorLog library. In SC52 device description 3.5.10.6 or later is required. See also How to use application error log. |
Safety parameter OD index which fails validation is added to output o_ErrorInIndex when MultiTool 6.4 or later, or MultiTool Creator is used. |
The following adds validation error to application log.
Code: |
EPEC_SERRLOG.S_AddError_DWORD( i_ErrorCode := ApplicationErrors.VALIDATE_SAFE_PAR, i_LibraryErrorCode := EC_ParameterValidation.EventID, i_Info1 := WORD_TO_DWORD(failed_index), // Safety parameter OD index i_Info2 := 1 // CAN bus ); o_ErrorInIndex := failed_index; |
S_ValidateConfigurations (PRG)
Verify that the program is generated
Verify that the generated S_ValidateParameters_CANX program is executed
Verify that the S_o_Valid flag of S_ValidateParameters_CANX program affects o_ParametersValid output
The following is an example where CAN1 bus has safety parameters and SRDO messages. See also Reviewing SRDO.
Code: |
// If initializing, or configuration valid status is in progress IF G_CAN1_VAR.ConfigurationValidStatus=EPEC_CANopen.CANopenGCL.G_CANOPEN_SRD_CONF_IN_PROGRESS OR i_Init THEN // Validate parameters and SRDO signatures S_ValidateParameters_CAN1(); S_ValidateSRDOSignatures_CAN1(); // If both passed, set configuration valid status to valid, otherwise set it to invalid IF S_ValidateParameters_CAN1.S_o_Valid AND S_ValidateSRDOSignatures_CAN1.S_o_Valid THEN G_CAN1_VAR.ConfigurationValidStatus:=EPEC_CANopen.CANopenGCL.G_CANOPEN_SRD_CONF_VALID; G_Common.ParhandlerEnableChanges:=TRUE; ELSE G_CAN1_VAR.ConfigurationValidStatus:=EPEC_CANopen.CANopenGCL.G_CANOPEN_SRD_CONF_INVALID; END_IF // Output statuses o_Ready:=TRUE; o_ParametersValid:=S_ValidateParameters_CAN1.S_o_Valid; o_SRDOSignaturesValid:=S_ValidateSRDOSignatures_CAN1.S_o_Valid; END_IF |
S_CopyValidatedParameters (PRG)
Verify that the program copies parameter values only when the valid flag is TRUE
Verify that each safety parameter defined in MultiTool Creator is copied from G_CANX_PAR variable to G_CANX_SPAR variable
Safety parameters have S_ prefix and use SAFE datatypes
Safety parameters defined in G_CANX_SPAR do not have %M addresses as is in G_CANX_PAR variables
An example of safety parameter value initialization:
Code: |
IF i_ParametersValid THEN G_CAN1_SPAR.S_Boom_X_PVGPosMaxPWM:=G_CAN1_PAR.Boom_X_PVGPosMaxPWM; G_CAN1_SPAR.S_Boom_X_PVGPosMinPWM:=G_CAN1_PAR.Boom_X_PVGPosMinPWM; |
S_ValidateAccessCode_CANX (PRG)
The purpose of this program is to verify safety parameter authentication and set a flag which is used to enable safety parameter write access.
Verify that the program is generated to the CAN bus containing safety parameters
Verify that the OD variables used in the program corresponds to the CAN bus number in the program name
The following is an example of access code validation when safety parameters are defined to CAN1.
Code: |
S_o_ValidationOk:=S_ValidateAccessCode(i_ChallengeCode:=G_CAN1_VAR.ChallengeCode, i_ResponseCode:=G_CAN1_VAR.ResponseCode, i_ProjectKey:=G_Common.ProjectKey, i_pEventCode:=ADR(o_EC_ValidateAccessCode), o_ParameterError => o_ParameterError, o_OutputValid => o_OutputValid);
IF G_CANOPEN_GFC_VALID=G_CANopen_CAN1_VAR.GFC_Status AND S_o_ValidationOk AND NOT S_ValidationOk_Old THEN G_Common.CAN1SSDOHandlerGrantAccess:=TRUE; G_CAN1_VAR.ConfigurationValidStatus:=EPEC_CANopen.CANopenGCL.G_CANOPEN_SRD_CONF_INVALID; G_CAN1_VAR.AuthenticationStatus:=G_CONSTANTS.G_SAFE_PARAMETERS_AUTHENTICATED; G_Common.ParhandlerDisableChanges:=TRUE; S_ValidationOk_Old:=S_o_ValidationOk; END_IF |
S_PLC_PRG
Verify that S_ValidateConfigurations is executed at the initialization phase
Code: |
ELSIF NOT S_ValidateConfigurations.o_Ready THEN S_ValidateConfigurations(i_Init:=TRUE); |
Verify that S_CopyValidatedParameters is executed at the initialization phase
Code: |
ELSIF NOT S_CopyValidatedParameters.o_Ready THEN S_CopyValidatedParameters(i_ParametersValid:=S_ValidateConfigurations.o_ParametersValid); |
Verify that S_ValidateConfigurations is executed at the run phase
Code: |
ELSIF PLC_PRG.o_Initdone THEN (*...*) S_ValidateConfigurations(i_Init:=FALSE); |
Verify that S_ValidateConfigurations.o_ParametersValid affects the S_Safety_Status program's input
Code: |
S_Safety_Status(i_Safe_InitDone:= o_InitDone, i_Nonsafe_InitDone:= PLC_PRG.o_InitDone, S_i_SafetySignaturesValid:= S_ValidateConfigurations.o_SRDOSignaturesValid, S_i_SafetyParametersValid:= S_ValidateConfigurations.o_ParametersValid, S_o_SafeOperationEnable => G_StatusFlags_Safe.S_SafeOperationEnable); |
Verify that S_ValidateAccessCode_CANX is executed at the run phase
Code: |
S_Main(); (*...*) S_ValidateAccessCode_CAN1(); |
PLC_PRG
Verify that the following code is generated to PLC_PRG, which is related to S_ValidateAccessCode_CANX and S_ValidateConfigurations.
Non-safety libraries cannot be executed at safety programs so global flags are used to trigger methods
The CAN bus number in G_CANopen_CAN1 corresponds to the CAN bus containing safety parameters
Code: |
|
(* Call non-safe blocks that have been flagged from the safe program *) IF G_Common.ParhandlerDisableChanges THEN G_Common.ParhandlerDisableChanges:=FALSE; G_Common.ParHandler.DisableChanges(TRUE); END_IF IF G_Common.ParhandlerEnableChanges THEN G_Common.ParhandlerEnableChanges:=FALSE; G_Common.ParHandler.DisableChanges(FALSE); END_IF IF G_Common.CAN1SSDOHandlerGrantAccess THEN G_Common.CAN1SSDOHandlerGrantAccess:= FALSE; G_CANopen_CAN1.SSDO_Handler.GrantAccessToSafetyParameters(TRUE); G_CANopen_CAN1.NMT.NmtState:= EPEC_CANopen.NMTState.Preoperational; END_IF |
Source file topic100553.htm
Last updated 19-Dec-2024