//This file was generated by the LASAL2 CodeGenerator  -- 
//Please, do not edit this file (it might be overwritten by the next generator run)
//{{LSL_DECLARATION
#include "..\..\Class\SdiasSafetyManager\SdiasSafetyManager.h"
#include "..\..\Class\SdiasManager\SdiasManager.h"
#include "..\..\Class\HwControl\HwControl.h"

(*!
<Class
	Name               = "SdiasSafetyManagerFSoE"
	Revision           = "1.40"
	GUID               = "{5BC70C54-F263-445B-950C-3A230EA234A9}"
	RealtimeTask       = "false"
	CyclicTask         = "false"
	BackgroundTask     = "true"
	DefBackground      = "100 ms"
	Sigmatek           = "true"
	OSInterface        = "false"
	HighPriority       = "false"
	Automatic          = "false"
	UpdateMode         = "Prescan"
	IconPath           = ".\Class\Safety.ico"
	SharedCommandTable = "true"
	Objectsize         = "(670,120)">
	<Channels>
		<Server Name="CanOut" GUID="{176F1C6C-40DC-4F52-A09A-F5FCB0886591}" Visualized="false" Initialize="false" WriteProtected="true" Retentive="false"/>
		<Server Name="ClassSvr">
		</Server>
		<Server Name="DesignerPrjName" GUID="{3800216A-F78D-4566-9518-138D0F55C7EF}" Class="String" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="use this channel to access the string functions"/>
		<Server Name="DesignerPrjRev" GUID="{8D8BA4D8-0422-454B-86B1-E7E52F9008D7}" Class="String" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="use this channel to access the string functions"/>
		<Server Name="FastUnsafeInputs" GUID="{7056D587-EC1A-4355-9927-0107A6F69388}" Visualized="true" Initialize="true" WriteProtected="false" Retentive="false"/>
		<Server Name="FastUnsafeOutputs" GUID="{3B2D285A-4040-493E-B44E-F076DA09CED6}" Visualized="true" Initialize="false" WriteProtected="false" Retentive="false"/>
		<Server Name="FCN_Command" GUID="{BD77EAE8-7D94-446E-8A9B-BA667AE65218}" Visualized="true" Initialize="false" WriteProtected="false" Retentive="false"/>
		<Server Name="FCN_HostSafetyNumber" GUID="{2186369F-B3F1-4FE5-B6B3-A632B71F6EBB}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false"/>
		<Server Name="FCN_StateMachine" GUID="{969EBC6D-DE62-4DF8-B689-826FF32ABD6B}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false"/>
		<Server Name="HGWOut" GUID="{89AAB324-2685-4A62-9ECA-A97120E9B570}" Visualized="false" Initialize="false" WriteProtected="true" Retentive="false"/>
		<Server Name="SdiasSafetyOut" GUID="{FBE550CC-290F-46C6-89BA-6ED77B07552B}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false"/>
		<Server Name="ValidationButtonState" GUID="{066BDF8E-D5AD-4394-A114-71AD11D6DAD3}" Visualized="false" Initialize="false" WriteProtected="true" Retentive="false" Comment="Shows the state of the validation button&#13;&#10;0: Validation button not used at the moment&#13;&#10;1: Select a command by pressing the button&#13;&#10;2: Command is executed&#13;&#10;3: Error in module"/>
		<Client Name="ProjectNameStr" Required="true" Internal="true"/>
		<Client Name="ProjectRevisionStr" Required="true" Internal="true"/>
	</Channels>
	<Dependencies>
		<Files>
			<File Path=".\Class\SdiasSafetyManager\SdiasSafetyManager.h" Include="true"/>
			<File Path=".\Class\SdiasManager\SdiasManager.h" Include="true"/>
			<File Path=".\Class\HwControl\HwControl.h" Include="true"/>
		</Files>
	</Dependencies>
	<RevDoku>
		<Owner Company="Sigmatek" Author="RamAnd"/>
		<Dokumentation Revision="1.40" Date="17.12.2024" Author="ZoePat" Company="Sigmatek" Description="Corrected possible access exception, if the safetyproject uses flexcon and safetyinputs are used across two or more SCPs (internal interface frames)."/>
		<Dokumentation Revision="1.39" Date="09.07.2024" Author="LanSte" Company="Sigmatek" Description="Corrected NewInst method GetDiagConnect::NewInst::SBCMD_SM_DIAG_SAVE_LOGFILE. 0 Termination of input parameter was not copied."/>
		<Dokumentation Revision="1.38" Date="16.04.2024" Author="RamAnd" Company="Sigmatek" Description="Corrected error that could have blocked the distribution of slave configurations if there was a safe analog input module used at the slave configuration.&#13;&#10;Corrected error that showed the HBG device ID at the object of an optional safe IO module that was not available."/>
		<Dokumentation Revision="1.37" Date="28.08.2023" Author="LanSte" Company="Sigmatek" Description="Corrected handling of CMD_SM_REMOVE_INPUT_PDO if a FSoE Frame was split over several SDIAS DOs."/>
		<Dokumentation Revision="1.36" Date="15.03.2023" Author="EisMic" Company="Sigmatek" Description="The newinst commando CMD_GET_HARDWARE_DIAGNOSIS now returns the hardware and firmware versions of the safety modules if the informations are available."/>
		<Dokumentation Revision="1.35" Date="19.01.2023" Author="EisMic" Company="Sigmatek" Description="Corrected an error that no values were shown at safety analog input modules when there were missing optional safety analog input modules. (e.g. 2 SAI041 modules (both optional and projected), but only one available at the hardware).&#13;&#10;Corrected an error that if there was a missing optional module and a HBG, the hardwareclass of the last missing optional module was showing _WrongHardware instead of _NoHardware.&#13;&#10;The behavior that the offset of the PDO data pointers are not always calculated in the StartDO method was changed because there was an error when a VI02x module with x modules unplugged and plugged in again with fewer than x modules. In this case the PDO pointers were wrong which leads to wrong server data at the safety modules behind the SCP.&#13;&#10;Corrected the calculation of the triple buffer config for the analog input data. The wrong calculation leads to wrong analog input values (High/Low byte error) at the last analog input of the last analog input module in the project."/>
		<Dokumentation Revision="1.34" Date="08.07.2022" Author="RamAnd" Company="Sigmatek" Description="Added possibility to try again later if adding an input PDO only failed temporarily because of a certain init step being active at that moment.&#13;&#10;Corrected an error from the last modification that could have blocked slave configurations from being distributed."/>
		<Dokumentation Revision="1.33" Date="16.03.2022" Author="RamAnd" Company="Sigmatek" Description="Added different quit error modi.&#13;&#10;Fixed a crash related to fast unsafe variables."/>
		<Dokumentation Revision="1.32" Date="31.01.2022" Author="EisMic" Company="Sigmatek" Description="Flag b_reInitMarker is now set also if non optional module will be added to routing tables. &#13;&#10;This leads that the safety CPU will read out its config again when an optional module will be connected later&#13;&#10;and calls the newinst command CMD_SM_MODULE_REINIT."/>
		<Dokumentation Revision="1.31" Date="17.05.2021" Author="EisMic" Company="Sigmatek" Description="Added support for analog input modules (SAI023,SAI041,SAI042)&#13;&#10;Corrected the error that the retcode from CanOut::NewInst was overwritten with READY in every case.&#13;&#10;Added forwarding of newer SDIAS_CMD_xxx."/>
		<Dokumentation Revision="1.30" Date="29.03.2021" Author="FurDom" Company="Sigmatek" Description="add support for Fast Unsafe Variablen with SCP211"/>
		<Dokumentation Revision="1.29" Date="05.11.2020" Author="PieSte" Company="Sigmatek" Description="Add new block type at SafetyBaseFSoE class."/>
		<Dokumentation Revision="1.28" Date="20.04.2021" Author="RamAnd" Company="Sigmatek" Description="Added 2 new servers ApplCRC and HwCRC to show the CRCs of the safety application logic as well as the hardware configuration."/>
		<Dokumentation Revision="1.27" Date="01.02.2021" Author="EisMic" Company="Sigmatek" Description="Corrected an error that caused the class to be stuck in _Wait4Synchronicity state when using unsafe variables.&#13;&#10;Returncode of method AddPDOToInputBuffer is now check at the newinst cmd SDIAS_SAFETY_GET_HGW_INFO."/>
		<Dokumentation Revision="1.26" Date="30.09.2020" Author="RamAnd" Company="Sigmatek" Description="Sending the BusReady message to the safety module could have been blocked by a new InputPDO being added in the process. This would have led to the class being stuck in the _WaitForSynchronicity state. Adding InputPDOs is now prevented while the BusReady signal is being sent out."/>
		<Dokumentation Revision="1.25" Date="03.06.2020" Author="RamAnd" Company="Sigmatek" Description="The Initialisation is now skipped if the DeviceID at the current SDIAS Place is wrong. Otherwise it would lead to timeouts in the SSDO-transfer which would unnecessarily block the safety task."/>
		<Dokumentation Revision="1.24" Date="25.03.2020" Author="RamAnd" Company="Sigmatek" Description="If the module is connected during runtime, there could be a problem when creating the internal safety configuration which would lead to PDOs of this module not working."/>
		<Dokumentation Revision="1.23" Date="24.07.2019" Author="RamAnd" Company="Sigmatek" Description="Corrected comparison before reusing PDO Input buffer.&#13;&#10;Corrected the background task being unnecessarily blocked after power cycling the safe CPU while the SDIAS bus power supply still remains on."/>
		<Dokumentation Revision="1.22" Date="18.07.2019" Author="RamAnd" Company="Sigmatek" Description="Corrected that SDO forwarding would not work properly in some cases."/>
		<Dokumentation Revision="1.21" Date="25.06.2019" Author="RamAnd" Company="Sigmatek" Description="Added support for FlexCon functionality."/>
		<Dokumentation Revision="1.20" Date="06.12.2018" Author="EisMic" Company="Sigmatek" Description="Machinenumber from HGW1033 is now used as a 4 Byte value instead of a 1 byte value."/>
		<Dokumentation Revision="1.19" Date="23.11.2018" Author="PieSte" Company="Sigmatek" Description="The PLC cycle time is written periodically into the module so that this time is used in the safety log file."/>
		<Dokumentation Revision="1.18" Date="18.10.2018" Author="LanSte" Company="Sigmatek" Description="Ignore QuitComError if not in ErrorState.&#13;&#10;Added support for custom FSoE Connections."/>
		<Dokumentation Revision="1.17" Date="24.10.2018" Author="EisMic" Company="Sigmatek" Description="Changes in newinst commands for HGW1033-3."/>
		<Dokumentation Revision="1.16" Date="05.07.2018" Author="PieSte&#13;&#10;EisMic" Company="Sigmatek" Description="Added support for HGW1033."/>
		<Dokumentation Revision="1.15" Date="24.04.2018" Author="RamAnd" Company="Sigmatek" Description="Fetch hardware versions of safe IO modules if this feature is supported by the firmware."/>
		<Dokumentation Revision="1.14" Date="10.04.2018" Author="PieSte" Company="Sigmatek" Description="Fixed an error in the UpDateNotStd() method. If a digital input or output module was optional and hardware was not available, the IOStates pointer was not increased. &#13;&#10;Add numbers for the assignment of the log messages."/>
		<Dokumentation Revision="1.13" Date="23.01.2018" Author="RamAnd" Company="Sigmatek" Description="Log messages have been standardized for easier maintenance, easier use in any class and to allow spam filtering. Code for the logging functions is now only located in HwControl."/>
		<Dokumentation Revision="1.12" Date="04.12.2017" Author="FurDom" Company="Sigmatek" Description="Added support to read out the error information on the channels"/>
		<Dokumentation Revision="1.11" Date="22.08.2017" Author="RamAnd" Company="Sigmatek" Description="Fixed an error which prevented two SCP111s on the same PLC from exchanging interfaceframes in both directions."/>
		<Dokumentation Revision="1.10" Date="23.05.2017" Author="RamAnd" Company="Sigmatek" Description="Extended diagnosis information (added firmware version, safety designer project name and revision)."/>
		<Dokumentation Revision="1.9" Date="12.06.2017" Author="RamAnd" Company="Sigmatek" Description="When another module disconnects before the connection is marked as synchrony, the counter for modules to synchronize is now decremented so the next connect can get synchrony properly."/>
		<Dokumentation Revision="1.8" Date="01.03.2017" Author="EisMic" Company="Sigmatek" Description="The configuration of the module is now also read out if the module is connected during runtime.&#13;&#10;Added retryhandling in InitModule()."/>
		<Dokumentation Revision="1.7" Date="14.02.2017" Author="EisMic" Company="Sigmatek" Description="Added support for ADD_DYN_SLAVE command."/>
		<Dokumentation Revision="1.6" Date="10.02.2016" Author="RamAnd" Company="Sigmatek" Description="Support for FSoE via IP added."/>
		<Dokumentation Revision="1.5" Date="04.07.2016" Author="RamAnd" Company="Sigmatek" Description="It&apos;s now allowed to have an object of an IO module or HBG if it&apos;s not set to required and it&apos;s neither projected in the safety designer nor physically available."/>
		<Dokumentation Revision="1.4" Date="08.03.2016" Author="EisMic" Company="Sigmatek" Description="Added support for SafetyDiagnosisInfo hardwareclass.&#13;&#10;Prevented access exception when a SCP was used with only SDI&apos;s."/>
		<Dokumentation Revision="1.3" Date="21.01.2016" Author="EisMic" Company="Sigmatek" Description="Outputs are now written in RtPostScan instead of RtPreScan to improve the reaction speed.&#13;&#10;The LED stati of the module were not displayed correctly if now IO modules were used."/>
		<Dokumentation Revision="1.2" Date="31.08.2015" Author="RamAnd" Company="Sigmatek" Description="If no configuration is available at the CPU, the optional settings are now ignored since they are not available in this state. This could have lead to SDIAS errors if safety modules were set to required."/>
		<Dokumentation Revision="1.1" Date="31.07.2015" Author="RamAnd" Company="Sigmatek" Description="Added server DesignerPrjConfigCRC to show the CRC of the SafetyDesigner project.&#13;&#10;Added support for optional Safe-IOs (configured in SafetyDesigner)."/>
		<Dokumentation Revision="1.0" Date="15.04.2015" Author="RamAnd" Company="Sigmatek" Description="First library version"/>
	</RevDoku>
	<Network Name="SdiasSafetyManagerFSoE">
		<!-- List of Components in this network -->
		<Components>
			<Object
				Name       = "_base"
				GUID       = "{A3277144-4D10-4DCB-BA66-865F09AFD22E}"
				Class      = "SafetyBaseFSoE"
				Position   = "(218,120)"
				Visualized = "true">
				<Channels>
					<Server Name="ApplCRC"/>
					<Server Name="ClassSvr"/>
					<Server Name="DesignerPrjConfigCRC"/>
					<Server Name="ErrorState"/>
					<Server Name="FirmwareVersion"/>
					<Server Name="GetDiagConnect"/>
					<Server Name="HwCRC"/>
					<Server Name="QuitComError"/>
					<Server Name="RunState"/>
					<Server Name="SafetyNumber"/>
					<Server Name="SafetyRetryCounter"/>
					<Server Name="SafetyState"/>
					<Server Name="ServiceMode"/>
					<Server Name="VoltageOK"/>
					<Client Name="DeviceID"/>
					<Client Name="FileSys"/>
					<Client Name="ServerUpdateTime" Value="50"/>
					<Client Name="ToBusInterface"/>
					<Client Name="ToSigCLib"/>
					<Client Name="ToStdLib"/>
				</Channels>
			</Object>
			<Object
				Name       = "ProjectNameStr"
				GUID       = "{20EAAF8C-A7BC-4457-9625-E78943BD2412}"
				Class      = "String"
				Position   = "(600,960)"
				Visualized = "true">
				<Channels>
					<Server Name="Data"/>
					<Client Name="SingleRealloc" Value="1"/>
				</Channels>
			</Object>
			<Object
				Name       = "ProjectRevisionStr"
				GUID       = "{32AE3537-6A01-4AE2-A277-3B9212D50A2E}"
				Class      = "String"
				Position   = "(600,1110)"
				Visualized = "true">
				<Channels>
					<Server Name="Data"/>
					<Client Name="SingleRealloc" Value="1"/>
				</Channels>
			</Object>
		</Components>
		<Comments>
		</Comments>
		<!-- List of Connections in this network -->
		<Connections>
			<Connection Source="this.ClassSvr" Destination="_base.ClassSvr" Vertices="(1088,210),(904,210),"/>
			<Connection Source="this.SafetyState" Destination="_base.SafetyState" Vertices="(1088,270),(904,270),"/>
			<Connection Source="this.VoltageOK" Destination="_base.VoltageOK" Vertices="(1088,330),(904,330),"/>
			<Connection Source="this.RunState" Destination="_base.RunState" Vertices="(1088,390),(904,390),"/>
			<Connection Source="this.ServiceMode" Destination="_base.ServiceMode" Vertices="(1088,450),(904,450),"/>
			<Connection Source="this.ErrorState" Destination="_base.ErrorState" Vertices="(1088,510),(904,510),"/>
			<Connection Source="this.QuitComError" Destination="_base.QuitComError" Vertices="(1088,570),(904,570),"/>
			<Connection Source="this.FirmwareVersion" Destination="_base.FirmwareVersion" Vertices="(1088,630),(904,630),"/>
			<Connection Source="this.SafetyNumber" Destination="_base.SafetyNumber" Vertices="(1088,690),(904,690),"/>
			<Connection Source="_base.ServerUpdateTime" Destination="this.ServerUpdateTime" Vertices="(218,270),(38,270),"/>
			<Connection Source="_base.ToBusInterface" Destination="this.ToBusInterface" Vertices="(218,210),(38,210),"/>
			<Connection Source="_base.DeviceID" Destination="this.DeviceID" Vertices="(218,330),(38,330),"/>
			<Connection Source="this.ProjectNameStr" Destination="ProjectNameStr.Data"/>
			<Connection Source="this.ProjectRevisionStr" Destination="ProjectRevisionStr.Data"/>
			<Connection Source="this.DesignerPrjName" Destination="ProjectNameStr.Data" Vertices="(1088,1050),(916,1050),"/>
			<Connection Source="this.DesignerPrjRev" Destination="ProjectRevisionStr.Data" Vertices="(1088,1110),(916,1200),"/>
			<Connection Source="this.SafetyRetryCounter" Destination="_base.SafetyRetryCounter" Vertices="(1088,750),(904,750),"/>
			<Connection Source="this.DesignerPrjConfigCRC" Destination="_base.DesignerPrjConfigCRC" Vertices="(1088,810),(904,810),"/>
			<Connection Source="this.GetDiagConnect" Destination="_base.GetDiagConnect" Vertices="(1088,990),(904,990),"/>
			<Connection Source="this.ApplCRC" Destination="_base.ApplCRC" Vertices="(1088,870),(904,870),"/>
			<Connection Source="this.HwCRC" Destination="_base.HwCRC" Vertices="(1088,930),(904,930),"/>
		</Connections>
		<!-- Headerfiles -->
		<Options>
		</Options>
	</Network>
</Class>
*)
#pragma using SafetyBaseFSoE

SdiasSafetyManagerFSoE : CLASS
: SafetyBaseFSoE
	TYPE
#pragma pack(push, 1)
	  t_AnalogTripleBufferConfig : STRUCT
	    usSizeuCtoCPU : USINT;
	    usSizeCPUtouC : USINT;
	  END_STRUCT;
#pragma pack(pop)
	  t_CheckIDSSW :
	  (
	    _Nothing,
	    _Wait4Idle,
	    _GetIDs
	  )$UDINT;
	  t_ConfigSSW :
	  (
	    _PrepareAccess,
	    _StartFirstAccess,
	    _StartAccess,
	    _Wait4Answer
	  )$UDINT;
#pragma pack(push, 1)
	  t_ConfigStruct : STRUCT
	    pData : pVoid;
	    Length : UINT;
	    Offset : HDINT;
	    BusConfigSSW : t_ConfigSSW;
	    SDOTimeMark : UDINT;
	    RestLength : UINT;
	    pActData : pVoid;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_FastTripleBufferConfig : STRUCT
	    SizeuCtoCPU : USINT;
	    SizeCPUtouC : USINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_FWVersion : STRUCT
	    aVersion : ARRAY [0..15] OF HDINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_HBG : STRUCT
	    pThis : pVirtualBase;
	    usExpectedDeviceID : USINT;
	    sdRequired : DINT;
	    pIOStates : ^HDINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_HwVersion : STRUCT
	    aVersion : ARRAY [0..15] OF HDINT;
	  END_STRUCT;
#pragma pack(pop)
	  t_InitSSW :
	  (
	    _PrepareInit,
	    _GetOptionalSettings,
	    _ReadModuleIDs,
	    _GetSafetyNr:=3,
	    _GetFirmwareVersion:=4,
	    _GetConfiguredState:=5,
	    _GetPDOSizes:=6,
	    _SetSysTime,
	    _DisablePLL,
	    _GetPLLSettings,
	    _ConfigurePLL,
	    _ConfigureTripleBufferAnalogReadData,
	    _ConfigureFastTripleBuffer,
	    _Finished,
	    _InitError
	  )$UDINT;
#pragma pack(push, 1)
	  t_LastSDO : STRUCT
	    Command : HINT;
	    Offset : DINT;
	    Length : UINT;
	    ResponseArrived : BOOL;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_LedAndIOStates : STRUCT
	    biLEDs : BINT
	    [
	      1 ValidationButtonBit0,
	      2 ValidationButtonBit1,
	      9 CanActiveBit0,
	      10 CanActiveBit1,
	      11 RunStateBit0,
	      12 RunStateBit1,
	      13 ServiceModeBit0,
	      14 ServiceModeBit1,
	      15 ErrorStateBit0,
	      16 ErrorStateBit1,
	    ];
	    HBGInputs : BINT
	    [
	    ];
	    IOStates : ARRAY [0..63] OF BSINT
	    [
	    ];
	  END_STRUCT;
#pragma pack(pop)
	  t_ModuleIDs : ARRAY [0..16] OF USINT;
#pragma pack(push, 1)
	  t_OptionalSettings : STRUCT
	    OptionalFlagsIOModules : BINT
	    [
	    ];
	    OptionalFlagHBG : BSINT
	    [
	    ];
	    ModuleIDsConfigured : ARRAY [0..15] OF USINT;
	    ModuleIDHBG : USINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_SyncConfig : STRUCT
	    Offset : UINT;
	    PeriodMultiplier : USINT;
	    SyncStartDelay : USINT;
	    SyncOutID : USINT;
	    ControlStatusRegister : BSINT
	    [
	      1 SyncOutEnable,
	      2 StartDelayEnable,
	      3 SyncSelector,
	    ];
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_PllRegister : STRUCT
	    SystemPeriodTime : UDINT;
	    SystemPeriodMeasured : UDINT;
	    StatusControl : BSINT
	    [
	      1 Locked,
	      2 Unlocked,
	      3 SyncEnable,
	    ];
	    PeriodDivider : BSINT
	    [
	    ];
	    CompensationDelay : USINT;
	    Reserved : USINT;
	    SyncOut0 : t_SyncConfig;
	    reserved2 : UINT;
	    SyncOut1 : t_SyncConfig;
	  END_STRUCT;
#pragma pack(pop)
	  t_ResponseState :
	  (
	    _idle,
	    _wait,
	    _valid
	  )$UDINT;
	  t_SerNoStr : ARRAY [0..11] OF CHAR;
#pragma pack(push, 1)
	  t_SafetySerNr : STRUCT
	    aSafetyNumbers : ARRAY [0..15] OF HDINT;
	    aSerialNumbers : ARRAY [0..15] OF t_SerNoStr;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_SdiasSafetyModuleInfo : STRUCT
	    pThis : pVirtualBase;
	    usExpectedDeviceID : USINT;
	    sdRequired : DINT;
	    usInputsNeeded : USINT;
	    usOutputsNeeded : USINT;
	    usIOsNeeded : USINT;
	    hdOutputMask : HDINT;
	    pIOStates : ^HDINT;
	    pUnsafeOutputStates : ^HDINT;
	    usAnalogInputByteSize : USINT;
	    pAnalogInputData : ^void;
	  END_STRUCT;
#pragma pack(pop)
	END_TYPE
  //Servers:
	DesignerPrjName 	: SvrChCmd_UDINT;
	DesignerPrjRev 	: SvrChCmd_UDINT;
	ValidationButtonState 	: SvrCh_DINT;
	FastUnsafeInputs 	: SvrCh_BDINT;
	FastUnsafeOutputs 	: SvrCh_BDINT;
	SdiasSafetyOut 	: SvrChCmd_DINT;
	CanOut 	: SvrChCmd_DINT;
	HGWOut 	: SvrChCmd_DINT;
	FCN_Command 	: SvrCh_UDINT;
	FCN_StateMachine 	: SvrCh_UDINT;
	FCN_HostSafetyNumber 	: SvrCh_HDINT;
  //Clients:
	ProjectNameStr 	: CltChCmd_String;
	ProjectRevisionStr 	: CltChCmd_String;
  //Variables:
		aSafetyModuleInfo : ARRAY [0..SDIAS_SAFETY_MAX_PLACE_NR] OF t_SdiasSafetyModuleInfo;

		aModuleIDs 	: t_ModuleIDs;
		MaxPlace 	: UDINT;
		Config 	: t_ConfigStruct;
		sPllRegister 	: t_PllRegister;
		eInitSSW 	: t_InitSSW;
		eInitSSWErrorStep 	: t_InitSSW;
		eInitAccessSSW 	: t_InitSSW;
		eInitAccessSSWErrorStep 	: t_InitSSW;
		eResponseState 	: t_ResponseState;
		SDOTimeMark 	: UDINT;
		LastSDO 	: t_LastSDO;
		b_AnyModuleRequired 	: BOOL;
		StateBytesUsed 	: UDINT;
		StateBitsUsed 	: UDINT;
		sHBG 	: t_HBG;
		sCPUConfig 	: t_ModuleCfg;
		sSafetySerNrs 	: t_SafetySerNr;
		CanActive 	: BOOL;
		OldCanActive 	: BOOL;
		b_DOsCreated 	: BOOL;
		RtRefreshData 	: t_RtRefresh;
		eCheckIDSSW 	: t_CheckIDSSW;
		pFastUnsafeOutThis 	: pVirtualBase;
		bUpdateModuleConfig 	: BOOL;
		b_GetOptionalSettings 	: BOOL;
		b_GotOptionalSettings 	: BOOL;
		OptionalSettings 	: t_OptionalSettings;
		usActStepRetries 	: USINT;
		usWrongDataCnt 	: USINT;
		sHwVersions 	: t_HwVersion;
		sFWVersions 	: t_FWVersion;
		ud_ResetGoneTime 	: UDINT;
		sAnalogTripleBufferConfig 	: t_AnalogTripleBufferConfig;
		sFastTripleBufferConfig 	: t_FastTripleBufferConfig;
		usMsgCntRead 	: USINT;
		bWriteAnalogTripleBufferConfig 	: BOOL;
		udAnalogInputByteSizeCalculated 	: UDINT;
  //Functions:
	
	FUNCTION VIRTUAL GLOBAL CyWork
		VAR_INPUT
			EAX 	: UDINT;
		END_VAR
		VAR_OUTPUT
			state (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL Background
		VAR_INPUT
			EAX 	: UDINT;
		END_VAR
		VAR_OUTPUT
			state (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION SdiasSafetyManagerFSoE
		VAR_OUTPUT
			ret_code 	: ConfStates;
		END_VAR;
				//! <Function Comment="initialize safety module (e.g. CPU) specific data" Name="InitSafeModule"/>
	FUNCTION VIRTUAL InitSafeModule
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
				//! <Function Comment="update of non SDO and PDO data" Name="UpDateNotStd"/>
	FUNCTION VIRTUAL UpDateNotStd
		VAR_INPUT
			calloption 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL ShowProjectRevision;
	
	FUNCTION VIRTUAL GLOBAL DisconnectEvent;
	
	FUNCTION VIRTUAL GetConfiguration;
	
	FUNCTION VIRTUAL SetSafetyState
		VAR_INPUT
			NewState 	: SafetyConfigStateType;
		END_VAR;
	
	FUNCTION VIRTUAL RefreshAsySrv;
	
	FUNCTION VIRTUAL SetRetryCounter;
	
	FUNCTION VIRTUAL SafeActModuleConfig
		VAR_INPUT
			sActModuleConfig 	: t_ModuleCfg;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL InitModule
		VAR_OUTPUT
			ModuleInitState 	: iprStates;
		END_VAR;
	
	FUNCTION GLOBAL InitAccess
		VAR_OUTPUT
			AccessInitState 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL BusConfigWrite
		VAR_INPUT
			Offset 	: HDINT;
			Length 	: UINT;
			pData 	: pVoid;
			IsControlAccess 	: BOOL := FALSE;
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL BusConfigRead
		VAR_INPUT
			Offset 	: HDINT;
			Length 	: UINT;
			pData 	: pVoid;
			IsControlAccess 	: BOOL := FALSE;
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL HwDiagFreeDynExtList
		VAR_INPUT
			pList 	: ^t_HWCGetHardwareDiagnosisOutDynExt;
		END_VAR;
	
	FUNCTION VIRTUAL HwDiagAddDynExt2List
		VAR_INPUT
			ppList 	: ^t_pHWCGetHardwareDiagnosisOutDynExt;
			EntryID 	: t_HWCGetHardwareDiagnosisOutType;
			udVersion 	: UDINT;
			udDataLength 	: UDINT;
		END_VAR
		VAR_OUTPUT
			pNewElement 	: t_pHWCGetHardwareDiagnosisOutDynExt;
		END_VAR;
	
	FUNCTION VIRTUAL GetFWVersion
		VAR_INPUT
			udPlace 	: UDINT;
			pData 	: ^CHAR;
			Length 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL ClassSvr::NewInst
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL FastUnsafeInputs::Write
		VAR_INPUT
			input (EAX) 	: BDINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: BDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL FastUnsafeOutputs::Write
		VAR_INPUT
			input (EAX) 	: BDINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: BDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL SdiasSafetyOut::NewInst
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL CanOut::NewInst
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL HGWOut::NewInst
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL FCN_Command::Write
		VAR_INPUT
			input (EAX) 	: UDINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: UDINT;
		END_VAR;
  //Tables:
	FUNCTION @STD
		VAR_OUTPUT
			ret_code	: CONFSTATES;
		END_VAR;
	FUNCTION GLOBAL TAB @CT_;
END_CLASS;

#pragma using String


//}}LSL_DECLARATION


FUNCTION GLOBAL TAB SdiasSafetyManagerFSoE::@CT_
0$UINT,
2#0100000000000000$UINT, //TY_SDIASSAFETYMANAGERFSOE
1$UINT, 40$UINT, (SIZEOF(::SdiasSafetyManagerFSoE))$UINT, 
11$UINT, 2$UINT, 0$UINT, 
TO_UDINT(1131165733), "SdiasSafetyManagerFSoE", //Class
TO_UDINT(3466252013), "SafetyBaseFSoE", 1$UINT, 38$UINT, //Baseclass
//Servers:
(::SdiasSafetyManagerFSoE.DesignerPrjName.pMeth)$UINT, _CH_SVR_OBJ$UINT, 2#0000000001000000$UINT, TO_UDINT(2397083450), "DesignerPrjName", 
(::SdiasSafetyManagerFSoE.DesignerPrjRev.pMeth)$UINT, _CH_SVR_OBJ$UINT, 2#0000000001000000$UINT, TO_UDINT(2854741250), "DesignerPrjRev", 
(::SdiasSafetyManagerFSoE.ValidationButtonState.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2335086012), "ValidationButtonState", 
(::SdiasSafetyManagerFSoE.FastUnsafeInputs.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1891345754), "FastUnsafeInputs", 
(::SdiasSafetyManagerFSoE.FastUnsafeOutputs.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(766673388), "FastUnsafeOutputs", 
(::SdiasSafetyManagerFSoE.SdiasSafetyOut.pMeth)$UINT, _CH_CMD$UINT, 2#0000000000000000$UINT, TO_UDINT(1660330439), "SdiasSafetyOut", 
(::SdiasSafetyManagerFSoE.CanOut.pMeth)$UINT, _CH_CMD$UINT, 2#0000000000000000$UINT, TO_UDINT(4133122455), "CanOut", 
(::SdiasSafetyManagerFSoE.HGWOut.pMeth)$UINT, _CH_CMD$UINT, 2#0000000000000000$UINT, TO_UDINT(1053584609), "HGWOut", 
(::SdiasSafetyManagerFSoE.FCN_Command.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2520919212), "FCN_Command", 
(::SdiasSafetyManagerFSoE.FCN_StateMachine.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(3844074925), "FCN_StateMachine", 
(::SdiasSafetyManagerFSoE.FCN_HostSafetyNumber.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(3307951323), "FCN_HostSafetyNumber", 
//Clients:
(::SdiasSafetyManagerFSoE.ProjectNameStr.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000010$UINT, TO_UDINT(1313311979), "ProjectNameStr", TO_UDINT(1850111279), "String", 1$UINT, 11$UINT, 
(::SdiasSafetyManagerFSoE.ProjectRevisionStr.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000010$UINT, TO_UDINT(1540301848), "ProjectRevisionStr", TO_UDINT(1850111279), "String", 1$UINT, 11$UINT, 
END_FUNCTION


#define USER_CNT_SdiasSafetyManagerFSoE 77

TYPE
	_LSL_STD_VMETH	: STRUCT
			CmdTable	: CMDMETH;
			UserFcts	: ARRAY[0..USER_CNT_SdiasSafetyManagerFSoE] OF ^Void;
	END_STRUCT;
END_TYPE

FUNCTION SdiasSafetyManagerFSoE::@STD
	VAR_OUTPUT
		ret_code	: CONFSTATES;
	END_VAR
	VAR
		vmt	: _LSL_STD_VMETH;
		nCmdSize	: UINT;
	END_VAR

	ret_code	:= SafetyBaseFSoE::@STD();
	IF ret_code <> C_OK THEN
		RETURN;
	END_IF;
	nCmdSize		:= SafetyBaseFSoE::ClassSvr.pMeth^.nCmds$UINT*SIZEOF(pVoid) + CMDMETH.Init;

	_memcpy((#vmt.CmdTable)$^USINT, SafetyBaseFSoE::ClassSvr.pMeth, nCmdSize);
	vmt.CmdTable.nCmds		:= nSTDCMD + USER_CNT_SdiasSafetyManagerFSoE;
	vmt.CmdTable.NewInstr		:= #ClassSvr::NewInst();
	vmt.CmdTable.CyWork		:= #CyWork();
#pragma warning (disable : 74)
	vmt.UserFcts[0]		:= #Background();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[29]		:= #InitSafeModule();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[31]		:= #UpDateNotStd();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[51]		:= #ShowProjectRevision();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[61]		:= #DisconnectEvent();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[63]		:= #GetConfiguration();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[64]		:= #SetSafetyState();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[65]		:= #RefreshAsySrv();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[66]		:= #SetRetryCounter();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[68]		:= #SafeActModuleConfig();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[71]		:= #InitModule();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[72]		:= #BusConfigWrite();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[73]		:= #BusConfigRead();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[74]		:= #HwDiagFreeDynExtList();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[75]		:= #HwDiagAddDynExt2List();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[76]		:= #GetFWVersion();

#pragma warning (default : 74)
	SafetyBaseFSoE::ClassSvr.pMeth		:= StoreCmd (pCmd := #vmt.CmdTable, SHARED);

	IF SafetyBaseFSoE::ClassSvr.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	_memcpy((#vmt.CmdTable)$^USINT, DesignerPrjName.pMeth, SIZEOF(CMDMETH));
	vmt.CmdTable.nCmds		:= nSTDCMD;
	DesignerPrjName.pMeth		:= StoreCmd (pCmd := #vmt.CmdTable, SHARED);

	IF DesignerPrjName.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	_memcpy((#vmt.CmdTable)$^USINT, DesignerPrjRev.pMeth, SIZEOF(CMDMETH));
	vmt.CmdTable.nCmds		:= nSTDCMD;
	DesignerPrjRev.pMeth		:= StoreCmd (pCmd := #vmt.CmdTable, SHARED);

	IF DesignerPrjRev.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	FastUnsafeInputs.pMeth			:= StoreMethod( #M_RD_DIRECT(), #FastUnsafeInputs::Write() );
	IF FastUnsafeInputs.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	FastUnsafeOutputs.pMeth			:= StoreMethod( #M_RD_DIRECT(), #FastUnsafeOutputs::Write() );
	IF FastUnsafeOutputs.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	_memcpy((#vmt.CmdTable)$^USINT, SdiasSafetyOut.pMeth, SIZEOF(CMDMETH));
	vmt.CmdTable.nCmds		:= nSTDCMD;
	vmt.CmdTable.NewInstr		:= #SdiasSafetyOut::NewInst();
	SdiasSafetyOut.pMeth		:= StoreCmd (pCmd := #vmt.CmdTable, SHARED);

	IF SdiasSafetyOut.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	_memcpy((#vmt.CmdTable)$^USINT, CanOut.pMeth, SIZEOF(CMDMETH));
	vmt.CmdTable.nCmds		:= nSTDCMD;
	vmt.CmdTable.NewInstr		:= #CanOut::NewInst();
	CanOut.pMeth		:= StoreCmd (pCmd := #vmt.CmdTable, SHARED);

	IF CanOut.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	_memcpy((#vmt.CmdTable)$^USINT, HGWOut.pMeth, SIZEOF(CMDMETH));
	vmt.CmdTable.nCmds		:= nSTDCMD;
	vmt.CmdTable.NewInstr		:= #HGWOut::NewInst();
	HGWOut.pMeth		:= StoreCmd (pCmd := #vmt.CmdTable, SHARED);

	IF HGWOut.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	FCN_Command.pMeth			:= StoreMethod( #M_RD_DIRECT(), #FCN_Command::Write() );
	IF FCN_Command.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	ret_code	:= SdiasSafetyManagerFSoE();

END_FUNCTION

//{{LSL_IMPLEMENTATION
VAR_EXTERNAL
  pSafetyManagerThis   : pVirtualBase;
// b_SafetyOnLocalCDIAS = TRUE means there is a CDIAS safety module on local CDIAS/SDIAS Bus => using internal move command is not possible
  b_SafetyOnLocalCDIAS : BOOL;
END_VAR

VAR_PRIVATE  
  a_SerialNo			      : ARRAY[0..sizeof(SdiasSafetyManagerFSoE::t_SerNoStr) ] OF CHAR;  
  a_FWVersion           : ARRAY[0..43] OF CHAR;  
  a_HWTEntryStr         : ARRAY[0.. VARAN_MAX_DEPTH+1] OF CHAR; //+1 because lenght is 2 byte
  pAdditionalDiagInfo   : ^t_HWCGetHardwareDiagnosisOutDynExt;
END_VAR

FUNCTION VIRTUAL GLOBAL SdiasSafetyManagerFSoE::SdiasSafetyOut::NewInst
  VAR_INPUT
    pPara 	: ^CmdStruct;
    pResult 	: ^results;
  END_VAR
  VAR_OUTPUT
    ret_code 	: iprStates;
  END_VAR
  VAR
    Place             : UDINT;
    tempCmd           : CmdStruct;
    _result           : results;
    pSafetyModuleInfo : ^t_SdiasSafetyModuleInfo;
  END_VAR
  
  ret_code := READY;

  CASE pPara^.uiCmd OF
//**********************************************************************************************************************************************************
    SDIAS_SAFETY_LOGIN:
      // check parameters
      if pPara^.aPara[0] & (pPara^.aPara[1]$UDINT < SDIAS_SAFETY_MAX_MODULE_NO) then
        // save the module info
        Place := pPara^.aPara[1]$UDINT;
        pSafetyModuleInfo := #aSafetyModuleInfo[Place];
        
        pSafetyModuleInfo^.pThis               := pPara^.aPara[0]$pVirtualBase;
        pSafetyModuleInfo^.usExpectedDeviceID  := pPara^.aPara[2]$USINT;
        pSafetyModuleInfo^.sdRequired          := pPara^.aPara[3];
        pSafetyModuleInfo^.usInputsNeeded      := pPara^.aPara[4]$USINT;
        pSafetyModuleInfo^.usOutputsNeeded     := pPara^.aPara[5]$USINT;
        pSafetyModuleInfo^.pIOStates           := pPara^.aPara[6]$^HDINT;
        pSafetyModuleInfo^.pUnsafeOutputStates := pPara^.aPara[7]$^HDINT;

        // saves time, because we don't have to add them in rt
        pSafetyModuleInfo^.usIOsNeeded := pSafetyModuleInfo^.usInputsNeeded + pSafetyModuleInfo^.usOutputsNeeded;

        // output mask to write the correct number of outputs to the memory (set as many bits as we need outputs)
        pSafetyModuleInfo^.hdOutputMask := to_udint(2.0**to_real(pSafetyModuleInfo^.usOutputsNeeded)) - 1;

        InputsCount  += pSafetyModuleInfo^.usInputsNeeded;
        OutputsCount += pSafetyModuleInfo^.usOutputsNeeded;

        // remember the highest place to save time in module scanning operations
        if (Place > MaxPlace) | (MaxPlace = SDIAS_SAFETY_INVALID_MAX_PLACE) then
          MaxPlace := Place;
        end_if;
        
        // if leds/hgb not added so far, add them
        if StateBytesUsed = 0 then
          StateBitsUsed := (sizeof(t_LedAndIOStates.biLEDs) + sizeof(t_LedAndIOStates.HBGInputs)) * 8;
        end_if;
        
        // add the number of used bits (2 bits for every I/O)
        StateBitsUsed += 2 * pSafetyModuleInfo^.usIOsNeeded;
        
        // refresh state bytes used value
        StateBytesUsed := ((StateBitsUsed-1) / 8) + 1;
        
        if pSafetyModuleInfo^.sdRequired & (b_AnyModuleRequired = FALSE) then
          b_AnyModuleRequired := TRUE;
          // if any access is required => the businterface is also required
          tempCmd.uiCmd := _BUS_IF_SET_REQUIRED;
          ToBusInterface.NewInst(pPara:=#tempCmd, pResult:=#_result);
          if _result.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then  
            LogError("@029D (SdiasSafetyManagerFSoE::SdiasSafetyOut::NewInst) Failed to set the BusInterface to required.");
          end_if;
        end_if;
      else
        ret_code := ERROR;
      end_if; 

//**********************************************************************************************************************************************************
    SDIAS_SAFETY_LOGIN_V2:
        
      //Check different versions
      if pPara^.aPara[0] = 0x01 then
      
        // check for valid this pointer and place number
        if pPara^.aPara[1] & (pPara^.aPara[2]$UDINT < SDIAS_SAFETY_MAX_MODULE_NO) then
        
          // save the module info
          Place := pPara^.aPara[2]$UDINT;
          pSafetyModuleInfo := #aSafetyModuleInfo[Place];
          
          pSafetyModuleInfo^.pThis                  := pPara^.aPara[1]$pVirtualBase;
          pSafetyModuleInfo^.usExpectedDeviceID     := pPara^.aPara[3]$USINT;
          pSafetyModuleInfo^.sdRequired             := pPara^.aPara[4];
          pSafetyModuleInfo^.usInputsNeeded         := pPara^.aPara[5]$USINT;
          pSafetyModuleInfo^.usOutputsNeeded        := pPara^.aPara[6]$USINT;
          pSafetyModuleInfo^.pIOStates              := pPara^.aPara[7]$^HDINT;
          pSafetyModuleInfo^.pUnsafeOutputStates    := pPara^.aPara[8]$^HDINT;
          pSafetyModuleInfo^.usAnalogInputByteSize  := pPara^.aPara[9]$USINT;
          pSafetyModuleInfo^.pAnalogInputData       := pPara^.aPara[10]$^HDINT;
          
          if pSafetyModuleInfo^.usAnalogInputByteSize then
            if pSafetyModuleInfo^.pAnalogInputData = NIL then
              ret_code := ERROR;            
              LogError("@0793 (SdiasSafetyManagerFSoE::SdiasSafetyOut::NewInst) Pointer for analog input data is invalid.");   
            else
              //Check if this is the first time we add an analog input module
              if usAnalogInputByteSize = 0 then
                usAnalogInputByteSize += pSafetyModuleInfo^.usAnalogInputByteSize + sizeof(USINT);  //Add one byte for message counter if not added yet (first byte of analog input buffer is messagecounter)
              else
                usAnalogInputByteSize += pSafetyModuleInfo^.usAnalogInputByteSize;          
              end_if;
            end_if;
          end_if;

          // saves time, because we don't have to add them in rt
          pSafetyModuleInfo^.usIOsNeeded := pSafetyModuleInfo^.usInputsNeeded + pSafetyModuleInfo^.usOutputsNeeded;

          // output mask to write the correct number of outputs to the memory (set as many bits as we need outputs)
          pSafetyModuleInfo^.hdOutputMask := to_udint(2.0**to_real(pSafetyModuleInfo^.usOutputsNeeded)) - 1;

          InputsCount  += pSafetyModuleInfo^.usInputsNeeded;
          OutputsCount += pSafetyModuleInfo^.usOutputsNeeded;
          
          // remember the highest place to save time in module scanning operations
          if (Place > MaxPlace) | (MaxPlace = SDIAS_SAFETY_INVALID_MAX_PLACE) then
            MaxPlace := Place;
          end_if;
          
          // if leds/hgb not added so far, add them
          if StateBytesUsed = 0 then
            StateBitsUsed := (sizeof(t_LedAndIOStates.biLEDs) + sizeof(t_LedAndIOStates.HBGInputs)) * 8;
          end_if;
          
          // add the number of used bits (2 bits for every I/O)
          StateBitsUsed += 2 * pSafetyModuleInfo^.usIOsNeeded;
          
          // refresh state bytes used value
          StateBytesUsed := ((StateBitsUsed-1) / 8) + 1;
          
          if pSafetyModuleInfo^.sdRequired & (b_AnyModuleRequired = FALSE) then
            b_AnyModuleRequired := TRUE;
            // if any access is required => the businterface is also required
            tempCmd.uiCmd := _BUS_IF_SET_REQUIRED;
            ToBusInterface.NewInst(pPara:=#tempCmd, pResult:=#_result);
            if _result.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then  
              LogError("@029D (SdiasSafetyManagerFSoE::SdiasSafetyOut::NewInst) Failed to set the BusInterface to required.");
            end_if;
          end_if;
        else
          ret_code := ERROR;
          LogError("@0795 (SdiasSafetyManagerFSoE::SdiasSafetyOut::NewInst) This pointer or place number invalid.");
        end_if; 
      
      else
        LogError("@0796 (SdiasSafetyManagerFSoE::SdiasSafetyOut::NewInst) Version of NewInst command SDIAS_SAFETY_LOGIN_V2 not supported.");
        //Not supported at the moment
        ret_code := ERROR;
      end_if;
            
//**********************************************************************************************************************************************************
    SDIAS_SET_QUITCOMERROR_IO:
      ret_code$DINT := QuitComError.Write(input:=pPara^.aPara[0]);
      
//**********************************************************************************************************************************************************
    // forward commands from clients to manager 
    SDIAS_CMD_ADD_RD_ACCESS,
    SDIAS_CMD_ADD_WR_ACCESS,
    SDIAS_CMD_SDO_SEND_REQUEST,
    SDIAS_CMD_CHANGE_LED_STATE,
    SDIAS_CMD_DA_RD_ACCESS,
    SDIAS_CMD_DA_WR_ACCESS,
    SDIAS_CMD_REQUIRED_ERROR,
    SDIAS_CMD_INIT_STATE_LOGIN,
    SDIAS_CMD_GET_HW_PATH,
    SDIAS_CMD_INSTALL_CYCLIC_TASK,
    SDIAS_CMD_GET_CONNECTION_TYPE,
    SDIAS_CMD_GET_MIB_ADDR,
    SDIAS_CMD_GET_MOI_ADDR,
    SDIAS_CMD_ADD_DYN_RD_ACCESS,
    SDIAS_CMD_ADD_DYN_WR_ACCESS,
    SDIAS_CMD_CHANGE_DYN_ACCESS,
    SDIAS_CMD_CREATE_MUTEX,
    SDIAS_CMD_IS_VARAN_AVAILABLE,
    SDIAS_CMD_GET_OWN_OBJECTPATH,
    SDIAS_CMD_ADD_DEVICE_ID,
    SDIAS_CMD_GET_SUPPORTED_FEATURES:
      ret_code := ToBusInterface.NewInst(pPara, pResult);
//**********************************************************************************************************************************************************
  END_CASE;

END_FUNCTION


FUNCTION SdiasSafetyManagerFSoE::SdiasSafetyManagerFSoE
  VAR_OUTPUT
    ret_code 	: ConfStates;
  END_VAR

  MaxPlace := SDIAS_SAFETY_INVALID_MAX_PLACE;

  // reset pointer used for additional diagnosis information
  pAdditionalDiagInfo := NIL;
  
  sFlexCon.pCommand               := #FCN_Command;
  sFlexCon.pStateMachine          := #FCN_StateMachine;
  sFlexCon.pHostSafetyNumber      := #FCN_HostSafetyNumber;

  ret_code := C_OK;

END_FUNCTION


FUNCTION VIRTUAL SdiasSafetyManagerFSoE::UpDateNotStd
  VAR_INPUT
    calloption 	: UDINT;
  END_VAR
  VAR
    i                       : UDINT;
    pSafetyModuleInfo       : ^t_SdiasSafetyModuleInfo;
    sTempStates             : t_LedAndIOStates;
    pActIOStates            : ^BSINT;
    usActIOBitsUsed         : USINT;
    pActUnsafeOuts          : ^BSINT;
    usActUnsafeOutBitsUsed  : USINT;
    MyPara 	                : CmdStruct;
    MyResult	              : results;
    sAnalogInputData        : ARRAY [0..255] OF USINT;
    usActAnalogInDataOffset : USINT;
    pActAnalogInData        : ^USINT;
  	pActFastUnsafeInput     : ^UnsafeIORoutingElement;
    pActFastUnsafeOutput    : ^UnsafeIORoutingElement;
    pTempStartBufferIn      : ^void;
    pTempStartBufferOut     : ^void;
    bAnyChanges             : BOOL;
    NewValue                : DINT;
    pBufferValue            : ^DINT;
  END_VAR 

  // copy only as many data as we need (safe time, because this may be PCI accesses)
  _memcpy(ptr1:=#sTempStates, ptr2:=pLEDandIOStates, cntr:=StateBytesUsed);
  
  if usAnalogInputByteSize then
    if aAnalogInputReadDOs[0].Length then
      _memcpy(ptr1:=#sAnalogInputData[0], ptr2:=aAnalogInputReadDOs[0].pData, cntr:=aAnalogInputReadDOs[0].Length);
    end_if;
    if aAnalogInputReadDOs[1].Length then
      _memcpy(ptr1:=#sAnalogInputData[SBF_MAX_BUS_USAGE], ptr2:=aAnalogInputReadDOs[1].pData, cntr:=aAnalogInputReadDOs[1].Length);
    end_if;
  end_if;


  if calloption = CALL_OPTION_RT_PRESCAN then
  
    // if AcceptState bit is set => accept state
    if sTempStates.biLEDs.ValidationButtonBit1 then
      ValidationButtonState := sTempStates.biLEDs.ValidationButtonBit0;
    else
      // otherwise, we have a blink code => state 2 or 3
      ValidationButtonState := sTempStates.biLEDs.ValidationButtonBit0 OR 2#10;
    end_if;
    RtRefreshData.LEDValidationButtonState := ValidationButtonState;

    // if AcceptState bit is set => accept state
    if sTempStates.biLEDs.CanActiveBit1 then
      CanActive := sTempStates.biLEDs.CanActiveBit0;
    end_if;

    // if AcceptState bit is set => accept state
    if sTempStates.biLEDs.RunStateBit1 then
      RunState := sTempStates.biLEDs.RunStateBit0;
    else
      // otherwise, there's an error
      RunState := -1;
    end_if;
    RtRefreshData.LEDRunState := RunState;

    // if AcceptState bit is set => accept state
    if sTempStates.biLEDs.ServiceModeBit1 then
      ServiceMode := sTempStates.biLEDs.ServiceModeBit0;
    else
      // otherwise, we have a blink code => state 2
      ServiceMode := 2;
    end_if;
    RtRefreshData.LEDServiceMode := ServiceMode;

    // if AcceptState bit is set => accept state
    if sTempStates.biLEDs.ErrorStateBit1 then
      ErrorState := sTempStates.biLEDs.ErrorStateBit0;
    else
      // otherwise, we have a blink code => state 2
      ErrorState := 2;
    end_if;
    RtRefreshData.LEDErrorState := ErrorState;

    // if we got a HBG, refresh it's inputs first
    if sHBG.pThis then
      // select the IO bits for the next module (shift out the IO bits we already used before)
      sHBG.pIOStates^ := sTempStates.HBGInputs;

      // let the module update the io servers
      sHBG.pThis^.RtWork(0);
    end_if;
    
    // if there are modules to update
    if MaxPlace <> SDIAS_SAFETY_INVALID_MAX_PLACE then
      pSafetyModuleInfo := #aSafetyModuleInfo[0];
      
      pActIOStates := #sTempStates.IOStates[0];

      pActAnalogInData := #sAnalogInputData[1]; //index 1 because index 0 is messagecounter
      
      usActAnalogInDataOffset := 0;
      usActIOBitsUsed := 0;
      
      for i := 0 to MaxPlace do
        if (pSafetyModuleInfo^.pThis) & (pSafetyModuleInfo^.usInputsNeeded | pSafetyModuleInfo^.usAnalogInputByteSize) then // if there are digital/analog inputs available
          if (pSafetyModuleInfo^.pThis^.pSvrChCmd$t_e_VaranErrors = _ClassOk) then
    //*****************************************************************************
    //** IO STATES FOR THE LOCAL INPUTS (DIGITAL AND ANALOG)                     **
    //*****************************************************************************
    
            if pSafetyModuleInfo^.usInputsNeeded then
              // select the IO bits for the next module (shift out the IO bits we already used before)
              pSafetyModuleInfo^.pIOStates^ := (pActIOStates$^HDINT)^ SHR usActIOBitsUsed;
            end_if;
            
            if pSafetyModuleInfo^.usAnalogInputByteSize then
              // Copy the analog input values to the module
              _memcpy(ptr1:=pSafetyModuleInfo^.pAnalogInputData, ptr2:=pActAnalogInData, cntr:=pSafetyModuleInfo^.usAnalogInputByteSize);
            end_if;
      
            // let the module update the io servers
            pSafetyModuleInfo^.pThis^.RtWork(0);
            
            if pSafetyModuleInfo^.usInputsNeeded then
              // increase the number of used bits (every input needs 2 bit)
              usActIOBitsUsed += pSafetyModuleInfo^.usInputsNeeded * 2;
              
              // increase pointer if we already passed more than 1 byte
              pActIOStates += usActIOBitsUsed / 8;
              
              // remember the rest of the bits
              usActIOBitsUsed := usActIOBitsUsed MOD 8;
            end_if;
            
            if pSafetyModuleInfo^.usAnalogInputByteSize then
              //Increase offset and pointer
              usActAnalogInDataOffset += pSafetyModuleInfo^.usAnalogInputByteSize;
              pActAnalogInData        += pSafetyModuleInfo^.usAnalogInputByteSize;      
            end_if;

          else
            //if modul is optional and class state is <> _ClassOk the io state pointer must be set to next entry
            if ((OptionalSettings.OptionalFlagsIOModules SHR i) and 0x01) = TRUE then
                        
              if pSafetyModuleInfo^.usInputsNeeded then
                // select the IO bits for the next module (shift out the IO bits we already used before)
                pSafetyModuleInfo^.pIOStates^ := (pActIOStates$^HDINT)^ SHR usActIOBitsUsed;
              end_if;
              
              if pSafetyModuleInfo^.usAnalogInputByteSize then
                // Copy the analog input values to the module
                _memcpy(ptr1:=pSafetyModuleInfo^.pAnalogInputData, ptr2:=pActAnalogInData, cntr:=pSafetyModuleInfo^.usAnalogInputByteSize);
              end_if;
        
              if pSafetyModuleInfo^.usInputsNeeded then
                // increase the number of used bits (every input needs 2 bit)
                usActIOBitsUsed += pSafetyModuleInfo^.usInputsNeeded * 2;
                
                // increase pointer if we already passed more than 1 byte
                pActIOStates += usActIOBitsUsed / 8;
                
                // remember the rest of the bits
                usActIOBitsUsed := usActIOBitsUsed MOD 8;
              end_if;
              
              if pSafetyModuleInfo^.usAnalogInputByteSize then
                //Increase offset and pointer
                usActAnalogInDataOffset += pSafetyModuleInfo^.usAnalogInputByteSize;
                pActAnalogInData        += pSafetyModuleInfo^.usAnalogInputByteSize;      
              end_if;
              
            end_if;
          end_if;          
        end_if;

        pSafetyModuleInfo += sizeof(t_SdiasSafetyModuleInfo);
      end_for;

      // start again with the first module
      pSafetyModuleInfo := #aSafetyModuleInfo[0];

      // now we got the io states for the outputs
      for i := 0 to MaxPlace do
        if (pSafetyModuleInfo^.pThis) &  pSafetyModuleInfo^.usOutputsNeeded then // if there are outputs available
          if (pSafetyModuleInfo^.pThis^.pSvrChCmd$t_e_VaranErrors = _ClassOk) then
  //*****************************************************************************
  //** IO STATES FOR THE LOCAL OUTPUTS                                         **
  //*****************************************************************************
            // select the IO bits for the next module (shift out the IO bits we already used before)
            pSafetyModuleInfo^.pIOStates^ := (pActIOStates$^HDINT)^ SHR usActIOBitsUsed;

            // let the module update the io servers
            pSafetyModuleInfo^.pThis^.RtWork(1);
            
            // increase the number of used bits (every output needs 2 bit)
            usActIOBitsUsed += pSafetyModuleInfo^.usOutputsNeeded * 2;
            
            // increase pointer if we already passed more than 1 byte
            pActIOStates += usActIOBitsUsed / 8;
            
            // remember the rest of the bits
            usActIOBitsUsed := usActIOBitsUsed MOD 8;
          else
            //if modul is optional and class state is <> _ClassOk the io state pointer must be set to next entry
            if ((OptionalSettings.OptionalFlagsIOModules SHR i) and 0x01) = TRUE then            
              // select the IO bits for the next module (shift out the IO bits we already used before)
              pSafetyModuleInfo^.pIOStates^ := (pActIOStates$^HDINT)^ SHR usActIOBitsUsed;
              
              // increase the number of used bits (every output needs 2 bit)
              usActIOBitsUsed += pSafetyModuleInfo^.usOutputsNeeded * 2;
              
              // increase pointer if we already passed more than 1 byte
              pActIOStates += usActIOBitsUsed / 8;
              
              // remember the rest of the bits
              usActIOBitsUsed := usActIOBitsUsed MOD 8;
            end_if;          
          end_if;
        end_if;

        pSafetyModuleInfo += sizeof(t_SdiasSafetyModuleInfo);
      end_for;
    end_if;

    // the module config has to be valid before we do anything related to fast unsafe variables (the info about the fast unsafe variables is part of the config)

    // only enter if it was valid and then set it to locked (don't use return inside if before swapping back via sigclib_atomic_swpU32)
    if sigclib_atomic_cmpxchgU32(pValue:=#udConfigValid, cmpVal:=SBF_LOCKCFG_VALID, newVal:=SBF_LOCKCFG_WAIT4RT) = SBF_LOCKCFG_VALID then
      if b_FastUnsafeOutputsActive then
        FastUnsafeOutputs := pFastUnsafeOutputs^;
        RtRefreshData.FastUnsafeOutputs := FastUnsafeOutputs;
      elsif ui_CntFastUnsafeOutputs then

        //Read msg cnt
        usMsgCntRead :=  aFastUnsafeReadDOs[0].pData^$USINT;
        
        //check for valid message counter   
        if (usMsgCntRead <> 0) then
          pTempStartBufferOut := pFastUnsafeOutBuffer;   
          for i := 0 to ReadFastUnsafeDOsUsed - 1 do
            //copy data into buffer
            _memcpy(ptr1:=pTempStartBufferOut, ptr2:=aFastUnsafeReadDOs[i].pData, cntr:=aFastUnsafeReadDOs[i].Length);
            
            //first DO readed -> set pointer to next DO
            pTempStartBufferOut += aFastUnsafeReadDOs[i].Length;
          end_for;

          pActFastUnsafeOutput := p_FastUnsafeOutputsTable;
          for i := 1 to ui_CntFastUnsafeOutputs do 
            if pActFastUnsafeOutput^.ud_Thisp <> NIL then        
              //write value to server
              WR(pActFastUnsafeOutput^.ud_Thisp$^void, (pActFastUnsafeOutput^.ud_Address$^DINT)^);
            end_if;
            
            //step to next entry
            pActFastUnsafeOutput += sizeof(UnsafeIORoutingElement);
          end_for;      
        end_if;
      end_if;
      
      // set config valid again (from locked)
      sigclib_atomic_swpU32(pValue:=#udConfigValid, swpVal:=SBF_LOCKCFG_VALID);
    end_if;
    
    MyPara.uiCmd := SDIAS_SET_RT_DATA;
    MyPara.aPara[0] := (#RtRefreshData)$DINT;
    ToBusInterface.NewInst(#MyPara, #MyResult);
    
    if pFastUnsafeOutThis then
      pFastUnsafeOutThis^.NewInst(#MyPara, #MyResult);
    end_if;
  
  elsif calloption = CALL_OPTION_RT_POSTSCAN then
  
    // if there are modules to update
    if MaxPlace <> SDIAS_SAFETY_INVALID_MAX_PLACE then
      pSafetyModuleInfo := #aSafetyModuleInfo[0];     
     
      pActUnsafeOuts := pUnsafeOutWrData;
      usActUnsafeOutBitsUsed := 0;

      // now we got the io states for the outputs
      for i := 0 to MaxPlace do
          if (( pSafetyModuleInfo^.pThis) & 
              ( pSafetyModuleInfo^.pThis^.pSvrChCmd$t_e_VaranErrors = _ClassOk )) then

    //*****************************************************************************
    //** UNSAFE ENABLE SIGNALS FOR OUTPUTS                                       **
    //*****************************************************************************
          // if there are outputs available
          if pSafetyModuleInfo^.usOutputsNeeded then
  
              // we take the part of the old value which is not modified by our masked bits and save our masked bits into the right place
              (pActUnsafeOuts$^HDINT)^ := ((pActUnsafeOuts$^HDINT)^ AND (NOT (pSafetyModuleInfo^.hdOutputMask SHL usActUnsafeOutBitsUsed))) OR ((pSafetyModuleInfo^.pUnsafeOutputStates^ AND pSafetyModuleInfo^.hdOutputMask) SHL usActUnsafeOutBitsUsed);
              
              // increase the number of used bits
              usActUnsafeOutBitsUsed += pSafetyModuleInfo^.usOutputsNeeded;
              
              // increase pointer if we already passed more than 1 byte
              pActUnsafeOuts += usActUnsafeOutBitsUsed / 8;
              
              // remember the rest of the bits
              usActUnsafeOutBitsUsed := usActUnsafeOutBitsUsed MOD 8;
          end_if;
        end_if;

        pSafetyModuleInfo += sizeof(t_SdiasSafetyModuleInfo);
      end_for;
    end_if; 
  
  
    // the module config has to be valid before we do anything related to fast unsafe variables (the info about the fast unsafe variables is part of the config)
    
    // only enter if it was valid and then set it to locked (don't use return inside if before swapping back via sigclib_atomic_swpU32)
    if sigclib_atomic_cmpxchgU32(pValue:=#udConfigValid, cmpVal:=SBF_LOCKCFG_VALID, newVal:=SBF_LOCKCFG_WAIT4RT) = SBF_LOCKCFG_VALID then
      // update fast unsafe variables
      if b_FastUnsafeInputsActive then
      
        pFastUnsafeInputs^ := FastUnsafeInputs;

      elsif ui_CntFastUnsafeInputs then
        
        bAnyChanges := FALSE;

        pActFastUnsafeInput := p_FastUnsafeInputsTable;
        for i := 1 to ui_CntFastUnsafeInputs do 
          //read value from server
          NewValue := RD(pActFastUnsafeInput^.ud_Thisp$^void);
          pBufferValue := pActFastUnsafeInput^.ud_Address$^DINT;
          
          //check for valid message counter  
          if (NewValue <> pBufferValue^) then
            pBufferValue^ := NewValue;
            
            bAnyChanges := TRUE;
          elsif pActFastUnsafeInput^.b_AlreadyTransmitted = FALSE then
            pBufferValue^ := NewValue;
            
            pActFastUnsafeInput^.b_AlreadyTransmitted := TRUE;
            
            bAnyChanges := TRUE;
          end_if;
          
          //step to next entry
          pActFastUnsafeInput += sizeof(UnsafeIORoutingElement);
        end_for;

        if bAnyChanges then
          if pFastUnsafeInBuffer^$USINT <> 0xFF then
            pFastUnsafeInBuffer^$USINT  += 1; //increase msg cnt
          else
            pFastUnsafeInBuffer^$USINT  := 1; //set msg cnt to 1 because msg cnt 0 is invalid
          end_if;
        end_if;

        pTempStartBufferIn := pFastUnsafeInBuffer;   
        for i := 0 to WriteFastUnsafeDOsUsed -1 do
          //copy data into buffer
          _memcpy(ptr1:=aFastUnsafeWriteDOs[i].pData, ptr2:=pTempStartBufferIn, cntr:=aFastUnsafeWriteDOs[i].Length);
          
          //first DO readed -> set pointer to next DO
          pTempStartBufferIn += aFastUnsafeWriteDOs[i].Length;
        end_for;       
      end_if;
      
      // set config valid again (from locked)
      sigclib_atomic_swpU32(pValue:=#udConfigValid, swpVal:=SBF_LOCKCFG_VALID);
    end_if;
    
  end_if;
  
END_FUNCTION


FUNCTION GLOBAL SdiasSafetyManagerFSoE::InitAccess
  VAR_OUTPUT
    AccessInitState 	: iprStates;
  END_VAR
  VAR
    SDORequestBuffer  : SDORequReadConfig;
    us_SDO_length     : USINT;
  END_VAR

  AccessInitState := BUSY;

  case eInitAccessSSW of      
//**********************************************************************************************************************************************************
    _PrepareInit:
      If DeviceIDOk = FALSE then  
        LogError("@06E3 (SdiasSafetyManagerFSoE::InitAccess) Canceled Initialisation, because the detected DeviceID is wrong");
        eInitAccessSSWErrorStep := eInitAccessSSW;
        eInitAccessSSW := _InitError;
        return;
      end_if;
    
      //add module to safety communication task with SDO
      if ( AddModuleToSafetyTask() ) then
        LogError("@029E (SdiasSafetyManagerFSoE::InitAccess) Failed to add module to safety task.");
        eInitAccessSSWErrorStep := eInitAccessSSW;
        eInitAccessSSW := _InitError;
        return;
      end_if;

#ifdef SAFETY_iDisableNonClassCommunication
      if ( pISafety^.udVersion >= 16#1002 ) then
        SAFETY_iDisableNonClassCommunication(uiMaster:=0, pucNode:=p_ObjectPath, uiDisable:=1);
        
        // clear the flag of the actual buffer if there is something
        if p_Handle_SDO_Read^.us_Status = SAFETY_SDO_DATA_VALID then
          p_Handle_SDO_Read^.us_Status := SAFETY_SDO_NO_DATA;
        end_if;
      end_if;
#endif


      // if leds/hgb not added so far, add them (even if there are no IO modules)
      if StateBytesUsed = 0 then
        StateBitsUsed := (sizeof(t_LedAndIOStates.biLEDs) + sizeof(t_LedAndIOStates.HBGInputs)) * 8;
                
        // refresh state bytes used value
        StateBytesUsed := ((StateBitsUsed-1) / 8) + 1;
      end_if;


      eInitAccessSSW := _GetConfiguredState;
      eResponseState := _idle;

//**********************************************************************************************************************************************************
    _GetConfiguredState:
      case eResponseState of
        _idle:
          if (LastRequest = _NoOpenRequest) & (p_Handle_SDO_Write^.us_Status = SAFETY_SDO_NO_DATA) then
          
            // get state via SDO communication                                  
            SDORequestBuffer.StdHeader.CRC  := 0;                                                   // CRC is always 0 in Std communication
            SDORequestBuffer.StdHeader.Cmd  := SBF_SDO_COMMAND_GET_STATE;                           // get-state command
            SDORequestBuffer.StdHeader.Typ  := SDO_STD;                                             // standard frame type
            SDORequestBuffer.StdHeader.SeqNr:= StandardSeqNr OR 16#80;                              // sequence number
            SDORequestBuffer.StdHeader.Len  := 4;                                                   // header
            SDORequestBuffer.ud_Address     := 0;
            SDORequestBuffer.us_Length      := 0;

            LastRequest := _DiagState;

            //copy SDO into write-buffer
            ToStdLib.MemCpy(dest := #p_Handle_SDO_Write^.SDOStructure, source := #SDORequestBuffer, size := (sizeof(SDOHeader.StdHeader.CRC) + SDORequestBuffer.StdHeader.Len));
                  
            //mark SDO data as valid
            p_Handle_SDO_Write^.us_Status := SAFETY_SDO_DATA_VALID;
            
            if ( pISafety^.udVersion >= 16#1001 ) then
              SAFETY_iPushSafetyTask();
            end_if;

            SDOTimeMark := ops.tAbsolute;
            eResponseState:= _wait; 
                  
            // check timeout
          elsif ((ops.tAbsolute - SDOTimeMark) > SDIAS_SAFTEY_SDO_RESPONSE_TIMEOUT) & (eResponseState <> _valid) then
            LogError("@029F (SdiasSafetyManagerFSoE::InitAccess) Timeout while waiting for the SDO Send buffer to get ready (get configured state)");
            eInitAccessSSWErrorStep := eInitAccessSSW;
            eInitAccessSSW := _InitError;
          end_if;
          
      //*****************************************************
        _wait: // wait for response

          //read SDO from module and send it to the target module
          //check, if SDO is available and valid
          if ( p_Handle_SDO_Read^.us_Status = SAFETY_SDO_DATA_VALID ) then
        
            //calculate length of SDO
            us_SDO_length := sizeof(SDOHeader.StdHeader.CRC) + p_Handle_SDO_Read^.SDOStructure.SDOHeader.StdHeader.Len;
            
            //copy SDO without first byte (=status byte)
            ToStdLib.MemCpy(dest := p_SDOOutputBuffer, source := #p_Handle_SDO_Read^.SDOStructure, size := us_SDO_length );

            //mark data as received
            p_Handle_SDO_Read^.us_Status := SAFETY_SDO_NO_DATA;
          
            //check, if it's our answer
            if ((p_SDOOutputBuffer^.SDOHeader.StdHeader.Typ$USINT AND SBF_SSDO_MASK_TYPE)$t_SafetyFrameType = SDO_STD) then
              StandardResponse := (p_SDOOutputBuffer$^StandardFrameType)^;
              if StandardResponse.SDOHeader.SeqNr = (StandardSeqNr OR 16#80) then
                if LastRequest = _DiagState then
                  if StandardResponse.SDOHeader.Cmd = SBF_SDO_COMMAND_GET_STATE then
                    _memcpy(ptr1 := #DiagVars.UserGetStateResp, 
                            ptr2 := #StandardResponse.aData + SIZEOF(USINT), 
                            cntr := sizeof(GetStateResponseType) );

                    LastRequest := _NoOpenRequest;
                    ud_AsyComRetryCounter := 0; // reset retry counter

                    eResponseState:= _valid; 
                  else
                    LogError("@02A0 (SdiasSafetyManagerFSoE::InitAccess) SDO Receive: Invalid command in standard frame response.");
                  end_if;
                else
                  LogError("@025A (SdiasSafetyManagerFSoE::InitAccess) SDO Receive: Invalid standard frame response.");
                end_if;

                // if request is deleted, increase sequence number to set next request
                if LastRequest = _NoOpenRequest then
                  if StandardSeqNr < 16#7F then
                    StandardSeqNr += 1;
                  else
                    StandardSeqNr := 0;
                  end_if;
                end_if;
              else
                LogError("@025B (SdiasSafetyManagerFSoE::InitAccess) SDO Receive: Invalid sequence number in Standard SDO response.");
                LogValue("expected: 0x{0} / received: 0x{1}", Value:=(StandardSeqNr OR 16#80), Value2:=StandardResponse.SDOHeader.SeqNr);
              end_if;
            else
              // ignore non-standard frames => the module may try to distribute it's configuration
            end_if;
          end_if;
        
          // check timeout
          if ((ops.tAbsolute - SDOTimeMark) > SDIAS_SAFTEY_SDO_RESPONSE_TIMEOUT) & (eResponseState <> _valid) then
            LogError("@02A1 (SdiasSafetyManagerFSoE::InitAccess) SDO Response timeout while waiting for the module configuration.");
            eInitAccessSSWErrorStep := eInitAccessSSW;
            eInitAccessSSW := _InitError;
          end_if;
      //*****************************************************
        _valid:
          // if the module is configured and we didn't create the DOs so far
          if (DiagVars.UserGetStateResp.ConfigState <> SBF_CFG_STATE_UNKNOWN) &
             (DiagVars.UserGetStateResp.ConfigState <> SBF_CFG_STATE_INVALID) &
             (DiagVars.UserGetStateResp.ConfigState <> SBF_CFG_STATE_NOT_CONFIGURED) &
             (b_DOsCreated = FALSE)
             then
             
            // remember to get the optional settings since the config seems to be ok
            b_GetOptionalSettings := TRUE;
            
            // get the pdo sizes
            
            eInitAccessSSW := _GetPDOSizes;
          else

            // don't get the optional settings, because there is no config => no optional settings to compare
            b_GetOptionalSettings := FALSE;

            // otherwise => assume them as zero
            _memset(dest:=#PdoSizeInfo, usByte:=0, cntr:=sizeof(t_PDOSizeInfo));

            eInitAccessSSW := _Finished;            
          end_if;

          eResponseState  := _idle;
      //*****************************************************
      end_case;
    
//**********************************************************************************************************************************************************
    _GetPDOSizes:
      case eResponseState of
        _idle:
            if (LastRequest = _NoOpenRequest) & (p_Handle_SDO_Write^.us_Status = SAFETY_SDO_NO_DATA) then
              SDORequestBuffer.StdHeader.CRC  := 0;                                                         // CRC is always 0 in Std communication
              SDORequestBuffer.StdHeader.Cmd  := SBF_SDO_COMMAND_READ;                                      // read command
              SDORequestBuffer.StdHeader.Typ  := SDO_STD;                                                   // standard frame type
              SDORequestBuffer.StdHeader.SeqNr:= StandardSeqNr OR 16#80;                                    // sequence number
              SDORequestBuffer.StdHeader.Len  := 4 + 4 + 1;                                                 // header + destination address + length of data
              SDORequestBuffer.ud_Address     := SBF_SDO_ADDRESS_SPECIAL_INFO;                              // address of pdo size info
              SDORequestBuffer.us_Length      := sizeof(UDINT) + sizeof(t_PDOSizeInfo);                     // length info + length of pdo size info

              LastRequest := _ReadData;

              //copy SDO into write-buffer
              ToStdLib.MemCpy(dest := #p_Handle_SDO_Write^.SDOStructure, source := #SDORequestBuffer, size := (sizeof(SDOHeader.StdHeader.CRC) + SDORequestBuffer.StdHeader.Len));
                    
              //mark SDO data as valid
              p_Handle_SDO_Write^.us_Status := SAFETY_SDO_DATA_VALID;
              
              if ( pISafety^.udVersion >= 16#1001 ) then
                SAFETY_iPushSafetyTask();
              end_if;

              SDOTimeMark := ops.tAbsolute;
              eResponseState:= _wait; 
                  
              // check timeout
            elsif ((ops.tAbsolute - SDOTimeMark) > SDIAS_SAFTEY_SDO_RESPONSE_TIMEOUT) & (eResponseState <> _valid) then
              LogError("@02A2 (SdiasSafetyManagerFSoE::InitAccess) Timeout while waiting for the SDO Send buffer to get ready (get PDO sizes)");
              eInitAccessSSWErrorStep := eInitAccessSSW;
              eInitAccessSSW := _InitError;
            end_if;
            
      //*****************************************************
        _wait: // wait for response

          //read SDO from module and send it to the target module
          //check, if SDO is available and valid
          if ( p_Handle_SDO_Read^.us_Status = SAFETY_SDO_DATA_VALID ) then
        
            //calculate length of SDO
            us_SDO_length := sizeof(SDOHeader.StdHeader.CRC) + p_Handle_SDO_Read^.SDOStructure.SDOHeader.StdHeader.Len;
            
            //copy SDO without first byte (=status byte)
            ToStdLib.MemCpy(dest := p_SDOOutputBuffer, source := #p_Handle_SDO_Read^.SDOStructure, size := us_SDO_length );

            //mark data as received
            p_Handle_SDO_Read^.us_Status := SAFETY_SDO_NO_DATA;
          
            //check, if it's our answer
            if ((p_SDOOutputBuffer^.SDOHeader.StdHeader.Typ$USINT AND SBF_SSDO_MASK_TYPE)$t_SafetyFrameType = SDO_STD) then
              StandardResponse := (p_SDOOutputBuffer$^StandardFrameType)^;
              if StandardResponse.SDOHeader.SeqNr = (StandardSeqNr OR 16#80) then
                if LastRequest = _ReadData then
                  // if we did read command, then save the value to corresponding server
                  if StandardResponse.SDOHeader.Cmd = SBF_SDO_COMMAND_READ then
                    // if returncode is 0 read succeeded
                    if StandardResponse.aData[0] = 0 then
                      // delete request
                      LastRequest := _NoOpenRequest;
                      ud_AsyComRetryCounter := 0; // reset retry counter

                      if StandardResponse.aData[2]$UDINT >= (sizeof(UDINT) + sizeof(t_PDOSizeInfo)) then
                        // copy the pdo length info to our local memory

                        _memcpy(ptr1:=#PdoSizeInfo, 
                                ptr2:=#StandardResponse.aData[6], 
                                cntr:=sizeof(t_PDOSizeInfo));
                                
                        if PdoSizeInfo.Version = 1 then
                        
                          MyPDOReadSize   := PdoSizeInfo.PDORdLen;
                          MyPDOWriteSize  := PdoSizeInfo.PDOWrLen;
                          
                          ActivateFastUnsafeIOs := PdoSizeInfo.FastUnsafeAvailable <> 0; 
                          
                        elsif PdoSizeInfo.Version = 2 then
                        
                          _memcpy(ptr1:=#PdoSizeInfoV2, 
                                  ptr2:=#StandardResponse.aData[6], 
                                  cntr:=sizeof(t_PDOSizeInfoV2));

                          MyPDOReadSize                 := PdoSizeInfo.PDORdLen;
                          MyPDOWriteSize                := PdoSizeInfo.PDOWrLen;
                                
                          uiNumberFastUnsafeRd                  := PdoSizeInfoV2.uiNumberFastUnsafeRdVar;
                          uiNumberFastUnsafeWr                  := PdoSizeInfoV2.uiNumberFastUnsafeWrVar;
                          
                          //Only calculcate size and add message count if we have bytes to read
                          if uiNumberFastUnsafeRd = 0 then
                            uiPDOReadSizeFastUnsafeVar    := 0;
                          else
                            uiPDOReadSizeFastUnsafeVar    := (uiNumberFastUnsafeRd *sizeof(UDINT)) + sizeof(USINT);  //*4 to get byte + 1 byte msg cnt                        
                          end_if;
                          
                          //Only calculcate size and add message count if we have bytes to write                          
                          if uiNumberFastUnsafeWr = 0 then
                            uiPDOWriteSizeFastUnsafeVar   := 0;
                          else
                            uiPDOWriteSizeFastUnsafeVar   := (uiNumberFastUnsafeWr *sizeof(UDINT)) + sizeof(USINT);  //*4 to get byte + 1 byte msg cnt
                          end_if;
                                                                    
                        else
                          LogError("@0783 (SdiasSafetyManagerFSoE::InitAccess) SDO Receive: Invalid Version of PDO Info.");
                          eInitAccessSSWErrorStep := eInitAccessSSW;
                          eInitAccessSSW := _InitError;
                        end_if;
                        
                        eResponseState:= _valid; 
                      else
                        LogError("@02A3 (SdiasSafetyManagerFSoE::InitAccess) SDO Receive: Invalid length of PDO size info.");
                        eInitAccessSSWErrorStep := eInitAccessSSW;
                        eInitAccessSSW := _InitError;
                      end_if;
                    end_if;
                  else
                    LogError("@02A4 (SdiasSafetyManagerFSoE::InitAccess) SDO Receive: Invalid command, read expected.");              
                    eInitAccessSSWErrorStep := eInitAccessSSW;
                    eInitAccessSSW := _InitError;
                  end_if;
                else
                  LogError("@025A (SdiasSafetyManagerFSoE::InitAccess) SDO Receive: Invalid standard frame response.");
                  eInitAccessSSWErrorStep := eInitAccessSSW;
                  eInitAccessSSW := _InitError;
                end_if;

                // if request is deleted, increase sequence number to set next request
                if LastRequest = _NoOpenRequest then
                  if StandardSeqNr < 16#7F then
                    StandardSeqNr += 1;
                  else
                    StandardSeqNr := 0;
                  end_if;
                end_if;
              else
                LogError("@025B (SdiasSafetyManagerFSoE::InitAccess) SDO Receive: Invalid sequence number in Standard SDO response.");
                LogValue("expected: 0x{0} / received: 0x{1}", Value:=(StandardSeqNr OR 16#80), Value2:=StandardResponse.SDOHeader.SeqNr);
                eInitAccessSSWErrorStep := eInitAccessSSW;
                eInitAccessSSW := _InitError;
              end_if;
            else
              // ignore non-standard frames => the module may try to distribute it's configuration
            end_if;
          end_if;
        
          // check timeout
          if ((ops.tAbsolute - SDOTimeMark) > SDIAS_SAFTEY_SDO_RESPONSE_TIMEOUT) & (eResponseState <> _valid) then
            LogError("@02A1 (SdiasSafetyManagerFSoE::InitAccess) SDO Response timeout while waiting for the module configuration.");
            eInitAccessSSWErrorStep := eInitAccessSSW;
            eInitAccessSSW := _InitError;
          end_if;
      //*****************************************************
        _valid:
          eInitAccessSSW := _Finished;
          eResponseState  := _idle;
      //*****************************************************
      
      end_case;
      
//**********************************************************************************************************************************************************
    _Finished:
      eInitAccessSSW         := _PrepareInit;
      
      if b_DOsCreated then
        AccessInitState := READY;
      else
        AccessInitState := AddDO();
        b_DOsCreated    := TRUE;
      end_if;
      
      if AccessInitState = READY then
        b_ModuleAccessReady := TRUE;
      end_if;

#ifdef SAFETY_iDisableNonClassCommunication
      if ( pISafety^.udVersion >= 16#1002 ) then
        SAFETY_iDisableNonClassCommunication(uiMaster:=0, pucNode:=p_ObjectPath, uiDisable:=0);
      end_if;
#endif

//**********************************************************************************************************************************************************
    _InitError:
      eInitAccessSSW    := _PrepareInit;      
      AccessInitState   := ERROR; 

#ifdef SAFETY_iDisableNonClassCommunication
      if ( pISafety^.udVersion >= 16#1002 ) then
        SAFETY_iDisableNonClassCommunication(uiMaster:=0, pucNode:=p_ObjectPath, uiDisable:=0);
      end_if;
#endif

//**********************************************************************************************************************************************************
  end_case;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SdiasSafetyManagerFSoE::InitModule
  VAR_OUTPUT
    ModuleInitState 	: iprStates;
  END_VAR
  VAR
    MyPara 	          : CmdStruct;
    MyResult	        : results;  	
    TmpRetCode        : iprStates;
    SDORequestBuffer  : SDORequReadConfig;
    us_SDO_length     : USINT;
    udBusTime         : UDINT;
    udBusTime_us      : UDINT;
  END_VAR

  ModuleInitState := BUSY;

  case eInitSSW of
//**********************************************************************************************************************************************************
    _PrepareInit:
      //add module to safety communication task with SDO (has to be done here too, for plug out/plug in case)
      if ( AddModuleToSafetyTask() ) then
        LogError("@029E (SdiasSafetyManagerFSoE::InitModule) Failed to add module to safety task.");
        eInitSSWErrorStep := eInitSSW;
        eInitSSW := _InitError;
        return;
      end_if;

#ifdef SAFETY_iDisableNonClassCommunication
      if ( pISafety^.udVersion >= 16#1002 ) then
        SAFETY_iDisableNonClassCommunication(uiMaster:=0, pucNode:=p_ObjectPath, uiDisable:=1);
        
        // clear the flag of the actual buffer if there is something
        if p_Handle_SDO_Read^.us_Status = SAFETY_SDO_DATA_VALID then
          p_Handle_SDO_Read^.us_Status := SAFETY_SDO_NO_DATA;
        end_if;
      end_if;
#endif

      eResponseState := _idle;
      
      usActStepRetries := 0;

      if b_GetOptionalSettings then
        eInitSSW := _GetOptionalSettings;
      else
        eInitSSW := _ReadModuleIDs;
      end_if;
      
//**********************************************************************************************************************************************************

    _GetOptionalSettings:
      case eResponseState of
        _idle:
          if (LastRequest = _NoOpenRequest) & (p_Handle_SDO_Write^.us_Status = SAFETY_SDO_NO_DATA) then
          
            // get state via SDO communication                                  
            SDORequestBuffer.StdHeader.CRC  := 0;                                                   // CRC is always 0 in Std communication
            SDORequestBuffer.StdHeader.Cmd  := SBF_SDO_COMMAND_READ;                                // read command
            SDORequestBuffer.StdHeader.Typ  := SDO_STD;                                             // standard frame type
            SDORequestBuffer.StdHeader.SeqNr:= StandardSeqNr OR 16#80;                              // sequence number
            SDORequestBuffer.StdHeader.Len  := 4 + 4 + 1;                                           // header + destination address + length of data
            SDORequestBuffer.ud_Address     := SBF_SDO_ADDRESS_OPTIONAL_CFG;
            SDORequestBuffer.us_Length      := sizeof(t_OptionalSettings);

            LastRequest := _ReadData;

            //copy SDO into write-buffer
            ToStdLib.MemCpy(dest := #p_Handle_SDO_Write^.SDOStructure, source := #SDORequestBuffer, size := (sizeof(SDOHeader.StdHeader.CRC) + SDORequestBuffer.StdHeader.Len));
                  
            //mark SDO data as valid
            p_Handle_SDO_Write^.us_Status := SAFETY_SDO_DATA_VALID;
            
            if ( pISafety^.udVersion >= 16#1001 ) then
              SAFETY_iPushSafetyTask();
            end_if;

            SDOTimeMark := ops.tAbsolute;
            eResponseState:= _wait; 
                  
            // reset wrong data count (this is needed to ignore the first response if it's wrong, because after plug off and in again we might receive a response to our last request to this module)
            usWrongDataCnt := 0;                  
                  
            // check timeout
          elsif ((ops.tAbsolute - SDOTimeMark) > SDIAS_SAFTEY_SDO_RESPONSE_TIMEOUT) & (eResponseState <> _valid) then
            LogError("@02A5 (SdiasSafetyManagerFSoE::InitModule) Timeout while waiting for the SDO Send buffer to get ready (get optional settings)");
            eInitSSWErrorStep := eInitSSW;
            eInitSSW := _InitError;
          end_if;
          
      //*****************************************************
        _wait: // wait for response

          //read SDO from module and send it to the target module
          //check, if SDO is available and valid
          if ( p_Handle_SDO_Read^.us_Status = SAFETY_SDO_DATA_VALID ) then
        
            //calculate length of SDO
            us_SDO_length := sizeof(SDOHeader.StdHeader.CRC) + p_Handle_SDO_Read^.SDOStructure.SDOHeader.StdHeader.Len;
            
            //copy SDO without first byte (=status byte)
            ToStdLib.MemCpy(dest := p_SDOOutputBuffer, source := #p_Handle_SDO_Read^.SDOStructure, size := us_SDO_length );

            //mark data as received
            p_Handle_SDO_Read^.us_Status := SAFETY_SDO_NO_DATA;
          
            //check, if it's our answer
            if ((p_SDOOutputBuffer^.SDOHeader.StdHeader.Typ$USINT AND SBF_SSDO_MASK_TYPE)$t_SafetyFrameType = SDO_STD) then
              StandardResponse := (p_SDOOutputBuffer$^StandardFrameType)^;
              if StandardResponse.SDOHeader.SeqNr = (StandardSeqNr OR 16#80) then
                if LastRequest = _ReadData then
                  if StandardResponse.SDOHeader.Cmd = SBF_SDO_COMMAND_READ then
                    // delete request
                    LastRequest := _NoOpenRequest;
                    ud_AsyComRetryCounter := 0; // reset retry counter
                    
                    eResponseState:= _valid;
                    
                    // if returncode is 0 read succeeded
                    if StandardResponse.aData[0] = 0 then

                      // copy the data into our local memory
                      _memcpy(ptr1:=#OptionalSettings, 
                              ptr2:=#StandardResponse.aData[2], 
                              cntr:=sizeof(OptionalSettings));

                      b_GotOptionalSettings := TRUE;
                    else
                      // if we get an error => we might have an old firmware version, ignore it
                      b_GotOptionalSettings := FALSE;
                    end_if;
                  else
                    if usWrongDataCnt | (b_Reconnect = FALSE) then
                  
                      LogError("@02A0 (SdiasSafetyManagerFSoE::InitModule) SDO Receive: Invalid command in standard frame response.");
                      eInitSSWErrorStep := eInitSSW;
                      eInitSSW := _InitError;
                    else
                      usWrongDataCnt += 1;
                    end_if;                      
                  end_if;
                else
                  LogError("@025A (SdiasSafetyManagerFSoE::InitModule) SDO Receive: Invalid standard frame response.");
                  eInitSSWErrorStep := eInitSSW;
                  eInitSSW := _InitError;
                end_if;

                // if request is deleted, increase sequence number to set next request
                if LastRequest = _NoOpenRequest then
                  if StandardSeqNr < 16#7F then
                    StandardSeqNr += 1;
                  else
                    StandardSeqNr := 0;
                  end_if;
                end_if;
              else
                if usWrongDataCnt then
                  LogError("@025B (SdiasSafetyManagerFSoE::InitModule) SDO Receive: Invalid sequence number in Standard SDO response.");
                  LogValue("expected: 0x{0} / received: 0x{1}", Value:=(StandardSeqNr OR 16#80), Value2:=StandardResponse.SDOHeader.SeqNr);
                  eInitSSWErrorStep := eInitSSW;
                  eInitSSW := _InitError;
                else
                  usWrongDataCnt += 1;
                end_if;
              end_if;
            else
              // ignore non-standard frames => the module may try to distribute it's configuration
            end_if;
          end_if;
        
          // check timeout
          if ((ops.tAbsolute - SDOTimeMark) > SDIAS_SAFTEY_SDO_RESPONSE_TIMEOUT) & (eResponseState <> _valid) then
            if usActStepRetries < 2 then
              usActStepRetries += 1;

              // reset timestamp and lastrequest (forget old request)
              SDOTimeMark := ops.tAbsolute;
              LastRequest := _NoOpenRequest;

              // retry
              eResponseState := _idle;
            else          
              LogError("@02A6 (SdiasSafetyManagerFSoE::InitModule) SDO Response timeout while waiting for the optional configuration.");
              eInitSSWErrorStep := eInitSSW;
              eInitSSW := _InitError;
            end_if;
          end_if;
      //*****************************************************
        _valid:
          eResponseState := _idle;
          eInitSSW := _ReadModuleIDs;
          usActStepRetries := 0;          
      //*****************************************************
      end_case;
      
//**********************************************************************************************************************************************************
    _ReadModuleIDs:
      case eResponseState of
        _idle:
          LastSDO.Command := _BUS_IF_READ_VIA_SDO;
          LastSDO.Offset  := SBF_OFFSET_IO_MODULE_IDS;
          LastSDO.Length  := sizeof(t_ModuleIDs);
        
          MyPara.uiCmd    := LastSDO.Command$UINT;
          MyPara.aPara[0] := LastSDO.Offset;
          MyPara.aPara[1] := LastSDO.Length;
          TmpRetcode := ToBusInterface.NewInst(#MyPara, #MyResult);    
          if TmpRetcode = READY then
            SDOTimeMark  := ops.tAbsolute;
            eResponseState:= _wait; 
          elsif TmpRetcode = ERROR then
            ModuleInitState := ERROR;
            LogError("@02A7 (SafetyBaseFSoE::InitModule) Failed to add read SDO for module configuration.");
          end_if;
          //*****************************************************
        _wait:
          // wait for response
          if ((ops.tAbsolute - SDOTimeMark) > SDIAS_SAFTEY_SDO_RESPONSE_TIMEOUT) then
            if usActStepRetries < 2 then
              usActStepRetries += 1;
              
              // retry
              eResponseState := _idle;
            else
          
              LogError("@02A1 (SdiasSafetyManagerFSoE::InitModule) SDO Response timeout while waiting for the module configuration.");
              eInitSSWErrorStep := eInitSSW;
              eInitSSW := _InitError;
            end_if;
          end_if;
        //*****************************************************
        _valid:
          usActStepRetries := 0;        
          eInitSSW := _GetSafetyNr;
          eResponseState  := _idle;
          SDOTimeMark := ops.tAbsolute;
        //*****************************************************
      end_case;

//**********************************************************************************************************************************************************
    _GetSafetyNr:
      case eResponseState of
        _idle:
          if (LastRequest = _NoOpenRequest) & (p_Handle_SDO_Write^.us_Status = SAFETY_SDO_NO_DATA) then
          
            // get state via SDO communication                                  
            SDORequestBuffer.StdHeader.CRC  := 0;                                                   // CRC is always 0 in Std communication
            SDORequestBuffer.StdHeader.Cmd  := SBF_SDO_COMMAND_GET_SAFENBR;                         // get-safety-number command
            SDORequestBuffer.StdHeader.Typ  := SDO_STD;                                             // standard frame type
            SDORequestBuffer.StdHeader.SeqNr:= StandardSeqNr OR 16#80;                              // sequence number
            SDORequestBuffer.StdHeader.Len  := 4;                                                   // header
            SDORequestBuffer.ud_Address     := 0;
            SDORequestBuffer.us_Length      := 0;

            LastRequest := _GetSafetyNbr;

            //copy SDO into write-buffer
            ToStdLib.MemCpy(dest := #p_Handle_SDO_Write^.SDOStructure, source := #SDORequestBuffer, size := (sizeof(SDOHeader.StdHeader.CRC) + SDORequestBuffer.StdHeader.Len));
                  
            //mark SDO data as valid
            p_Handle_SDO_Write^.us_Status := SAFETY_SDO_DATA_VALID;
            
            if ( pISafety^.udVersion >= 16#1001 ) then
              SAFETY_iPushSafetyTask();
            end_if;

            SDOTimeMark := ops.tAbsolute;
            eResponseState:= _wait; 
                  
            // check timeout
          elsif ((ops.tAbsolute - SDOTimeMark) > SDIAS_SAFTEY_SDO_RESPONSE_TIMEOUT) & (eResponseState <> _valid) then
            LogError("@02A8 (SdiasSafetyManagerFSoE::InitModule) Timeout while waiting for the SDO Send buffer to get ready (get safety number)");
            eInitSSWErrorStep := eInitSSW;
            eInitSSW := _InitError;
          end_if;
          
      //*****************************************************
        _wait: // wait for response

          //read SDO from module and send it to the target module
          //check, if SDO is available and valid
          if ( p_Handle_SDO_Read^.us_Status = SAFETY_SDO_DATA_VALID ) then
        
            //calculate length of SDO
            us_SDO_length := sizeof(SDOHeader.StdHeader.CRC) + p_Handle_SDO_Read^.SDOStructure.SDOHeader.StdHeader.Len;
            
            //copy SDO without first byte (=status byte)
            ToStdLib.MemCpy(dest := p_SDOOutputBuffer, source := #p_Handle_SDO_Read^.SDOStructure, size := us_SDO_length );

            //mark data as received
            p_Handle_SDO_Read^.us_Status := SAFETY_SDO_NO_DATA;
          
            //check, if it's our answer
            if ((p_SDOOutputBuffer^.SDOHeader.StdHeader.Typ$USINT AND SBF_SSDO_MASK_TYPE)$t_SafetyFrameType = SDO_STD) then
              StandardResponse := (p_SDOOutputBuffer$^StandardFrameType)^;
              if StandardResponse.SDOHeader.SeqNr = (StandardSeqNr OR 16#80) then
                if LastRequest = _GetSafetyNbr then
                  if StandardResponse.SDOHeader.Cmd = SBF_SDO_COMMAND_GET_SAFENBR then
                    SafetyNumber := StandardResponse.aData[1]$HDINT;

                    LastRequest := _NoOpenRequest;
                    ud_AsyComRetryCounter := 0; // reset retry counter

                    eResponseState:= _valid; 
                  else
                    LogError("@02A0 (SdiasSafetyManagerFSoE::InitModule) SDO Receive: Invalid command in standard frame response.");
                    eInitSSWErrorStep := eInitSSW;
                    eInitSSW := _InitError;
                  end_if;
                else
                  LogError("@025A (SdiasSafetyManagerFSoE::InitModule) SDO Receive: Invalid standard frame response.");
                  eInitSSWErrorStep := eInitSSW;
                  eInitSSW := _InitError;
                end_if;

                // if request is deleted, increase sequence number to set next request
                if LastRequest = _NoOpenRequest then
                  if StandardSeqNr < 16#7F then
                    StandardSeqNr += 1;
                  else
                    StandardSeqNr := 0;
                  end_if;
                end_if;
              else
                LogError("@025B (SdiasSafetyManagerFSoE::InitModule) SDO Receive: Invalid sequence number in Standard SDO response.");
                LogValue("expected: 0x{0} / received: 0x{1}", Value:=(StandardSeqNr OR 16#80), Value2:=StandardResponse.SDOHeader.SeqNr);
                eInitSSWErrorStep := eInitSSW;
                eInitSSW := _InitError;
              end_if;
            else
              // ignore non-standard frames => the module may try to distribute it's configuration
            end_if;
          end_if;
        
          // check timeout
          if ((ops.tAbsolute - SDOTimeMark) > SDIAS_SAFTEY_SDO_RESPONSE_TIMEOUT) & (eResponseState <> _valid) then
            if usActStepRetries < 2 then
              usActStepRetries += 1;
              
              // retry
              eResponseState := _idle;
            else          
              LogError("@02A1 (SdiasSafetyManagerFSoE::InitModule) SDO Response timeout while waiting for the module configuration.");
              eInitSSWErrorStep := eInitSSW;
              eInitSSW := _InitError;
            end_if;
          end_if;
      //*****************************************************
        _valid:
          eInitSSW := _GetFirmwareVersion;            
          eResponseState  := _idle;
          usActStepRetries := 0;          
      //*****************************************************
      end_case;
      
//**********************************************************************************************************************************************************
    _GetFirmwareVersion:
      case eResponseState of
        _idle:
          if (LastRequest = _NoOpenRequest) & (p_Handle_SDO_Write^.us_Status = SAFETY_SDO_NO_DATA) then
          
            // get state via SDO communication                                  
            SDORequestBuffer.StdHeader.CRC  := 0;                                                   // CRC is always 0 in Std communication
            SDORequestBuffer.StdHeader.Cmd  := SBF_SDO_COMMAND_GET_FW_VERSION;                      // get-fw-version command
            SDORequestBuffer.StdHeader.Typ  := SDO_STD;                                             // standard frame type
            SDORequestBuffer.StdHeader.SeqNr:= StandardSeqNr OR 16#80;                              // sequence number
            SDORequestBuffer.StdHeader.Len  := 4;                                                   // header
            SDORequestBuffer.ud_Address     := 0;
            SDORequestBuffer.us_Length      := 0;

            LastRequest := _GetFWVersion;

            //copy SDO into write-buffer
            ToStdLib.MemCpy(dest := #p_Handle_SDO_Write^.SDOStructure, source := #SDORequestBuffer, size := (sizeof(SDOHeader.StdHeader.CRC) + SDORequestBuffer.StdHeader.Len));
                  
            //mark SDO data as valid
            p_Handle_SDO_Write^.us_Status := SAFETY_SDO_DATA_VALID;
            
            if ( pISafety^.udVersion >= 16#1001 ) then
              SAFETY_iPushSafetyTask();
            end_if;

            SDOTimeMark := ops.tAbsolute;
            eResponseState:= _wait; 
                  
            // check timeout
          elsif ((ops.tAbsolute - SDOTimeMark) > SDIAS_SAFTEY_SDO_RESPONSE_TIMEOUT) & (eResponseState <> _valid) then
            LogError("@02A9 (SdiasSafetyManagerFSoE::InitModule) Timeout while waiting for the SDO Send buffer to get ready (get firmware version)");
            eInitSSWErrorStep := eInitSSW;
            eInitSSW := _InitError;
          end_if;
          
      //*****************************************************
        _wait: // wait for response

          //read SDO from module and send it to the target module
          //check, if SDO is available and valid
          if ( p_Handle_SDO_Read^.us_Status = SAFETY_SDO_DATA_VALID ) then
        
            //calculate length of SDO
            us_SDO_length := sizeof(SDOHeader.StdHeader.CRC) + p_Handle_SDO_Read^.SDOStructure.SDOHeader.StdHeader.Len;
            
            //copy SDO without first byte (=status byte)
            ToStdLib.MemCpy(dest := p_SDOOutputBuffer, source := #p_Handle_SDO_Read^.SDOStructure, size := us_SDO_length );

            //mark data as received
            p_Handle_SDO_Read^.us_Status := SAFETY_SDO_NO_DATA;
          
            //check, if it's our answer
            if ((p_SDOOutputBuffer^.SDOHeader.StdHeader.Typ$USINT AND SBF_SSDO_MASK_TYPE)$t_SafetyFrameType = SDO_STD) then
              StandardResponse := (p_SDOOutputBuffer$^StandardFrameType)^;
              if StandardResponse.SDOHeader.SeqNr = (StandardSeqNr OR 16#80) then
                if LastRequest = _GetFWVersion then
                  if StandardResponse.SDOHeader.Cmd = SBF_SDO_COMMAND_GET_FW_VERSION then
                    _memcpy(ptr1 := #sFirmwareVersion, 
                            ptr2 := #StandardResponse.aData + SIZEOF(USINT), 
                            cntr := sizeof(FirmwareVersionType) );

                    LastRequest := _NoOpenRequest;
                    ud_AsyComRetryCounter := 0; // reset retry counter

                    eResponseState:= _valid; 
                  else
                    LogError("@02A0 (SdiasSafetyManagerFSoE::InitModule) SDO Receive: Invalid command in standard frame response.");
                    eInitSSWErrorStep := eInitSSW;
                    eInitSSW := _InitError;
                  end_if;
                else
                  LogError("@025A (SdiasSafetyManagerFSoE::InitModule) SDO Receive: Invalid standard frame response.");
                  eInitSSWErrorStep := eInitSSW;
                  eInitSSW := _InitError;
                end_if;

                // if request is deleted, increase sequence number to set next request
                if LastRequest = _NoOpenRequest then
                  if StandardSeqNr < 16#7F then
                    StandardSeqNr += 1;
                  else
                    StandardSeqNr := 0;
                  end_if;
                end_if;
              else
                LogError("@025B (SdiasSafetyManagerFSoE::InitModule) SDO Receive: Invalid sequence number in Standard SDO response.");
                LogValue("expected: 0x{0} / received: 0x{1}", Value:=(StandardSeqNr OR 16#80), Value2:=StandardResponse.SDOHeader.SeqNr);
                eInitSSWErrorStep := eInitSSW;
                eInitSSW := _InitError;
              end_if;
            else
              // ignore non-standard frames => the module may try to distribute it's configuration
            end_if;
          end_if;
        
          // check timeout
          if ((ops.tAbsolute - SDOTimeMark) > SDIAS_SAFTEY_SDO_RESPONSE_TIMEOUT) & (eResponseState <> _valid) then
            if usActStepRetries < 2 then
              usActStepRetries += 1;
              
              // retry
              eResponseState := _idle;
            else
              LogError("@02A1 (SdiasSafetyManagerFSoE::InitModule) SDO Response timeout while waiting for the module configuration.");
              eInitSSWErrorStep := eInitSSW;
              eInitSSW := _InitError;
            end_if;
          end_if;
      //*****************************************************
        _valid:
          FirmwareVersion := sFirmwareVersion.RevMinor OR (sFirmwareVersion.RevMajor SHL 16);

          // Minor Versions starting with 9xxx mark Bootloader versions
          if (sFirmwareVersion.RevMinor >= 9000) & (sFirmwareVersion.RevMinor < 10000) then
            LogError("@01D9 (SdiasSafetyManagerFSoE::InitModule) Bootloader version of safety firmware detected! Download a firmware or contact Sigmatek Support!");
          end_if;
          
           // retrycounter is always supported by FSoE modules
          b_RetryCounterAvailable := TRUE;

          // add own safety number to routing table
          AddRoutingElement( ud_SafeNumber  := SafetyNumber
                           , ud_thisp       := this$UDINT
                           , pPathInfo      := NIL
                           );

          // give the manager more details about the module
          if pSafetyManagerThis then
            MyPara.uiCmd := CMD_SM_ADD_MODULE_INFO;
            MyPara.aPara[0] := THIS$DINT;
            MyPara.aPara[1] := SafetyNumber$DINT;
            MyPara.aPara[2] := FirmwareVersion$DINT;
            MyPara.aPara[3] := 16#FF; // fake FPGA_Version (only needed for CDIAS CPUs)
            MyPara.aPara[4] := to_DINT(p_ObjectPath^$USINT) + 1; // size of path (length + 1 for the length information)
            MyPara.aPara[5] := p_ObjectPath$DINT;
            pSafetyManagerThis^.NewInst(#MyPara, #MyResult);
          else
            LogError("@01DB (SdiasSafetyManagerFSOE::InitModule) Couldn't find object of HwControl class, which is needed for safety time synchronisation!");
          end_if;
          
          // if it has been reconnected, show the project name and revison from last time
          if pPrjNameStr & pPrjRevStr then
            ShowProjectRevision();
          end_if;

          eInitSSW        := _SetSysTime;            
          eResponseState  := _idle;
      //*****************************************************
      end_case;
      
//**********************************************************************************************************************************************************
    _SetSysTime:
      case eResponseState of
        _idle:
          if (LastRequest = _NoOpenRequest) & (p_Handle_SDO_Write^.us_Status = SAFETY_SDO_NO_DATA) then
            StandardRequest.SDOHeader.CRC  := 0;                              // CRC is always 0 in Std communication
            StandardRequest.SDOHeader.Cmd  := SBF_SDO_COMMAND_WRITE;          // read command
            StandardRequest.SDOHeader.Typ  := SDO_STD;                        // standard frame type
            StandardRequest.SDOHeader.SeqNr:= StandardSeqNr OR 16#80;         // sequence number
            StandardRequest.SDOHeader.Len  := 4 + 4 + 1 + sizeof(UDINT);      // header + destination address + length of data + size of data
            StandardRequest.aData[0]$UDINT := SBF_SDO_ADDRESS_FW_SYSTIME;     // address of system time safety firmware
            StandardRequest.aData[4]       := sizeof(UDINT);                  // length of data
            StandardRequest.aData[5]$UDINT := ToSigCLib.UnixTimeStampGet();   // system time of plc as unix timestamp

            LastRequest := _WriteSysTime;

            //copy SDO into write-buffer
            ToStdLib.MemCpy(dest := #p_Handle_SDO_Write^.SDOStructure, source := #StandardRequest, size := (sizeof(SDOHeader.StdHeader.CRC) + StandardRequest.SDOHeader.Len));
                  
            //mark SDO data as valid
            p_Handle_SDO_Write^.us_Status := SAFETY_SDO_DATA_VALID;
            
            if ( pISafety^.udVersion >= 16#1001 ) then
              SAFETY_iPushSafetyTask();
            end_if;

            SDOTimeMark       := ops.tAbsolute;
            ud_LastSetSysTime := ops.tAbsolute;
            eResponseState    := _wait; 
                
            // check timeout
          elsif ((ops.tAbsolute - SDOTimeMark) > SDIAS_SAFTEY_SDO_RESPONSE_TIMEOUT) & (eResponseState <> _valid) then
            LogError("@029F (SdiasSafetyManagerFSoE::InitModule) Timeout while waiting for the SDO Send buffer to get ready (set system time)");
            eInitSSWErrorStep := eInitSSW;
            eInitSSW          := _InitError;
          end_if;
            
      //*****************************************************
        _wait: // wait for response

          //check id sdo sending was ok
          if ( p_Handle_SDO_Read^.us_Status = SAFETY_SDO_DATA_VALID ) then
        
            //calculate length of SDO
            us_SDO_length := sizeof(SDOHeader.StdHeader.CRC) + p_Handle_SDO_Read^.SDOStructure.SDOHeader.StdHeader.Len;
            
            //copy SDO without first byte (=status byte)
            ToStdLib.MemCpy(dest := p_SDOOutputBuffer, source := #p_Handle_SDO_Read^.SDOStructure, size := us_SDO_length );

            //mark data as received
            p_Handle_SDO_Read^.us_Status := SAFETY_SDO_NO_DATA;
          
            //check, if it's our answer
            if ((p_SDOOutputBuffer^.SDOHeader.StdHeader.Typ$USINT AND SBF_SSDO_MASK_TYPE)$t_SafetyFrameType = SDO_STD) then
              StandardResponse := (p_SDOOutputBuffer$^StandardFrameType)^;
              if StandardResponse.SDOHeader.SeqNr = (StandardSeqNr OR 16#80) then
                if LastRequest = _WriteSysTime then
                  // delete request
                  LastRequest           := _NoOpenRequest;
                  ud_AsyComRetryCounter := 0; // reset retry counter                        
                  eResponseState        := _valid; 
                  // if returnvalue is 34 (E_SM_SSDO_INVALID_VIRTADDR) the virtual address is not supported by firmware
                  if StandardResponse.aData[0] <> 34 then
                    //virtual adress for write of timestamp is supported
                    b_SetSysTime := TRUE;
                  else  
                    b_SetSysTime := FALSE;                  
                  end_if;
                else
                  LogError("@025A (SdiasSafetyManagerFSoE::InitModule) SDO Receive: Invalid standard frame response.");
                  eInitSSWErrorStep := eInitSSW;
                  eInitSSW          := _InitError;
                end_if;

                // if request is deleted, increase sequence number to set next request
                if LastRequest = _NoOpenRequest then
                  if StandardSeqNr < 16#7F then
                    StandardSeqNr += 1;
                  else
                    StandardSeqNr := 0;
                  end_if;
                end_if;
              else
                LogError("@025B (SdiasSafetyManagerFSoE::InitModule) SDO Receive: Invalid sequence number in Standard SDO response.");
                LogValue("expected: 0x{0} / received: 0x{1}", Value:=(StandardSeqNr OR 16#80), Value2:=StandardResponse.SDOHeader.SeqNr);
                eInitSSWErrorStep := eInitSSW;
                eInitSSW          := _InitError;
              end_if;
            else
              // ignore non-standard frames => the module may try to distribute it's configuration
            end_if;
          end_if;
        
          // check timeout
          if ((ops.tAbsolute - SDOTimeMark) > SDIAS_SAFTEY_SDO_RESPONSE_TIMEOUT) & (eResponseState <> _valid) then
            LogError("@02A1 (SdiasSafetyManagerFSoE::InitModule) SDO Response timeout while waiting for the module configuration.");
            eInitSSWErrorStep := eInitSSW;
            eInitSSW          := _InitError;
          end_if;
      //*****************************************************
        _valid:
          eInitSSW        := _DisablePLL;
          eResponseState  := _idle;
      //*****************************************************
      end_case;
            

//**********************************************************************************************************************************************************
    _DisablePLL: // disable the PLL
      TmpRetCode := BusConfigWrite(Offset:=SDIAS_SAFETY_PLL_OFFSET + t_PllRegister.StatusControl, Length:=sizeof(sPllRegister.StatusControl), pData:=#sPllRegister.StatusControl, IsControlAccess:=TRUE);
    
      if TmpRetCode = READY then
        eInitSSW := _GetPLLSettings;
      elsif TmpRetCode = ERROR then
        eInitSSW := _InitError;
      end_if;

//**********************************************************************************************************************************************************
    _GetPLLSettings: // get the actual PLL settings
      TmpRetCode := BusConfigRead(Offset:=SDIAS_SAFETY_PLL_OFFSET, Length:=sizeof(sPllRegister), pData:=#sPllRegister, IsControlAccess:=TRUE);
    
      if TmpRetCode = READY then
        // get bus cycle time for the PLL settings
        MyPara.uiCmd     := _BUS_IF_GET_BUSCYCLE_TIME;

        ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
        if MyResult.aData[0]$t_GetBusCycleTime.retcode = _BUS_IF_RETVAL_OK then
          udBusTime       := MyResult.aData[0]$t_GetBusCycleTime.udBusCycleTime;
        else
          // use this just to have 
          udBusTime := 1000;
          LogError("@02AA (SdiasSafetyManagerFSOE::InitModule) Failed to get bus cycle settings BusInterface.");
        end_if;

        udBusTime_us := udBusTime / 1000;

        // settings for pll
        sPllRegister.SystemPeriodTime           := udBusTime / 10;            // convert to 10*ns
        sPllRegister.StatusControl              := 0;
        sPllRegister.StatusControl.SyncEnable   := 1;
        sPllRegister.PeriodDivider              := to_usint(udBusTime_us / 1000);  // Bustime / 1ms to get divider (0 and 1 gets the same result)
        //sPllRegister.CompensationDelay // Keep value
        sPllRegister.SyncOut0.Offset            := 0;
        sPllRegister.SyncOut0.PeriodMultiplier  := to_usint(1000 / udBusTime_us);  // 1ms / Bustime to get multiplier (0 and 1 gets the same result);
        sPllRegister.SyncOut0.SyncStartDelay    := 0;
        sPllRegister.SyncOut0.ControlStatusRegister.SyncOutEnable     := 1;
        sPllRegister.SyncOut0.ControlStatusRegister.StartDelayEnable  := 0;
        if sPllRegister.PeriodDivider <= 1 then
          // no divider use system sync
          sPllRegister.SyncOut0.ControlStatusRegister.SyncSelector       := 1;  // no divider use system sync
        else
          // a divider is defined -> use it
          sPllRegister.SyncOut0.ControlStatusRegister.SyncSelector       := 0;
        end_if;

        eInitSSW := _ConfigurePLL;
      elsif TmpRetCode = ERROR then
        eInitSSW := _InitError;
      end_if;

//**********************************************************************************************************************************************************
    _ConfigurePLL:
      TmpRetCode := BusConfigWrite(Offset:=SDIAS_SAFETY_PLL_OFFSET, Length:=sizeof(sPllRegister), pData:=#sPllRegister, IsControlAccess:=TRUE);
    
      if TmpRetCode = READY then
      
        eInitSSW := _ConfigureTripleBufferAnalogReadData;
      elsif TmpRetCode = ERROR then
        eInitSSW := _InitError;
      end_if;

//**********************************************************************************************************************************************************
    _ConfigureTripleBufferAnalogReadData:
      
      //check if config from triple buffer for analog data is necessary
      if usAnalogInputByteSize then      
      
        // configure the triple buffer - the required bytes are passed to the FPGA.
        sAnalogTripleBufferConfig.usSizeuCtoCPU := usAnalogInputByteSize - sizeof(USINT); //-1 byte for messagecounter
        sAnalogTripleBufferConfig.usSizeCPUtouC := 0; //Analog write when supported
        
        TmpRetCode := BusConfigWrite(Offset:=SBF_OFFSET_ANALOG_VALUE_TRIPLE_PUFFER_SWITCH_OFFSET_WR_1, Length:=sizeof(sAnalogTripleBufferConfig), pData:=#sAnalogTripleBufferConfig, IsControlAccess:=FALSE);
    
        if TmpRetCode = READY then
          eInitSSW := _ConfigureFastTripleBuffer;
        elsif TmpRetCode = ERROR then
          eInitSSW := _InitError;
        end_if;
      else
        eInitSSW := _ConfigureFastTripleBuffer; 
      end_if;

//**********************************************************************************************************************************************************
    _ConfigureFastTripleBuffer:
      
      //check if init from triple buffer is necessary
      if uiPDOReadSizeFastUnsafeVar <> 0 |
        uiPDOWriteSizeFastUnsafeVar <> 0 then
      
        // configure the triple buffer - the required bytes are passed to the FPGA.
        sFastTripleBufferConfig.SizeuCtoCPU := uiPDOReadSizeFastUnsafeVar$USINT - 1;
        sFastTripleBufferConfig.SizeCPUtouC := uiPDOWriteSizeFastUnsafeVar$USINT - 1;
        
        TmpRetCode := BusConfigWrite(Offset:=SBF_OFFSET_FAST_UNSAFE_BUFFER_CONFIG, Length:=sizeof(sFastTripleBufferConfig), pData:=#sFastTripleBufferConfig, IsControlAccess:=FALSE);
    
        if TmpRetCode = READY then
          eInitSSW := _Finished;
        elsif TmpRetCode = ERROR then
          eInitSSW := _InitError;
        end_if;
      else
        eInitSSW := _Finished; 
      end_if;

//**********************************************************************************************************************************************************
    _Finished:
      //Only set online here to 1 if we don't have to adjust the the triple buffer config, otherwise online will be set in cyclic after correcting the triple buffer config
      if b_ModuleAccessReady & (bWriteAnalogTripleBufferConfig = FALSE) then
        Online := 1;
      end_if;
      
      eInitSSW          := _PrepareInit;      
      ModuleInitState   := READY;

#ifdef SAFETY_iDisableNonClassCommunication
      if ( pISafety^.udVersion >= 16#1002 ) then
        SAFETY_iDisableNonClassCommunication(uiMaster:=0, pucNode:=p_ObjectPath, uiDisable:=0);
      end_if;
#endif

//**********************************************************************************************************************************************************
    _InitError:
      eInitSSW          := _PrepareInit;      
      ModuleInitState   := ERROR; 

#ifdef SAFETY_iDisableNonClassCommunication
      if ( pISafety^.udVersion >= 16#1002 ) then
        SAFETY_iDisableNonClassCommunication(uiMaster:=0, pucNode:=p_ObjectPath, uiDisable:=0);
      end_if;
#endif
      
//**********************************************************************************************************************************************************
  end_case;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SdiasSafetyManagerFSoE::ClassSvr::NewInst
  VAR_INPUT
    pPara 	: ^CmdStruct;
    pResult 	: ^results;
  END_VAR
  VAR_OUTPUT
    ret_code 	: iprStates;
  END_VAR
  VAR
    i                 : UDINT;
    pSafetyModuleInfo : ^t_SdiasSafetyModuleInfo;
    MyPara 	          : CmdStruct;
    MyResult          : Results;
    HBGPlace          : UDINT;
    bRequiredError    : BOOL;
    bHWConfigError    : BOOL;

    pStr_HWTRequested     : ^CHAR;
    tmpplace      : USINT;
    pStr_HWTreeEntry : ^CHAR;
    usNextPlace   : USINT;
    pNewElement   : t_pHWCGetHardwareDiagnosisOutDynExt;
    usTmpAnalogInputByteSize : USINT;
  END_VAR
    
  ret_code := ERROR;

  CASE pPara^.uiCmd OF

//*****************************************************************************
//**  COMMANDS FROM BUS INTERFACE                                            **
//*****************************************************************************

//**********************************************************************************************************************************************************
    _BUS_IF_INIT_ACCESSES:
      // is called until the module is ready or in error state (only done once when no accesses have been created yet)
      ret_code := InitAccess();

//**********************************************************************************************************************************************************
    _BUS_IF_INIT_MODULE:
      // is called until the module is ready or in error state (done every time the module is connected)
      ret_code := InitModule();

//**********************************************************************************************************************************************************
    _BUS_IF_SDO_RESPONSE:
      // check if the command matches the one we're waiting for
      if (pPara^.aPara[0] = LastSDO.Command) &
         (pPara^.aPara[1] = LastSDO.Offset)  &
         (pPara^.aPara[2] = LastSDO.Length) then
      
        if pPara^.aPara[3]$iprStates = READY then
          if (LastSDO.Command = _BUS_IF_READ_VIA_SDO) then
            if (LastSDO.Offset = SBF_OFFSET_IO_MODULE_IDS) then
              if eResponseState = _wait then
                if pPara^.aPara[5] = LastSDO.Length then  
                  if pPara^.aPara[4] then
                    // all parameters are fine, so we're ready
                    ret_code := READY;
                    
                    _memcpy(ptr1:=#aModuleIDs, ptr2:=pPara^.aPara[4]$pVoid, cntr:=LastSDO.Length);
                    
                    bRequiredError := FALSE;
                    bHWConfigError := FALSE;
                    
                    //Set byte size of analog inputs to zero (will be summarized with every analog module)
                    usTmpAnalogInputByteSize := 0;
                    
                    // search for a HBG in the module IDs
                    HBGPlace := SDIAS_SAFETY_INVALID_MAX_PLACE;
                    for i := 0 to 16 do
                      if (aModuleIDs[i] AND SDIAS_SAFETY_MODULE_ID_BUS_MASK) = SDIAS_SAFETY_MODULE_ID_CAN_BUS_MASK then
                        HBGPlace := i;
                        exit;
                      end_if;
                    end_for;

                    // now we got the module IDs according to the safety cpu => check if it matches our configuration (only available on newer firmware versions)
                    if b_GotOptionalSettings then
                      pSafetyModuleInfo := #aSafetyModuleInfo[0];
                      
                      // always the same command
                      MyPara.uiCmd := SDIAS_SET_CLASS_STATE;

                      for i := 0 to 15 do
                        MyPara.aPara[1] := aModuleIDs[i];
                       
                        // if a required module is not matching => required error
                        if pSafetyModuleInfo^.sdRequired & (aModuleIDs[i] <> pSafetyModuleInfo^.usExpectedDeviceID) then
                          MyPara.aPara[0] := _RequiredError$DINT;
                          bRequiredError := TRUE;
                          if aModuleIDs[i] = SDIAS_SAFETY_INVALID_DEVICE_ID then
                            LogValue("@02AB (SdiasSafetyManagerFSoE::ClassSvr::NewInst) No safety IO module at required place {0}", Value:=i);                              
                          else
                            LogValue("@02AC (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Wrong safety IO module at required place {0}", Value:=i);                              
                          end_if;

                        // check if the configuration in the safety designer matches the configuration in the hardware classes
                        elsif pSafetyModuleInfo^.usExpectedDeviceID = OptionalSettings.ModuleIDsConfigured[i] then
                          // if it's an invalid device ID, it's only allowed if there is no module
                          if pSafetyModuleInfo^.usExpectedDeviceID = SDIAS_SAFETY_INVALID_DEVICE_ID then
                            if aModuleIDs[i] = SDIAS_SAFETY_INVALID_DEVICE_ID then
                              // correct (no module configured and no module found)
                              MyPara.aPara[0] := _ClassOk$DINT;  // this value is not being written to the module since if the ID is 0, there is also no this pointer to call the newinst
                            elsif (i <> HBGPlace) then
                              // no module configured but a module has been found at this place
                              LogValue("@02AD (SdiasSafetyManagerFSoE::ClassSvr::NewInst) No module configured in hardware classes and safety designer but found module at place {0}", Value:=i);
                              MyPara.aPara[0] := _WrongHardware$DINT; // again no object to write this value to
                              bHWConfigError := TRUE;
                            end_if;
                        
                          // now check if we got the expected ID at this position
                          elsif aModuleIDs[i] = pSafetyModuleInfo^.usExpectedDeviceID then
                            // correct module
                            MyPara.aPara[0] := _ClassOk$DINT;
                            
                            //Check if this is an analog module
                            if pSafetyModuleInfo^.usAnalogInputByteSize then
                              //Increase our byte size --> mabye we need to refresh the byte size in the tripple buffer of the analog values if the amount of configured modules
                              //differs to the amount of available modules on the hardware (e.g optional modules)
                              if usTmpAnalogInputByteSize = 0 then
                                usTmpAnalogInputByteSize += pSafetyModuleInfo^.usAnalogInputByteSize + sizeof(USINT);  //Add one byte for message counter if not added yet (first byte of analog input buffer is messagecounter)
                              else
                                usTmpAnalogInputByteSize += pSafetyModuleInfo^.usAnalogInputByteSize;          
                              end_if;
                            end_if;
                          
                            // if this module is optional
                          elsif OptionalSettings.OptionalFlagsIOModules AND (1 SHL i) then  
                            // if it's a blank module
                            if aModuleIDs[i] = SDIAS_SAFETY_MODULE_ID_BLANK_MODULE then
                              // ok: blank is allowed at optional place
                              MyPara.aPara[0] := _NoHardware$DINT;
                              
                              // don't send the blank-module ID
                              MyPara.aPara[1] := SDIAS_SAFETY_INVALID_DEVICE_ID;
                            else
                              if aModuleIDs[i] = SDIAS_SAFETY_INVALID_DEVICE_ID then
                                // ok: no module instead of the configured one (allowed since it's the last module. no more modules possible after an invalid device id)
                                MyPara.aPara[0] := _NoHardware$DINT;
                              
                              //optional module, maybe this module is the HBG itself
                              elsif (HBGPlace <> SDIAS_SAFETY_INVALID_MAX_PLACE) & (i = HBGPlace) then
                                
                                //OK: optional module is not available and this one is the HBG
                                MyPara.aPara[0] := _NoHardware$DINT;
                                MyPara.aPara[1] := SDIAS_SAFETY_INVALID_DEVICE_ID;                                
                              else
                                // wrong module detected
                                MyPara.aPara[0] := _WrongHardware$DINT;
                                bHWConfigError := TRUE;
                                LogValue("@02AE (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Wrong safety IO module at place {0}. (configured as optional)", Value:=i);
                              end_if;
                            end_if;
                          else
                            // the module id does not match (missing or wrong module)
                            if aModuleIDs[i] = SDIAS_SAFETY_INVALID_DEVICE_ID then
                              MyPara.aPara[0] := _NoHardware$DINT;
                            else
                              MyPara.aPara[0] := _WrongHardware$DINT;
                            end_if;
                            
                            // check if it's required
                            if MyPara.aPara[0] = _NoHardware$DINT then
                              LogValue("@02AF (SdiasSafetyManagerFSoE::ClassSvr::NewInst) No safety IO module at place {0}.", Value:=i);
                            else
                              LogValue("@02B0 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Wrong safety IO module at place {0}.", Value:=i);                              
                            end_if;

                            bHWConfigError := TRUE;
                          end_if;
                        else
                          // the configuration in the safety designer differs from the configuration via the hardware classes
                          
                          // if the available hardware matches the safety designer configuration and there is no module (only in hw class configuration)
                          if (OptionalSettings.ModuleIDsConfigured[i] = SDIAS_SAFETY_INVALID_DEVICE_ID) & 
                             ((aModuleIDs[i] = SDIAS_SAFETY_INVALID_DEVICE_ID) | (i = HBGPlace)) & 
                             (pSafetyModuleInfo^.usExpectedDeviceID <> SDIAS_SAFETY_INVALID_DEVICE_ID) then
                            // that's allowed
                            LogValue("@02B1 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Module in hardware class configuration which is neither available physically nor in safety designer configuration at place {0}", Value:=i);                          
                            MyPara.aPara[0] := _NoHardware$DINT;
                            
                          else
                            // in all other cases, it isn't
                            LogValue("@02B2 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Module in hardware class configuration differs from safety designer configuration at place {0}", Value:=i);                          
                            MyPara.aPara[0] := _InvalidConfguration$DINT;
                            bHWConfigError := TRUE;
                          end_if;
                        end_if;

                        if pSafetyModuleInfo^.pThis then
                          pSafetyModuleInfo^.pThis^.NewInst(#MyPara, #MyResult);
                        end_if;
                          
                        pSafetyModuleInfo += sizeof(t_SdiasSafetyModuleInfo);
                      end_for;
                      
                      //Check if our calculated size differs to the set one --> there must be optional analog modules which are not available
                      //So we need to set the size of the triple buffer config again, otherwise it won't work
                      if usTmpAnalogInputByteSize <> usAnalogInputByteSize then
                        usAnalogInputByteSize := usTmpAnalogInputByteSize;
                        bWriteAnalogTripleBufferConfig := TRUE;
                      end_if;

                      // check for hbg
                      if sHBG.pThis then
                        CanActive := OldCanActive := FALSE;
                        MyPara.uiCmd := SDIAS_SET_CLASS_STATE;

                        if HBGPlace <> SDIAS_SAFETY_INVALID_MAX_PLACE then
                          MyPara.aPara[1] := aModuleIDs[HBGPlace];

                          // if it's the wrong module and it's required => required error
                          if sHBG.sdRequired & (aModuleIDs[HBGPlace] <> sHBG.usExpectedDeviceID) then
                            MyPara.aPara[0] := _RequiredError$DINT;
                            bRequiredError := TRUE;
                            LogError("@02B3 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Wrong safety CAN terminal found instead of the configured required module!");
                            
                          elsif (OptionalSettings.ModuleIDHBG = sHBG.usExpectedDeviceID) then
                            // the configured ID of LASAL and safety designer are equal
                            
                            // if the module ID found is also the same => everthing is fine
                            if aModuleIDs[HBGPlace] = sHBG.usExpectedDeviceID then
                              MyPara.aPara[0] := _ClassOk$DINT;
                              CanActive := OldCanActive := TRUE;
                            else
                              // found something else
                              LogError("@02B4 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Wrong safety CAN terminal found (config of safety designer and hw classes match)");
                              MyPara.aPara[0] := _WrongHardware$DINT;
                              bHWConfigError := TRUE;
                            end_if;
                          else
                            // configuration of safety designer and hw classes does not match
                            LogError("@02B5 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Safety CAN terminal in hardware class configuration differs from safety designer configuration.");
                            MyPara.aPara[0] := _InvalidConfguration$DINT;
                            bHWConfigError := TRUE;
                          end_if;
                        else
                          MyPara.aPara[1] := SDIAS_SAFETY_INVALID_DEVICE_ID;

                          // projected in LASAL but not found in hardware
                          if sHBG.sdRequired then
                            MyPara.aPara[0] := _RequiredError$DINT;
                            bRequiredError := TRUE;
                            LogError("@02B6 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Required safety CAN terminal not available!");
                          else
                            // module is configured in safety designer
                            if (OptionalSettings.ModuleIDHBG <> SDIAS_SAFETY_INVALID_DEVICE_ID) then
                              // if the configuration does not match with the hardware classes
                              if (OptionalSettings.ModuleIDHBG <> sHBG.usExpectedDeviceID) then
                                LogError("@02B5 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Safety CAN terminal in hardware class configuration differs from safety designer configuration.");
                                MyPara.aPara[0] := _InvalidConfguration$DINT;
                                bHWConfigError := TRUE;
                              
                              // the IDs match but it's not optional. since it's not available => error
                              elsif (OptionalSettings.OptionalFlagHBG.1 = FALSE) then
                                MyPara.aPara[0] := _NoHardware$DINT;
                                LogError("@02B7 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Could not find the non-optional Safety CAN terminal defined in the safety designer configuration.");
                                bHWConfigError := TRUE;
                              
                              else
                                // if the IDs match and it's optional => just show no hardware (no error)
                                MyPara.aPara[0] := _NoHardware$DINT;
                              end_if;
                            else
                              LogError("@02B8 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Safety CAN terminal in hardware class configuration but not physically available and not in safety designer configuration.");
                              MyPara.aPara[0] := _NoHardware$DINT;
                            end_if;
                          end_if;
                        end_if;
                        sHBG.pThis^.NewInst(#MyPara, #MyResult);
                      else
                        // nothing projected for HBG in the lasal project
                        
                        // if module is configured in safety designer
                        if (OptionalSettings.ModuleIDHBG <> SDIAS_SAFETY_INVALID_DEVICE_ID) then
                          // if a HBG has been found
                          if HBGPlace <> SDIAS_SAFETY_INVALID_MAX_PLACE then
                            // if it's not the configured module
                            if (aModuleIDs[HBGPlace] <> OptionalSettings.ModuleIDHBG) then
                              LogError("@02B9 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Safety CAN terminal found doesn't match the safety designer configuration.");
                              bHWConfigError := TRUE;
                            end_if;
                          else
                            // module not available (only a problem if it's not optional)
                            if (OptionalSettings.OptionalFlagHBG.1 = FALSE) then
                              LogError("@02BA (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Could not find the non-optional Safety CAN terminal defined in the safety designer configuration.");
                              bHWConfigError := TRUE;
                            end_if;
                          end_if;
                        else
                          // module not configured in safety designer. if there is a module available, the number of IOs in safety does not match the config
                          if HBGPlace <> SDIAS_SAFETY_INVALID_MAX_PLACE then
                            LogError("@02BB (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Safety CAN terminal found but not projected in the safety designer configuration.");
                            bHWConfigError := TRUE;
                          end_if;
                        end_if;
                      end_if;
                    else
                      // old firmware (no optional settings available)
                      if MaxPlace <> SDIAS_SAFETY_INVALID_MAX_PLACE then
                        pSafetyModuleInfo := #aSafetyModuleInfo[0];
                        
                        // always the same command
                        MyPara.uiCmd := SDIAS_SET_CLASS_STATE;

                        for i := 0 to MaxPlace do
                          if pSafetyModuleInfo^.pThis then
                            MyPara.aPara[1] := aModuleIDs[i];
                            if aModuleIDs[i] = pSafetyModuleInfo^.usExpectedDeviceID then
                              MyPara.aPara[0] := _ClassOk$DINT;
                            elsif aModuleIDs[i] <> SDIAS_SAFETY_INVALID_DEVICE_ID then
                              if pSafetyModuleInfo^.sdRequired then
                                MyPara.aPara[0] := _RequiredError$DINT;
                                bRequiredError := TRUE;   
                                LogValue("@02AC (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Wrong safety IO module at required place {0}.", Value:=i);
                              else
                                MyPara.aPara[0] := _WrongHardware$DINT;   
                                bHWConfigError  := TRUE;
                              end_if;
                            else
                              if pSafetyModuleInfo^.sdRequired then
                                MyPara.aPara[0] := _RequiredError$DINT;
                                bRequiredError := TRUE;
                                LogValue("@02AB (SdiasSafetyManagerFSoE::ClassSvr::NewInst) No safety IO module at required place {0}.", Value:=i);
                              else
                                MyPara.aPara[0] := _NoHardware$DINT;  
                                // Hardwareclass placed in Project but no physical Hardware available is allowed
                                // bHWConfigError  := TRUE;
                              end_if;
                            end_if;
                            pSafetyModuleInfo^.pThis^.NewInst(#MyPara, #MyResult);
                          
                          elsif aModuleIDs[i] <> SDIAS_SAFETY_INVALID_DEVICE_ID then  // HWK this pointer is NIL but a module is identified 
                            bHWConfigError  := TRUE;
                          end_if;

                          pSafetyModuleInfo += sizeof(t_SdiasSafetyModuleInfo);
                        end_for;
                      end_if;
                      
                      // Check if a module info was passed for which there is no corrosponding HWK object.
                      if MaxPlace + 1 < sizeof(t_ModuleIDs) then
                        // it's only a config error if it's not the HBG
                        if (aModuleIDs[MaxPlace + 1] <> SDIAS_SAFETY_INVALID_DEVICE_ID) & ((MaxPlace + 1) <> HBGPlace) then
                          bHWConfigError  := TRUE;
                        end_if;
                      end_if;
                      
                      // check for hbg
                      if sHBG.pThis then
                        MyPara.uiCmd := SDIAS_SET_CLASS_STATE;
                        if HBGPlace <> SDIAS_SAFETY_INVALID_MAX_PLACE then
                          MyPara.aPara[1] := aModuleIDs[HBGPlace];

                          if aModuleIDs[HBGPlace] = sHBG.usExpectedDeviceID then
                            MyPara.aPara[0] := _ClassOk$DINT;
                            CanActive := OldCanActive := TRUE;
                            bHWConfigError := FALSE;
                          elsif aModuleIDs[HBGPlace] <> SDIAS_SAFETY_INVALID_DEVICE_ID then
                            if sHBG.sdRequired then
                              MyPara.aPara[0] := _RequiredError$DINT;
                              bRequiredError := TRUE;
                              LogError("@02BE (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Wrong safety IO module at required HBG place.");
                            else
                              MyPara.aPara[0] := _WrongHardware$DINT;
                              CanActive := OldCanActive := FALSE;
                            end_if;
                          else
                            if sHBG.sdRequired then
                              MyPara.aPara[0] := _RequiredError$DINT;
                              bRequiredError := TRUE;
                              LogError("@02BF (SdiasSafetyManagerFSoE::ClassSvr::NewInst) HBG required but not available!");
                            else
                              MyPara.aPara[0] := _NoHardware$DINT;
                              CanActive := OldCanActive := FALSE;
                            end_if;
                          end_if;
                        else
                          MyPara.aPara[1] := SDIAS_SAFETY_INVALID_DEVICE_ID;
                          if sHBG.sdRequired then
                            MyPara.aPara[0] := _RequiredError$DINT;
                            bRequiredError := TRUE;
                            LogError("@02BE (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Wrong safety IO module at required HBG place.");
                          else
                            MyPara.aPara[0] := _WrongHardware$DINT;
                            CanActive := OldCanActive := FALSE;
                          end_if;
                        end_if;
                        sHBG.pThis^.NewInst(#MyPara, #MyResult);
                      end_if;                    
                    end_if;
                    
                    if bRequiredError then
                      MyPara.uiCmd := _BUS_IF_SET_REQUIRED_ERROR;
                      ToBusInterface.NewInst(#MyPara, #MyResult);
                    end_if;                    

                    if bHWConfigError then
                      // if we have optional settings, we already logged the reason
                      if b_GotOptionalSettings = FALSE then
                        LogError("@02C0 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Hardwareconfiguration does not match objects placed in network.");                    
                      end_if;
                    
                      // Check if Safetymanyger is required                      
                      MyPara.uiCmd     := _BUS_IF_GET_REQUIRED_SETTING;
                      ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
                      if MyResult.aData[0]$t_BusIFRetvalErrorcode = _BUS_IF_RETVAL_OK then
                        // if it's required => set required error
                        if MyResult.aData[4] then
                          
                          MyPara.uiCmd := _BUS_IF_SET_REQUIRED_ERROR;
                          ToBusInterface.NewInst(#MyPara, #MyResult);
                        else
                        
                          SetSafetyState(_WrongSafetyHW);
                          Online      := 0;
                          
                          // Update BusIF ClassState
                          MyPara.uiCmd := _BUS_IF_SET_CLASS_STATE;
                          MyPara.aPara[0] := _WrongHardware$DINT;
                          ToBusInterface.NewInst(#MyPara, #MyResult);
                          
                          // Cancel init
                          eInitSSWErrorStep := eInitSSW;
                          eInitSSW := _InitError;
                          
                          // Set Module states                          
                          pSafetyModuleInfo := #aSafetyModuleInfo[0];
                          // always the same command
                          MyPara.uiCmd := SDIAS_SET_CLASS_STATE;
                          MyPara.aPara[0] := _ModuleFoundButManagerIsOff$DINT;

                          if MaxPlace <> SDIAS_SAFETY_INVALID_MAX_PLACE then
                            for i := 0 to MaxPlace do
                              if pSafetyModuleInfo^.pThis then
                                MyPara.aPara[1] := aModuleIDs[i];
                                pSafetyModuleInfo^.pThis^.NewInst(#MyPara, #MyResult);                              
                              end_if;
                              pSafetyModuleInfo += sizeof(t_SdiasSafetyModuleInfo);
                            end_for;
                          end_if;
                          
                          // check for hbg
                          if sHBG.pThis then
                            sHBG.pThis^.NewInst(#MyPara, #MyResult);
                          end_if;
                          
                        end_if;
                        
                      end_if;                      
                      
                    end_if;

                  else
                    LogError("@02C1 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Invalid SDO response buffer pointer.");
                  end_if;
                else
                  LogError("@02C2 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Invalid length for SDO response data.");
                end_if;
              
                eResponseState := _valid;
              else
                LogError("@02C3 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) SDO response arrived when no response was expected.");
              end_if;           
            end_if;
          elsif (LastSDO.Command = _BUS_IF_WRITE_VIA_SDO) then

              ret_code := READY;
              
              // we got the response to our write memory access
              LastSDO.ResponseArrived := TRUE;
              
          elsif (LastSDO.Command = _BUS_IF_READ_VIA_SDO_CTRL) then
            if LastSDO.ResponseArrived = FALSE then
              if pPara^.aPara[5] = LastSDO.Length then  
                if pPara^.aPara[4] then
                  // all parameters are fine, so we're ready
                  ret_code := READY;
                  
                  // copy the response data
                  _memcpy(ptr1:=Config.pActData, ptr2:=pPara^.aPara[4]$pVoid, cntr:=LastSDO.Length);
                else
                  LogError("@02C1 (SdiasSafetyManagerFSoE::ClassState::NewInst) Invalid SDO response buffer pointer.");
                end_if;
              else
                LogError("@02C2 (SdiasSafetyManagerFSoE::ClassState::NewInst) Invalid length for SDO response data.");
              end_if;
            
              LastSDO.ResponseArrived := TRUE;
            else
              LogError("@02C3 (SdiasSafetyManagerFSoE::ClassState::NewInst) SDO response arrived when no response was expected.");
            end_if;
          elsif (LastSDO.Command = _BUS_IF_WRITE_VIA_SDO_CTRL) then
            if LastSDO.ResponseArrived = FALSE then
              // all parameters are fine, so we're ready
              ret_code := READY;
            
              LastSDO.ResponseArrived := TRUE;
            else
              LogError("@02C3 (SdiasSafetyManagerFSoE::ClassState::NewInst) SDO response arrived when no response was expected.");
            end_if;
          end_if;
        else
          LogError("@02C4 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) SDO transfer failed.");        
        end_if;
      else
        LogError("@02C5 (SdiasSafetyManagerFSoE::ClassSvr::NewInst) Received invalid SDO response.");
      end_if;

//**********************************************************************************************************************************************************     
    _BUS_IF_DATA_POINTER_AVAILABLE:
      // does nothing in the FSoE version
      ret_code := READY;

//**********************************************************************************************************************************************************
    _BUS_IF_RESET_DETECTED:
      // don't overwrite other errors
      if SafetyState = _SafetyClassOK then      
        SafetyState := _LostPowerSupply;
      end_if;

      // check if module is requred
      MyPara.uiCmd     := _BUS_IF_GET_REQUIRED_SETTING;
      ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
      if MyResult.aData[0]$t_BusIFRetvalErrorcode = _BUS_IF_RETVAL_OK then
        // if it's required => set required error
        if MyResult.aData[4] then
          
          MyPara.uiCmd := _BUS_IF_SET_REQUIRED_ERROR;
          ToBusInterface.NewInst(#MyPara, #MyResult);
        end_if;
      end_if;
    
      // drop config of connected modules
      
      // initialize the message for the periphery
      MyPara.uiCmd := SDIAS_SET_CLASS_STATE;
      MyPara.aPara[1] := 0;// no device ID
      MyPara.aPara[0] := _NoHardware$DINT;

      // tell the connected IO module objects
      if MaxPlace <> SDIAS_SAFETY_INVALID_MAX_PLACE then
        pSafetyModuleInfo := #aSafetyModuleInfo[0];

        for i := 0 to MaxPlace do
          if pSafetyModuleInfo^.pThis then
            pSafetyModuleInfo^.pThis^.NewInst(#MyPara, #MyResult);
          end_if;

          pSafetyModuleInfo += sizeof(t_SdiasSafetyModuleInfo);
        end_for;
      end_if;
      
      // tell the hbg (if available)
      if sHBG.pThis then
        sHBG.pThis^.NewInst(#MyPara, #MyResult);
      end_if; 
      
//**********************************************************************************************************************************************************
    _BUS_IF_RESET_GONE_DETECTED:
      if SafetyState = _LostPowerSupply then
      
        // get safety and serial numbers of connected modules
        bUpdateModuleConfig := TRUE;
        
        // remember the time. in case we don't get the SDO response to signal the firmware being ready, we use a timeout
        ud_ResetGoneTime := ops.tAbsolute;
        
        // we wait for an asynchronous SDO response in the cyclic of the base class. once we got that, the firmware is ready
        b_WaitForFirmwareBoot := TRUE;

        // refetch IDs of connected modules
        eCheckIDSSW := _Wait4Idle;

        SafetyState := _SafetyClassOK;
      end_if;

//**********************************************************************************************************************************************************
    
    CMD_GET_HARDWARE_DIAGNOSIS:
      //Returns module info
      ret_code := ERROR;
      pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR;

      pStr_HWTRequested := pPara^.aPara[0]$t_HWCGetHardwareDiagnosisIn.pStr_HardewareTreeEntry;
      
      tmpplace := (pStr_HWTRequested+pPara^.aPara[0]$t_HWCGetHardwareDiagnosisIn.us_current_index)^$USINT;  
      
      //Check if pointer is valid
      if aSafetyModuleInfo[tmpplace].pThis then
        
        // Set Offline Device ID        
        pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_DeviceID := (aSafetyModuleInfo[tmpplace].usExpectedDeviceID AND 2#00111000 ) shr 3;   // Bit 3-5 Modul typ
        pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_Variante :=  aSafetyModuleInfo[tmpplace].usExpectedDeviceID AND 2#00000111;  // Bit 0-2 Submodul typ
        
        if aModuleIDs[tmpplace] = aSafetyModuleInfo[tmpplace].usExpectedDeviceID then
          
          ret_code := READY;
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_OK;
          
          pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_DeviceID  := (aModuleIDs[tmpplace] AND 2#00111000 ) shr 3;  // Bit 3-5 Modul typ
          pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_Variante  :=  aModuleIDs[tmpplace] AND 2#00000111; // // Bit 0-2 Submodul typ
          pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_Place     := tmpplace;
          pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.hd_HWVersion :=  sHwVersions.aVersion[tmpplace];  //Hardware version of module
                    
          //Get firmware version of module (if available)
          GetFWVersion(udPlace:=tmpplace, pData:=#a_FWVersion[0],sizeof(a_FWVersion));
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.pStr_FWVersion := #a_FWVersion[0];
                  
          // Get Serialno ---------------------------------------------------------------------------------------------          
          _memcpy(ptr1 := #a_SerialNo[0]
                , ptr2 := #sSafetySerNrs.aSerialNumbers[tmpplace]
                , cntr := sizeof(sSafetySerNrs.aSerialNumbers[tmpplace]) );
          
          a_SerialNo[sizeof(sSafetySerNrs.aSerialNumbers[tmpplace])] := 0;  // 0 Terminierung
          
          pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pStr_SerialNo := #a_SerialNo[0];
          
          
          pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.hd_SafetyNumber  := sSafetySerNrs.aSafetyNumbers[tmpplace];        


          // first free the old then create the memory (linked list) for the additional information
          
          if pAdditionalDiagInfo then
            HwDiagFreeDynExtList(pList:=pAdditionalDiagInfo);
          end_if;
          pAdditionalDiagInfo      := NIL;
          
          // add the firmware version
          pNewElement := HwDiagAddDynExt2List(ppList:=#pAdditionalDiagInfo, EntryID:=_HWC_DIAG_ID_SAFETY_FIRMWARE_VERSION, udVersion:=1, udDataLength:=sizeof(HDINT));
          
          if pNewElement then
            // add the data in the reserved memory
            (pNewElement$^HDINT + sizeof(t_HWCGetHardwareDiagnosisOutDynExt))^ := FirmwareVersion;
          end_if;

          // add the safety designer project name
          pNewElement := HwDiagAddDynExt2List(ppList:=#pAdditionalDiagInfo, EntryID:=_HWC_DIAG_ID_SAFETY_DESIGNER_PROJECT_NAME, udVersion:=1, udDataLength:=ProjectNameStr.GetLength());
          
          if pNewElement then
            // add the data in the reserved memory
            ProjectNameStr.ReadDataOff(udOff:=0, pData:=pNewElement$^USINT + sizeof(t_HWCGetHardwareDiagnosisOutDynExt), udMax:=pNewElement^.ud_DataLength);
          end_if;

          // add the safety designer project revision
          pNewElement := HwDiagAddDynExt2List(ppList:=#pAdditionalDiagInfo, EntryID:=_HWC_DIAG_ID_SAFETY_DESIGNER_PROJECT_REVISION, udVersion:=1, udDataLength:=ProjectRevisionStr.GetLength());
          
          if pNewElement then
            // add the data in the reserved memory
            ProjectRevisionStr.ReadDataOff(udOff:=0, pData:=pNewElement$^USINT + sizeof(t_HWCGetHardwareDiagnosisOutDynExt), udMax:=pNewElement^.ud_DataLength);
          end_if;

          pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.p_DynExtList := pAdditionalDiagInfo;

        elsif aModuleIDs[tmpplace] <> SDIAS_SAFETY_INVALID_DEVICE_ID then          
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_WRONG_HARDWARE;
        else          
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_NO_HARDWARE;
        end_if;
      
      else
        pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_SDIAS_MODULE_NOT_FOUND;
      end_if;

      
//**********************************************************************************************************************************************************    
    CMD_GET_HARDWARE_TREE_ENTRY:
      //Returns module info
      
      ret_code := ERROR;
      pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_ERROR;
      
      pStr_HWTreeEntry := pPara^.aPara[0]$t_HWCGetHardwareTreeEntryIn.pStr_LastHardewareTreeEntry;
      
      //First HWT Path
      if (pStr_HWTreeEntry + pStr_HWTreeEntry$^UINT^)^ <> HWT_ESCAPE_INTERNALBUS_SDIAS_SAFETY then  // + 1 for Byte length -1 for 2nd last element of string
        
        if aSafetyModuleInfo[0].pThis then
        
          _memcpy(ptr1 := #a_HWTEntryStr[0]
                , ptr2 := pPara^.aPara[0]$t_HWCGetHardwareTreeEntryIn.pStr_LastHardewareTreeEntry
                , cntr := pPara^.aPara[0]$t_HWCGetHardwareTreeEntryIn.pStr_LastHardewareTreeEntry$^UINT^ +2 );  // +2 2 Byte Strlength is not included in the stringlength 
          
          // Add escape sequence 
          a_HWTEntryStr[0]$UINT += 1;
          a_HWTEntryStr[a_HWTEntryStr[0]$UINT+1] := HWT_ESCAPE_INTERNALBUS_SDIAS_SAFETY;
          
          // Add Place
          a_HWTEntryStr[0]$UINT += 1;
          a_HWTEntryStr[a_HWTEntryStr[0]$UINT+1] := 0;   
          
          //Return Hardware Tree Entry and set return codes
          pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.pStr_NextHardewareTreeEntry := #a_HWTEntryStr[0];
          
          pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_OK_HWTSTR_RETURNED;
          ret_code := READY;          
          
        else
          pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_ERROR_SDIAS_MODULE_NOT_FOUND;
        end_if;

      //search next module
      else
      
        usNextPlace := (pStr_HWTreeEntry  + pPara^.aPara[0]$t_HWCGetHardwareTreeEntryIn.us_current_index)^$USINT+1;
            
        if usNextPlace <= SDIAS_SAFETY_MAX_PLACE_NR &
           aSafetyModuleInfo[usNextPlace].pThis then
        
          _memcpy(ptr1 := #a_HWTEntryStr[0]
                , ptr2 := pPara^.aPara[0]$t_HWCGetHardwareTreeEntryIn.pStr_LastHardewareTreeEntry
                , cntr := pPara^.aPara[0]$t_HWCGetHardwareTreeEntryIn.pStr_LastHardewareTreeEntry$^UINT^ +2 );  // +2 2 Byte Strlength is not included in the stringlength 
          
          // Set new Place
          a_HWTEntryStr[a_HWTEntryStr[0]$UINT + 1] := usNextPlace; 
          
          pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.pStr_NextHardewareTreeEntry := #a_HWTEntryStr[0];
          
          //Return Hardware Tree Entry and set return codes
          pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_OK_HWTSTR_RETURNED;
          ret_code := READY; 
          
        else
          ret_code := READY;
          pResult^.aData$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_OK_END_OF_LIST;
        end_if;
      end_if;

//**********************************************************************************************************************************************************     

//*****************************************************************************
//** INTERNAL COMMANDS                                                       **
//*****************************************************************************

//**********************************************************************************************************************************************************     
    CMD_SM_READ_PDO_SIZE:
      // get the size of the PDO
      LastSDO.Command := _BUS_IF_READ_VIA_SDO;
      LastSDO.Offset  := SBF_OFFSET_SPDO_LENGTH;
      LastSDO.Length  := sizeof(UINT);
    
      MyPara.uiCmd    := LastSDO.Command$UINT;
      MyPara.aPara[0] := LastSDO.Offset;
      MyPara.aPara[1] := LastSDO.Length;
      ret_code := ToBusInterface.NewInst(#MyPara, #MyResult);    

//**********************************************************************************************************************************************************
  else
    ret_code := SafetyBaseFSoE::NewInst(pPara, pResult);
//**********************************************************************************************************************************************************
  END_CASE;

END_FUNCTION


FUNCTION VIRTUAL SdiasSafetyManagerFSoE::ShowProjectRevision

  ProjectNameStr.WriteDataOff(udLen:=PrjNameStrLen + 1, udOff:=0, pData:=pPrjNameStr);

  ProjectRevisionStr.WriteDataOff(udLen:=PrjRevStrLen + 1, udOff:=0, pData:=pPrjRevStr);

END_FUNCTION


FUNCTION VIRTUAL SdiasSafetyManagerFSoE::InitSafeModule
  VAR_OUTPUT
    sd_retval 	: DINT;
  END_VAR

  // allocate memory for finding unsafe-IO-Servers
  // in first place we allocate 512 byte for our blocked transfers
  p_BlockedTransferMemory := ToStdLib.Malloc( size := SBF_CONFIG_MEMORY_BLOCK_SIZE );
  IF p_BlockedTransferMemory <> NIL THEN
    ud_BlockedTransferMemorySize := SBF_CONFIG_MEMORY_BLOCK_SIZE;
  ELSE
    SafetyState := _MemAllocFailed;
    sd_retval := -100;
    return;
  END_IF;

  // if there is a safety manager to gather the configuration
  if pSafetyManagerThis then
    // allocate memory for gathering configuration information => in first place we allocate 512 byte
    pConfigMem := ToStdLib.Malloc( size := SBF_CONFIG_MEMORY_BLOCK_SIZE );
    IF pConfigMem <> NIL THEN
      ConfigMemSize := SBF_CONFIG_MEMORY_BLOCK_SIZE;
      ConfigMemSizeUsed := 4;
    ELSE
      SafetyState := _MemAllocFailed;
      sd_retval := -100;
      return;
    END_IF;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SdiasSafetyManagerFSoE::CanOut::NewInst
  VAR_INPUT
    pPara 	: ^CmdStruct;
    pResult 	: ^results;
  END_VAR
  VAR_OUTPUT
    ret_code 	: iprStates;
  END_VAR
  VAR
    tempCmd         : CmdStruct;
    _result         : results;
  END_VAR
  
  ret_code := ERROR;  //Default is error  

  CASE pPara^.uiCmd OF
//**********************************************************************************************************************************************************
    SDIAS_SAFETY_LOGIN_HBG:
      // check parameters
      if pPara^.aPara[0] & pPara^.aPara[1] then

        ret_code := READY;  //Parameters are ok, set retcode
        
        sHBG.pThis               := pPara^.aPara[0]$pVirtualBase;
        sHBG.usExpectedDeviceID  := pPara^.aPara[1]$USINT;
        sHBG.sdRequired          := pPara^.aPara[2];
        sHBG.pIOStates           := pPara^.aPara[3]$^HDINT;

        // if leds/hgb not added so far, add them
        if StateBytesUsed = 0 then
          StateBitsUsed := (sizeof(t_LedAndIOStates.biLEDs) + sizeof(t_LedAndIOStates.HBGInputs)) * 8;
          // refresh state bytes used value
          StateBytesUsed := ((StateBitsUsed-1) / 8) + 1;
        end_if;

        if sHBG.sdRequired & (b_AnyModuleRequired = FALSE) then
          b_AnyModuleRequired := TRUE;
          // if any access is required => the businterface is also required
          tempCmd.uiCmd := _BUS_IF_SET_REQUIRED;
          ToBusInterface.NewInst(pPara:=#tempCmd, pResult:=#_result);
          if _result.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then  
            LogError("@029D (SdiasSafetyManagerFSoE::CanOut::NewInst) Failed to set the BusInterface to required.");
          end_if;
        end_if;
      end_if;
//**********************************************************************************************************************************************************
  END_CASE;

END_FUNCTION


FUNCTION VIRTUAL SdiasSafetyManagerFSoE::GetConfiguration
  VAR
    pHelp                 : ^void;
    SizeToGo              : UINT;
    ActSize               : UINT;
    ActAddr               : HDINT;
    SDOReqBuf             : SDORequReadConfig;
    SDORspBuf             : ARRAY [0..SBF_SDO_MAX_LENGTH-1] OF USINT;
    pRspBuf               : ^SDORespReadConfig;
    i                     : DINT;
    pSafetyModuleInfo     : ^t_SdiasSafetyModuleInfo;
    MyPara 	              : CmdStruct;
    MyResult              : Results;
  END_VAR

  //initialize header-data for request
  
  //calculate length without crc
  SDOReqBuf.StdHeader.Len := sizeof(SDORequReadConfig) - sizeof(SDOHeader.StdHeader.CRC);
  
  //type
  SDOReqBuf.StdHeader.Typ := SDO_STD;
  
  //command for reading config data
  SDOReqBuf.StdHeader.Cmd := SBF_SDO_COMMAND_READ;


  // read the complete 256 Bytes of safety and serial number info
  pHelp    := #sSafetySerNrs;
  SizeToGo := sizeof(sSafetySerNrs);
  pRspBuf  := (#SDORspBuf)$^SDORespReadConfig;
  ActAddr  := SBF_SDO_ADDRESS_SER_NR_DATA;

  while SizeToGo do
    if SizeToGo > SDIAS_SAFTEY_SDO_MAX_DATA_PER_PAKET then
      ActSize := SDIAS_SAFTEY_SDO_MAX_DATA_PER_PAKET;
    else
      ActSize := SizeToGo;
    end_if;

    if SDOReadCfgRequ(p_SDORequestBuffer  := #SDOReqBuf, 
                      p_SDOResponseBuffer := pRspBuf, 
                      ud_Address          := ActAddr, 
                      us_Length           := ActSize$USINT,
                      b_UseCache          := FALSE) then
      LogError("@02C6 (SdiasSafetyManagerFSoE::GetConfiguration) Failed to get safety and serial numbers of the IO modules.");
      return;
    else
      _memcpy(ptr1:=pHelp, ptr2:=#pRspBuf^.ud_Data, cntr:=ActSize);
    end_if;
  
    SizeToGo  -= ActSize;
    ActAddr   += ActSize;
    pHelp     += ActSize;
  end_while;


  // read the complete 64 Bytes of hardware version info
  pHelp    := #sHwVersions;
  SizeToGo := sizeof(sHwVersions);
  pRspBuf  := (#SDORspBuf)$^SDORespReadConfig;
  ActAddr  := SBF_SDO_ADDRESS_HW_VERSIONS; 

  while SizeToGo do
    if SizeToGo > SDIAS_SAFTEY_SDO_MAX_DATA_PER_PAKET then
      ActSize := SDIAS_SAFTEY_SDO_MAX_DATA_PER_PAKET;
    else
      ActSize := SizeToGo;
    end_if;

    if SDOReadCfgRequ(p_SDORequestBuffer  := #SDOReqBuf, 
                      p_SDOResponseBuffer := pRspBuf, 
                      ud_Address          := ActAddr, 
                      us_Length           := ActSize$USINT,
                      b_UseCache          := FALSE) then
      LogError("@02F9 (SdiasSafetyManagerFSoE::GetConfiguration) Failed to get hw versions of the Safe IO modules!");
      return;
    else
      // if the return code in the response buffer is not 0 => the virtual memory is not available
      if pRspBuf^.us_Returncode <> 0 then
        // reset array to make sure there are no hw versions stored
        _memset(dest:=#sHwVersions.aVersion[0], usByte:=0, cntr:=sizeof(sHwVersions));
        exit;
      end_if;

      _memcpy(ptr1:=pHelp, ptr2:=#pRspBuf^.ud_Data, cntr:=ActSize);
    end_if;
  
    SizeToGo  -= ActSize;
    ActAddr   += ActSize;
    pHelp     += ActSize;
  end_while;
  
  // check if the firmware version info is availble
  if sFirmwareVersion.RevMinor >= SBF_FW_VER_FW_INFO_AVAILABLE then

    // read the complete 64 Bytes of firmware version info
    pHelp    := #sFWVersions;
    SizeToGo := sizeof(sFWVersions);
    pRspBuf  := (#SDORspBuf)$^SDORespReadConfig;
    ActAddr  := SBF_SDO_ADDRESS_HW_VERSIONS + sizeof(sHwVersions); //After the hw version, there is a 64 byte block with the fw version of each module

    while SizeToGo do
      if SizeToGo > SDIAS_SAFTEY_SDO_MAX_DATA_PER_PAKET then
        ActSize := SDIAS_SAFTEY_SDO_MAX_DATA_PER_PAKET;
      else
        ActSize := SizeToGo;
      end_if;

      if SDOReadCfgRequ(p_SDORequestBuffer  := #SDOReqBuf, 
                        p_SDOResponseBuffer := pRspBuf, 
                        ud_Address          := ActAddr, 
                        us_Length           := ActSize$USINT,
                        b_UseCache          := FALSE) then
        LogError("@0790 (SdiasSafetyManagerFSoE::GetConfiguration) Failed to get fw versions of the Safe IO modules!");
        return;
      else
        // if the return code in the response buffer is not 0 => the virtual memory is not available
        if pRspBuf^.us_Returncode <> 0 then
          // reset array to make sure there are no fw versions stored
          _memset(dest:=#sFWVersions.aVersion[0], usByte:=0, cntr:=sizeof(sFWVersions));
          exit;
        end_if;

        _memcpy(ptr1:=pHelp, ptr2:=#pRspBuf^.ud_Data, cntr:=ActSize);
      end_if;
    
      SizeToGo  -= ActSize;
      ActAddr   += ActSize;
      pHelp     += ActSize;
    end_while;
  
  end_if;

  // only available for IOs, not the HBG
  if MaxPlace <> SDIAS_SAFETY_INVALID_MAX_PLACE then
    // always the same command
    MyPara.uiCmd := SDIAS_SET_NUMBERS;
  
    pSafetyModuleInfo := #aSafetyModuleInfo[0];
    for i := 0 to MaxPlace$DINT do
      // safety number
      MyPara.aPara[0] := (sSafetySerNrs.aSafetyNumbers[i])$DINT;
      
      // pointer to serial number string
      MyPara.aPara[1] := (#sSafetySerNrs.aSerialNumbers[i][0])$DINT;

      // hw version
      MyPara.aPara[2] := (sHwVersions.aVersion[i])$DINT;
      
      // fw version
      MyPara.aPara[3] := (sFWVersions.aVersion[i])$DINT;      

      if pSafetyModuleInfo^.pThis then
        pSafetyModuleInfo^.pThis^.NewInst(#MyPara, #MyResult);
      end_if;
      
      pSafetyModuleInfo += sizeof(t_SdiasSafetyModuleInfo);
    end_for;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SdiasSafetyManagerFSoE::DisconnectEvent
  VAR
    i                 : UDINT;
    pSafetyModuleInfo : ^t_SdiasSafetyModuleInfo;
    MyPara 	          : CmdStruct;
    MyResult          : Results;
  END_VAR

  SafetyBaseFSoE::DisconnectEvent();

  // initialize the message for the periphery
  MyPara.uiCmd := SDIAS_SET_CLASS_STATE;
  MyPara.aPara[1] := 0;// no device ID
  MyPara.aPara[0] := _NoHardware$DINT;

  // tell the connected IO module objects
  if MaxPlace <> SDIAS_SAFETY_INVALID_MAX_PLACE then
    pSafetyModuleInfo := #aSafetyModuleInfo[0];

    for i := 0 to MaxPlace do
      if pSafetyModuleInfo^.pThis then
        pSafetyModuleInfo^.pThis^.NewInst(#MyPara, #MyResult);
      end_if;

      pSafetyModuleInfo += sizeof(t_SdiasSafetyModuleInfo);
    end_for;
  end_if;
  
  // tell the hbg (if available)
  if sHBG.pThis then
    sHBG.pThis^.NewInst(#MyPara, #MyResult);
  end_if; 
  
  // clear the strings
  ProjectNameStr.Clear();
  ProjectRevisionStr.Clear();

END_FUNCTION


FUNCTION VIRTUAL SdiasSafetyManagerFSoE::SetSafetyState
  VAR_INPUT
    NewState 	: SafetyConfigStateType;
  END_VAR
  VAR
    MyPara 	  : CmdStruct;
    MyResult	: results;
  END_VAR

  // use it locally
  SafetyState := NewState;
  
  // tell the outer class
  MyPara.uiCmd := SDIAS_SET_SAFETY_STATE;
  MyPara.aPara[0] := NewState$DINT;
  ToBusInterface.NewInst(#MyPara, #MyResult);

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SdiasSafetyManagerFSoE::CyWork
  VAR_INPUT
    EAX 	: UDINT;
  END_VAR
  VAR_OUTPUT
    state (EAX) 	: UDINT;
  END_VAR
  VAR
    MyPara 	          : CmdStruct;
    MyResult          : Results;
    TmpRetCode        : iprStates;
  END_VAR
  
  if bWriteAnalogTripleBufferConfig then
        
    // configure the triple buffer - the required bytes are passed to the FPGA.
    if usAnalogInputByteSize = 0 then
      sAnalogTripleBufferConfig.usSizeuCtoCPU := 0; //no analog data used
    else
      sAnalogTripleBufferConfig.usSizeuCtoCPU := usAnalogInputByteSize - sizeof(USINT); //-1 byte for messagecounter
    end_if;

    sAnalogTripleBufferConfig.usSizeCPUtouC := 0; //Analog write when supported
    
    TmpRetCode := BusConfigWrite(Offset:=SBF_OFFSET_ANALOG_VALUE_TRIPLE_PUFFER_SWITCH_OFFSET_WR_1, Length:=sizeof(sAnalogTripleBufferConfig), pData:=#sAnalogTripleBufferConfig, IsControlAccess:=FALSE);

    if TmpRetCode = READY then
      bWriteAnalogTripleBufferConfig := FALSE;
      if b_ModuleAccessReady then
        //Set online, because we now have set the correct offset for the triple buffer to switch
        Online := 1;
      end_if;
      
    elsif TmpRetCode = ERROR then
      bWriteAnalogTripleBufferConfig := FALSE;
      LogError("@08A4 (SdiasSafetyManagerFSoE::CyWork) Failed to configure triple buffer for analog input data.");
    end_if;    
  end_if;

  // if the initialisiation has been finished and there is an object for the hbg check if it's has been connected or disconnected
  if Online then
  
    case eCheckIDSSW of
  //**********************************************************************************************************************************************************
      _Nothing:
        if sHBG.pThis then
          // check for a can connect event
          if CanActive > OldCanActive then
            // if we're already idle => get it on
            if eResponseState = _idle then
              eCheckIDSSW := _GetIDs;        
            else
              // otherwise, wait for it (need to remember the connect event)
              eCheckIDSSW := _Wait4Idle;
            end_if;
            
          // check for a can disconnect event
          elsif CanActive < OldCanActive then
            if sHBG.sdRequired then
              // if it's required => required error
              MyPara.uiCmd := _BUS_IF_SET_REQUIRED_ERROR;
              ToBusInterface.NewInst(#MyPara, #MyResult);
            else
              // otherwise show that it has been disconnected
              MyPara.uiCmd := SDIAS_SET_CLASS_STATE;
              MyPara.aPara[1] := 0;// no device ID
              MyPara.aPara[0] := _NoHardware$DINT;
              sHBG.pThis^.NewInst(#MyPara, #MyResult);
            end_if;
          end_if;
          OldCanActive := CanActive;        
        end_if;
        
  //**********************************************************************************************************************************************************
      _Wait4Idle:
        if eResponseState = _idle then
          eCheckIDSSW := _GetIDs;        
        end_if;

  //**********************************************************************************************************************************************************
      _GetIDs:
        case eResponseState of
        //*****************************************************
          _idle:
            LastSDO.Command := _BUS_IF_READ_VIA_SDO;
            LastSDO.Offset  := SBF_OFFSET_IO_MODULE_IDS;
            LastSDO.Length  := sizeof(t_ModuleIDs);
          
            MyPara.uiCmd    := LastSDO.Command$UINT;
            MyPara.aPara[0] := LastSDO.Offset;
            MyPara.aPara[1] := LastSDO.Length;
            TmpRetcode := ToBusInterface.NewInst(#MyPara, #MyResult);    
            if TmpRetcode = READY then
              SDOTimeMark  := ops.tAbsolute;
              eResponseState:= _wait; 
            elsif TmpRetcode = ERROR then
              LogError("@02A7 (SdiasSafetyManagerFSoE::InitModule) Failed to add read SDO for module configuration.");
            end_if;
        //*****************************************************
          _wait:
            // wait for response
            if ((ops.tAbsolute - SDOTimeMark) > SDIAS_SAFTEY_SDO_RESPONSE_TIMEOUT) then
              LogError("@02A1 (SdiasSafetyManagerFSoE::InitModule) SDO Response timeout while waiting for the module configuration.");
              eCheckIDSSW := _Nothing;
              eResponseState := _idle;
            end_if;
        //*****************************************************
          _valid:
            eCheckIDSSW := _Nothing;
            eResponseState := _idle;
        //*****************************************************
        end_case;
  //**********************************************************************************************************************************************************
    end_case;
  end_if;

  state := SafetyBaseFSoE::CyWork(0);

END_FUNCTION


FUNCTION VIRTUAL SdiasSafetyManagerFSoE::RefreshAsySrv
  VAR
    i                 : UDINT;
    pSafetyModuleInfo : ^t_SdiasSafetyModuleInfo;
    MyPara 	          : CmdStruct;
    MyResult          : Results;
    AsyValues         : t_AsyRefresh;
  END_VAR

  // tell the outer class
  MyPara.uiCmd := SDIAS_SET_ASY_STATE;
  AsyValues.QuitComError := QuitComError;
  MyPara.aPara[0] := (#AsyValues)$DINT;
  ToBusInterface.NewInst(#MyPara, #MyResult);  

  // tell the connected IO module objects
  if MaxPlace <> SDIAS_SAFETY_INVALID_MAX_PLACE then
    pSafetyModuleInfo := #aSafetyModuleInfo[0];

    for i := 0 to MaxPlace do
      if pSafetyModuleInfo^.pThis then
        pSafetyModuleInfo^.pThis^.NewInst(#MyPara, #MyResult);
      end_if;

      pSafetyModuleInfo += sizeof(t_SdiasSafetyModuleInfo);
    end_for;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SdiasSafetyManagerFSoE::FastUnsafeOutputs::Write
  VAR_INPUT
    input (EAX) 	: BDINT;
  END_VAR
  VAR_OUTPUT
    result (EAX) 	: BDINT;
  END_VAR
  VAR
    pUnsafeOutLogin : ^t_FastUnsafeOuts;
  END_VAR

  // if the pointer is valid and we're in the first init run (the firstscan check prevents a crash caused by someone writing on the server during runtime)
  if input & (us_FirstScan < 2) then
    pUnsafeOutLogin := input$^t_FastUnsafeOuts;
    // check if it's the correct usage of the class
    if pUnsafeOutLogin^.Kennung = SDIAS_SAFETY_FAST_UNSAFE_KENNUNG then
      pFastUnsafeOutThis := pUnsafeOutLogin^.pThis;
    end_if;
  end_if;
  
  result := input;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SdiasSafetyManagerFSoE::FastUnsafeInputs::Write
  VAR_INPUT
    input (EAX) 	: BDINT;
  END_VAR
  VAR_OUTPUT
    result (EAX) 	: BDINT;
  END_VAR

  FastUnsafeInputs := input;
  result := FastUnsafeInputs;

END_FUNCTION

FUNCTION VIRTUAL SdiasSafetyManagerFSoE::SetRetryCounter
  VAR
    pSafetyModuleInfo : ^t_SdiasSafetyModuleInfo;
    MyPara 	 : CmdStruct;
    MyResult : Results;
    i        :  USINT;
  END_VAR
    
  if b_RetryCounterAvailable then

    if MaxPlace <> SDIAS_SAFETY_INVALID_MAX_PLACE then
      //Command for new inst call in sdiassafetybase
      MyPara.uiCmd := SDIAS_SET_RETRY_COUNTER;

      //calls newinst method of all safety modules which exists.
      for i := 0 to MaxPlace do
        pSafetyModuleInfo := #aSafetyModuleInfo[i];
        MyPara.aPara[0] := a_RetryCnt[i];
        MyPara.aPara[1] := a_RetryCnt[i+16];  //+16 for retry counter of µC2
        pSafetyModuleInfo^.pThis^.NewInst(#MyPara, #MyResult);
      end_for;
    end_if;
  else
    //Retrycounter not available -> show -1 at servers.
    SafetyRetryCounter := -1; //Not available

    if MaxPlace <> SDIAS_SAFETY_INVALID_MAX_PLACE then
      MyPara.uiCmd := SDIAS_RETRY_COUNTER_NOT_AVAILABLE;
      for i := 0 to MaxPlace do
        pSafetyModuleInfo := #aSafetyModuleInfo[i];
        pSafetyModuleInfo^.pThis^.NewInst(#MyPara, #MyResult);
      end_for;
    end_if;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SdiasSafetyManagerFSoE::Background
  VAR_INPUT
    EAX 	: UDINT;
  END_VAR
  VAR_OUTPUT
    state (EAX) 	: UDINT;
  END_VAR

  // if we have to update the module config, are not busy and the firmware has already booted (or a timeout on the boot occured)
  if bUpdateModuleConfig & (eCheckIDSSW = _Nothing) & ((b_WaitForFirmwareBoot = FALSE) | ((ops.tAbsolute - ud_ResetGoneTime) > SBF_FIRMWARE_BOOTUP_TIMEOUT)) then
    bUpdateModuleConfig := FALSE;

    GetConfiguration();    
  end_if;

  state := SafetyBaseFSoE::Background(0);

END_FUNCTION


FUNCTION VIRTUAL SdiasSafetyManagerFSoE::BusConfigWrite
	VAR_INPUT
		Offset 	: HDINT;
		Length 	: UINT;
		pData 	: pVoid;
		IsControlAccess 	: BOOL;(* := FALSE *)
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR
  VAR
    TmpRetcode  : iprStates;
    MyPara      : CmdStruct;
    MyResult    : results;
  END_VAR

  retcode := BUSY;

  case Config.BusConfigSSW of
//**********************************************************************************************************************************************************
    _PrepareAccess:
      Config.RestLength := Length;
      Config.pActData   := pData;
      
      Config.BusConfigSSW := _StartAccess;
      
//**********************************************************************************************************************************************************
    _StartAccess:
      if IsControlAccess then
        LastSDO.Command := _BUS_IF_WRITE_VIA_SDO_CTRL;
      else
        LastSDO.Command := _BUS_IF_WRITE_VIA_SDO;      
      end_if;

      LastSDO.Offset  := Offset$DINT;
      if Config.RestLength > SDIAS_SAFETY_MAX_SDO_DATA_PER_CYCLE then
        LastSDO.Length  := SDIAS_SAFETY_MAX_SDO_DATA_PER_CYCLE;
      else
        LastSDO.Length  := Config.RestLength;
      end_if;
      LastSDO.ResponseArrived := FALSE;

      MyPara.uiCmd    := LastSDO.Command;
      MyPara.aPara[0] := LastSDO.Offset;
      MyPara.aPara[1] := LastSDO.Length;
      MyPara.aPara[2] := Config.pActData$DINT;
      TmpRetcode := ToBusInterface.NewInst(#MyPara, #MyResult);    
      if TmpRetcode = READY then
        Config.SDOTimeMark  := ops.tAbsolute;
        Config.BusConfigSSW := _Wait4Answer;
      elsif TmpRetcode = ERROR then
        retcode := ERROR;
        LogError("@02BC (SdiasSafetyManagerFSoE::BusConfigWrite) Failed to add write SDO for module configuration.");
      end_if;

//**********************************************************************************************************************************************************
    _Wait4Answer:
      // wait for response
      
      // check for response
      if LastSDO.ResponseArrived then
        Config.RestLength -= LastSDO.Length;
        Config.pActData   += LastSDO.Length;

        if Config.RestLength = 0 then
          retcode := READY;
          Config.BusConfigSSW := _PrepareAccess;
        end_if;
      elsif ((ops.tAbsolute - Config.SDOTimeMark) > SDIAS_SAFTEY_SDO_RESPONSE_TIMEOUT) then
        LogError("@02BD (SdiasSafetyManagerFSoE::BusConfigWrite) SDO Response timeout while waiting for the write response.");
        retcode := ERROR;
      end_if;
      
//**********************************************************************************************************************************************************
  end_case;

END_FUNCTION


FUNCTION VIRTUAL SdiasSafetyManagerFSoE::BusConfigRead
	VAR_INPUT
		Offset 	: HDINT;
		Length 	: UINT;
		pData 	: pVoid;
		IsControlAccess 	: BOOL;(* := FALSE *)
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR
  VAR
    TmpRetcode  : iprStates;
    MyPara      : CmdStruct;
    MyResult    : results;
  END_VAR

  retcode := BUSY;

  case Config.BusConfigSSW of
//**********************************************************************************************************************************************************
    _PrepareAccess:
      Config.RestLength := Length;
      Config.pActData   := pData;
      
      Config.BusConfigSSW := _StartAccess;
      
//**********************************************************************************************************************************************************
    _StartAccess:
      if IsControlAccess then
        LastSDO.Command := _BUS_IF_READ_VIA_SDO_CTRL;
      else
        LastSDO.Command := _BUS_IF_READ_VIA_SDO;      
      end_if;

      LastSDO.Offset  := Offset$DINT;
      if Config.RestLength > SDIAS_SAFETY_MAX_SDO_DATA_PER_CYCLE then
        LastSDO.Length  := SDIAS_SAFETY_MAX_SDO_DATA_PER_CYCLE;
      else
        LastSDO.Length  := Config.RestLength;
      end_if;
      LastSDO.ResponseArrived := FALSE;

      MyPara.uiCmd    := LastSDO.Command;
      MyPara.aPara[0] := LastSDO.Offset;
      MyPara.aPara[1] := LastSDO.Length;
      TmpRetcode := ToBusInterface.NewInst(#MyPara, #MyResult);    
      if TmpRetcode = READY then
        Config.SDOTimeMark  := ops.tAbsolute;
        Config.BusConfigSSW := _Wait4Answer;
      elsif TmpRetcode = ERROR then
        retcode := ERROR;
        LogError("@02BC (SdiasSafetyManagerFSoE::BusConfigRead) Failed to add write SDO for module configuration.");
      end_if;

//**********************************************************************************************************************************************************
    _Wait4Answer:
      // wait for response
      
      // check for response
      if LastSDO.ResponseArrived then
        Config.RestLength -= LastSDO.Length;
        Config.pActData   += LastSDO.Length;

        if Config.RestLength = 0 then
          retcode := READY;
          Config.BusConfigSSW := _PrepareAccess;
        end_if;
      elsif ((ops.tAbsolute - Config.SDOTimeMark) > SDIAS_SAFTEY_SDO_RESPONSE_TIMEOUT) then
        LogError("@02BD (SdiasSafetyManagerFSoE::BusConfigRead) SDO Response timeout while waiting for the write response.");
        retcode := ERROR;
      end_if;
      
//**********************************************************************************************************************************************************
  end_case;

END_FUNCTION


FUNCTION VIRTUAL SdiasSafetyManagerFSoE::HwDiagFreeDynExtList
	VAR_INPUT
		pList 	: ^t_HWCGetHardwareDiagnosisOutDynExt;
	END_VAR
  VAR
    pHelp 	: ^t_HWCGetHardwareDiagnosisOutDynExt;
  END_VAR
  
  while pList do
    // remember the current entry
    pHelp := pList;
  
    // set plist to the next entry and free pHelp
    pList := pList^.p_Next;
    
    // free the current entry
    ToStdLib.Free(mptr:=pHelp);
  end_while;

END_FUNCTION


FUNCTION VIRTUAL SdiasSafetyManagerFSoE::HwDiagAddDynExt2List
	VAR_INPUT
		ppList 	: ^t_pHWCGetHardwareDiagnosisOutDynExt;
		EntryID 	: t_HWCGetHardwareDiagnosisOutType;
		udVersion 	: UDINT;
		udDataLength 	: UDINT;
	END_VAR
	VAR_OUTPUT
		pNewElement 	: t_pHWCGetHardwareDiagnosisOutDynExt;
	END_VAR

  if ppList^ = NIL then
    ppList^$pVoid := ToStdLib.Malloc(size:=sizeof(t_HWCGetHardwareDiagnosisOutDynExt) + udDataLength);
    pNewElement := ppList^;    
  else
    pNewElement := ppList^;
    while pNewElement^.p_Next <> NIL do
      pNewElement := pNewElement^.p_Next;
    end_while;
    pNewElement^.p_Next$pVoid := ToStdLib.Malloc(size:=sizeof(t_HWCGetHardwareDiagnosisOutDynExt) + udDataLength);
    pNewElement := pNewElement^.p_Next;
  end_if;
  
  if pNewElement <> NIL then
    // initialize the new memory
    pNewElement^.DiagID         := EntryID;
    pNewElement^.ud_Version     := udVersion;
    pNewElement^.p_Next         := NIL;
    pNewElement^.ud_DataLength  := udDataLength;
    
    if udDataLength then
      _memset(dest:=pNewElement + sizeof(t_HWCGetHardwareDiagnosisOutDynExt), usByte:=0, cntr:=udDataLength);
    end_if;  
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SdiasSafetyManagerFSoE::HGWOut::NewInst
  VAR_INPUT
    pPara 	: ^CmdStruct;
    pResult 	: ^Results;
  END_VAR
  VAR_OUTPUT
    ret_code 	: iprStates;
  END_VAR
  VAR
    tempCmd         : CmdStruct;
    _result         : results;
    dRetCode        : DINT;
  END_VAR
  
  ret_code := READY;  

  case pPara^.uiCmd of
   
    //**********************************************************************************************************************************************************    
    SDIAS_SAFETY_GET_HGW_INFO:       
    
      //Check for valid version
      //*****************************************************************************
      if (pPara^.aPara[0] = 0x1) | (pPara^.aPara[0] = 0x2) then

        //Return version number
        pResult^.aData[0] := pPara^.aPara[0]$USINT;
        
        //pointer to input data to scp
        sHGW.pInputPDO           := pPara^.aPara[1]$^void;   
        
        if sHGW.pInputPDO = nil then
          ret_code := ERROR;
          LogError(e_msg:="@03DD (SdiasSafetyManagerFSoE::HGWOut::NewInst) Pointer to input data of SCP is invalid.");
          return;
        end_if; 
        
        // add PDO input data 
        dRetCode := AddPDOToInputBuffer(ud_p2Buffer         := sHGW.pInputPDO$UDINT
                                      , ud_SafetyNr         := sHGW.hdSafetyNrb$UDINT
                                      , b_IsOptional        := FALSE
                                      , ui_PdoLen           := sHGW.InputPDOLength
                                      , ui_TargetOffset     := sHGW.InputPDOOffset
                                      );

        if dRetCode = -2 then
          //busy
          ret_code := BUSY;
          return;
        elsif dRetCode <> 0 then
          ret_code := ERROR;
          LogError(e_msg:="@072B (SdiasSafetyManagerFSoE::HGWOut::NewInst) Failed to add HGW PDO to input buffer.");
          return;
        end_if;

        // return the pointer to the Buffer (is linear local memory, so the offset can be added later)
        sHGW.pOutputPDO$UDINT := GetPointer2PDOBuffer(); 
        
        // here we have a difference depending on the version
        if pPara^.aPara[0] = 0x1 then        
        
          pResult^.uiLng := 27;      
          pResult^.aData[1]$UDINT := (sHGW.pOutputPDO+sHGW.OutputPDOOffset)$UDINT;
          pResult^.aData[5]$UINT  := sHGW.InputPDOLength;  //data to scp
          pResult^.aData[7]$UINT  := sHGW.OutputPDOLength; //data to hgw
          pResult^.aData[9]$UINT  := sHGW.uiSlotID;
          pResult^.aData[11]$UINT  := sHGW.uiCommunicationID;
          pResult^.aData[13]$USINT := sHGW.udMachineNrb$USINT;    //Old version, 1 byte machine number       
          pResult^.aData[17]$USINT := sCPUConfig.CompPathLen$USINT;
          pResult^.aData[18]$UDINT := sCPUConfig.pCompPath$UDINT;
          pResult^.aData[22]$UDINT := sCPUConfig.SafetyNbr$UDINT;
          pResult^.aData[26]$UDINT := (#ErrorState)$UDINT;
          
        elsif pPara^.aPara[0] = 0x2 then
        
          pResult^.uiLng := 30;      
          pResult^.aData[1]$UDINT := (sHGW.pOutputPDO+sHGW.OutputPDOOffset)$UDINT;
          pResult^.aData[5]$UINT  := sHGW.InputPDOLength;  //data to scp
          pResult^.aData[7]$UINT  := sHGW.OutputPDOLength; //data to hgw
          pResult^.aData[9]$UINT  := sHGW.uiSlotID;
          pResult^.aData[11]$UINT  := sHGW.uiCommunicationID;
          pResult^.aData[13]$UDINT := sHGW.udMachineNrb;
          pResult^.aData[17]$USINT := sCPUConfig.CompPathLen$USINT;
          pResult^.aData[18]$UDINT := sCPUConfig.pCompPath$UDINT;
          pResult^.aData[22]$UDINT := sCPUConfig.SafetyNbr$UDINT;
          pResult^.aData[26]$UDINT := (#ErrorState)$UDINT;
          
        end_if;
        
      //*****************************************************************************
      else
        // unknown version of the request
        ret_code := ERROR;
      end_if;
  
    //**********************************************************************************************************************************************************
    SDIAS_SAFETY_LOGIN_HGW:

      //Check for valid version
      if pPara^.aPara[0] = 0x1 then

      // check parameters
        if pPara^.aPara[1] then        
          sHGW.pThis         := pPara^.aPara[1]$pVirtualBase; //this pointer of connect hgw communication class
          sHGW.sdRequired    := pPara^.aPara[2];              //required   

        if sHGW.sdRequired & (b_AnyModuleRequired = FALSE) then
          b_AnyModuleRequired := TRUE;
          // if any access is required => the businterface is also required
          tempCmd.uiCmd := _BUS_IF_SET_REQUIRED;
          ToBusInterface.NewInst(pPara:=#tempCmd, pResult:=#_result);
          if _result.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then  
            LogError("@03DE (SdiasSafetyManagerFSoE::HGWOut::NewInst) Failed to set the BusInterface to required");
          end_if;
        end_if;
      else
          ret_code := ERROR;
        end_if;
      
      else
        // unknown version of the request
        ret_code := ERROR;
      end_if;

    //**********************************************************************************************************************************************************
    CMD_SM_ADD_ROUTING_INFO:

      if sHGW.hdSafetyNrb <> pPara^.aPara[0]$HDINT then
        //safe act hgw safety number
        sHGW.hdSafetyNrb := pPara^.aPara[0]$HDINT;
        //add routing element for hgw panel
        dRetCode := AddRoutingElement(ud_SafeNumber:=sHGW.hdSafetyNrb, ud_thisp:=sHGW.pThis$UDINT, pPathInfo:=NIL);
        if dRetCode <> 0 then
          ret_code := ERROR;
        end_if;          
      end_if;
      
    //**********************************************************************************************************************************************************
    CMD_SM_ADD_SDO_TO_BUFFER:
      ret_code := ClassSvr.NewInst(pPara:=pPara, pResult:=pResult);      
    
  //**********************************************************************************************************************************************************
  
  else
    //if command is not known send it to safety manager
    if pSafetyManagerThis then      
      ret_code := pSafetyManagerThis^.NewInst(pPara, pResult);
    end_if;

  end_case;

END_FUNCTION

FUNCTION VIRTUAL SdiasSafetyManagerFSoE::SafeActModuleConfig
  VAR_INPUT
    sActModuleConfig 	: t_ModuleCfg;
  END_VAR
  VAR
  	pCompPath : pVoid;
  END_VAR

  //only copy required information for HGW connection, see SDIAS_SAFETY_GET_HGW_INFO
  //do not copy pointers of paths, they point to a temporary memory. copy the content
  sCPUConfig.SafetyNbr := sActModuleConfig.SafetyNbr;
  if sCPUConfig.pCompPath then
    pCompPath := ToStdLib.ReAlloc(sCPUConfig.pCompPath, sActModuleConfig.CompPathLen);
  else
    pCompPath := ToStdLib.Malloc(sActModuleConfig.CompPathLen);
  end_if;
  if pCompPath then
    _memcpy(pCompPath, sActModuleConfig.pCompPath, sActModuleConfig.CompPathLen);
    sCPUConfig.pCompPath := pCompPath$^USINT;
    sCPUConfig.CompPathLen := sActModuleConfig.CompPathLen;
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL SdiasSafetyManagerFSoE::FCN_Command::Write
  VAR_INPUT
    input (EAX) 	: UDINT;
  END_VAR
  VAR_OUTPUT
    result (EAX) 	: UDINT;
  END_VAR

  // only if input is valid and we're in the right state
  if (input = 1) & (FCN_StateMachine = 1) then
    sFlexCon.CommandRequest := input;
  end_if;

  result := input;

END_FUNCTION


FUNCTION VIRTUAL SdiasSafetyManagerFSoE::GetFWVersion
	VAR_INPUT
    udPlace : UDINT;
		pData 	: ^CHAR;
		Length 	: UDINT;
	END_VAR
  
  //Returns the fw version of the Sdias IO modules behind the SCP
  
  //Check pointer
  if pData then
    //Length of Firmwareversion (HDINT) -> 8Byte +1 byte zero termination
    if Length >= 9 then
      //Check if fw version is available
      if sFWVersions.aVersion[udPlace] then
        _itoa(udNumber:=sFWVersions.aVersion[udPlace], pString:=pData);  
      else
        pData^ := 0;  //No firmware version available
      end_if;
    else
      pData^ := 0;  //Invalid length
    end_if; 
  end_if;

END_FUNCTION
