//This file was generated by the LASAL2 CodeGenerator  -- 
//Please, do not edit this file (it might be overwritten by the next generator run)

//{{LSL_DEFINES
#ifndef _T_SAFETYBASE_H
#define _T_SAFETYBASE_H

// always allocate blocks for 5 more SDOs
#define SDO_BUFFER_ALLOC_BLOCK 5

// time between the CRC-Checks (CRC-Check to find out if configuration has changed)
#define CRC_CHECK_TIME  5000

#define TDO_BUFFER_SIZE 50

// time for SDO transfer on CDIAS
#define SDO_TRANSFERTIME_CDIAS 10 // maximum measured time was  6ms + 4ms reserve
#define SDO_TRANSFERTIME_VARAN 10 // maximum measured time was  6ms + 4ms reserve
#define SDO_TRANSFERTIME_MOVER 30 // maximum measured time was 22ms + 3ms reserve

// timeout for optional modules to be synchron
#define OPTIONAL_MODULE_SYNC_TIMEOUT  5000

// maximum number of tries to execute an asynchronous command (5 = if 5 consecutive tries to make an asynchronous communication fail, the class goes into error _AsyncComError)
#define SDO_MAX_TRIES 5

// version number of safety dll from which the quit error on CDIAS is supported
#define SAFETY_DLL_VERSION_CDIAS_QE 6


// if defined, the DO traffic is monitored
//#define DO_DEBUG
#ifdef DO_DEBUG
#pragma message("DO_DEBUG for Safety-Modules activated! Needs more CPU ressources!")
#endif

#endif // _T_SAFETYBASE_H
//}}LSL_DEFINES

//{{LSL_DECLARATION
#include "..\..\Class\SafetyCDIAS_Base\SafetyCDIAS_Base.h"
#include "..\..\Source\interfaces\lsl_st_safety.h"
#include "..\..\Class\SafetyManager\SafetyManager.h"

(*!
<Class
	Name               = "SafetyCDIAS_Base"
	Revision           = "3.19"
	GUID               = "{EA629206-D9FC-4C90-AAB0-E5D2CE0DCE76}"
	RealtimeTask       = "false"
	CyclicTask         = "false"
	BackgroundTask     = "false"
	Sigmatek           = "true"
	OSInterface        = "false"
	HighPriority       = "false"
	Automatic          = "false"
	UpdateMode         = "Prescan"
	IconPath           = ".\Class\Safety.ico"
	SharedCommandTable = "true"
	Objectsize         = "(546,120)">
	<Channels>
		<Server Name="ApplCRC" GUID="{6B61EEE6-63A9-4CEB-BA1E-4F5AF0475C47}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Shows the CRC of the safety logic (see CRC Dialog in the SafetyDesigner)"/>
		<Server Name="ClassState" GUID="{5D135176-5DDA-48A5-9E04-A1901F10F6FB}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Shows state of safety module&#13;&#10;&#13;&#10;_ModuleNotFound:&#13;&#10; - Module has not been found at the given position&#13;&#10;&#13;&#10;_WaitForSynchronicity:&#13;&#10; - Waiting to get synchrony with interacting modules&#13;&#10;&#13;&#10;_SafetyClassOK:&#13;&#10; - Module has been found and no errors reported&#13;&#10;&#13;&#10;_MemAllocFailed: &#13;&#10; - Failed to allocate or reallocate some memory for the module&#13;&#10;&#13;&#10;_ReadFWVerFailed:&#13;&#10; - Failed to read firmware version of module&#13;&#10;&#13;&#10;_ReinitConfig:&#13;&#10; - Only for CPU: Config of CPU has changed and update is in progress&#13;&#10;&#13;&#10;_ModFromCfgNotFound (Only for CPU):&#13;&#10; - Module in configuration, which is not physically available and HW-Class is placed&#13;&#10; - Module in configuration, which is not physically available and no HW-Class is placed&#13;&#10; - Module in configuration, which is not a CDIAS module (according to it&apos;s HW-Path)&#13;&#10;&#13;&#10;_UnsafeVarNotFound (Only for CPU):&#13;&#10; - Couldn&apos;t find an unsafe variable in the project. Compare spelling in Designer and in project.&#13;&#10;&#13;&#10;_UnknownCfgError (Only for CPU):&#13;&#10; - Error in reading config or creating routing tables occured.&#13;&#10;&#13;&#10;_AsyncComError: &#13;&#10; - Too many consecutive asynchronous commands failed! Please contact Sigmatek Support! &#13;&#10; &#13;&#10;_DOsIncreasedRestartApp: &#13;&#10; - Number or size of module accesses increased with new safety project! &#13;&#10; - =&gt; Can&apos;t continue, because the new data is not covered by the actual accesses! Restart Application! &#13;&#10; &#13;&#10;_LostPowerSupply: &#13;&#10; - The power supply of the safe CPU has been lost. &#13;&#10; &#13;&#10;_WrongSafetyHW: &#13;&#10; - The Safety objects in the project do not match the physical modules. &#13;&#10; - For every physical module a safety object must be placed in the project!"/>
		<Server Name="DesignerPrjConfigCRC" GUID="{E27AA6C4-4DC9-4B9F-BB0E-7A948D380F0C}" Visualized="false" Initialize="false" WriteProtected="true" Retentive="false" Comment="Shows the CRC of the whole SafetyDesigner project configuration (see CRC Dialog in the SafetyDesigner)"/>
		<Server Name="Error" GUID="{7722C658-8D6B-4FE0-8C80-E9F739F976B8}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="0: no error&#13;&#10;1: error&#13;&#10;2: communication timeout on input data from other safety modules"/>
		<Server Name="FPGA_Version" GUID="{4DB5A077-1B49-4156-8066-3B58AA893422}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="FPGA version&#13;&#10;&#13;&#10;Format:&#13;&#10;16#000000XY&#13;&#10;&#13;&#10;X = Major Revision (16#F marks a test version)&#13;&#10;Y = Minor Revision"/>
		<Server Name="FW_Version" GUID="{6D0EDCE0-AE52-49C7-8AB7-4C89E2B4B6DC}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Firmware version&#13;&#10;&#13;&#10;Format:&#13;&#10;16#XXXXYYYY&#13;&#10;&#13;&#10;XXXX = Major Revision&#13;&#10;YYYY = Minor Revision"/>
		<Server Name="GetDiagConnect" GUID="{D5C265C8-D8C7-420C-8D12-1D95B7FB263E}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false"/>
		<Server Name="HwCRC" GUID="{813147EE-EA80-4C9D-91F4-9C430E290E43}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Shows the CRC of the hardware configuration (see CRC Dialog in the SafetyDesigner)"/>
		<Server Name="QuitComError" GUID="{1686D7E3-4EC5-48D3-8D8D-97BFF997515F}" Visualized="true" Initialize="false" WriteProtected="false" Retentive="false" Comment="Write to this server to quit communication errors (indicated if Server Error = 2)&#13;&#10;This server can also quit general errors (Server Error = 1) if the safety.dlm is used.&#13;&#10;&#13;&#10;To detect the used quit method, read the server directly after writing. In both cases the error quitting is done asynchronously (= not immediately).&#13;&#10;&#13;&#10;Server shows actual quit-state&#13;&#10;  2..busy with quitting general errors (safety dll version 6 or higher required)&#13;&#10;  1..busy with quitting communication error&#13;&#10;  0..ready&#13;&#10; -1..error at creating a new safety state&#13;&#10; -2..failed to disable user prompt for quit error&#13;&#10; -3..failed to select module via safety number&#13;&#10; -4..error at establishing connection to module (safety designer must not be online at the same time!)&#13;&#10; -5..failed to send the quit error command to the module&#13;&#10; -6..failed to delete the created safety state"/>
		<Server Name="RunState" GUID="{E4C9B590-1462-458E-ABB1-EFD49D8FBD53}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="0: not running&#13;&#10;1: running in operational or temporary operational mode"/>
		<Server Name="SafetyNumber" GUID="{8120C4EB-E871-47BD-8BF0-B96C48AEF70C}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Shows the unique safety number of this module"/>
		<Server Name="ServiceMode" GUID="{E42BD191-733B-4DA2-B45C-665F3692A8E6}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="0: operational mode&#13;&#10;1: service mode or temporary operational mode&#13;&#10;2: check configuration phase"/>
		<Server Name="State">
		</Server>
		<Server Name="VoltageOK" GUID="{7AB9794E-0FFD-471F-882A-DDA30354037D}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="0: voltage of output/pulse output supply not ok&#13;&#10;1: voltage of output/pulse output supply ok"/>
		<Client Name="ActivateFastUnsafeIOs" Required="false" Internal="false" DefValue="0" Comment="Setting to activate fast unsafe variables (realtime communication to the safety module)&#13;&#10;&#13;&#10;0..no fast unsafe IO variables active&#13;&#10;1..fast unsafe IO variables active (Servers FastUnsafeInput1..8 and FastUnsafeOutput1..8)"/>
		<Client Name="AdditionalSPDOs" Required="false" Internal="false" DefValue="0" Comment="configure number of additional SPDOs transmitted every cycle to this safety module (by default 1 SPDO is transmitted)&#13;&#10;&#13;&#10;possible values are from 0 to 9&#13;&#10;&#13;&#10;to get the lowest transmission time, start your system with this client on 0&#13;&#10;read the value of the first private variable of this object (ui_cnt_PDOInputBuffer) subtract 1 and put this value to the client&#13;&#10;&#13;&#10;ATTENTION!&#13;&#10;The higher this value is, the more load will be on this modules cycle (has to process more PDOs)&#13;&#10;The size of the additional SPDOs can be set with the client SPDOWriteSize."/>
		<Client Name="DelayedStartup" Required="false" Internal="false" DefValue="0" Comment="0 .. If a Safety module would be connected after the startup phase of CPU, no reconfiguration is initiated.&#13;&#10;&#13;&#10;1 .. Reconfiguration of safety CPUs is initiated when modules are connected after the startup phase of CPU.&#13;&#10;If they are connected between the time gap of the check config time (3 minutes) of the safety CPU, there will be no error be active on the Safety CPU.&#13;&#10;If they are connected after the timeout of check config time, an error will be set at the safetymodules which can be quitted via the QuitComError server or the safety designer."/>
		<Client Name="FileSys" Required="false" Internal="false"/>
		<Client Name="ServerUpdateTime" Required="false" Internal="false" DefValue="50" Comment="Time in ms, how long the Servers (unsafe variables in Safety Designer) should take to update.&#13;&#10;This Client is automatically updated, if the given time is too short to handle with the current amount of servers."/>
	</Channels>
	<Dependencies>
		<Files>
			<File Path=".\Class\SafetyCDIAS_Base\SafetyCDIAS_Base.h" Include="true"/>
			<File Path=".\Source\interfaces\lsl_st_safety.h" Include="true"/>
			<File Path=".\Class\VaranManager_Base\VaranManager_Base.h" Include="false"/>
			<File Path=".\Class\SafetyManager\SafetyManager.h" Include="true"/>
		</Files>
	</Dependencies>
	<RevDoku>
		<Owner Company="Sigmatek" Author="RamAnd"/>
		<Dokumentation Revision="3.19" 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="3.18" 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."/>
		<Dokumentation Revision="3.17" Date="05.10.2020" Author="EisMic" Company="Sigmatek" Description="Added support to get the visual error code offset for the class SafetyDiagnosisInfo.&#13;&#10;Diagnosis info data is now fetched even if the the manager initialisation is not finished."/>
		<Dokumentation Revision="3.16" Date="20.04.2018" Author="ZoePat" Company="Sigmatek" Description="Corrected logging of &quot;No thispointer available for Server of local unsafe input variable&quot;. Since v3.14 it was logged every few cyclic-tasks if the error occured. Now it is logged once if the error occures the first time."/>
		<Dokumentation Revision="3.15" Date="06.03.2018" Author="EisMic" Company="Sigmatek" Description="Attached header files no longer point to the installation directory of LASAL but instead now point to the the source/interfaces folder."/>
		<Dokumentation Revision="3.14" 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="3.13" Date="27.11.2017" Author="FurDom" Company="Sigmatek" Description="Added support to read out the error information on the channels"/>
		<Dokumentation Revision="3.12" Date="24.10.2017" Author="HaeTho" Company="Sigmatek" Description="SA38381:&#13;&#10;. If in a system with EDGE2-CPU a CDIAS Safety Module connected via VARAN the VARAN distributor module is no more recognized.&#13;&#10;Solution:&#13;&#10;. If a safety module is present on a local CDIAS/SDIAS - bus the intern Move-Modus is no more activated.&#13;&#10;. The start of the data objects has been moved from the callback functions to the UpdateRT funktion."/>
		<Dokumentation Revision="3.11" Date="23.05.2017" Author="RamAnd" Company="Sigmatek" Description="A pointer for dynamic parameters has been added to the hardware diagnosis. Added initialisation of the pointer with NIL."/>
		<Dokumentation Revision="3.10" Date="28.02.2017" Author="EisMic" Company="Sigmatek" Description="Corrected an error which lead to a synchronisation problem between more CSCP0x if not all modules were present at startup."/>
		<Dokumentation Revision="3.9" Date="16.02.2017" Author="EisMic" Company="Sigmatek" Description="Added server DesignerPrjConfigCRC."/>
		<Dokumentation Revision="3.8" Date="06.06.2016" Author="EisMic" Company="Sigmatek" Description="Corrected error if distributed safety modules are connected after the initialisation phase."/>
		<Dokumentation Revision="3.7" Date="11.05.2016" Author="RamAnd" Company="Sigmatek" Description="Suppressed warning that would occur with target ARM on compiler version 30 or higher."/>
		<Dokumentation Revision="3.6" Date="08.03.2016" Author="EisMic" Company="Sigmatek" Description="Added support for SafetyDiagnosisInfo hardwareclass."/>
		<Dokumentation Revision="3.5" Date="17.02.2016" Author="RamAnd&#13;&#10;EisMic" Company="Sigmatek" Description="Moved logging in case of an error from realtime to cyclic priority to prevent a RT-Runtime error.&#13;&#10;Set the base object in the reference network to visualized, so the Server SerialNo from the derivations can be visualized in Lasal Screen."/>
		<Dokumentation Revision="3.4" 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;Added clients SPDOReadSize and SPDOWriteSize to set the length of the specific SPDO Dataobject."/>
		<Dokumentation Revision="3.3" Date="17.03.2015" Author="RamAnd" Company="Sigmatek" Description="Improved Method DtoH."/>
		<Dokumentation Revision="3.2" Date="07.07.2014" Author="EisMic" Company="Sigmatek" Description="Added support for hardware tree diagnosis."/>
		<Dokumentation Revision="3.1" Date="17.06.2014" Author="RamAnd" Company="Sigmatek" Description="Added possibility to quit other errors than communication errors server QuitComError."/>
		<Dokumentation Revision="3.0" Date="22.01.2014" Author="RamAnd&#13;&#10;RamAnd" Company="Sigmatek" Description="Removed double assignment which could lead to a problem on ARM targets.&#13;&#10;If connected via VARAN, the PDOs are now activated in realtime to prevent errors at transmission."/>
		<Dokumentation Revision="2.90" Date="05.12.2013" Author="RamAnd&#13;&#10;RamAnd&#13;&#10;RamAnd&#13;&#10;LanSte" Company="Sigmatek" Description="Reactivated time synchronisation after reconnecting an optional module.&#13;&#10;Removed domain support&#13;&#10;Class has been adapted for communication with SDIAS Safety modules (class SafetyBase).&#13;&#10;Added Payload Support"/>
		<Dokumentation Revision="2.80" Date="30.08.2013" Author="EisMic" Company="Sigmatek" Description="Added serial number display"/>
		<Dokumentation Revision="2.70" Date="18.07.2013" Author="RamAnd&#13;&#10;RamAnd&#13;&#10;RamAnd" Company="Sigmatek" Description="Corrected error in handling of unsafe BDINT input variables which could have lead to a _MemAllocFailed State of the class.&#13;&#10;If an optimized CDIAS module has been used via CIV512, the new time sync handshake access could have failed (required or not required frame error occured).&#13;&#10;Added Server QuitComError to quit communication errors indicated if Server Error has the value 2."/>
		<Dokumentation Revision="2.60" Date="07.03.2013" Author="RamAnd&#13;&#10;RamAnd&#13;&#10;BeiWol&#13;&#10;ZoePat" Company="Sigmatek" Description="Changed range of the safety NewInst commands. Range for HW-Classes: 0x8000-0x8FFF; Range for Safety HW-Classes: 0x8100-0x81FF&#13;&#10;Added dependency to HwControl, which is needed for use of the SafetyManager.&#13;&#10;Added functionality to use module optional via define DEACTIVATED_LSL as Place value.&#13;&#10;Add all modules to the safetymanager, to be able to route SDOs in every case. Corrected minimal length of configuration."/>
		<Dokumentation Revision="2.50" Date="22.01.2013" Author="ZoePat&#13;&#10;ZoePat&#13;&#10;RamAnd&#13;&#10;RamAnd&#13;&#10;ZoePat" Company="Sigmatek" Description="Support for SCP010 added&#13;&#10;Added Methode IsOptimizedCPU() to be able to overload it.&#13;&#10;Added functionality for domain internal interface frames&#13;&#10;Added new state _AsyncComError which occures if 5 consecutive tries of making an asynchronous communication to the module fail.&#13;&#10;Corrected response time for STDO&apos;s if module is connected via VARAN without mover."/>
		<Dokumentation Revision="2.39" Date="23.08.2012" Author="RamAnd" Company="Sigmatek" Description="Added compatibility between old and new safety modules (e.g. CSCP011 and CSCP012)"/>
		<Dokumentation Revision="2.38" Date="20.07.2012" Author="ObeChr" Company="Sigmatek" Description="Implemented time measurement for internal tests in methods UpdateRt, UpdateRtPostScan and UpdateCy"/>
		<Dokumentation Revision="2.37" Date="23.03.2012" Author="RamAnd" Company="Sigmatek" Description="Added support for fast unsafe variables, unsafe BDINT variables as well as for unsafe variables to be transported to or from other domains."/>
		<Dokumentation Revision="2.36" Date="12.03.2012" Author="RamAnd" Company="Sigmatek" Description="Reworked handling of unsafe variables. Corrected errors where unsafe variables weren&apos;t written to safety cpu after startup of PLC or startup of safety cpu."/>
		<Dokumentation Revision="2.35" Date="25.01.2012" Author="RamAnd" Company="Sigmatek" Description="Changed init value of unsafe outputs from 1 to 0."/>
		<Dokumentation Revision="2.34" Date="28.10.2011" Author="RamAnd" Company="Sigmatek" Description="SetBusReady signal is now sent to all modules at the same time (problems with SF_EDM function block)"/>
		<Dokumentation Revision="2.33" Date="20.01.2012" Author="RamAnd" Company="Sigmatek" Description="Crash fixed, if a module is needed by the configuration found in a safety CPU but physically not available."/>
		<Dokumentation Revision="2.32" Date="01.12.2011" Author="RamAnd" Company="Sigmatek" Description="Error in additional SPDOs fixed, which could have led to a loss of SPDO data =&gt; Error 199 in Safety Designer."/>
		<Dokumentation Revision="2.31" Date="04.10.2011" Author="RamAnd" Company="Sigmatek" Description="If all used Safety-CPUs have been connected via VARAN and there were some Safety-IO modules on local CDIAS the PDO move command at the outputs was enabled wrongly =&gt; Ensured disabling of PDO move command if there is any safety module connected via local CDIAS"/>
		<Dokumentation Revision="2.30" Date="06.09.2011" Author="RamAnd" Company="Sigmatek" Description="All methods are now virtual, so they can be overwritten by derivations like SafetyVARAN_Base."/>
		<Dokumentation Revision="2.29" Date="27.06.2011" Author="RamAnd" Company="Sigmatek" Description="Support of sorting VARAN commands by priority added (needed for communication between safety-modules)."/>
		<Dokumentation Revision="2.28" Date="20.06.2011" Author="RamAnd" Company="Sigmatek" Description="Added UpdateRtPostScan Method, to improve performance of safety frame transmission."/>
		<Dokumentation Revision="2.27" Date="08.06.2011" Author="RamAnd" Company="Sigmatek" Description="Fixed that the PDO move command was not enabled in some cases."/>
		<Dokumentation Revision="2.26" Date="31.03.2011" Author="RamAnd" Company="Sigmatek" Description="Corrected error in transfer of unsafe variables which could have lead to a timeout in the communication of the unsafe variables."/>
		<Dokumentation Revision="2.25" Date="31.03.2011" Author="RamAnd" Company="Sigmatek" Description="Content of corresponding LASAL Hardware Description file (.lhd) which is necessary for the hardware editor has been updated"/>
		<Dokumentation Revision="2.24" Date="16.12.2010" Author="RamAnd" Company="Sigmatek" Description="The first time unsafe variables were written to the safety cpu, their values weren&apos;t correct."/>
		<Dokumentation Revision="2.23" Date="14.12.2010" Author="RamAnd" Company="Sigmatek" Description="Adresses for the PDO move command are now also compatible with upcoming linux operating systems."/>
		<Dokumentation Revision="2.22" Date="07.12.2010" Author="RamAnd" Company="Sigmatek" Description="Wait until all necessary modules are synchrony before sending the Bus Ready signal (ClassState shows &quot;_WaitForSynchronicity&quot;)"/>
		<Dokumentation Revision="2.21" Date="02.12.2010" Author="RamAnd" Company="Sigmatek" Description="Fixed wrong behavior, if an unsave variable couldn&apos;t be found which could lead to a crash."/>
		<Dokumentation Revision="2.20" Date="29.11.2010" Author="RamAnd" Company="Sigmatek" Description="Fixed memory leak in PDO move command"/>
		<Dokumentation Revision="2.19" Date="17.11.2010" Author="RamAnd" Company="Sigmatek" Description="Corrected an error in initialisation which could lead to a loss of the first STDO-Requests after starting up the project."/>
		<Dokumentation Revision="2.18" Date="11.11.2010" Author="RamAnd" Company="Sigmatek" Description="Corrected error, where scheduler is waiting for the first PDO to come but we have no PDO input for this module."/>
		<Dokumentation Revision="2.17" Date="09.11.2010" Author="BleErn" Company="Sigmatek" Description="Corrected handshake of STDO-transfer&#13;&#10;Implemented a buffer for STDO-transfer"/>
		<Dokumentation Revision="2.16" Date="19.10.2010" Author="RamAnd" Company="Sigmatek" Description="Added a special move command which is used if all safety modules are connected over VARAN. Copying of the PDOs is done now by the VARAN Manager instead of the CPU. This will reduce the realtime CPU load significantly and increases the load of the isochronous VARAN task only slightly."/>
		<Dokumentation Revision="2.15" Date="05.10.2010" Author="RamAnd" Company="Sigmatek" Description="Added some Entries in debugger trace and logfile if something goes wrong."/>
		<Dokumentation Revision="2.14" Date="27.09.2010" Author="BleErn" Company="Sigmatek" Description="Integration of scheduler for unsafe data"/>
		<Dokumentation Revision="2.13" Date="03.08.2010" Author="RamAnd" Company="Sigmatek" Description="Corrected transfer of unsafe variables (didn&apos;t work, if 12 or more variables should be transferred in one direction)"/>
		<Dokumentation Revision="2.12" Date="22.07.2010" Author="WocPet" Company="Sigmatek" Description="Changes in base class: new client &quot;Required&quot; added"/>
		<Dokumentation Revision="2.11" Date="01.07.2010" Author="RamAnd" Company="Sigmatek" Description="Content of corresponding LASAL Hardware Description file (.lhd) which is necessary for the hardware editor has been corrected"/>
		<Dokumentation Revision="2.10" Date="09.06.2010" Author="RamAnd" Company="Sigmatek" Description="First library version"/>
	</RevDoku>
	<Network Name="SafetyCDIAS_Base">
		<!-- List of Components in this network -->
		<Components>
			<Object
				Name       = "_base"
				GUID       = "{38593693-E812-4005-8B38-4C74C9743C65}"
				Class      = "HwBaseCDIAS"
				Position   = "(235,120)"
				Visualized = "true">
				<Channels>
					<Server Name="SerialNo"/>
					<Server Name="State"/>
					<Client Name="MasterConnect"/>
					<Client Name="Place"/>
					<Client Name="Required"/>
					<Client Name="TimeBase" Value="0"/>
					<Client Name="TimeBaseOffset" Value="0"/>
					<Client Name="To_StdLib"/>
				</Channels>
			</Object>
		</Components>
		<Comments>
		</Comments>
		<!-- List of Connections in this network -->
		<Connections>
			<Connection Source="_base.MasterConnect" Destination="this.MasterConnect" Vertices="(235,210),(38,210),"/>
			<Connection Source="this.State" Destination="_base.State" Vertices="(707,210),(535,210),"/>
			<Connection Source="_base.Place" Destination="this.Place" Vertices="(235,270),(38,270),"/>
			<Connection Source="_base.Required" Destination="this.Required" Vertices="(235,330),(38,330),"/>
			<Connection Source="this.SerialNo" Destination="_base.SerialNo" Vertices="(707,270),(535,270),"/>
		</Connections>
		<!-- Headerfiles -->
		<Options>
		</Options>
	</Network>
</Class>
*)
#pragma using HwBaseCDIAS

SafetyCDIAS_Base : CLASS
: HwBaseCDIAS
	TYPE
#pragma pack(push, 1)
	  AdditionalPDOsType : STRUCT
	    InputMovHandle : ^LSL_VARANFRAME;
	    InputMovSettings : ^t_VaranDOSettingsMov;
	    p_HandlePDOWrite : ^LSL_VARANFRAME;
	    p_HandlePDOWriteEnable : ^USINT;
	    pPDOWriteData : ^USINT;
	    p_SettingsPDOWrite : ^t_VaranDOSettingsWr;
	    ud_LocalMoveDestAddr : HDINT;
	    ud_HandlePDOWriteMoverDO : UDINT;
	  END_STRUCT;
#pragma pack(pop)
	  DiagLogSaveSSW :
	  (
	    GetLogHeader,
	    GetLogFileBlocks,
	    GetLogHeader2,
	    SaveLogFile
	  )$UDINT;
#pragma pack(push, 1)
	  GetStateResponseType : STRUCT
	    RuntimeState : USINT;
	    ConfigState : USINT;
	    LoginLevel : USINT;
	    ConfigCRC : UDINT;
	    ListHeaderCRC : UDINT;
	    ErrorCount : UINT;
	    InterfaceCRC : HDINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  DiagStructType : STRUCT
	    UserWantsDiagState : BOOL;
	    UserDiagStateReady : BOOL;
	    UserGetStateResp : GetStateResponseType;
	    UserWantsDiagInfo : BOOL;
	    UserDiagInfoReady : BOOL;
	    UserGetDiagInfoResp : SafetyDiagInfo;
	    ucChoiceDiagInfo : USINT;
	    ucChoiceSaveLog : USINT;
	    DPNE : ARRAY [0..99] OF CHAR;
	    SavingLogInProgress : BOOL;
	    SavingLogSuccessful : SINT;
	    SavingLogSSW : DiagLogSaveSSW;
	    LogHeader : STRUCT
	      uControllerID : USINT;  //! <Type Comment="ID of µController (0 = µC1, else µC2)" Name="DiagStructType.LogHeader.uControllerID"/>
	      LogMemSize : UDINT;  //! <Type Comment="in Bytes" Name="DiagStructType.LogHeader.LogMemSize"/>
	      WriteCounter : UDINT;
	    END_STRUCT;
	    pLogFileMem : ^USINT;
	    LogMemToGet : UDINT;
	    ReadBaseAdr : UDINT;
	    BytesToGet : USINT;
	    UserErrorInfoReady : BOOL;
	    UserWantsErrorInfo : BOOL;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  FirmwareVersionType : STRUCT
	    RevMinor : UDINT;
	    RevMajor : UINT;
	    ModuleType : UINT;
	    BootLoaderVer : UDINT;
	  END_STRUCT;
#pragma pack(pop)
	  FrameTypeType : BSINT
	  [
	    1 Cfg,
	    2 ToP,
	    3 Standard,
	    4 PDO,
	    5 TDO,
	    6 Reserved1,
	    7 Reserved2,
	    8 Response,
	  ];
#pragma pack(push, 1)
	  PathInfoType : STRUCT
	    p_us_Path : ^USINT;
	    p_us_PathComp : ^USINT;
	    ui_PathCompLen : UINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  PDOInputBuffer : STRUCT
	    ud_p2Buffer : HDINT;
	    us_PDOLen : USINT;
	    ud_HandleSourceDO : UDINT;
	    ud_MoveSourceAddr : HDINT;
	    ud_MoveSourceOffset : UDINT;
	    b_TimeSynchron : BOOL;
	    ud_SafetyNr : HDINT;
	    b_IsOptional : BOOL;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  PDOMoverList : STRUCT
	    pThis : pVirtualBase;
	    pNext : ^PDOMoverList;
	  END_STRUCT;
#pragma pack(pop)
	  PDOMoveState :
	  (
	    _Invalid,
	    _Active,
	    _Inactive
	  )$UDINT;
#pragma pack(push, 1)
	  PDOType : STRUCT
	    CRC : HDINT;
	    Byte5_Zero : USINT;
	    FrameType : FrameTypeType;
	    Byte7_Zero : USINT;
	    Length : USINT;
	    SourceAdr : HDINT;
	    SourceAdrCopy : HDINT;
	    msTimeStamp : DINT;
	    DataAndCopy : ARRAY [0..107] OF USINT;
	  END_STRUCT;
#pragma pack(pop)
	  pPDOMoverList : ^PDOMoverList;
#pragma pack(push, 1)
	  UnsafeIORoutingElement : STRUCT
	    ud_Thisp : UDINT;
	    ud_Address : HDINT;
	    sd_OldValue : DINT;
	    sd_NewValue4External : DINT;
	    UnsafeType : t_UnsafeVarType;
	    BitMask : BDINT
	    [
	    ];
	    NameLength : UINT;
	    pName : ^CHAR;
	    b_AlreadyTransmitted : BOOL;
	    b_IsValid : BOOL;
	    pNext : ^UnsafeIORoutingElement;
	  END_STRUCT;
#pragma pack(pop)
	  pUnsafeIORoutingElement : ^UnsafeIORoutingElement;
	  RequestType :
	  (
	    _NoOpenRequest,
	    _ReadData,
	    _ReadValues,
	    _WriteValues,
	    _GetCRC,
	    _SetBusReady,
	    _DiagState,
	    _DiagInfo,
	    _ErrorChannelInfo
	  )$UDINT;
#pragma pack(push, 1)
	  RoutElement : STRUCT
	    ud_SafeNumber : HDINT;
	    ud_Thisp : UDINT;
	    p_CompressedPath : ^USINT;
	    ui_ComprPathLen : UINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  SDOStdHeader : STRUCT
	    CRC : UDINT;
	    Cmd : USINT;
	    Typ : FrameTypeType;
	    SeqNr : USINT;
	    Len : USINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  SDOHeader : STRUCT  //! <Type Public="true" Name="SDOHeader"/>
	    StdHeader : SDOStdHeader;
	    SrcAdr : HDINT;
	    DstAdr : HDINT;
	    SessId : UDINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  SDORespStd : STRUCT
	    SDOHeader : SDOHeader;
	    us_Returncode : USINT;
	    us_Data : USINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  SDOBufferStructure : STRUCT
	    us_Status : USINT;
	    SDOStructure : SDORespStd;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  SDORequReadConfig : STRUCT
	    StdHeader : SDOStdHeader;
	    ud_Address : HDINT;
	    us_Length : USINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  SDORespReadConfig : STRUCT
	    StdHeader : SDOStdHeader;
	    us_Returncode : USINT;
	    us_Length : USINT;
	    ud_Data : UDINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  SDOStdResp : STRUCT
	    StdHeader : SDOStdHeader;
	    us_Returncode : USINT;
	    us_Data : USINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  SDOviaPath : STRUCT
	    StdHeader : SDOStdHeader;
	    ZeroBytes : DINT;
	    TopologyPath : ARRAY [0..35] OF USINT;
	  END_STRUCT;
#pragma pack(pop)
	  SetBusReadySSW :
	  (
	    WaitPDOsSyncron:=0,
	    WaitAllModulesSyncron:=1,
	    SendSetBusReady:=2,
	    SetBusReadyFinished:=3
	  )$UDINT;
#pragma pack(push, 1)
	  StandardFrameType : STRUCT
	    SDOHeader : SDOStdHeader;
	    aData : ARRAY [0..63] OF USINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_CRCInfo : STRUCT
	    ApplCRC : HDINT;
	    HwCRC : HDINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_DataObjectCheck : STRUCT
	    LastTime : UDINT;
	    TimeDiff : UDINT;
	    TimeDiffMin : UDINT;
	    TimeDiffMax : UDINT;
	    SameFrameCnt : DINT;
	    LastHeader : SDOStdHeader;
	  END_STRUCT;
#pragma pack(pop)
	  t_LogOnceMarker : BDINT
	  [
	    1 NoThisForUnsafeIn,
	    2 WrongUnsafeVarType,
	    3 MoveSourceInvalid,
	    5 TdoLen0,
	    6 TdoLenInvalid,
	    7 InvalidSchedulerState,
	  ];
#pragma pack(push, 1)
	  t_TimeSyncDOActiveType : STRUCT
	    Wait4ResponseNo : UINT;
	    OwnSyncActive : UINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  TDOType : STRUCT
	    StdHeader : SDOStdHeader;
	    SrcAdr : HDINT;
	    DstAdr : HDINT;
	    TimeInfo1 : UDINT;
	    TimeInfo2 : UDINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  TDORingbuffer : STRUCT
	    ud_ReadPos : UDINT;
	    ud_WritePos : DINT;
	    ud_Entries : UDINT;
	    b_ErrorTriggered : DINT;
	    Entry : ARRAY [0..TDO_BUFFER_SIZE-1] OF TDOType;
	    ud_maxEntries : UDINT;
	    b_RequestAvailable : BOOL;
	    RequestTDO : TDOType;
	  END_STRUCT;
#pragma pack(pop)
	  UnsafeReadPackages : ARRAY [0..14] OF HDINT;
	  UnsafeSchedulerSSW :
	  (
	    UnsafeSchedulerSetBusReady,
	    UnsafeSchedulerGetDiagVars,
	    UnsafeSchedulerGetCRC,
	    UnsafeSchedulerWriteData,
	    UnsafeSchedulerReadData,
	    UnsafeSchedulerDiagState,
	    UnsafeSchedulerDiagInfo,
	    UnsafeSchedulerChannelError
	  )$UDINT;
#pragma pack(push, 1)
	  UnsafeWritePackage : STRUCT
	    ud_Address : HDINT;
	    Value : DINT;
	  END_STRUCT;
#pragma pack(pop)
	  UnsafeWritePackages : ARRAY [0..MAX_UNSAFE_WRITE_PACKAGES-1] OF UnsafeWritePackage;
#pragma pack(push, 1)
	  VaranDOSettingsRd : STRUCT
	    us_Command : USINT;
	    ud_Address : UDINT;
	    us_ByteCnt : USINT;
	    us_CommandRecv : USINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  VaranDOSettingsWr : STRUCT
	    us_Command : USINT;
	    ud_Address : UDINT;
	    us_ByteCnt : USINT;
	  END_STRUCT;
#pragma pack(pop)
	END_TYPE
  //Servers:
	ClassState 	: SvrCh_SafetyConfigStateType;
	VoltageOK 	: SvrCh_DINT;
	RunState 	: SvrCh_DINT;
	ServiceMode 	: SvrCh_DINT;
	Error 	: SvrCh_DINT;
	QuitComError 	: SvrCh_DINT;
	FW_Version 	: SvrCh_HDINT;
	FPGA_Version 	: SvrCh_HDINT;
	SafetyNumber 	: SvrCh_HDINT;
	GetDiagConnect 	: SvrChCmd_DINT;
	DesignerPrjConfigCRC 	: SvrCh_HDINT;
	ApplCRC 	: SvrCh_HDINT;
	HwCRC 	: SvrCh_HDINT;
  //Clients:
	AdditionalSPDOs 	: CltCh_DINT;
	ServerUpdateTime 	: CltCh_UDINT;
	FileSys 	: CltChCmd__FileSys;
	ActivateFastUnsafeIOs 	: CltCh_DINT;
	DelayedStartup 	: CltCh_DINT;
  //Variables:
		FirmwareVersion 	: FirmwareVersionType;
		ui_cnt_PDOInputBuffer 	: UINT;
		aPDOInputBuffer : ARRAY [0..PDO_MAX_NUMBER-1] OF PDOInputBuffer;

		PDOOutputIsUsed 	: BOOL;
		PDOOutputBuffer 	: PDOType;
		ui_cnt_SDOInputBuffer 	: UINT;
		p_SDOInputBuffer 	: ^UDINT;
		InputBufferAllocatedNo 	: UDINT;
		p_SDOOutputBuffer 	: ^SDORespStd;
		ui_MyPlace 	: UINT;
		sd_VaranType 	: DINT;
		a_RoutTable : ARRAY [0..MAX_NUMBER_ROUT_ELEMENTS-1] OF RoutElement;

		p_RoutTable 	: ^RoutElement;
		ui_CntRoutElements 	: UINT;
		ui_cnt_PDOInBufferAct 	: UINT;
		b_im 	: BOOL;
		us_FirstScan 	: USINT;
		pPDOReadData 	: ^USINT;
		pPDOReadLengthData 	: ^USINT;
		pPDOWriteData 	: ^USINT;
		p_us_Handle_TDO_Read 	: ^USINT;
		p_us_Handle_TDO_Read_Length 	: ^USINT;
		p_us_Handle_TDO_Write 	: ^USINT;
		p_us_Handle_TDO_Status_Write 	: ^USINT;
		p_us_Handle_TimeSyncHS_Read 	: ^USINT;
		p_us_Handle_TimeSyncHS_Write 	: ^USINT;
		p_us_Handle_FastUnsafeOutputs 	: ^USINT;
		p_us_Handle_FastUnsafeInputs 	: ^USINT;
		p_ui_UnsafeOutWrite 	: ^UINT;
		a_Handle_PDO_Read : ARRAY [0..15] OF DINT;

		a_Handle_PDO_Write : ARRAY [0..15] OF DINT;

		a_Handle_TDO_Read : ARRAY [0..15] OF DINT;

		a_Handle_TDO_Write : ARRAY [0..15] OF DINT;

		p_us_Handle_PDOReadLen 	: ^USINT;
		p_us_Handle_TDOReadLen 	: ^USINT;
		p_Handle_SDO_Read 	: ^SDOBufferStructure;
		p_Handle_SDO_Write 	: ^SDOBufferStructure;
		pISafety 	: ^LSL_SAFETY;
		us_CntSequNr 	: USINT;
		p_KernelLog 	: ^DINT;
		ui_CntUnsafeInputs 	: UINT;
		MaxVarsPerWritePackage 	: USINT;
		WriteFramesNeeded 	: UDINT;
		p_UnsafeInputsTable 	: ^UnsafeIORoutingElement;
		ui_CntUnsafeOutputs 	: UINT;
		MaxVarsPerReadPackage 	: USINT;
		ReadFramesNeeded 	: UDINT;
		p_UnsafeOutputsTable 	: ^UnsafeIORoutingElement;
		StandardRequest 	: StandardFrameType;
		StandardResponse 	: StandardFrameType;
		StandardSeqNr 	: USINT;
		UnsafeReadTransNr 	: UDINT;
		UnsafeWriteTransNr 	: UDINT;
		UnsafeWritingActive 	: BOOL;
		LastUnsafeUpdate 	: UDINT;
		pUnsafeOutElement 	: ^UnsafeIORoutingElement;
		pUnsafeInElement 	: ^UnsafeIORoutingElement;
		p_HandlePDORead 	: ^LSL_VARANFRAME;
		p_HandlePDOReadEnable 	: ^USINT;
		ud_HandlePDOReadMoverDO 	: UDINT;
		p_HandlePDOWrite 	: ^LSL_VARANFRAME;
		p_HandlePDOWriteEnable 	: ^USINT;
		ud_HandlePDOWriteMoverDO 	: UDINT;
		p_HandlePDOReadLength 	: ^LSL_VARANFRAME;
		p_HandleTDORead 	: ^LSL_VARANFRAME;
		b_DOIsRunningTDORead 	: t_SingleRunState;
		p_HandleTDOWrite 	: ^LSL_VARANFRAME;
		b_DOIsRunningTDOWrite 	: t_SingleRunState;
		p_HandleTDOWriteEnable 	: ^USINT;
		p_HandleTDOReadLength 	: ^LSL_VARANFRAME;
		p_HandleLED 	: ^LSL_VARANFRAME;
		p_HandleUnsafeOutWrite 	: ^LSL_VARANFRAME;
		b_DOIsRunningUnsafeOutWrite 	: t_SingleRunState;
		p_Handle_TimeSyncHS_Write 	: ^LSL_VARANFRAME;
		p_Handle_TimeSyncHS_WriteEnable 	: ^USINT;
		b_DOIsRunning_TimeSyncHS 	: t_SingleRunState;
		p_HandleFastUnsafeIOs 	: ^LSL_VARANFRAME;
		TDOInfo 	: USINT;
		TDOFrame 	: TDOType;
		p_ud_Handle_LED 	: ^UDINT;
		pCDIASBase 	: ^pHwBaseCDIAS;			//! <Variable Comment="this pointer exists just to take global type with the class to avoid compiler errors" Name="pCDIASBase"/>
		b_CheckCRC 	: BOOL;
		ud_ConfigCRC 	: UDINT;
		ud_LastCrcCheck 	: UDINT;
		b_GetNewConfiguration 	: BOOL;
		b_CheckConfigured 	: BOOL;
		ud_LastCheckConfig 	: UDINT;
		LastRequest 	: RequestType;
		PDOReadLen 	: USINT;
		PDOWriteLen 	: USINT;
		TDOTransStarted 	: BOOL;
		UnsafeOutputStates 	: UINT;
		OldUnsafeOutputStates 	: UINT;
		MaxLengthPDORead 	: USINT;
		MaxLengthPDOWrite 	: USINT;
		TDOSingleRunActive 	: BOOL;
		PDOSingleRunActive 	: USINT;
		DiagVars 	: DiagStructType;
		us_SetBusReadyState 	: SetBusReadySSW;
		UnsafeScheduler 	: UnsafeSchedulerSSW;
		ud_UnsafeTimeoutCounter 	: UDINT;
		ud_TransfertimePerPackage 	: UDINT;
		p_BlockedTransferMemory 	: ^void;
		ud_BlockedTransferMemorySize 	: UDINT;
		b_ReadConfigFailed 	: BOOL;
		ud_ServerUpdateTime 	: UDINT;
		b_MoveCommandInputActive 	: PDOMoveState;
		b_MoveCommandOutputActive 	: PDOMoveState;
		InputMovHandle 	: ^LSL_VARANFRAME;
		InputMovSettings 	: ^t_VaranDOSettingsMov;
		ud_LocalMoveSourceAddr 	: HDINT;			//! <Variable Comment="address offset in FPGA of pdo read data of this module" Name="ud_LocalMoveSourceAddr"/>
		ud_LocalMoveDestAddr 	: HDINT;			//! <Variable Comment="address offset in FPGA of pdo write data of this module" Name="ud_LocalMoveDestAddr"/>
		ReadPDO 	: PDOType;
		WritePDO 	: PDOType;
		pPDOMoverListInputs 	: ^PDOMoverList;
		pPDOMoverListOutputs 	: ^PDOMoverList;
		TDOErrorDetectedCnt 	: UDINT;
		s_TDORingbuffer 	: TDORingbuffer;
		ud_UnsafeVarsNotFound 	: UDINT;
		udTDORdCnt 	: UDINT;
		InitStep 	: DINT;
		RequestDropCounter 	: DINT;
		aAdditionalPDOs : ARRAY [0..8] OF AdditionalPDOsType;

		ui_ActIRQSyncOffset 	: UINT;
		SystemTime_ms 	: USINT;
		b_SafetyInfoOK 	: BOOL;
		b_NewSyncMode 	: BOOL;
		b_TimeSyncActive 	: BOOL;
		b_ManagerInitialisationFinished 	: BOOL;
		PrjNameMemLen 	: UDINT;
		PrjNameStrLen 	: UDINT;
		pPrjNameStr 	: ^CHAR;
		PrjRevStrLen 	: UDINT;
		pPrjRevStr 	: ^CHAR;
		LastExtPDOCRC 	: UDINT;
		b_GotNewRevision 	: BOOL;
		PDOWrite 	: t_DataObjectCheck;
		PDORead 	: t_DataObjectCheck;
		SDOWrite 	: t_DataObjectCheck;
		SDORead 	: t_DataObjectCheck;
		TDOWrite 	: t_DataObjectCheck;
		TDORead 	: t_DataObjectCheck;
		TimeSyncHSSingleRunActive 	: USINT;
		NewHandShakeValue : BSINT
		[
		  1 NewTimeSyncActive,
		  2 StartTimeSync1,
		  3 StartTimeSync2,
		];

		pConfigMem 	: ^void;
		ConfigMemSize 	: UDINT;
		ConfigMemSizeUsed 	: UDINT;
		ModuleCfgNo 	: USINT;
		pFirstModuleCfg 	: ^t_ModuleListElem;
		PdoCfgNo 	: USINT;
		pFirstPdoCfg 	: ^t_PdoListElem;
		SlaveCfgNo 	: USINT;
		pFirstSlaveCfg 	: ^t_SlaveListElem;
		MyPDOSize 	: USINT;
		OldRunState 	: DINT;
		FastUnsafeOutputs : BSINT
		[
		];

		FastUnsafeInputs : BSINT
		[
		];

		b_FastUnsafeInputsActive 	: BOOL;
		b_FastUnsafeOutputsActive 	: BOOL;
		us_Variant 	: USINT;
		NewConfigType 	: t_ConfigStateType;
		bd_LogOnceMarker 	: t_LogOnceMarker;
		bd_AlreadyLoggedMarker 	: t_LogOnceMarker;
		ud_MyModuleID 	: UDINT;
		ud_OptionalTimeoutStart 	: UDINT;
		ud_AsyComRetryCounter 	: UDINT;
		TimeSyncDOActive 	: t_TimeSyncDOActiveType;
		b_ManagerReadyForSDO 	: DINT;
		NeedsHwControl 	: ^HwControl;			//! <Variable Comment="a pointer to HwControl ensures it&apos;s always in the project" Name="NeedsHwControl"/>
		b_ManualQuit 	: BOOL;			//! <Variable Comment="this marks if a manual quit of communication errors has been done&#13;&#10;the quit mechanism will resend the bus ready command, where normally no PDOs are sent before the errors are being quit&#13;&#10;this variable is used to override the waiting for the bus ready to be finished and allows PDOs to be sent during the bus ready resend." Name="b_ManualQuit"/>
		ud_ConfigReadTime 	: UDINT;
		b_Reconnect 	: BOOL;
		b_StartDOs 	: BOOL;
		b_QuitErrorAvailable 	: BOOL;
		b_ReInitMarker 	: BOOL;
		b_PostInitPassed 	: BOOL;
		StartRtDOs 	: DINT;
		aErrorMem : ARRAY [0..256] OF USINT;

		remainingPacketlength 	: INT;
		actoffset 	: UDINT;
		CRCInfo 	: t_CRCInfo;
  //Functions:
	
	FUNCTION VIRTUAL GLOBAL Init;
				//! <Function Comment="constructor" Name="SafetyCDIAS_Base"/>
	FUNCTION SafetyCDIAS_Base
		VAR_OUTPUT
			ret_code 	: ConfStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL UpDataCY
		VAR_INPUT
			Handle 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL UpDateRT
		VAR_INPUT
			Handle 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL UpDateRTPostScan
		VAR_INPUT
			Handle 	: UDINT := 0;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL GetModuleType
		VAR_OUTPUT
			ui_ModuleType 	: UINT;
		END_VAR;
				//! <Function Comment="This method returns the firmware version of the module.&#13;&#10;Has to be overwritten in every module which has a FW." Name="GetFWVersion"/>
	FUNCTION VIRTUAL GetFWVersion
		VAR_INPUT
			pData 	: ^CHAR;
			length 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL CheckVariant
		VAR_INPUT
			us_ActVariant 	: USINT;
		END_VAR
		VAR_OUTPUT
			b_IsOK 	: BOOL;
		END_VAR;
				//! <Function Comment="add SDO to incoming message buffer; This function is called from the SDO sending class." Name="AddSDOToBuffer"/>
	FUNCTION VIRTUAL AddSDOToBuffer
		VAR_INPUT
			p_us_message 	: ^USINT;
			us_length 	: USINT;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
				//! <Function Comment="write incoming PDO from other module to hardware " Name="WritePDO2Module"/>
	FUNCTION VIRTUAL WritePDO2Module;
	
	FUNCTION VIRTUAL WriteTDO2Module
		VAR_INPUT
			pTDO 	: ^TDOType;
		END_VAR;
	
	FUNCTION VIRTUAL InitSafetyBase
		VAR_OUTPUT
			retcode 	: BOOL;
		END_VAR;
	
	FUNCTION VIRTUAL InitBuffers
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
				//! <Function Comment="allocate buffers for reading config data and creating routing tables" Name="GetRoutingData"/>
	FUNCTION VIRTUAL GetRoutingData
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
				//! <Function Comment="read config data via SDOs and fill routing tables" Name="ReadSDOConfig"/>
	FUNCTION VIRTUAL ReadSDOConfig
		VAR_INPUT
			p_SDORequestBuffer 	: ^SDORequReadConfig;
			p_SDOResponseBuffer 	: ^SDORespReadConfig;
			pModule 	: ^PathInfoType;
			pListHeader 	: ^PathInfoType;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
				//! <Function Comment="send request for reading config data" Name="SDOReadCfgRequ"/>
	FUNCTION VIRTUAL SDOReadCfgRequ
		VAR_INPUT
			p_SDORequestBuffer 	: ^SDORequReadConfig;
			p_SDOResponseBuffer 	: ^SDORespReadConfig;
			ud_Address 	: UDINT;
			us_Length 	: USINT;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
				//! <Function Comment="send request with no additional data" Name="SDOStdRequ"/>
	FUNCTION VIRTUAL SDOStdRequ
		VAR_INPUT
			us_Command 	: USINT;
			p_us_RespData 	: ^USINT;
			us_RespLength 	: USINT;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL AddSafetyTask;
				//! <Function Comment="add data objects for PDO, state etc." Name="AddDO"/>
	FUNCTION VIRTUAL AddDO
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
				//! <Function Comment="returns pointer to the own outgoing PDO buffer" Name="GetPointer2PDOBuffer"/>
	FUNCTION VIRTUAL GetPointer2PDOBuffer
		VAR_OUTPUT
			ud_PDOBuffer 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL AddUnsafeRoutElement
		VAR_INPUT
			pRoutTable 	: ^pUnsafeIORoutingElement;
			pRoutElementsNo 	: ^UINT;
			ud_Address 	: UDINT;
			ui_NameLen 	: UINT;
			pNameNewElement 	: ^CHAR;
			BitMask 	: BDINT := 0;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
				//! <Function Comment="read this-pointer from correct object and add it to the routing tables" Name="AddModuleToRoutingTabs"/>
	FUNCTION VIRTUAL AddModuleToRoutingTabs
		VAR_INPUT
			pModule 	: ^PathInfoType;
			pListHeader 	: ^PathInfoType;
			b_IsOptional 	: BOOL;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
				//! <Function Comment="add module to routing table" Name="AddRoutingElement"/>
	FUNCTION VIRTUAL AddRoutingElement
		VAR_INPUT
			ud_SafeNumber 	: HDINT;
			ud_thisp 	: UDINT;
			pObject 	: ^PathInfoType;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
				//! <Function Comment="get this-pointer of routing-element based on safety-number" Name="GetRoutingPointerByNumber"/>
	FUNCTION VIRTUAL GetRoutingPointerByNumber
		VAR_INPUT
			ud_SafeNumber 	: HDINT;
		END_VAR
		VAR_OUTPUT
			ud_thisp 	: UDINT;
		END_VAR;
				//! <Function Comment="This function is called during initialization by the Safe-CPU class." Name="ConfigSafetyInput"/>
	FUNCTION VIRTUAL ConfigSafetyInput
		VAR_INPUT
			ud_SafeNrCPU 	: HDINT;
			ud_thisp 	: UDINT;
			p_PDOBuffer 	: ^UDINT;
			pMoveActive 	: ^PDOMoveState;
			p_ud_HandleSourceDO 	: ^UDINT;
			p_ud_MoveSourceAddr 	: ^UDINT;
			p_ud_MoveSourceOffset 	: ^UDINT;
		END_VAR
		VAR_OUTPUT
			ud_SafeNrModul 	: HDINT;
		END_VAR;
				//! <Function Comment="This function is called during initialization by the Safe-CPU class." Name="ConfigSafetyOutput"/>
	FUNCTION VIRTUAL ConfigSafetyOutput
		VAR_INPUT
			ud_SafeNrCPU 	: HDINT;
			ud_thisp 	: UDINT;
			ud_p_PDOBuffer 	: UDINT;
			pObject 	: ^PathInfoType;
			pMoveActive 	: ^PDOMoveState;
			ud_HandleSourceDO 	: UDINT;
			ud_MoveSourceAddr 	: UDINT;
			ud_MoveSourceOffset 	: UDINT;
			b_IsOptional 	: BOOL;
		END_VAR
		VAR_OUTPUT
			ud_SafeNrModul 	: HDINT;
		END_VAR;
				//! <Function Comment="get this-pointer of routing-element based on Crc of hardware-path" Name="GetRoutingPointerByPath"/>
	FUNCTION VIRTUAL GetRoutingPointerByPath
		VAR_INPUT
			p_ActObjectPath 	: ^USINT;
			ActPathLen 	: UINT;
		END_VAR
		VAR_OUTPUT
			ud_thisp 	: UDINT;
		END_VAR;
				//! <Function Comment="add PDO buffer to list of PDO input buffers" Name="AddPDOToInputBuffer"/>
	FUNCTION VIRTUAL AddPDOToInputBuffer
		VAR_INPUT
			ud_p2Buffer 	: UDINT;
			ud_HandleSourceDO 	: UDINT;
			ud_MoveSourceAddr 	: UDINT := 0;
			ud_MoveSourceOffset 	: UDINT;
			ud_SafetyNr 	: HDINT;
			b_IsOptional 	: BOOL;
			us_PdoLen 	: USINT := 0;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL ConfigSafetyCPU
		VAR_OUTPUT
			ud_SafeNrModul 	: HDINT;
		END_VAR;
	
	FUNCTION VIRTUAL AddCall2Main;
	
	FUNCTION VIRTUAL AddCall2List;
				//! <Function Comment="callback methode called by varan-interrupt" Name="Varan_CallbackSafe"/>
	FUNCTION VIRTUAL Varan_CallbackSafe
		VAR_INPUT
			ud_reason 	: UDINT;
		END_VAR;
				//! <Function Comment="get pointer on PDO input buffer element" Name="GetPDOInputBuffer"/>
	FUNCTION VIRTUAL GetPDOInputBuffer
		VAR_INPUT
			ud_p2Buffer 	: UDINT;
		END_VAR
		VAR_OUTPUT
			p_InputBuffer 	: ^PDOInputBuffer;
		END_VAR;
				//! <Function Comment="Add module to safety task in OS and get pointers on SDO buffers." Name="AddModuleToSafetyTask"/>
	FUNCTION VIRTUAL AddModuleToSafetyTask
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
				//! <Function Comment="The methode returns the module ID which the module must have. It has to be overwritten." Name="GetModuleID"/>
	FUNCTION VIRTUAL GetModuleID
		VAR_OUTPUT
			ud_ModuleID 	: UDINT;
		END_VAR;
				//! <Function Comment="Returns the task priority; A value &lt;&gt; 0 changes the order of executing the update methods. 0 = highest = default priority;" Name="GetTaskPriority"/>
	FUNCTION VIRTUAL GetTaskPriority
		VAR_OUTPUT
			us_TaskPriority 	: USINT;
		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="start data objects" Name="StartDO"/>
	FUNCTION VIRTUAL StartDO;
				//! <Function Comment="stop data objects" Name="StopDO"/>
	FUNCTION VIRTUAL StopDO;
				//! <Function Comment="requests own safety number from module via SDO communication" Name="GetSafetyNumber"/>
	FUNCTION VIRTUAL GetSafetyNumber
		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 Comment="extract module path out of config data" Name="ReadModulePath"/>
	FUNCTION VIRTUAL ReadModulePath
		VAR_INPUT
			p_SDORequestBuffer 	: ^SDORequReadConfig;
			p_SDOResponseBuffer 	: ^SDORespReadConfig;
			p_ud_Address 	: ^UDINT;
			pModule 	: ^PathInfoType;
			p_ud_ModulePathLen_Max 	: ^UDINT;
			p_ud_ModulePathCompLen_Max 	: ^UDINT;
			us_SDOMaxDataSize 	: USINT;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
				//! <Function Comment="returns the pointer on routing element with searched this-pointer" Name="GetRoutingElementByThis"/>
	FUNCTION VIRTUAL GetRoutingElementByThis
		VAR_INPUT
			ud_thisp 	: UDINT;
		END_VAR
		VAR_OUTPUT
			p_RoutElement 	: ^RoutElement;
		END_VAR;
	
	FUNCTION VIRTUAL GetThisViaServerName
		VAR_INPUT
			pObjectDotServer 	: ^CHAR;
		END_VAR
		VAR_OUTPUT
			ThisPtr 	: pVoid;
		END_VAR;
	
	FUNCTION VIRTUAL InitPathInfo
		VAR_INPUT
			pPathInfo 	: ^PathInfoType;
		END_VAR;
	
	FUNCTION VIRTUAL ResetConfig;
	
	FUNCTION VIRTUAL GLOBAL MyBackground;
	
	FUNCTION VIRTUAL RemoveCPUFromTable
		VAR_INPUT
			ud_SafetyNr 	: HDINT;
		END_VAR;
	
	FUNCTION VIRTUAL CheckUnsafeUpdateCycle;
				//! <Function Comment="Make a request to fetch the diagnosis data (RunState, ConfigState, Login Level, ErrorCounterIOState)" Name="FetchDiagState"/>
	FUNCTION VIRTUAL GLOBAL FetchDiagState;
				//! <Function Comment="Get diagnosis state of the safety CPU.&#13;&#10;Check if the diagnosis data have arrived (if so, retcode = TRUE)." Name="GetDiagState"/>
	FUNCTION VIRTUAL GLOBAL GetDiagState
		VAR_INPUT
			pDiagState 	: ^SafetyDiagState;			//! <Variable Comment="Pointer to the data where the diagnosis state should be written." Name="GetDiagState.pDiagState"/>
		END_VAR
		VAR_OUTPUT
			StateReady 	: BOOL;			//! <Variable Comment="FALSE...State is not ready (value of &quot;input parameter&quot; not changed)&#13;&#10;TRUE....State is ready (input parameter)" Name="GetDiagState.StateReady"/>
		END_VAR;
				//! <Function Comment="Make a request to fetch the diagnosis information data (Controller ID, Act Error Code, First Error Code, Reasoncode 0,1)" Name="FetchDiagInfo"/>
	FUNCTION VIRTUAL GLOBAL FetchDiagInfo
		VAR_INPUT
			ucChoice 	: USINT;			//! <Variable Comment="   0..µC1&#13;&#10;&lt;&gt; 0..µC2" Name="FetchDiagInfo.ucChoice"/>
		END_VAR;
				//! <Function Comment="Get diagnosis information of the safety CPU.&#13;&#10;Check if the diagnosis data have arrived (if so, retcode = TRUE)." Name="GetDiagInfo"/>
	FUNCTION VIRTUAL GLOBAL GetDiagInfo
		VAR_INPUT
			pDiagInfo 	: ^SafetyDiagInfo;			//! <Variable Comment="Pointer to the data where the diagnosis information should be written." Name="GetDiagInfo.pDiagInfo"/>
		END_VAR
		VAR_OUTPUT
			StateReady 	: BOOL;			//! <Variable Comment="FALSE...No new data available&#13;&#10;TRUE....New Data available" Name="GetDiagInfo.StateReady"/>
		END_VAR;
				//! <Function Comment="saves the log file from a specified µC to a file (not readable for user, send it to sigmatek support)" Name="SaveLog"/>
	FUNCTION VIRTUAL GLOBAL SaveLog
		VAR_INPUT
			ucChoice 	: USINT;			//! <Variable Comment="   0..µC1&#13;&#10;&lt;&gt; 0..µC2" Name="SaveLog.ucChoice"/>
			pDPNE 	: ^CHAR;			//! <Variable Comment="Pointer to the Directory Path Name Extension (e.g. C:\Filename.bin)" Name="SaveLog.pDPNE"/>
		END_VAR
		VAR_OUTPUT
			Success 	: DINT;			//! <Variable Comment="TRUE...saving log to drive is starting&#13;&#10;FALSE..couldn&apos;t start, other log saving process running" Name="SaveLog.Success"/>
		END_VAR;
				//! <Function Comment="Returns the state if Save Log is active or not." Name="SaveLogActive"/>
	FUNCTION VIRTUAL GLOBAL SaveLogActive
		VAR_OUTPUT
			InProgress 	: BOOL;			//! <Variable Comment="0 .. Save Log not active.&#13;&#10;1 .. Save Log is active." Name="SaveLogActive.InProgress"/>
		END_VAR;
	
	FUNCTION VIRTUAL SDORequ
		VAR_INPUT
			us_Command 	: USINT;
			p_us_RequData 	: ^USINT;
			us_RequLength 	: USINT;
			p_us_RespData 	: ^USINT;
			us_RespLength 	: USINT;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL BlockedTransferLength
		VAR_INPUT
			ud_Datalength 	: UDINT;
			us_MaxBlocklength 	: USINT;
		END_VAR
		VAR_OUTPUT
			us_ActBlocklength 	: USINT;
		END_VAR;
	
	FUNCTION VIRTUAL AddToPDOMoverList
		VAR_INPUT
			pThis 	: pVirtualBase;
			pList 	: ^pPDOMoverList;
		END_VAR;
	
	FUNCTION VIRTUAL WalkThroughPDOMoverList
		VAR_INPUT
			pList 	: ^pPDOMoverList;
			NewState 	: PDOMoveState;
		END_VAR;
	
	FUNCTION VIRTUAL CleanupPDOMoverList
		VAR_INPUT
			pList 	: ^pPDOMoverList;
		END_VAR;
	
	FUNCTION VIRTUAL RecordFrame
		VAR_INPUT
			pFrame 	: ^DINT;
			FrameState 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL AddFrame
		VAR_INPUT
			pFrame 	: ^SafetyCDIAS_Base::SDOStdHeader;
			FrameState 	: DINT;
			CallerSafetyNr 	: HDINT;
		END_VAR;
	
	FUNCTION VIRTUAL ShowProjectRevision;
	
	FUNCTION DOCheck
		VAR_INPUT
			pFrame 	: ^SDOStdHeader;
			pCheckStruct 	: ^t_DataObjectCheck;
		END_VAR;
	
	FUNCTION VIRTUAL CalcPDOLength
		VAR_INPUT
			BoolVarNo 	: UDINT;
			DintVarNo 	: UDINT;
		END_VAR
		VAR_OUTPUT
			PdoLen 	: USINT;
		END_VAR;
	
	FUNCTION VIRTUAL AddModuleToCfg
		VAR_INPUT
			ModuleCfg 	: t_ModuleCfg;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL AddPdoToCfg
		VAR_INPUT
			PdoCfg 	: t_PdoCfg;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL AddSlaveToCfg
		VAR_INPUT
			pModule 	: ^PathInfoType;
			b_IsOptional 	: BOOL;
			b_IsInterface 	: BOOL := FALSE;
			InterfaceCRC 	: HDINT := 0;
		END_VAR;
	
	FUNCTION VIRTUAL FreeCfgLists;
	
	FUNCTION VIRTUAL CreateAndSendCfg;
	
	FUNCTION SendAllUnsafeValues;
	
	FUNCTION GetDestinationCRCs;
	
	FUNCTION CountBits
		VAR_INPUT
			BitMask 	: BDINT;
		END_VAR
		VAR_OUTPUT
			BitNo 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL IsOptimizedCPU
		VAR_OUTPUT
			IsOptimized 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL CheckConfigMemSize
		VAR_INPUT
			AddConfigSize 	: UDINT;
		END_VAR
		VAR_OUTPUT
			pCfg 	: ^void;
		END_VAR;
	
	FUNCTION DToH
		VAR_INPUT
			pt 	: ^CHAR;
			value 	: DINT;
		END_VAR;
	
	FUNCTION LogHWPath
		VAR_INPUT
			pString 	: ^CHAR;
			pHWPath 	: ^USINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL FetchChannelInfo;
	
	FUNCTION VIRTUAL GetChannelInfo
		VAR_INPUT
			pErrorMemUser 	: ^UINT;
			pErrorMem 	: ^USINT;
			ErrorDataLength 	: INT;
		END_VAR
		VAR_OUTPUT
			StateReady 	: BOOL;
		END_VAR;
	
	FUNCTION VIRTUAL GetDiagVisualOffsetErrorCode
		VAR_OUTPUT
			udOffset 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL State::NewInst
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL QuitComError::Write
		VAR_INPUT
			input (EAX) 	: DINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL GetDiagConnect::NewInst
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
  //Tables:
	FUNCTION @STD
		VAR_OUTPUT
			ret_code	: CONFSTATES;
		END_VAR;
	FUNCTION GLOBAL TAB @CT_;
END_CLASS;

#pragma usingLtd _FileSys


//}}LSL_DECLARATION


FUNCTION GLOBAL TAB SafetyCDIAS_Base::@CT_
0$UINT,
2#0100000000000000$UINT, //TY_SAFETYCDIAS_BASE
3$UINT, 19$UINT, (SIZEOF(::SafetyCDIAS_Base))$UINT, 
13$UINT, 5$UINT, 0$UINT, 
TO_UDINT(2652646482), "SafetyCDIAS_Base", //Class
TO_UDINT(1800499398), "HwBaseCDIAS", 2$UINT, 56$UINT, //Baseclass
//Servers:
(::SafetyCDIAS_Base.ClassState.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1096059024), "ClassState", 
(::SafetyCDIAS_Base.VoltageOK.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2158378107), "VoltageOK", 
(::SafetyCDIAS_Base.RunState.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2759549320), "RunState", 
(::SafetyCDIAS_Base.ServiceMode.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1978843086), "ServiceMode", 
(::SafetyCDIAS_Base.Error.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2861137601), "Error", 
(::SafetyCDIAS_Base.QuitComError.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1389350282), "QuitComError", 
(::SafetyCDIAS_Base.FW_Version.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(4146995427), "FW_Version", 
(::SafetyCDIAS_Base.FPGA_Version.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(4169732363), "FPGA_Version", 
(::SafetyCDIAS_Base.SafetyNumber.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2430374202), "SafetyNumber", 
(::SafetyCDIAS_Base.GetDiagConnect.pMeth)$UINT, _CH_CMD$UINT, 2#0000000000000000$UINT, TO_UDINT(1383671281), "GetDiagConnect", 
(::SafetyCDIAS_Base.DesignerPrjConfigCRC.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(349909197), "DesignerPrjConfigCRC", 
(::SafetyCDIAS_Base.ApplCRC.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2412485999), "ApplCRC", 
(::SafetyCDIAS_Base.HwCRC.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(3992965099), "HwCRC", 
//Clients:
(::SafetyCDIAS_Base.AdditionalSPDOs.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(1736723450), "AdditionalSPDOs", 
(::SafetyCDIAS_Base.ServerUpdateTime.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(247674937), "ServerUpdateTime", 
(::SafetyCDIAS_Base.FileSys.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000000$UINT, TO_UDINT(1422438244), "FileSys", TO_UDINT(545279513), "_FileSys", 1$UINT, 20$UINT, 
(::SafetyCDIAS_Base.ActivateFastUnsafeIOs.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(1566529156), "ActivateFastUnsafeIOs", 
(::SafetyCDIAS_Base.DelayedStartup.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(836192644), "DelayedStartup", 
END_FUNCTION


#define USER_CNT_SafetyCDIAS_Base 96

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

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

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

	_memcpy((#vmt.CmdTable)$^USINT, HwBaseCDIAS::State.pMeth, nCmdSize);
	vmt.CmdTable.nCmds		:= nSTDCMD + USER_CNT_SafetyCDIAS_Base;
	vmt.CmdTable.NewInstr		:= #State::NewInst();
	vmt.CmdTable.Init		:= #Init();
#pragma warning (disable : 74)
	vmt.UserFcts[0]		:= #UpDataCY();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	IF GetDiagConnect.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	ret_code	:= SafetyCDIAS_Base();

END_FUNCTION

#pragma usingLtd HwControl

//{{LSL_IMPLEMENTATION
VAR_GLOBAL
  pAnalyzerThis         : ^DINT;
  pAnalyzerMethod       : ^UDINT;
  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;
  ModuleSyncNo          : DINT; // Number of modules which need to be synchron before everyone sends the set bus ready signal
END_VAR

VAR_PRIVATE
  // For Typelabel
  a_SerialNo			      : ARRAY[0..31] OF CHAR;  
  a_FWVersion           : ARRAY[0..31] OF CHAR;
  a_HWTEntryStr         : ARRAY[0.. VARAN_MAX_DEPTH+1] OF CHAR;  // VaranMaxDepth +1 because length is 2 byte long
END_VAR


FUNCTION VIRTUAL SafetyCDIAS_Base::AddSDOToBuffer
	VAR_INPUT
		p_us_message 	: ^USINT;
		us_length 	  : USINT;
	END_VAR
	VAR_OUTPUT
		sd_retval 	  : DINT;
	END_VAR
  
  // if the message is ok and there is space left in the buffer => save it
  if ( p_us_message ) & (us_length <= SDO_MAX_LENGTH) & (ui_cnt_SDOInputBuffer < 1000) then
  
    if ( p_SDOInputBuffer = NIL ) then
    
      sd_retval := -2;
      return;
      
    end_if;

    // if the allocated memory is full, we allocate some more
    if ui_cnt_SDOInputBuffer = InputBufferAllocatedNo then
    
      //reallocate list
      InputBufferAllocatedNo += SDO_BUFFER_ALLOC_BLOCK;
      p_SDOInputBuffer$^void := To_StdLib.Realloc(mptr := p_SDOInputBuffer$^void, newsize := InputBufferAllocatedNo * SDO_MAX_LENGTH);
      
      if ( p_SDOInputBuffer = NIL ) then
        State.uiIO_Flags				          := 0;
        State.uiIO_Flags.PhysicAccessOff  := 1;
        ClassState  := _MemAllocFailed;
        sd_retval   := -3;
        return;
      end_if;

    end_if;

    //copy SDO into new list element
    To_StdLib.MemCpy( dest    := ( p_SDOInputBuffer + ( ui_cnt_SDOInputBuffer * SDO_MAX_LENGTH))$^void
                    , source  := p_us_message
                    , size    := us_length
                    );

    ui_cnt_SDOInputBuffer += 1;
    
    sd_retval := 0;
    
  else
  
    sd_retval := -1;
    
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::InitSafetyBase
	VAR_OUTPUT
		retcode 	: BOOL;
	END_VAR

  retcode := FALSE;

  HwBaseCDIAS::Init();

#ifdef DO_DEBUG
  PDOWrite.TimeDiffMin := 16#FFFFFFFF;
  PDORead.TimeDiffMin  := 16#FFFFFFFF;

  SDOWrite.TimeDiffMin := 16#FFFFFFFF;
  SDORead.TimeDiffMin  := 16#FFFFFFFF;

  TDOWrite.TimeDiffMin := 16#FFFFFFFF;
  TDORead.TimeDiffMin  := 16#FFFFFFFF;
#endif
  
  ud_MyModuleID := GetModuleID();

  ui_MyPlace := Place$UINT * 16#100;

	sd_VaranType := MasterConnect.IsVaranAvailable();

  // get number of additional SPDOs and limit it to the valid range
  AdditionalSPDOs := AdditionalSPDOs.Read();

  if AdditionalSPDOs < 0 then
    AdditionalSPDOs := 0;
  end_if;

  if AdditionalSPDOs > 9 then
    AdditionalSPDOs := 9;
  end_if;

  // first thing to do in cyclic is to set the bus ready
  LastRequest := _NoOpenRequest;
  
  // initialize pointers with NIL (they get valid pointers in a later init-run if an object of the analyzer or safety manager class is available)
  pAnalyzerThis         := NIL;
  pAnalyzerMethod       := NIL;

  pSafetyManagerThis    := NIL;

  // use static memory for routing table
  p_RoutTable := #a_RoutTable[0];

  //initialize buffers
  if ( InitBuffers() ) then
    return;
  end_if;

  //no safety interface -> no work
  if ( pISafety = NIL ) then
    return;
  end_if;

  if ( b_VaranAvailable ) then

    // by default the mover is invalid. it will be initialized when reading the configuration
    b_MoveCommandInputActive  := _Invalid;
    b_MoveCommandOutputActive := _Invalid;

    //set callback for civ
		MasterConnect.SetObjectCallback( us_place := Place$USINT, ud_action_ptr := ( #Varan_CallbackSafe() )$UDINT, ud_thisp := this$UDINT );
    
    if ( sd_VaranType = 1 ) then
      if ( AddDO() ) then
            
        return;
            
      end_if;

    end_if;

    retcode := TRUE;
  else
    
    // if no VARAN, we can't move the PDOs
    b_MoveCommandInputActive  := _Inactive;
    b_MoveCommandOutputActive := _Inactive;

    // this module is not connected via VARAN => tell the other objects of this class
    b_SafetyOnLocalCDIAS := TRUE;
    
    // check kennung
    if ( Kennung = ud_MyModuleID ) then
      
      // get variant from eeprom
      us_Variant := 16#FF;
      MasterConnect.I2CReadOneByte( AdressCDIAS := ui_MyPlace + 3
                                  , pData       := #us_Variant); 
    
      // check variant
      if CheckVariant(us_Variant) then
#ifdef SAFETY_OVER_DIAS
       
        if ( MasterType = 2 & Connection <> 0 ) then
          
          b_im := TRUE;
        
        else
        
          b_im := FALSE;
          
        end_if;
#endif
              
        //add module to safety communication task with SDO
        if ( AddModuleToSafetyTask() ) then
          return;
        end_if;
        
        //read own safety number and firmware version
        if ( GetSafetyNumber() ) then
          return;
        end_if;     
        
        State.uiIO_Flags                  := 0;
        
        if ClassState = _ModuleNotFound then
          ClassState := _WaitForSynchronicity;
        end_if;
      else
        State.uiIO_Flags                  := 0;
            
        if ( Kennung = 255 ) then
          State.uiIO_Flags.NoHW 			    := 1;
        else
          State.uiIO_Flags.WrongHW 		    := 1;
        end_if; 
            
        State.uiIO_Flags.PhysicAccessOff 	:= 1;
      end_if;
    else
      State.uiIO_Flags                    := 0;
          
      if ( Kennung = 255 ) then
        State.uiIO_Flags.NoHW 			      := 1;
      else
        State.uiIO_Flags.WrongHW 		      := 1;
      end_if; 
          
      State.uiIO_Flags.PhysicAccessOff 	  := 1;
    end_if;

    retcode := TRUE;
    
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::AddSafetyTask

  if ( b_VaranAvailable ) then

    // if there is any module connected via CDIAS, we have to disable our internal move command
    if b_SafetyOnLocalCDIAS then
      b_MoveCommandInputActive  := _Inactive;
      b_MoveCommandOutputActive := _Inactive;      
    end_if;


    //add update call
		MasterConnect.AddVaranTask( ud_dol_type := VARAN_DOL_ISO
                              , p_this      := this 
#ifdef CALL_OPTION_RT_POSTSCAN
                              , callOptions := CALL_OPTION_RT_PRESCAN OR CALL_OPTION_RT_POSTSCAN
#endif 
                              );
    
    //add update call for SDO data
    MasterConnect.AddVaranTask(ud_dol_type := VARAN_DOL_ASY, p_this := this);
   
    //set task priority to change order of update tasks on C-Dias
    if ( GetTaskPriority() ) then
    
      MasterConnect.SetTaskPriority(us_place := Place$USINT, us_priority := GetTaskPriority(), ud_dol_type := VARAN_DOL_ISO);
      
    end_if;

  else
      
    if ( State.uiIO_Flags = 0 ) then
#ifdef SAFETY_OVER_DIAS
      if ( b_im ) then
      
        AddCall2Main();
      
      else        
#endif
        AddCall2List();
#ifdef SAFETY_OVER_DIAS
      end_if;
#endif

    end_if;
  
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::AddCall2Main
  VAR
    i       : USINT;
  END_VAR

  // get FPGA Version
  FPGA_Version := (MasterConnect.Rd8Bit(Adress:= ui_MyPlace + OFFSET_FPGA_VERSION))$UDINT;

  // add update task for SDOs
  MasterConnect.AddCall2Main(Mode := DMCONTINUE, RTCY := DMCYCLIC, thisp := this);
  
  MasterConnect.AddRet(RTCY := DMCYCLIC);

  // add update task for PDOs and TDOs
  MasterConnect.AddCall2Main(Mode := DMCONTINUE
                           , RTCY := DMREALTIME
                           , thisp := this
#ifdef CALL_OPTION_RT_POSTSCAN
                           , callOptions := CALL_OPTION_RT_PRESCAN OR CALL_OPTION_RT_POSTSCAN
#endif 
                           );

  for i := 0 to 15 do 
        
    a_Handle_PDO_Read[i] := ( MasterConnect.AddRd16Bit( Adress  := ui_MyPlace + OFFSET_SPDO_DATA + (i * 2)
                                                      , RTCY    := DMREALTIME
                                                      , thisp   := this
                                                      ) + _IOSegment$DINT);
          
  end_for;

  //add handle for PdoReadLength
  p_us_Handle_PDOReadLen := ( MasterConnect.AddRd8Bit(  Adress  := ui_MyPlace + OFFSET_SPDO_LENGTH
                                                      , RTCY    := DMREALTIME
                                                      , thisp   := this
                                                      ) + _IOSegment$DINT)$^USINT;


  for i := 0 to 15 by 1 do 
        
    a_Handle_PDO_Write[i] := ( MasterConnect.AddWr16Bit( Adress  := ui_MyPlace + OFFSET_SPDO_DATA + (i * 2)
                                                       , RTCY    := DMREALTIME
                                                       , thisp   := this
                                                       , data    := 0
                                                       ) + _IOSegment$DINT);
          
  end_for;

  for i := 0 to 15 by 1 do 
        
    a_Handle_TDO_Read[i] := ( MasterConnect.AddRd16Bit( Adress  := ui_MyPlace + OFFSET_STDO_DATA + (i * 2)
                                                      , RTCY    := DMREALTIME
                                                      , thisp   := this
                                                      ) + _IOSegment$DINT);
          
  end_for;

  //add handle for TdoReadLength
  p_us_Handle_TDOReadLen := ( MasterConnect.AddRd8Bit(  Adress  := ui_MyPlace + OFFSET_STDO_STATUS
                                                      , RTCY    := DMREALTIME
                                                      , thisp   := this
                                                      ) + _IOSegment$DINT)$^USINT;


  for i := 0 to 15 by 1 do 
        
    a_Handle_TDO_Write[i] := ( MasterConnect.AddWr16Bit( Adress  := ui_MyPlace + OFFSET_STDO_DATA + (i * 2)
                                                       , RTCY    := DMREALTIME
                                                       , thisp   := this
                                                       , data    := 0
                                                       ) + _IOSegment$DINT);
          
  end_for;

  //add handles for LEDs
  p_ud_Handle_LED := ( MasterConnect.AddRd32Bit( Adress  := ui_MyPlace + OFFSET_LED
                                               , RTCY    := DMREALTIME
                                               , thisp   := this
                                               ) + _IOSegment$DINT)$^UDINT;

  MasterConnect.AddRet(RTCY := DMREALTIME);
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::AddCall2List
  VAR
  	i : DINT;
  END_VAR
  
  // This method is not used when connected via VARAN

  // get FPGA Version
  FPGA_Version := (IOSegmentByte + OFFSET_FPGA_VERSION)^;

  // initialize the PLL

  // get our system time
  IF _WhoAmI = 16#23 | _WhoAmI = 16#27 | _WhoAmI = 16#28 | _WhoAmI = 16#29 THEN
    SystemTime_ms := ops.RtInterv_mSec$USINT;
  ELSE
    SystemTime_ms := (MasterConnect.GetPllTime())$USINT;
  END_IF;

  // write it in ms to the pll period register
  (IOSegmentByte + OFFSET_PLL_CONFIG2)^ := SystemTime_ms;

  // check what module we got for writing the sync offset
  case Kennung of
    CSDI16x_ID: // if there are only inputs
      // sync offset to the beginning of the access on the CDIAS (with the CDIAS sync)
      ui_ActIRQSyncOffset := SYNC_OFFSET_NO_DELAY;
      
    CSTO08x_ID, CSCP01x_ID: // if there are also outputs
      // sync offset right after the access on the CDIAS (about half a cycle later)
      ui_ActIRQSyncOffset := SYNC_OFFSET_DELAY_OUTPUTS;
  end_case;
  
  // write the value to the module
  (IOSegmentWord + OFFSET_SYNC_IRQ_DELAY)^ := ui_ActIRQSyncOffset;

  // add update task for SDOs
  MasterConnect.AddCall2List(Mode := 0, RTCY := DMCYCLIC,   thisp := this);

  // add update task for PDOs and TDOs
  MasterConnect.AddCall2List(Mode         := 0
                           , RTCY         := DMREALTIME
                           , thisp        := this
#ifdef CALL_OPTION_RT_POSTSCAN
                           , callOptions  := CALL_OPTION_RT_PRESCAN OR CALL_OPTION_RT_POSTSCAN
#endif 
                           );


  // define handles
  pPDOReadData        := IOSegmentByte + OFFSET_SPDO_DATA;

  pPDOReadLengthData  := IOSegmentByte + OFFSET_SPDO_LENGTH;

  pPDOWriteData       := IOSegmentByte + OFFSET_SPDO_DATA;

  if (AdditionalSPDOs > 0) then      
    for i := 0 to (AdditionalSPDOs-1) do
      // all additional PDO write accesses are done on the same address
      aAdditionalPDOs[i].pPDOWriteData := pPDOWriteData;
    end_for;
  end_if;

  p_us_Handle_TDO_Read        := IOSegmentByte + OFFSET_STDO_DATA;
  
  p_us_Handle_TDO_Read_Length := IOSegmentByte + OFFSET_STDO_STATUS;

  p_us_Handle_TDO_Write       := IOSegmentByte + OFFSET_STDO_DATA;

  p_ud_Handle_LED             := IOSegmentByte + OFFSET_LED;
  
  p_us_Handle_TDO_Status_Write:= IOSegmentByte + OFFSET_STDO_STATUS_WRITE;
  
  p_us_Handle_TimeSyncHS_Read := p_us_Handle_TimeSyncHS_Write := IOSegmentByte + OFFSET_TIMESYNC_HANDSHAKE;

  // fast unsafe variables (only if activated)
  if ActivateFastUnsafeIOs then
    p_us_Handle_FastUnsafeInputs := p_us_Handle_FastUnsafeOutputs := IOSegmentByte + OFFSET_FAST_UNSAFE_IOS;
  end_if;
  
  // only for modules with outputs
  if Kennung <> CSDI16x_ID then
    p_ui_UnsafeOutWrite       := IOSegmentWord + OFFSET_UNSAFE_VAR;
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::AddDO
	VAR_OUTPUT
		sd_retval 	: DINT;
	END_VAR
  VAR
  	i : DINT;
    tmplength   : USINT;
  END_VAR
  
  if b_PayloadSupport then  // With Payload Support *******************************************************************************
  
    if sd_VaranType = 1 then
      //add data object for PDO read  
      sd_retval := AddRdPayloadDO(ud_dol_type         := VARAN_DOL_ISO
                                , p_ud_handle         := ( #p_HandlePDORead )$^UDINT
                                , ud_offset_read      := ui_MyPlace + OFFSET_SPDO_DATA
                                , ud_length_read      := MaxLengthPDORead
                                , p_ud_data_read      := ( #pPDOReadData )$^UDINT
                                , ud_type             := 1
                                , ud_priority         := DM_PRIORITY_SAFTY_READ_DO
                                , ud_WritePayloadType := 1
                                );
                                
      //look for an error
      if ( sd_retval <> 0 ) then
        State.uiIO_Flags				          := 0;
        State.uiIO_Flags.NoCalibration	  := 1;			
        State.uiIO_Flags.PhysicAccessOff  := 1;
        return;
      end_if;

    else
      // for mover we have to allow Enable and Disable DO
      //add data object for PDO read  
      sd_retval := AddRdPayloadDO(ud_dol_type         := VARAN_DOL_ISO
                                , p_ud_handle         := ( #p_HandlePDORead )$^UDINT
                                , ud_offset_read      := ui_MyPlace + OFFSET_SPDO_DATA
                                , ud_length_read      := MaxLengthPDORead
                                , p_ud_data_read      := ( #pPDOReadData )$^UDINT
                                , ud_type             := 1
                                , ud_priority         := DM_PRIORITY_SAFTY_READ_DO
                                , ud_WritePayloadType := 1
                                , p_UserDOHandle      := #ud_HandlePDOReadMoverDO
                                );
    
      //look for an error
      if ( sd_retval <> 0 ) then
        State.uiIO_Flags				          := 0;
        State.uiIO_Flags.NoCalibration	  := 1;			
        State.uiIO_Flags.PhysicAccessOff  := 1;
        return;
      end_if;
    end_if;
    
    ud_LocalMoveSourceAddr := pPDOReadData$UDINT;
    
     // only for modules with outputs     
    if ud_MyModuleID <> CSDI16x_ID then // Kennung is not yet avalable at this point wih Payload and Mover
     
      if sd_VaranType = 1 then  // Without Mover------------------------------------------------------------------------------
    
        //add data object for PDO write
        sd_retval := AddWrPayloadDO(ud_dol_type         := VARAN_DOL_ISO
                                  , p_ud_handle         := ( #p_HandlePDOWrite )$^UDINT
                                  , ud_offset_write     := ui_MyPlace + OFFSET_SPDO_DATA
                                  , ud_length_write     := MaxLengthPDOWrite
                                  , p_ud_data_write     := ( #pPDOWriteData )$^UDINT
                                  , ud_type             := 1 
                                  , ud_priority         := DM_PRIORITY_SAFTY_WRITE_DO
                                  , ud_WritePayloadType := 1
                                  );
                                  
        //look for an error
        if ( sd_retval <> 0 ) then
          State.uiIO_Flags				          := 0;
          State.uiIO_Flags.NoCalibration	  := 1;			
          State.uiIO_Flags.PhysicAccessOff  := 1;
          return;
        end_if;

if b_SafetyOnLocalCDIAS = FALSE then

        sd_retval := AddMovePayloadDO(ud_dol_type                 := VARAN_DOL_ISO
                                    , p_ud_handle                 := (#InputMovHandle)$^UDINT
                                    , ud_sourceReadDOHandle       := p_HandlePDORead$UDINT
                                    , ud_SourceReadOffset         := 0
                                    , ud_destinationWriteDOHandle := p_HandlePDOWrite$UDINT
                                    , ud_DestinationWriteOffset   := 0
                                    , ud_lengthmove               := MaxLengthPDORead             // = MaxLengthPDOWrite
                                    , ud_priority                 := DM_PRIORITY_SAFTY_MOVE_DO
                                    );
                                    
        //look for an error
        if ( sd_retval <> 0 ) then
          State.uiIO_Flags				          := 0;
          State.uiIO_Flags.NoCalibration	  := 1;			
          State.uiIO_Flags.PhysicAccessOff  := 1;
          return;
        end_if;

        ud_LocalMoveDestAddr := pPDOWriteData$UDINT;
end_if;
        
        if (AdditionalSPDOs > 0) then      
          for i := 0 to (AdditionalSPDOs-1) do            
            //add data object for PDO write
            sd_retval := AddWrPayloadDO(ud_dol_type         := VARAN_DOL_ISO
                                      , p_ud_handle         := ( #aAdditionalPDOs[i].p_HandlePDOWrite )$^UDINT
                                      , ud_offset_write     := ui_MyPlace + OFFSET_SPDO_DATA
                                      , ud_length_write     := MaxLengthPDOWrite
                                      , p_ud_data_write     := ( #aAdditionalPDOs[i].pPDOWriteData )$^UDINT
                                      , ud_type             := 1
                                      , ud_priority         := DM_PRIORITY_SAFTY_WRITE_DO
                                      , ud_WritePayloadType := 1
                                      );
                                      
            //look for an error
            if ( sd_retval <> 0 ) then
              State.uiIO_Flags				          := 0;
              State.uiIO_Flags.NoCalibration	  := 1;			
              State.uiIO_Flags.PhysicAccessOff  := 1;
              return;
            end_if;
if b_SafetyOnLocalCDIAS = FALSE then

            // add data object to move our data
            sd_retval := AddMovePayloadDO(ud_dol_type                 := VARAN_DOL_ISO
                                        , p_ud_handle                 := (#aAdditionalPDOs[i].InputMovHandle)$^UDINT
                                        , ud_sourceReadDOHandle       := p_HandlePDORead$UDINT
                                        , ud_SourceReadOffset         := 0
                                        , ud_destinationWriteDOHandle := ( aAdditionalPDOs[i].p_HandlePDOWrite )$UDINT
                                        , ud_DestinationWriteOffset   := 0
                                        , ud_lengthmove               := MaxLengthPDORead             // = MaxLengthPDOWrite
                                        , ud_priority                 := DM_PRIORITY_SAFTY_MOVE_DO
                                        );

            //look for an error
            if ( sd_retval <> 0 ) then
              State.uiIO_Flags				          := 0;
              State.uiIO_Flags.NoCalibration	  := 1;			
              State.uiIO_Flags.PhysicAccessOff  := 1;
              return;
            end_if;

            aAdditionalPDOs[i].ud_LocalMoveDestAddr := aAdditionalPDOs[i].pPDOWriteData$UDINT;
end_if;
          end_for;
        end_if;
  
      else  // With Mover ----------------------------------------------------------------------------------------------------
        // for mover we have to allow Enable and Disable DO        
        //add data object for PDO write
                
        tmplength := MaxLengthPDOWrite;
        
        //One Byte for mover
        if tmplength = SPDO_MAX_LENGTH then
          tmplength := SPDO_MAX_LENGTH-1;
        end_if;
          
        sd_retval := AddWrPayloadDO(ud_dol_type     := VARAN_DOL_ISO
                                  , p_ud_handle     := ( #p_HandlePDOWrite )$^UDINT
                                  , ud_offset_write := ui_MyPlace + OFFSET_SPDO_DATA
                                  , ud_length_write := tmplength    // we need 1 byte for enable (is done in later methods)
                                  , p_ud_data_write := ( #pPDOWriteData )$^UDINT
                                  , ud_type         := 1 
                                  , ud_priority     := DM_PRIORITY_SAFTY_WRITE_DO
                                  , pp_Enable       := ( #p_HandlePDOWriteEnable )$^pVoid
                                  , p_UserDOHandle  := #ud_HandlePDOWriteMoverDO
                                  );
          
        //look for an error
        if ( sd_retval <> 0 ) then
          State.uiIO_Flags				          := 0;
          State.uiIO_Flags.NoCalibration	  := 1;			
          State.uiIO_Flags.PhysicAccessOff  := 1;
          return;
        end_if;        

if b_SafetyOnLocalCDIAS = FALSE then

        // Move DO can only be created after VaranDataMover DO are created (at 2nd HW Connect call)
        if ud_HandlePDOReadMoverDO & ud_HandlePDOWriteMoverDO then
          // Valid DO HAndles need to be passed on Move DO creation, they will be changed later to the correct handles
          sd_retval := AddMovePayloadDO(ud_dol_type                 := VARAN_DOL_ISO
                                      , p_ud_handle                 := (#InputMovHandle)$^UDINT
                                      , ud_sourceReadDOHandle       := ud_HandlePDOReadMoverDO
                                      , ud_SourceReadOffset         := 0
                                      , ud_destinationWriteDOHandle := ud_HandlePDOWriteMoverDO
                                      , ud_DestinationWriteOffset   := 0
                                      , ud_lengthmove               := MaxLengthPDORead - 1           // = MaxLengthPDOWrite - 1
                                      , ud_priority                 := DM_PRIORITY_SAFTY_MOVE_DO
                                      );
                                      
          //look for an error
          if ( sd_retval <> 0 ) then
            State.uiIO_Flags				          := 0;
            State.uiIO_Flags.NoCalibration	  := 1;			
            State.uiIO_Flags.PhysicAccessOff  := 1;
            return;
          end_if;
        end_if;        

end_if;

        (p_HandlePDOWriteEnable$^USINT )^ := VARAN_DO_NO_RUN;

        ud_LocalMoveDestAddr := pPDOWriteData$UDINT;
        
        if (AdditionalSPDOs > 0) then      
          for i := 0 to (AdditionalSPDOs-1) do
            
            tmplength := MaxLengthPDOWrite;
            
            //One Byte for mover
            if tmplength = SPDO_MAX_LENGTH then
              tmplength := SPDO_MAX_LENGTH-1;
            end_if;
            
            
            //add data object for PDO write
            sd_retval := AddWrPayloadDO(ud_dol_type     := VARAN_DOL_ISO
                                      , p_ud_handle     := ( #aAdditionalPDOs[i].p_HandlePDOWrite )$^UDINT
                                      , ud_offset_write := ui_MyPlace + OFFSET_SPDO_DATA
                                      , ud_length_write := tmplength // we need 1 byte for enable
                                      , p_ud_data_write := ( #aAdditionalPDOs[i].pPDOWriteData )$^UDINT
                                      , ud_type         := 1
                                      , ud_priority     := DM_PRIORITY_SAFTY_WRITE_DO
                                      , pp_Enable       := ( #aAdditionalPDOs[i].p_HandlePDOWriteEnable )$^pVoid
                                      , p_UserDOHandle  := #aAdditionalPDOs[i].ud_HandlePDOWriteMoverDO
                                      );
            //look for an error
            if ( sd_retval <> 0 ) then
              State.uiIO_Flags				          := 0;
              State.uiIO_Flags.NoCalibration	  := 1;			
              State.uiIO_Flags.PhysicAccessOff  := 1;
              return;
            end_if;            
            
            // Move DO can only be created after VaranDataMover DO are created (at 2nd HW Connect call)
            if ud_HandlePDOReadMoverDO & aAdditionalPDOs[i].ud_HandlePDOWriteMoverDO then
              // Valid DO HAndles need to be passed on Move DO creation, they will be changed later to the correct handles
              // add data object to move our data
              sd_retval := AddMovePayloadDO(ud_dol_type                 := VARAN_DOL_ISO
                                          , p_ud_handle                 := (#aAdditionalPDOs[i].InputMovHandle)$^UDINT
                                          , ud_sourceReadDOHandle       := ud_HandlePDOReadMoverDO
                                          , ud_SourceReadOffset         := 0
                                          , ud_destinationWriteDOHandle := aAdditionalPDOs[i].ud_HandlePDOWriteMoverDO
                                          , ud_DestinationWriteOffset   := 0
                                          , ud_lengthmove               := MaxLengthPDORead - 1           // = MaxLengthPDOWrite - 1
                                          , ud_priority                 := DM_PRIORITY_SAFTY_MOVE_DO
                                          );
  

              //look for an error
              if ( sd_retval <> 0 ) then
                State.uiIO_Flags				          := 0;
                State.uiIO_Flags.NoCalibration	  := 1;			
                State.uiIO_Flags.PhysicAccessOff  := 1;
                return;
              end_if;  
            end_if;
            
            aAdditionalPDOs[i].p_HandlePDOWriteEnable^ := VARAN_DO_NO_RUN;
            
            aAdditionalPDOs[i].ud_LocalMoveDestAddr := aAdditionalPDOs[i].pPDOWriteData$UDINT;
          end_for;
        end_if;         
            
      end_if; // if sd_VaranType = 1 then  // Without Mover------------------------------------------------------------------------------
      
    end_if;  // if ud_MyModuleID <> CSDI16x_ID then
    
    if sd_VaranType = 1 then

      //add data object for TDO write
      sd_retval := AddWrPayloadDO(ud_dol_type     := VARAN_DOL_ISO
                                , p_ud_handle     := ( #p_HandleTDOWrite )$^UDINT
                                , ud_offset_write := ui_MyPlace + OFFSET_STDO_DATA
                                , ud_length_write := STDO_LENGTH
                                , p_ud_data_write := ( #p_us_Handle_TDO_Write )$^UDINT
                                , ud_type         := 1
                                );

      //look for an error
      if ( sd_retval <> 0 ) then
        State.uiIO_Flags				          := 0;
        State.uiIO_Flags.NoCalibration	  := 1;			
        State.uiIO_Flags.PhysicAccessOff  := 1;
        return;
      end_if;    
    else  // for mover we have to say it's a single execution

      //add data object for TDO write
      sd_retval := AddWrPayloadDO(ud_dol_type     := VARAN_DOL_ISO
                                , p_ud_handle     := ( #p_HandleTDOWrite )$^UDINT
                                , ud_offset_write := ui_MyPlace + OFFSET_STDO_DATA
                                , ud_length_write := STDO_LENGTH
                                , p_ud_data_write := ( #p_us_Handle_TDO_Write )$^UDINT
                                , ud_type         := 1                                
                                , pp_Enable       := ( #p_HandleTDOWriteEnable)$^pVoid 
                                );      
                                        
      //look for an error
      if ( sd_retval <> 0 ) then
        State.uiIO_Flags				          := 0;
        State.uiIO_Flags.NoCalibration	  := 1;			
        State.uiIO_Flags.PhysicAccessOff  := 1;
        return;
      end_if;

      p_HandleTDOWriteEnable^ := VARAN_DO_NO_RUN;
    end_if;
    
    // only for modules with outputs
    if ud_MyModuleID <> CSDI16x_ID then // Kennung is not yet avalable at this point wih Payload and Mover

      //add data object for unsafe output write
      sd_retval := AddWrPayloadDO(ud_dol_type     := VARAN_DOL_ISO
                                , p_ud_handle     := ( #p_HandleUnsafeOutWrite )$^UDINT
                                , ud_offset_write := ui_MyPlace + OFFSET_UNSAFE_VAR
                                , ud_length_write := UNSAFE_OUT_LENGTH
                                , p_ud_data_write := ( #p_ui_UnsafeOutWrite )$^UDINT
                                , ud_type         := 1
                                );      

      //look for an error
      if ( sd_retval <> 0 ) then
        State.uiIO_Flags				          := 0;
        State.uiIO_Flags.NoCalibration	  := 1;			
        State.uiIO_Flags.PhysicAccessOff  := 1;
        return;
      end_if;
    end_if;

    //data object for LEDs, SSDO State, STDO State, SPDO DataLength and time sync handshake
    sd_retval := AddRdPayloadDO(ud_dol_type     := VARAN_DOL_ISO
                              , p_ud_handle     := ( #p_HandleLED )$^UDINT
                              , ud_offset_read  := ui_MyPlace + OFFSET_LED
                              , ud_length_read  := 15 
                              , p_ud_data_read  := ( #p_ud_Handle_LED )$^UDINT
                              , ud_type         := 1
                              );    
      
    //look for an error
    if ( sd_retval <> 0 ) then
      State.uiIO_Flags				          := 0;
      State.uiIO_Flags.NoCalibration	  := 1;			
      State.uiIO_Flags.PhysicAccessOff  := 1;
      return;
    end_if;

    p_us_Handle_TDO_Read_Length   := p_ud_Handle_LED + (OFFSET_STDO_STATUS - OFFSET_LED);
    p_us_Handle_TDO_Read_Length^  := 0;
    
    pPDOReadLengthData            := p_ud_Handle_LED + (OFFSET_SPDO_LENGTH - OFFSET_LED);
    pPDOReadLengthData^           := 0;
    
    p_us_Handle_TDO_Status_Write  := p_ud_Handle_LED + (OFFSET_STDO_STATUS_WRITE - OFFSET_LED);
    p_us_Handle_TDO_Status_Write^ := 0;

    p_us_Handle_TimeSyncHS_Read   := p_ud_Handle_LED + (OFFSET_TIMESYNC_HANDSHAKE - OFFSET_LED);
    p_us_Handle_TimeSyncHS_Read^  := 0;
    
    if sd_VaranType = 1 then

      //add data object for time sync handshake
      sd_retval := AddWrPayloadDO(ud_dol_type     := VARAN_DOL_ISO
                                , p_ud_handle     := ( #p_Handle_TimeSyncHS_Write )$^UDINT
                                , ud_offset_write := ui_MyPlace + OFFSET_TIMESYNC_HANDSHAKE 
                                , ud_length_write := 1
                                , p_ud_data_write := ( #p_us_Handle_TimeSyncHS_Write )$^UDINT
                                , ud_type         := 1
                                );      
                                        
    else  // for mover we have to say it's a single execution

      //add data object for time sync handshake
      sd_retval := AddWrPayloadDO(ud_dol_type     := VARAN_DOL_ISO
                                , p_ud_handle     := ( #p_Handle_TimeSyncHS_Write )$^UDINT
                                , ud_offset_write := ui_MyPlace + OFFSET_TIMESYNC_HANDSHAKE
                                , ud_length_write := 1
                                , p_ud_data_write := ( #p_us_Handle_TimeSyncHS_Write )$^UDINT
                                , ud_type         := 1
                                , pp_Enable       := ( #p_Handle_TimeSyncHS_WriteEnable )$^pVoid 
                                );
  
      p_Handle_TimeSyncHS_WriteEnable^ := VARAN_DO_NO_RUN;
    end_if;

    //look for an error
    if ( sd_retval <> 0 ) then
      State.uiIO_Flags				          := 0;
      State.uiIO_Flags.NoCalibration	  := 1;			
      State.uiIO_Flags.PhysicAccessOff  := 1;
      return;
    end_if;


    //add data object for TDO read
    sd_retval := AddRdPayloadDO(ud_dol_type     := VARAN_DOL_ISO
                              , p_ud_handle     := ( #p_HandleTDORead )$^UDINT
                              , ud_offset_read  := ui_MyPlace + OFFSET_STDO_DATA
                              , ud_length_read  := STDO_LENGTH
                              , p_ud_data_read  := ( #p_us_Handle_TDO_Read )$^UDINT
                              , ud_type         := 1
                              ); 
    
    //look for an error
    if ( sd_retval <> 0 ) then
      State.uiIO_Flags				          := 0;
      State.uiIO_Flags.NoCalibration	  := 1;			
      State.uiIO_Flags.PhysicAccessOff  := 1;
      return;
    end_if;
    
    // fast unsafe variables (only if activated)
    if ActivateFastUnsafeIOs then
      //add data object for fast unsafe output and input variables
      sd_retval := AddRdWrPayloadDO(ud_dol_type     := VARAN_DOL_ISO
                                  , p_ud_handle     := ( #p_HandleFastUnsafeIOs )$^UDINT
                                  , ud_offset_read  := ui_MyPlace + OFFSET_FAST_UNSAFE_IOS
                                  , ud_length_read  := 1
                                  , p_ud_data_read  := ( #p_us_Handle_FastUnsafeOutputs )$^UDINT
                                  , ud_offset_write := ui_MyPlace + OFFSET_FAST_UNSAFE_IOS
                                  , ud_length_write := 1
                                  , p_ud_data_write := ( #p_us_Handle_FastUnsafeInputs )$^UDINT
                                  , ud_type         := 1
                                  );

      //look for an error
      if ( sd_retval <> 0 ) then
        State.uiIO_Flags				          := 0;
        State.uiIO_Flags.NoCalibration	  := 1;			
        State.uiIO_Flags.PhysicAccessOff  := 1;
        return;
      end_if;
    end_if;
   
    
  else  // Without Payload Suport **************************************************************************************************************
  
    //add data object for PDO read
    sd_retval := MasterConnect.AddRdDO( ud_dol_type   := VARAN_DOL_ISO
                                      , p_ud_handle	  := ( #p_HandlePDORead )$^UDINT
                                      , ud_address	  := ui_MyPlace + OFFSET_SPDO_DATA
                                      , ud_length	    := MaxLengthPDORead
                                      , p_ud_data	    := ( #pPDOReadData )$^UDINT
                                      , ud_type			  := 1 OR VM_PRIORITY_1
                                      );

    //look for an error
    if ( sd_retval <> 0 ) then
      State.uiIO_Flags				          := 0;
      State.uiIO_Flags.NoCalibration	  := 1;			
      State.uiIO_Flags.PhysicAccessOff  := 1;
      return;
    end_if;
    
    ud_LocalMoveSourceAddr := pPDOReadData$UDINT;

    // only for modules with outputs
    if Kennung <> CSDI16x_ID then

        // add data object to move our data      
      sd_retval := MasterConnect.AddMovDO(ud_dol_type       := VARAN_DOL_ISO
                                        , p_ud_handle       := (#InputMovHandle)$^UDINT
                                        , p_ud_MovSettings  := ( #InputMovSettings)$^UDINT
                                        , ud_type           := VM_PRIORITY_2
                                        );

      //look for an error
      if ( sd_retval <> 0 ) then
        State.uiIO_Flags				          := 0;
        State.uiIO_Flags.NoCalibration	  := 1;			
        State.uiIO_Flags.PhysicAccessOff  := 1;
        return;
      end_if;

    //  end_if;
      
      if sd_VaranType = 1 then
        if (AdditionalSPDOs > 0) then      
          for i := 0 to (AdditionalSPDOs-1) do
            
            // add data object to move our data
            sd_retval := MasterConnect.AddMovDO(ud_dol_type       := VARAN_DOL_ISO
                                              , p_ud_handle       := (#aAdditionalPDOs[i].InputMovHandle)$^UDINT
                                              , p_ud_MovSettings  := ( #aAdditionalPDOs[i].InputMovSettings)$^UDINT
                                              , ud_type           := VM_PRIORITY_2
                                              );

            //look for an error
            if ( sd_retval <> 0 ) then
              State.uiIO_Flags				          := 0;
              State.uiIO_Flags.NoCalibration	  := 1;			
              State.uiIO_Flags.PhysicAccessOff  := 1;
              return;
            end_if;
            

            //add data object for PDO write
            sd_retval := MasterConnect.AddWrDO( ud_dol_type   := VARAN_DOL_ISO
                                              , p_ud_handle	  := ( #aAdditionalPDOs[i].p_HandlePDOWrite )$^UDINT
                                              , ud_address	  := ui_MyPlace + OFFSET_SPDO_DATA
                                              , ud_length	    := MaxLengthPDOWrite
                                              , p_ud_data	    := ( #aAdditionalPDOs[i].pPDOWriteData )$^UDINT
                                              , ud_type			  := 1 OR VM_PRIORITY_3
                                              );

            //look for an error
            if ( sd_retval <> 0 ) then
              State.uiIO_Flags				          := 0;
              State.uiIO_Flags.NoCalibration	  := 1;			
              State.uiIO_Flags.PhysicAccessOff  := 1;
              return;
            end_if;
            
            aAdditionalPDOs[i].ud_LocalMoveDestAddr := aAdditionalPDOs[i].pPDOWriteData$UDINT;
          end_for;
        end_if;

        //add data object for PDO write
        sd_retval := MasterConnect.AddWrDO( ud_dol_type   := VARAN_DOL_ISO
                                          , p_ud_handle	  := ( #p_HandlePDOWrite )$^UDINT
                                          , ud_address	  := ui_MyPlace + OFFSET_SPDO_DATA
                                          , ud_length	    := MaxLengthPDOWrite
                                          , p_ud_data	    := ( #pPDOWriteData )$^UDINT
                                          , ud_type			  := 1 OR VM_PRIORITY_3
                                          );

        //look for an error
        if ( sd_retval <> 0 ) then
          State.uiIO_Flags				          := 0;
          State.uiIO_Flags.NoCalibration	  := 1;			
          State.uiIO_Flags.PhysicAccessOff  := 1;
          return;
        end_if;
        
      else  // for mover we have to say it's a single execution (OR VM_SINGLE_ID)
        if (AdditionalSPDOs > 0) then      
          for i := 0 to (AdditionalSPDOs-1) do
            
            // add data object to move our data
            sd_retval := MasterConnect.AddMovDO(ud_dol_type       := VARAN_DOL_ISO
                                              , p_ud_handle       := (#aAdditionalPDOs[i].InputMovHandle)$^UDINT
                                              , p_ud_MovSettings  := ( #aAdditionalPDOs[i].InputMovSettings)$^UDINT
                                              , ud_type           := VM_PRIORITY_2
                                              );

            //look for an error
            if ( sd_retval <> 0 ) then
              State.uiIO_Flags				          := 0;
              State.uiIO_Flags.NoCalibration	  := 1;			
              State.uiIO_Flags.PhysicAccessOff  := 1;
              return;
            end_if;
            
            tmplength := MaxLengthPDOWrite;
            
            //One Byte for mover
            if tmplength = SPDO_MAX_LENGTH then
              tmplength := 127;
            end_if;
            
            

            //add data object for PDO write
            sd_retval := MasterConnect.AddWrDO( ud_dol_type   := VARAN_DOL_ISO
                                              , p_ud_handle	  := ( #aAdditionalPDOs[i].p_HandlePDOWrite )$^UDINT
                                              , ud_address	  := ui_MyPlace + OFFSET_SPDO_DATA
                                              , ud_length	    := tmplength // we need 1 byte for enable
                                              , p_ud_data	    := ( #aAdditionalPDOs[i].pPDOWriteData )$^UDINT
                                              , ud_type			  := 1 OR VM_SINGLE_ID OR VM_PRIORITY_3
                                              );

            //look for an error
            if ( sd_retval <> 0 ) then
              State.uiIO_Flags				          := 0;
              State.uiIO_Flags.NoCalibration	  := 1;			
              State.uiIO_Flags.PhysicAccessOff  := 1;
              return;
            end_if;
            
            (aAdditionalPDOs[i].p_HandlePDOWrite$^USINT )^ := VARAN_DO_NO_RUN;
            
            aAdditionalPDOs[i].ud_LocalMoveDestAddr := aAdditionalPDOs[i].pPDOWriteData$UDINT;
          end_for;
        end_if;
        
        tmplength := MaxLengthPDOWrite;
    
        //One Byte for mover
        if tmplength = SPDO_MAX_LENGTH then
          tmplength := 127;
        end_if;
    
        
        //add data object for PDO write
        sd_retval := MasterConnect.AddWrDO( ud_dol_type   := VARAN_DOL_ISO
                                          , p_ud_handle	  := ( #p_HandlePDOWrite )$^UDINT
                                          , ud_address	  := ui_MyPlace + OFFSET_SPDO_DATA
                                          , ud_length	    := tmplength // we need 1 byte for enable
                                          , p_ud_data	    := ( #pPDOWriteData )$^UDINT
                                          , ud_type			  := 1 OR VM_SINGLE_ID OR VM_PRIORITY_3
                                          );

        //look for an error
        if ( sd_retval <> 0 ) then
          State.uiIO_Flags				          := 0;
          State.uiIO_Flags.NoCalibration	  := 1;			
          State.uiIO_Flags.PhysicAccessOff  := 1;
          return;
        end_if;
        
        p_HandlePDOWrite^$USINT := VARAN_DO_NO_RUN;
      end_if;

      ud_LocalMoveDestAddr := pPDOWriteData$UDINT;
    end_if;

    if sd_VaranType = 1 then

      //add data object for TDO write
      sd_retval := MasterConnect.AddWrDO( ud_dol_type   := VARAN_DOL_ISO
                                        , p_ud_handle	  := ( #p_HandleTDOWrite )$^UDINT
                                        , ud_address	  := ui_MyPlace + OFFSET_STDO_DATA
                                        , ud_length	    := STDO_LENGTH
                                        , p_ud_data	    := ( #p_us_Handle_TDO_Write )$^UDINT
                                        , ud_type			  := 1
                                        );

      //look for an error
      if ( sd_retval <> 0 ) then
        State.uiIO_Flags				          := 0;
        State.uiIO_Flags.NoCalibration	  := 1;			
        State.uiIO_Flags.PhysicAccessOff  := 1;
        return;
      end_if;    
    else  // for mover we have to say it's a single execution

      //add data object for TDO write
      sd_retval := MasterConnect.AddWrDO( ud_dol_type   := VARAN_DOL_ISO
                                        , p_ud_handle	  := ( #p_HandleTDOWrite )$^UDINT
                                        , ud_address	  := ui_MyPlace + OFFSET_STDO_DATA
                                        , ud_length	    := STDO_LENGTH
                                        , p_ud_data	    := ( #p_us_Handle_TDO_Write )$^UDINT
                                        , ud_type			  := 1 OR VM_SINGLE_ID
                                        );
                                        
      //look for an error
      if ( sd_retval <> 0 ) then
        State.uiIO_Flags				          := 0;
        State.uiIO_Flags.NoCalibration	  := 1;			
        State.uiIO_Flags.PhysicAccessOff  := 1;
        return;
      end_if;

      (p_HandleTDOWrite$^USINT )^ := VARAN_DO_NO_RUN;
    end_if;


    // only for modules with outputs
    if Kennung <> CSDI16x_ID then

      //add data object for unsafe output write
      sd_retval := MasterConnect.AddWrDO( ud_dol_type   := VARAN_DOL_ISO
                                        , p_ud_handle	  := ( #p_HandleUnsafeOutWrite )$^UDINT
                                        , ud_address	  := ui_MyPlace + OFFSET_UNSAFE_VAR
                                        , ud_length	    := UNSAFE_OUT_LENGTH
                                        , p_ud_data	    := ( #p_ui_UnsafeOutWrite )$^UDINT
                                        , ud_type			  := 1
                                        );

      //look for an error
      if ( sd_retval <> 0 ) then
        State.uiIO_Flags				          := 0;
        State.uiIO_Flags.NoCalibration	  := 1;			
        State.uiIO_Flags.PhysicAccessOff  := 1;
        return;
      end_if;
    end_if;

    //data object for LEDs, SSDO State, STDO State, SPDO DataLength and time sync handshake
    sd_retval := MasterConnect.AddRdDO( ud_dol_type   := VARAN_DOL_ISO
                                      , p_ud_handle   := ( #p_HandleLED )$^UDINT
                                      , ud_address    := ui_MyPlace + OFFSET_LED
                                      , ud_length     := 15
                                      , p_ud_data     := ( #p_ud_Handle_LED )$^UDINT
                                      , ud_type       := 1
                                      );
      
    //look for an error
    if ( sd_retval <> 0 ) then
      State.uiIO_Flags				          := 0;
      State.uiIO_Flags.NoCalibration	  := 1;			
      State.uiIO_Flags.PhysicAccessOff  := 1;
      return;
    end_if;

    p_us_Handle_TDO_Read_Length   := p_ud_Handle_LED + (OFFSET_STDO_STATUS - OFFSET_LED);
    p_us_Handle_TDO_Read_Length^  := 0;
    
    pPDOReadLengthData := p_ud_Handle_LED + (OFFSET_SPDO_LENGTH - OFFSET_LED);
    pPDOReadLengthData^ := 0;
    
    p_us_Handle_TDO_Status_Write  := p_ud_Handle_LED + (OFFSET_STDO_STATUS_WRITE - OFFSET_LED);
    p_us_Handle_TDO_Status_Write^ := 0;

    p_us_Handle_TimeSyncHS_Read   := p_ud_Handle_LED + (OFFSET_TIMESYNC_HANDSHAKE - OFFSET_LED);
    p_us_Handle_TimeSyncHS_Read^  := 0;

    if sd_VaranType = 1 then

      //add data object for time sync handshake
      sd_retval := MasterConnect.AddWrDO( ud_dol_type   := VARAN_DOL_ISO
                                        , p_ud_handle	  := ( #p_Handle_TimeSyncHS_Write )$^UDINT
                                        , ud_address	  := ui_MyPlace + OFFSET_TIMESYNC_HANDSHAKE
                                        , ud_length	    := 1
                                        , p_ud_data	    := ( #p_us_Handle_TimeSyncHS_Write )$^UDINT
                                        , ud_type			  := 1
                                        );
                                        
    else  // for mover we have to say it's a single execution

      //add data object for TDO write
      sd_retval := MasterConnect.AddWrDO( ud_dol_type   := VARAN_DOL_ISO
                                        , p_ud_handle	  := ( #p_Handle_TimeSyncHS_Write )$^UDINT
                                        , ud_address	  := ui_MyPlace + OFFSET_TIMESYNC_HANDSHAKE
                                        , ud_length	    := 1
                                        , p_ud_data	    := ( #p_us_Handle_TimeSyncHS_Write )$^UDINT
                                        , ud_type			  := 1 OR VM_SINGLE_ID
                                        );
      (p_Handle_TimeSyncHS_Write$^USINT )^ := VARAN_DO_NO_RUN;
    end_if;

    //look for an error
    if ( sd_retval <> 0 ) then
      State.uiIO_Flags				          := 0;
      State.uiIO_Flags.NoCalibration	  := 1;			
      State.uiIO_Flags.PhysicAccessOff  := 1;
      return;
    end_if;


    //add data object for TDO read
    sd_retval := MasterConnect.AddRdDO( ud_dol_type   := VARAN_DOL_ISO
                                      , p_ud_handle	  := ( #p_HandleTDORead )$^UDINT
                                      , ud_address	  := ui_MyPlace + OFFSET_STDO_DATA
                                      , ud_length	    := STDO_LENGTH
                                      , p_ud_data	    := ( #p_us_Handle_TDO_Read )$^UDINT
                                      , ud_type			  := 1
                                      );
    
    //look for an error
    if ( sd_retval <> 0 ) then
      State.uiIO_Flags				          := 0;
      State.uiIO_Flags.NoCalibration	  := 1;			
      State.uiIO_Flags.PhysicAccessOff  := 1;
      return;
    end_if;
    
    // fast unsafe variables (only if activated)
    if ActivateFastUnsafeIOs then
      //add data object for fast unsafe output and input variables
      sd_retval :=  MasterConnect.AddRdWrDO(ud_dol_type       := VARAN_DOL_ISO
                                          , p_ud_handle       := ( #p_HandleFastUnsafeIOs )$^UDINT
                                          , ud_address_read   := ui_MyPlace + OFFSET_FAST_UNSAFE_IOS
                                          , ud_length_read    := 1
                                          , p_ud_data_read    := ( #p_us_Handle_FastUnsafeOutputs )$^UDINT
                                          , ud_address_write  := ui_MyPlace + OFFSET_FAST_UNSAFE_IOS
                                          , ud_length_write   := 1
                                          , p_ud_data_write   := ( #p_us_Handle_FastUnsafeInputs )$^UDINT
                                          , ud_type           := 1
                                          );

      //look for an error
      if ( sd_retval <> 0 ) then
        State.uiIO_Flags				          := 0;
        State.uiIO_Flags.NoCalibration	  := 1;			
        State.uiIO_Flags.PhysicAccessOff  := 1;
        return;
      end_if;
    end_if;
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::GetPointer2PDOBuffer
	VAR_OUTPUT
		ud_PDOBuffer 	: UDINT;
	END_VAR

  PDOOutputIsUsed := TRUE;

  //set pointer to address of buffer pointer
  ud_PDOBuffer := ( #PDOOutputBuffer )$UDINT;
   
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::AddRoutingElement
	VAR_INPUT
		ud_SafeNumber 	: HDINT;
		ud_thisp 	      : UDINT;
		pObject 	      : ^PathInfoType;
	END_VAR
	VAR_OUTPUT
		sd_retval 	    : DINT;
	END_VAR
  VAR
  	p_RoutElement   : ^RoutElement;
    ui_PathLength   : UINT;
    NewElement      : BOOL;
  END_VAR

  if ( ( ud_SafeNumber <> 0 ) & ( ud_thisp <> NIL ) ) then
    if ui_CntRoutElements < MAX_NUMBER_ROUT_ELEMENTS then

      NewElement := TRUE;
    
      if ui_CntRoutElements then
        //check if object this-pointer already exists in routing table
        p_RoutElement := GetRoutingElementByThis( ud_thisp := ud_thisp );
      else
        p_RoutElement := NIL;
      end_if;

      if p_RoutElement = NIL then
        //add new element
      
        //set pointer to empty element on last position
        p_RoutElement := p_RoutTable + ( ui_CntRoutElements ) * sizeof(RoutElement);
      else
        // we don't have a new element, we just update an existing
        NewElement := FALSE;
      end_if;
    
      //add path

      // path isn't stored if it's the routing table of safe input module, because
      // it doesn't need the information
      if pObject^.p_us_Path & pObject^.p_us_PathComp 
         & ((NewElement = TRUE) | ((NewElement = FALSE) & (p_RoutElement^.p_CompressedPath = NIL) & (p_RoutElement^.ui_ComprPathLen = 0))) // only if it isn't already set
         then
          
        // the whole object path isn't stored, because the path can't be used for routing of SDOs;
        // The length of the path varies and it's possible, that the path is too long
        // to transfer it in SDO header. Instead of it the compressed path is used for addressing.
        
        ui_PathLength := pObject^.ui_PathCompLen;
        p_RoutElement^.p_CompressedPath$pVoid := To_StdLib.Malloc(size := ui_PathLength);

        if ( p_RoutElement^.p_CompressedPath = NIL ) then
        
          State.uiIO_Flags                  := 0;
          State.uiIO_Flags.PhysicAccessOff 	:= 1;
          sd_retval                         :=-1;
          ClassState := _MemAllocFailed;
          return;
          
        end_if;

        // store compressed path into actual routing element
        To_StdLib.MemCpy(dest := p_RoutElement^.p_CompressedPath, source := pObject^.p_us_PathComp, size := ui_PathLength);      
        p_RoutElement^.ui_ComprPathLen := ui_PathLength;
      elsif NewElement then
          
        // not routing table of safety CPU of safety output
        p_RoutElement^.p_CompressedPath := NIL;
        p_RoutElement^.ui_ComprPathLen  := 0;
      end_if;
        
      //insert data
      p_RoutElement^.ud_SafeNumber      := ud_SafeNumber;
      p_RoutElement^.ud_thisp           := ud_thisp;
      
      if NewElement then
        //increase counter
        ui_CntRoutElements += 1;
      end_if;
        
      sd_retval := 0;
    else
    
      sd_retval := -1;
      LogError("@ZZZZ (SafetyCDIAS_Base::AddRoutingElement) Maximum number of possible routing elements reached");
    end_if;
  else
  
    sd_retval := -1;
  
    if ud_SafeNumber = 0 then
      LogError("@ZZZZ (SafetyCDIAS_Base::AddRoutingElement) 0 is an invalid safety number");
    else
      LogError("@ZZZZ (SafetyCDIAS_Base::AddRoutingElement) NIL pointer given as this pointer");
    end_if;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::GetRoutingPointerByNumber
	VAR_INPUT
		ud_SafeNumber 	: HDINT;
	END_VAR
	VAR_OUTPUT
		ud_thisp 	      : UDINT;
	END_VAR
  VAR
  	i               : UINT;
    p_RoutElement   : ^RoutElement;
  END_VAR

  ud_thisp := 0;
  
  //no valid safety number
  if ( ud_SafeNumber = 0 ) then
    return;
  end_if;
  
  //set pointer on first routing element
  p_RoutElement := p_RoutTable;
  
  //check each element
  if ( ui_CntRoutElements > 0 ) then
    for i := 0 to ui_CntRoutElements - 1 by 1 do 
    
      //if searched safety number is found, this-pointer is returned
      if ( p_RoutElement^.ud_SafeNumber = ud_SafeNumber ) then
      
        ud_thisp := p_RoutElement^.ud_thisp;
        return;
        
      end_if;
      
      //set pointer to next element
      p_RoutElement += sizeof ( RoutElement );
    
    end_for;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::GetRoutingPointerByPath
	VAR_INPUT
		p_ActObjectPath 	: ^USINT;
		ActPathLen 	      : UINT;
	END_VAR
	VAR_OUTPUT
		ud_thisp          : UDINT;
	END_VAR
  VAR
  	i                 : UINT;
    p_RoutElement     : ^RoutElement;
    retcode           : UINT;
  END_VAR

  ud_thisp := 0;
  
  //set pointer on first routing element
  p_RoutElement := p_RoutTable;
  
  //check each element
  if ( ui_CntRoutElements > 0 ) then
    for i := 0 to ui_CntRoutElements - 1 by 1 do 
    
      if p_RoutElement^.p_CompressedPath & (p_RoutElement^.ui_ComprPathLen = ActPathLen) then
      
        //if searched path is found, this-pointer is returned
        retcode := To_StdLib.MemCmp(dest:= p_ActObjectPath, source:= p_RoutElement^.p_CompressedPath , size:= ActPathLen);
        
        if retcode = 0 then
        
          ud_thisp := p_RoutElement^.ud_thisp;
          return;
          
        end_if;
      end_if;
      
      //set pointer to next element
      p_RoutElement += sizeof ( RoutElement );
    
    end_for;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::ConfigSafetyInput
	VAR_INPUT
		ud_SafeNrCPU 	        : HDINT;
		ud_thisp 	            : UDINT;
		p_PDOBuffer 	        : ^UDINT;
		pMoveActive 	        : ^PDOMoveState;
		p_ud_HandleSourceDO 	: ^UDINT;
		p_ud_MoveSourceAddr 	: ^UDINT;
		p_ud_MoveSourceOffset : ^UDINT;
	END_VAR
	VAR_OUTPUT
		ud_SafeNrModul 	      : HDINT;
	END_VAR
  VAR
  	TempPathInfo          : PathInfoType;
  END_VAR

  ud_SafeNrModul := 0;
  
  if (State.uiIO_Flags = 0) then
    if ( ud_SafeNrCPU ) then

      // if pMoveActive is available, the data are sent to a CPU via VARAN => moving is possible
      if pMoveActive then
        // if input module is also accessed via VARAN => activate moving
        if b_VaranAvailable & (b_SafetyOnLocalCDIAS = FALSE) then
          // pdos are moved from csdi to cscp
          b_MoveCommandOutputActive := _Active;
          
          p_ud_MoveSourceAddr^      := pPDOReadData$UDINT;
          
          // Return DO Handle and Offset, Needed for Payload Move DOs
          if sd_VaranType = 1 then  // Return DO Handle
            p_ud_HandleSourceDO^    := p_HandlePDORead$UDINT;
          else                      // Return VaranDataMoversDO Handle
            p_ud_HandleSourceDO^    := 0;
          end_if;
          
          p_ud_MoveSourceOffset^    := 0; 
          
          // Return DO Handle and Offset, Needed for Payload Move DOs
          if sd_VaranType = 1 then  // Return DO Handle
            p_ud_HandleSourceDO^    := p_HandlePDORead$UDINT;
          else                      // Return VaranDataMoversDO Handle
            p_ud_HandleSourceDO^    := ud_HandlePDOReadMoverDO;
          end_if;
          
          p_ud_MoveSourceOffset^    := 0; 
        else
          // pdos are not moved from csdi to cscp or cscp to csto
          pMoveActive^              := _Inactive;
          b_MoveCommandOutputActive := _Inactive;
        end_if;
      else
        b_MoveCommandOutputActive   := _Inactive;
      end_if;

      // we start the data object for continous writing to the module after we know that there is an input for this module and the move command is active
      if b_VaranAvailable & (b_MoveCommandOutputActive = _Active) then
        if sd_VaranType = 1 then
          if StartRtDOs = 0 then
            StartRtDOs := 1;
          end_if;
        end_if;
      end_if;

      InitPathInfo(#TempPathInfo);
    
      //add CPU to routing table for SDO
      if ( AddRoutingElement( ud_SafeNumber   := ud_SafeNrCPU
                            , ud_thisp        := ud_thisp
                            , pObject         := #TempPathInfo
                            ) = 0 ) then
      
        //return own safety number
        ud_SafeNrModul := SafetyNumber;
        
      end_if;
      
      //set pointer to address of buffer pointer
      p_PDOBuffer^ := GetPointer2PDOBuffer();
    else
      LogError("@ZZZZ (SafetyCDIAS_Base::ConfigSafetyInput) 0 is an invalid safety number for the safety CPU");
      b_ReInitMarker := TRUE;
    end_if;
  else
    LogError("@ZZZZ (SafetyCDIAS_Base::ConfigSafetyInput) A module with safety outputs, which is used in the safety CPU configuration is not available");
    b_ReInitMarker := TRUE;
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::ConfigSafetyOutput
	VAR_INPUT
		ud_SafeNrCPU 	      : HDINT;
		ud_thisp 	          : UDINT;
		ud_p_PDOBuffer 	    : UDINT;
		pObject 	          : ^PathInfoType;
		pMoveActive 	      : ^PDOMoveState;
    ud_HandleSourceDO   : UDINT;
		ud_MoveSourceAddr   : UDINT;
    ud_MoveSourceOffset : UDINT;
    b_IsOptional        : BOOL;
	END_VAR
	VAR_OUTPUT
		ud_SafeNrModul      : HDINT;
	END_VAR
  VAR
  	i                   : DINT;
  END_VAR

  ud_SafeNrModul := 0;
  
  if (State.uiIO_Flags = 0) then
    if ( ud_SafeNrCPU ) then
    
      //add CPU to routing table for SDO
      if ( AddRoutingElement( ud_SafeNumber   := ud_SafeNrCPU
                            , ud_thisp        := ud_thisp
                            , pObject         := pObject
                            ) = 0 ) then
      
        //return own safety number and object path
        ud_SafeNrModul := SafetyNumber;
        
      end_if;

      //add PDO of CPU to list of input elements
      AddPDOToInputBuffer(ud_p2Buffer         := ud_p_PDOBuffer
                        , ud_HandleSourceDO   := ud_HandleSourceDO
                        , ud_MoveSourceAddr   := ud_MoveSourceAddr
                        , ud_MoveSourceOffset :=ud_MoveSourceOffset
                        , ud_SafetyNr         := ud_SafeNrCPU
                        , b_IsOptional        := b_IsOptional
                        );

      // if we got an adress of the source data from cpu, the cpu must be connected via VARAN => moving is possible
      if ud_MoveSourceAddr then
        
        // if output module is also accessed via VARAN => activate moving
        if b_VaranAvailable & (b_SafetyOnLocalCDIAS = FALSE) then
          // pdos are moved from cscp to csto
          b_MoveCommandInputActive  := _Active;
        else
          // pdos are not moved from cscp to csto because csto is not connected via VARAN
          if pMoveActive then
            pMoveActive^            := _Inactive;        
          end_if;
          b_MoveCommandInputActive  := _Inactive;      
        end_if;      
      else
        // pdos are not moved from cscp to csto because cscp (and/or csto) is not connected via VARAN
        if pMoveActive then
          pMoveActive^              := _Inactive;        
        end_if;
        b_MoveCommandInputActive    := _Inactive;      
      end_if;

      // we start the data object for continous writing to the module after we know that there is an input for this module and the move command is active
      if b_VaranAvailable & (b_MoveCommandInputActive = _Active) then
        b_StartDOs := TRUE;
      elsif b_VaranAvailable & (sd_VaranType = 1) then
        MasterConnect.ResetDO( p_data_object := p_HandlePDOWrite$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := MaxLengthPDOWrite);
        
        if AdditionalSPDOs & (ui_cnt_PDOInputBuffer > 1) then
          if AdditionalSPDOs > (ui_cnt_PDOInputBuffer-1) then
            AdditionalSPDOs := ui_cnt_PDOInputBuffer-1;
          end_if;

          for i := 0 to (AdditionalSPDOs-1) do
            MasterConnect.ResetDO( p_data_object := aAdditionalPDOs[i].p_HandlePDOWrite$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := MaxLengthPDOWrite);
          end_for;
        end_if;
      end_if;
    else
      LogError("@ZZZZ (SafetyCDIAS_Base::ConfigSafetyOutput) 0 is an invalid safety number for the safety CPU");
      b_ReInitMarker := TRUE;
    end_if;  
  else
    LogError("@ZZZZ (SafetyCDIAS_Base::ConfigSafetyOutput) A module with safety outputs, which is used in the safety CPU configuration is not available");
    b_ReInitMarker := TRUE;
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::ConfigSafetyCPU
	VAR_OUTPUT
		ud_SafeNrModul 	: HDINT;
	END_VAR

  //return own safety number
  ud_SafeNrModul := SafetyNumber;      
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::AddPDOToInputBuffer
	VAR_INPUT
		ud_p2Buffer 	        : UDINT;
		ud_HandleSourceDO 	  : UDINT;
		ud_MoveSourceAddr 	  : UDINT;
		ud_MoveSourceOffset 	: UDINT;
		ud_SafetyNr 	        : HDINT;
		b_IsOptional 	        : BOOL;
		us_PdoLen 	          : USINT;
	END_VAR
	VAR_OUTPUT
		sd_retval 	          : DINT;
	END_VAR
  VAR
  	p_BufferElement       : ^PDOInputBuffer;
  END_VAR
  
  sd_retval := 0;
  
  //check if input buffer is already in list
  p_BufferElement := GetPDOInputBuffer(ud_p2Buffer := ud_p2Buffer);
  
  //buffer already in list -> do nothing
  if ( p_BufferElement ) then
    return;
  else
    aPDOInputBuffer[ui_cnt_PDOInputBuffer].ud_p2Buffer        := ud_p2Buffer;
    aPDOInputBuffer[ui_cnt_PDOInputBuffer].ud_HandleSourceDO  := ud_HandleSourceDO;   //LanSte 28.05.2013 For Payload support
    aPDOInputBuffer[ui_cnt_PDOInputBuffer].ud_MoveSourceAddr  := ud_MoveSourceAddr;
    aPDOInputBuffer[ui_cnt_PDOInputBuffer].ud_MoveSourceOffset:= ud_MoveSourceOffset; //LanSte 28.05.2013 For Payload support
    //*****************************************************************************
    
    aPDOInputBuffer[ui_cnt_PDOInputBuffer].b_TimeSynchron     := FALSE;
    aPDOInputBuffer[ui_cnt_PDOInputBuffer].ud_SafetyNr        := ud_SafetyNr;
    aPDOInputBuffer[ui_cnt_PDOInputBuffer].us_PDOLen          := us_PDOLen;
    aPDOInputBuffer[ui_cnt_PDOInputBuffer].b_IsOptional       := b_IsOptional;

    if ui_cnt_PDOInputBuffer = 0 then
      // only when adding the first input PDO we increment our module counter
      ModuleSyncNo += 1;
    end_if;

    ui_cnt_PDOInputBuffer += 1;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::WritePDO2Module
  VAR
    p_PDOInBufferAct  : ^PDOInputBuffer;
    p_PDO_data        : ^UINT;
    PDOLength         : USINT;
    p_addressWr		    : ^VaranDOSettingsWr;
    i                 : DINT;
  END_VAR

  // if last PDO was selected (or a PDO which doesn't exist anymore), select first
  if ( ui_cnt_PDOInBufferAct >= ui_cnt_PDOInputBuffer ) then
    ui_cnt_PDOInBufferAct := 0;
  end_if;

  p_PDOInBufferAct := #aPDOInputBuffer[ui_cnt_PDOInBufferAct];

  if b_MoveCommandInputActive <> _Active then
    p_PDO_data := p_PDOInBufferAct^.ud_p2Buffer$^UINT;

    // get length out of PDO frame
    PDOLength := (p_PDO_data$^USINT + PDOType.Length)^ + sizeof(PDOType.CRC);
    
    //Save length to variable
    PDOWriteLen := PDOLength;
    
    // only if length is bigger than minimum and smaller than maximum
    if ( PDOLength > PDOType.Length ) & ( PDOLength <= SPDO_MAX_LENGTH ) then
  #ifdef SAFETY_OVER_DIAS  
      if ( b_im ) then
      
        //copy word by word
        for i := 0 to ((PDOLength/2)-1) by 1 do 
          
          (( a_Handle_PDO_Write[i] )$^UINT )^ := ( p_PDO_data + ( i * 2 ))^;
          
        end_for;
      
      else
  #endif

        //copy whole PDO 
        To_StdLib.MemCpy(dest := pPDOWriteData, source := p_PDO_data, size := PDOLength);

#ifdef DO_DEBUG
        DOCheck(pFrame:=p_PDO_data$^SDOStdHeader, pCheckStruct:=#PDOWrite);
#endif


#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
  RecordFrame(p_PDO_data$^DINT, 1);
#endif

        if b_VaranAvailable then
        
          if b_PayloadSupport then
          
            if (sd_VaranType = 1) then
            
            // correct size of data object to PDOLength
              ChangeDOLengthOffset( ud_DOHandle     := p_HandlePDOWrite$UDINT              
                                  , ud_length_write := PDOLength
                                  );              
              EnableDO(ud_DOHandle := p_HandlePDOWrite$UDINT );              
              PDOSingleRunActive := 2;  // No singlerun with Payload
            else            
              p_HandlePDOWriteEnable^ := VARAN_MOVER_DO_CONT_RUN;
              PDOSingleRunActive := 2;
            end_if;
            
          else
            if (sd_VaranType = 1) then
          
              // correct size of data object to PDOLength
              p_addressWr := pPDOWriteData - sizeof(VaranDOSettingsWr);
              p_addressWr^.us_ByteCnt := PDOLength;
              p_HandlePDOWrite^.usSendBufferLength := sizeof(VaranDOSettingsWr) + to_uint(PDOLength);

              p_HandlePDOWrite^.ucCtrlStat := VARAN_DO_SINGLE_RUN;
            else
              (p_HandlePDOWrite$^USINT )^ := VARAN_MOVER_DO_CONT_RUN;            
              PDOSingleRunActive := 2;  // This Marker is also used for aAdditionalPDOs 
            end_if;
            
          end_if;        
          
        end_if;

        if AdditionalSPDOs then
        
          for i := 0 to (AdditionalSPDOs-1) do
          
            //increase counter for pointer position for next PDO
            ui_cnt_PDOInBufferAct += 1;

            //if last PDO was read, reset counter for first PDO 
            if ( ui_cnt_PDOInBufferAct = ui_cnt_PDOInputBuffer ) then
              ui_cnt_PDOInBufferAct := 0;
            end_if;

            p_PDOInBufferAct := #aPDOInputBuffer[ui_cnt_PDOInBufferAct];

            p_PDO_data := p_PDOInBufferAct^.ud_p2Buffer$^UINT;

            // get length out of PDO frame
            PDOLength := (p_PDO_data$^USINT + PDOType.Length)^ + sizeof(PDOType.CRC);

            // only if length is bigger than minimum and smaller than maximum
            if ( PDOLength > PDOType.Length ) & ( PDOLength <= SPDO_MAX_LENGTH ) then

              //copy whole PDO 
              To_StdLib.MemCpy(dest := aAdditionalPDOs[i].pPDOWriteData, source := p_PDO_data, size := PDOLength);

#ifdef DO_DEBUG
              DOCheck(pFrame:=p_PDO_data$^SDOStdHeader, pCheckStruct:=#PDOWrite);
#endif

#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
  RecordFrame(p_PDO_data$^DINT, 1);
#endif

              if b_VaranAvailable then
                if b_PayloadSupport then
                  if (sd_VaranType = 1) then
                  // correct size of data object to PDOLength
                    ChangeDOLengthOffset( ud_DOHandle     := aAdditionalPDOs[i].p_HandlePDOWrite$UDINT
                                        , ud_length_write := PDOLength
                                        );
                    EnableDO(ud_DOHandle := aAdditionalPDOs[i].p_HandlePDOWrite$UDINT); // PDOSingleRunActive is used to deactivates these again
                  
                  else
                    aAdditionalPDOs[i].p_HandlePDOWriteEnable^ := VARAN_MOVER_DO_CONT_RUN;  // PDOSingleRunActive is used to deactivates these again
                  end_if;
                else
                  if (sd_VaranType = 1) then
                      // correct size of data object to PDOLength
                    p_addressWr := aAdditionalPDOs[i].pPDOWriteData - sizeof(VaranDOSettingsWr);
                    p_addressWr^.us_ByteCnt := PDOLength;
                    aAdditionalPDOs[i].p_HandlePDOWrite^.usSendBufferLength := sizeof(VaranDOSettingsWr) + to_uint(PDOLength);

                    aAdditionalPDOs[i].p_HandlePDOWrite^.ucCtrlStat := VARAN_DO_SINGLE_RUN;
                  else
                    (aAdditionalPDOs[i].p_HandlePDOWrite$^USINT )^ := VARAN_MOVER_DO_CONT_RUN;  // PDOSingleRunActive is used to deactivates these again
                  end_if;
                end_if;                
              end_if;
            end_if;
          end_for;
        end_if;
  #ifdef SAFETY_OVER_DIAS
      end_if;
  #endif
    end_if;
  else
    if (p_PDOInBufferAct^.ud_MoveSourceAddr) then

#ifdef VM_DEBUG_PAYLOAD
      if b_PayloadSupport = true &
        p_PDOInBufferAct^.ud_HandleSourceDO = 0 then
        // Handle mus be valid with payload support
        ((0)$^USINT)^ := 0; 
      end_if;  
#endif

      PDOLength := ((p_PDOInBufferAct^.ud_MoveSourceAddr)$^USINT + PDOType.Length)^ + sizeof(PDOType.CRC);
      
      //Save length to variable
      PDOWriteLen := PDOLength;
      
      if ( PDOLength > PDOType.Length ) & ( PDOLength <= MaxLengthPDOWrite) then

        if (sd_VaranType = 1) then
           
          if b_PayloadSupport then
          // correct size of data object to PDOLength
            ChangeDOLengthOffset( ud_DOHandle     := p_HandlePDOWrite$UDINT
                                , ud_length_write := PDOLength
                                );
            //start data object
            EnableDO(ud_DOHandle := p_HandlePDOWrite$UDINT);
          else
            // correct size of data object to PDOLength
            p_addressWr := pPDOWriteData - sizeof(VaranDOSettingsWr);
            p_addressWr^.us_ByteCnt := PDOLength;
            p_HandlePDOWrite^.usSendBufferLength := sizeof(VaranDOSettingsWr) + to_uint(PDOLength);

            //start data object
            MasterConnect.ResetDO( p_data_object := p_HandlePDOWrite$^DINT, us_state := VARAN_DO_CONT_RUN, ud_bytes := PDOLength );          
          end_if;
          
        elsif b_PayloadSupport = false then // No Payload + Mover
          PDOLength := MaxLengthPDOWrite-1;
        end_if;

        if b_PayloadSupport then

          if sd_VaranType = 1 then
            ChangeMovDOLengthOffset(ud_MovDOHandle              := InputMovHandle$UDINT                                  
                                  , ud_sourceReadDOHandle       := p_PDOInBufferAct^.ud_HandleSourceDO
                                  , ud_SourceReadOffset         := p_PDOInBufferAct^.ud_MoveSourceOffset
                                  , ud_destinationWriteDOHandle := p_HandlePDOWrite$UDINT
                                  , ud_DestinationWriteOffset   := 0
                                  , ud_lengthmove               := PDOLength);
          else  // VaranDatamover
            ChangeMovDOLengthOffset(ud_MovDOHandle              := InputMovHandle$UDINT                                  
                                  , ud_sourceReadDOHandle       := p_PDOInBufferAct^.ud_HandleSourceDO
                                  , ud_SourceReadOffset         := p_PDOInBufferAct^.ud_MoveSourceOffset
                                  , ud_destinationWriteDOHandle := ud_HandlePDOWriteMoverDO
                                  , ud_DestinationWriteOffset   := 0
                                  , ud_lengthmove               := PDOLength);
          end_if; 

          // moving is done every cycle
          EnableDO(ud_DOHandle := InputMovHandle$UDINT);
  
        else
          InputMovSettings^.ud_AddressDest := ud_LocalMoveDestAddr;
          InputMovSettings^.ud_AddressSrc  := p_PDOInBufferAct^.ud_MoveSourceAddr;
          InputMovSettings^.ui_ByteCnt     := PDOLength;
          
          // moving is done every cycle
          InputMovHandle^.ucCtrlStat := VARAN_DO_CONT_RUN;
        end_if;

        if AdditionalSPDOs then
        
          for i := 0 to (AdditionalSPDOs-1) do
          
            //increase counter for pointer position for next PDO
            ui_cnt_PDOInBufferAct += 1;

            //if last PDO was read, reset counter for first PDO 
            if ( ui_cnt_PDOInBufferAct = ui_cnt_PDOInputBuffer ) then
              ui_cnt_PDOInBufferAct := 0;
            end_if;
            
            p_PDOInBufferAct := #aPDOInputBuffer[ui_cnt_PDOInBufferAct];

            if p_PDOInBufferAct^.ud_MoveSourceAddr then      
              PDOLength := ((p_PDOInBufferAct^.ud_MoveSourceAddr)$^USINT + PDOType.Length)^ + sizeof(PDOType.CRC);
              
              if ( PDOLength > PDOType.Length ) & ( PDOLength <= MaxLengthPDOWrite) then

                if (sd_VaranType = 1) then
                  
                  if b_PayloadSupport then

                  // correct size of data object to PDOLength
                    ChangeDOLengthOffset( ud_DOHandle     := aAdditionalPDOs[i].p_HandlePDOWrite$UDINT
                                        , ud_length_write := PDOLength
                                        );
                                        
                    //start data object
                    EnableDO(ud_DOHandle := aAdditionalPDOs[i].p_HandlePDOWrite$UDINT);
                  else
                    // correct size of data object to PDOLength
                    p_addressWr := aAdditionalPDOs[i].pPDOWriteData - sizeof(VaranDOSettingsWr);
                    p_addressWr^.us_ByteCnt := PDOLength;
                    aAdditionalPDOs[i].p_HandlePDOWrite^.usSendBufferLength := sizeof(VaranDOSettingsWr) + to_uint(PDOLength);

                    //start data object
                    MasterConnect.ResetDO( p_data_object := aAdditionalPDOs[i].p_HandlePDOWrite$^DINT, us_state := VARAN_DO_CONT_RUN, ud_bytes := PDOLength );
                  end_if;
                  
                elsif b_PayloadSupport = false then // No Payload Mover
                  PDOLength := MaxLengthPDOWrite-1;
                end_if;
              end_if;
              
              if b_PayloadSupport then
                if sd_VaranType = 1 then
                  ChangeMovDOLengthOffset(ud_MovDOHandle              := aAdditionalPDOs[i].InputMovHandle$UDINT
                                        , ud_sourceReadDOHandle       := p_PDOInBufferAct^.ud_HandleSourceDO
                                        , ud_SourceReadOffset         := p_PDOInBufferAct^.ud_MoveSourceOffset
                                        , ud_destinationWriteDOHandle := aAdditionalPDOs[i].p_HandlePDOWrite$UDINT
                                        , ud_DestinationWriteOffset   := 0
                                        , ud_lengthmove               := PDOLength);
                else  // VaranDataMover
                  ChangeMovDOLengthOffset(ud_MovDOHandle              := aAdditionalPDOs[i].InputMovHandle$UDINT
                                        , ud_sourceReadDOHandle       := p_PDOInBufferAct^.ud_HandleSourceDO
                                        , ud_SourceReadOffset         := p_PDOInBufferAct^.ud_MoveSourceOffset
                                        , ud_destinationWriteDOHandle := aAdditionalPDOs[i].ud_HandlePDOWriteMoverDO
                                        , ud_DestinationWriteOffset   := 0
                                        , ud_lengthmove               := PDOLength);
                end_if;
                // moving is done every cycle                
                EnableDO(ud_DOHandle := aAdditionalPDOs[i].InputMovHandle$UDINT);
              else
                aAdditionalPDOs[i].InputMovSettings^.ud_AddressDest := aAdditionalPDOs[i].ud_LocalMoveDestAddr;
                aAdditionalPDOs[i].InputMovSettings^.ud_AddressSrc  := p_PDOInBufferAct^.ud_MoveSourceAddr;
                aAdditionalPDOs[i].InputMovSettings^.ui_ByteCnt     := PDOLength;
                
                // moving is done every cycle
                aAdditionalPDOs[i].InputMovHandle^.ucCtrlStat       := VARAN_DO_CONT_RUN;
              end_if;
              
            end_if;
          end_for;
        end_if;
      end_if;
    else
      bd_LogOnceMarker.MoveSourceInvalid := TRUE;
    end_if;
  end_if;

  //increase counter for pointer position for next PDO
  ui_cnt_PDOInBufferAct += 1;

  //if last PDO was read, reset counter for first PDO 
  if ( ui_cnt_PDOInBufferAct = ui_cnt_PDOInputBuffer ) then
    ui_cnt_PDOInBufferAct := 0;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::Varan_CallbackSafe
	VAR_INPUT
		ud_reason 	: UDINT;
	END_VAR
  VAR
		MyPara 	    : CmdStruct;
		MyResult	  : results;
  END_VAR

	//look for reason
	if ( ud_reason = 0 ) then		//connect
    if b_PayloadSupport & (sd_VaranType = 2) then
      if ( AddDO() ) then
		
        return;
      
      end_if;
    end_if;
		//read Kennung
		Kennung := MasterConnect.GetKennung( Place );

    // Only Read Serial No if Kennung was successfully read. Otherwise we get an EPROM Error at the CIV even if the module is not required
    if Kennung & Kennung <> 16#ff then
      GetSerialNo();
    end_if;
     
		//check right module id
	 	if ( Kennung = ud_MyModuleID ) then

      // get variant from eeprom
      us_Variant := 16#FF;
      MasterConnect.I2CReadOneByte( AdressCDIAS := ui_MyPlace + 3
                                  , pData       := #us_Variant
                                  ); 
    
      // check variant
      if CheckVariant(us_Variant) then

        MasterConnect.RdDO(ud_address:=Place*16#100 + OFFSET_FPGA_VERSION, ud_length:=1, p_ud_data:=#FPGA_Version, ud_type:=1);

        // initialize the PLL

        // get our system time
        SystemTime_ms := (MasterConnect.GetPllTime())$USINT;

        // write it in ms to the pll period register
        MasterConnect.WrDO(ud_address:=Place*16#100 + OFFSET_PLL_CONFIG2, ud_length:=1, p_ud_data:=#SystemTime_ms, ud_type:=1);

        // check what module we got for writing the sync offset
        case Kennung of
          CSDI16x_ID: // if there are only inputs
            // sync offset to the beginning of the access on the CDIAS (with the CDIAS sync)
            ui_ActIRQSyncOffset := SYNC_OFFSET_NO_DELAY;
            
          CSTO08x_ID, CSCP01x_ID: // if there are also outputs
            // sync offset right after the access on the CDIAS (about half a cycle later)
            ui_ActIRQSyncOffset := SYNC_OFFSET_DELAY_OUTPUTS;
        end_case;
        
        // write the value to the module
        MasterConnect.WrDO(ud_address:=Place*16#100 + OFFSET_SYNC_IRQ_DELAY, ud_length:=2, p_ud_data:=#ui_ActIRQSyncOffset, ud_type:=1);
        if ( sd_VaranType = 2 & b_PayloadSupport = FALSE ) then

          if ( AddDO() ) then
            
            return;
          
          end_if;
              
        elsif ( sd_VaranType = 1 ) then

          StartRtDOs := 2;

          //start DOs
//          StartDO();
        
        end_if;

        //add module to safety communication task with SDO
        if ( AddModuleToSafetyTask() ) then
          return;
        end_if;
              
        //read own safety number 
        if ( GetSafetyNumber() ) then
          return;
        end_if;

        // initialize of length of PDO to read
        PDOReadLen  := 0;
        PDOWriteLen := 0;
        
        State.uiIO_Flags := 0;
        
        if ClassState = _ModuleNotFound then
          if ModuleSyncNo = 0 then
            ClassState := _SafetyClassOK;
          else
            ClassState := _WaitForSynchronicity;
          end_if;
        end_if;

        // whenever the postinit has passed and we got a connect (module has been plugged in after booting the application) => get it's config
        if b_PostInitPassed = TRUE then
          // start reading the config in background (if we're in init the post-init read-out will be faster)
          
          ClassState            := _ReinitConfig;
          b_GetNewConfiguration := TRUE;
        end_if;

        // if we we're already connected => tell the sdias manager we're back (safetythis has to be valid if b_Reconnect is set, therefore we don't have to check it here)
        if b_Reconnect then
          MyPara.uiCmd    := CMD_SM_MODULE_RECONNECT;
          MyPara.aPara[0] := THIS$DINT;
          pSafetyManagerThis^.NewInst(#MyPara, #MyResult);
        else
            // if first connect, check for the reinit marker
            // send message to safetymanager, so all modules with the reinit marker can be reinitialized
            MyPara.uiCmd    := CMD_SM_MODULE_REINIT;
            MyPara.aPara[0] := THIS$DINT;
            pSafetyManagerThis^.NewInst(#MyPara, #MyResult);

        end_if;
      else

        State.uiIO_Flags                  := 0;
        if ( Kennung = 255 ) then
          State.uiIO_Flags.NoHW           := 1;
        else	
          State.uiIO_Flags.WrongHW        := 1;
        end_if;
        State.uiIO_Flags.PhysicAccessOff  := 1;

      end_if;
      
    else

      State.uiIO_Flags                    := 0;
			if ( Kennung = 255 ) then
				State.uiIO_Flags.NoHW             := 1;
			else	
				State.uiIO_Flags.WrongHW          := 1;
			end_if;
			State.uiIO_Flags.PhysicAccessOff    := 1;

    end_if;

	else  //disconnect

    // reset variables if it's a cpu
    if GetModuleID() = CSCP01x_ID then
    
      // delete request
      LastRequest := _NoOpenRequest;
      ud_AsyComRetryCounter := 0; // reset retry counter

      // remove the cpu from all classes, which use it
      ResetConfig();

      if UnsafeScheduler <> UnsafeSchedulerSetBusReady then
        us_SetBusReadyState := WaitPDOsSyncron;
        UnsafeScheduler := UnsafeSchedulerSetBusReady;
      end_if;

      MaxVarsPerReadPackage   := 0;
      ReadFramesNeeded        := 0;
      MaxVarsPerWritePackage  := 0;
      WriteFramesNeeded       := 0;        
    end_if;

    if ( sd_VaranType = 1 ) then

      //stop DOs
      StopDO();
		
    end_if;
    
    // reset time sync state and tell the manager
    if pSafetyManagerThis then
      MyPara.uiCmd := CMD_SM_MODULE_DISCONNECT;
      MyPara.aPara[0] := THIS$DINT;
      pSafetyManagerThis^.NewInst(#MyPara, #MyResult);
      
      b_Reconnect := TRUE;
    end_if;
    
    b_TimeSyncActive                  := FALSE;
    TimeSyncDOActive.OwnSyncActive    := 0;

    State.uiIO_Flags					        := 0;
		State.uiIO_Flags.NoHW	 			      := 1;		
		State.uiIO_Flags.PhysicAccessOff  := 1;
	
    ClassState := _ModuleNotFound;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyCDIAS_Base::UpDataCY
	VAR_INPUT
		Handle 	: UDINT;
	END_VAR
  VAR
  	p_SDO_act             : ^SDOHeader;
    us_SDO_length         : USINT;
    i                     : UINT;
    p_ReceiveObj          : pVirtualBase;
    p_SDOviaPath          : ^SDOviaPath;
    sd_retval             : DINT;
    IsStandardResp        : BOOL;
		SDORequestBuffer      : SDORequReadConfig;
    DataLen               : USINT;
    us_UnsafeSchedulerRun : USINT;
    p_PDOInBufferAct      : ^PDOInputBuffer;
    EverythingSynchron    : BOOL;
		MyPara 	              : CmdStruct;
		MyResult	            : results;
    UnsafeWrPackageNo     : USINT;
    aUnsafeWrPackages     : UnsafeWritePackages;
    UnsafeRdPackageNo     : USINT;
    aUnsafeRdPackages     : UnsafeReadPackages;
    TmpVal                : DINT;
    AddUnsafePackage      : BOOL;
    GotNewUnsafeValue     : BOOL;
    pHelpUnsafe           : ^UnsafeIORoutingElement;
    BDINTWriteVars        : USINT;
  END_VAR

//============================ Profiler start======================================================
#ifdef  DM_Profiler								
  StartTimeMeasurement(usMode := DMTIME_CY);
#endif	
//============================ Profiler end========================================================

  // do logging if necessary
  if bd_LogOnceMarker <> bd_AlreadyLoggedMarker then
    if bd_LogOnceMarker.MoveSourceInvalid > bd_AlreadyLoggedMarker.MoveSourceInvalid then
      bd_AlreadyLoggedMarker.MoveSourceInvalid := TRUE;
      LogError("@ZZZZ (SafetyCDIAS_Base::WritePDO2Module) [SL] Can't change Move-Command, because the new source address is invalid");
    end_if;

    if bd_LogOnceMarker.TdoLen0 > bd_AlreadyLoggedMarker.TdoLen0 then
      bd_AlreadyLoggedMarker.TdoLen0 := TRUE;
      LogError("@ZZZZ (SafetyCDIAS_Base::UpDateRT) [SL] Found TDOFrame with Length = 0");
    end_if;

    if bd_LogOnceMarker.TdoLenInvalid > bd_AlreadyLoggedMarker.TdoLenInvalid then
      bd_AlreadyLoggedMarker.TdoLenInvalid := TRUE;
      LogError("@ZZZZ (SafetyCDIAS_Base::UpDateRT) [SL] Found TDOFrame with invalid Length value inside (must be 20)");
    end_if;
  end_if;


  // do sdo communication only, if module has been found and initialized correctly and if there are some LEDs on (else a FW-Update is running)
  if ( State.uiIO_Flags = 0 ) & (VoltageOK | RunState | ServiceMode | Error) &
     (( ClassState = _SafetyClassOK ) | ( ClassState = _WaitForSynchronicity ) | ( ClassState = _ReinitConfig ) | ( ClassState = _ModFromCfgNotFound ) | ( ClassState = _UnknownCfgError ) | ( ClassState = _UnsafeVarNotFound )) then

    // wait until the safetymanager has initialized connection
    if b_ManagerReadyForSDO = FALSE then
      return;
    end_if;

    //Update of service messages doesn't take place in realtime

    // if we have to quit the communication errors and there is no other request open at this time
    if (QuitComError = 1) & (LastRequest = _NoOpenRequest) then
      if UnsafeScheduler <> UnsafeSchedulerSetBusReady then
        us_SetBusReadyState := WaitPDOsSyncron; 
        UnsafeScheduler     := UnsafeSchedulerSetBusReady;  
      end_if;
      
      QuitComError := 0;
    end_if;

    //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)
      To_StdLib.MemCpy(dest := p_SDOOutputBuffer, source := #p_Handle_SDO_Read^.SDOStructure, size := us_SDO_length );

#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
  RecordFrame(p_SDOOutputBuffer$^DINT, 0);
#endif

      //mark data as received
      p_Handle_SDO_Read^.us_Status := SAFETY_SDO_NO_DATA;
    
      //find target object for routing
      p_ReceiveObj    := NIL;

      IsStandardResp  := FALSE;
      //check, if receiver is addressed by safety number or hardware path
      if ( (p_SDOOutputBuffer^.SDOHeader.StdHeader.Typ AND SSDO_MASK_TYPE) = FRM_TYPECODE_SSDO_MOD ) then
      
        //search this-pointer of receiver with safety number
        p_ReceiveObj := ( GetRoutingPointerByNumber(ud_SafeNumber := p_SDOOutputBuffer^.SDOHeader.DstAdr))$pVirtualBase;
        
      elsif ( (p_SDOOutputBuffer^.SDOHeader.StdHeader.Typ AND SSDO_MASK_TYPE) = FRM_TYPECODE_SSDO_MOD_TP ) then

        //search this-pointer of receiver with hardware path
        p_SDOviaPath := p_SDOOutputBuffer$^SDOviaPath;
        p_ReceiveObj := ( GetRoutingPointerByPath(p_ActObjectPath := #p_SDOviaPath^.TopologyPath[0], p_SDOviaPath^.StdHeader.Len - 8))$pVirtualBase;

      elsif ( (p_SDOOutputBuffer^.SDOHeader.StdHeader.Typ AND SSDO_MASK_TYPE) = FRM_TYPECODE_STD ) then
        IsStandardResp    := TRUE;
        StandardResponse  := (p_SDOOutputBuffer$^StandardFrameType)^;
        if StandardResponse.SDOHeader.SeqNr = (StandardSeqNr OR 16#80) then

          case LastRequest of
            _NoOpenRequest: // error, no open request, but we got a response
              LogError("@ZZZZ (SafetyCDIAS_Base::UpDataCY) Standard frame response received, without open request");
            
            _SetBusReady:
              IF StandardResponse.SDOHeader.Cmd = SDO_COMMAND_SET_BUS_READY THEN
                if us_SetBusReadyState <> SendSetBusReady then
                  LogError("@ZZZZ (SafetyCDIAS_Base::UpDataCY) Got Response of SetBusReady, but SSW is not in the right step");
                  return;
                end_if;
                us_SetBusReadyState := SetBusReadyFinished;
                b_ManualQuit    := FALSE;
                UnsafeScheduler := UnsafeSchedulerGetDiagVars; // Go on with the action-steps, done here so we don't lose a whole cycle
                LastRequest     := _NoOpenRequest;
                ud_AsyComRetryCounter := 0; // reset retry counter
                if ClassState = _WaitForSynchronicity then
                  ClassState    := _SafetyClassOK;
                end_if;
              else
                LogError("@ZZZZ (SafetyCDIAS_Base::UpDataCY) Invalid command: bus ready expected");  
              END_IF;
            
            _ReadData:
              // if we did read command, then save the value to corresponding server
              if StandardResponse.SDOHeader.Cmd = SDO_COMMAND_READ then
                // if returncode is 0 read succeeded
                if StandardResponse.aData[0] = 0 then
                  // check if length is correct
                  if StandardResponse.aData[1] = StandardRequest.aData[4] then
                    // delete request
                    LastRequest := _NoOpenRequest;
                    ud_AsyComRetryCounter := 0; // reset retry counter

                    if (DiagVars.SavingLogSSW = GetLogFileBlocks) then
                      // save the last block in the memory for the file
                      _memcpy(ptr1:=DiagVars.pLogFileMem$pVoid + (DiagVars.LogHeader.LogMemSize - DiagVars.LogMemToGet), 
                              ptr2:=#StandardResponse.aData[2], 
                              cntr:=DiagVars.BytesToGet);

                      DiagVars.LogMemToGet -= DiagVars.BytesToGet;
                      
                      if DiagVars.LogMemToGet = 0 then
                        DiagVars.SavingLogSSW := GetLogHeader2;
                      end_if;
                    else
                      LogError("@ZZZZ (SafetyCDIAS_Base::UpDataCY) SDO Receive: Invalid Read response (no diagnostic read active)");
                    end_if;
                  end_if;
                end_if;
              else
                LogError("@ZZZZ (SafetyCDIAS_Base::UpDataCY) SDO Receive: Invalid command, read expected");              
              end_if;

            _ReadValues:
              // if we did read command, then save the value to corresponding server
              if StandardResponse.SDOHeader.Cmd = SDO_COMMAND_READ_VALUES then
                // if returncode is 0 read succeeded
                if StandardResponse.aData[0] = 0 then
                  // check if length is correct
                  if StandardResponse.aData[1] = StandardRequest.aData[0] then
                    // delete request
                    LastRequest := _NoOpenRequest;
                    ud_AsyComRetryCounter := 0; // reset retry counter

                    // if we got some outputs in the routing table and a valid pointer, write values to servers
                    if ui_CntUnsafeOutputs & pUnsafeOutElement then
                      
                      // depending on length we do different number of server write-methods to set the data we just read
//                      pUnsafeOutElement := p_UnsafeOutputsTable + (UnsafeReadTransNr * MaxVarsPerReadPackage * sizeof(UnsafeIORoutingElement));  // the pointer is already on this element
                      for i := 0 to (StandardResponse.aData[1] - 1) do
                        // save the new value temporarily
                        TmpVal := StandardResponse.aData[2 + (i * sizeof(DINT))]$DINT;
                        if pUnsafeOutElement^.ud_Thisp then
                          if pUnsafeOutElement^.UnsafeType = BDINTOutput then
                            pUnsafeOutElement^.sd_OldValue := RD(pUnsafeOutElement^.ud_Thisp$^void)$DINT;
                            TmpVal := ((pUnsafeOutElement^.sd_OldValue$UDINT AND (NOT pUnsafeOutElement^.BitMask)) OR
                                      (TmpVal$UDINT AND pUnsafeOutElement^.BitMask))$DINT;
                            
                            // now we have to write the value to the server
                            WR(pUnsafeOutElement^.ud_Thisp$^void, TmpVal);              
                          else
                            WR(pUnsafeOutElement^.ud_Thisp$^void, TmpVal);                              
                          end_if;
                        elsif (pUnsafeOutElement^.UnsafeType = ExternalOutput) | (pUnsafeOutElement^.UnsafeType = ExternalBDINTOutput) then
                          pUnsafeOutElement^.sd_NewValue4External := TmpVal;
                          
                          // mark the value as valid
                          pUnsafeOutElement^.b_IsValid := TRUE;
                        end_if;
                        pUnsafeOutElement += sizeof(UnsafeIORoutingElement);
                      end_for;
                    end_if;
                  
                    UnsafeReadTransNr += 1;
                  end_if;
                end_if;
              else
                LogError("@ZZZZ (SafetyCDIAS_Base::UpDataCY) SDO Receive: Invalid command, read values expected");              
              end_if;
            
            _WriteValues:
              if IsOptimizedCPU() then
                // if we did a write command, just check 
                if StandardResponse.SDOHeader.Cmd = SDO_COMMAND_WRITE_VALUES then
                  // delete request
                  LastRequest := _NoOpenRequest;
                  ud_AsyComRetryCounter := 0; // reset retry counter

                  // if there is no more element to send or check for changes => proceed to the next step
                  if pUnsafeInElement = NIL then
                    UnsafeScheduler := UnsafeSchedulerReadData; //We need to set scheduler to next step....
                  end_if;                
                else
                  LogError("@ZZZZ (SafetyCDIAS_Base::UpDataCY) SDO Receive: Invalid command, write expected");          
                end_if;
              else
                // on CSCP011 the SDO_COMMAND_WRITE_VALUES didn't exist
                
                // if we did a write command, just check 
                if StandardResponse.SDOHeader.Cmd = SDO_COMMAND_WRITE then
                  // delete request
                  LastRequest           := _NoOpenRequest;
                  ud_AsyComRetryCounter := 0; // reset retry counter

                  if UnsafeWriteTransNr < (WriteFramesNeeded - 1) then
                    UnsafeWriteTransNr  += 1;
                  else
                    UnsafeWriteTransNr  := 0;
                    UnsafeWritingActive := FALSE;
                    UnsafeScheduler     := UnsafeSchedulerReadData; //We need to set scheduler to next step....
                  end_if;
                else
                  LogError("@ZZZZ (SafetyCDIAS_Base::UpDataCY) SDO Receive: Invalid command, write expected");          
                end_if;
              end_if;


            _GetCRC:
              // check if it's a response to a read command
              if StandardResponse.SDOHeader.Cmd = SDO_COMMAND_READ then
                // if returncode is 0 read succeeded
                if StandardResponse.aData[0] = 0 then
                  // check if length is correct
                  if StandardResponse.aData[1] = 4 then
                  
                    // delete request
                    LastRequest := _NoOpenRequest;
                    ud_AsyComRetryCounter := 0; // reset retry counter

                    if ud_ConfigCRC <> StandardResponse.aData[2]$UDINT then
                      // CRC has changed => save the new crc
                      ud_ConfigCRC          := StandardResponse.aData[2]$UDINT;
                      //Show CRC on Server
                      DesignerPrjConfigCRC  := ud_ConfigCRC;
                      
                      // show that we read the config of the class again
                      ClassState            := _ReinitConfig;

                      if pSafetyManagerThis then
                        MyPara.uiCmd    := CMD_SM_NEW_SAFETY_PROJECT;
                        MyPara.aPara[0] := 4;
                        MyPara.aPara[4] := (#SafetyNumber)$DINT;
                        pSafetyManagerThis^.NewInst(#MyPara, #MyResult);    
                      end_if;

                      // remove the cpu from all classes, which use it
                      ResetConfig();
                      
                      // we have to return here because:
                      // the command CMD_SM_NEW_SAFETY_PROJECT will trigger a disconnect of this class which will set the unsafe scheduler to setbusready, 
                      // which would skip the synchron check in the actual cyclic run because everything of the old configuration is synchron now
                      return;
                    end_if;
                  end_if;
                end_if;
              end_if;
                
            _DiagState:
              if StandardResponse.SDOHeader.Cmd = SDO_COMMAND_GET_STATE then
                _memcpy(ptr1 := #DiagVars.UserGetStateResp, 
                        ptr2 := #StandardResponse.aData + SIZEOF(USINT), 
                        cntr := sizeof(GetStateResponseType) );
                DiagVars.UserDiagStateReady := TRUE;
                DiagVars.UserWantsDiagState := FALSE;
                LastRequest                 := _NoOpenRequest;
                ud_AsyComRetryCounter       := 0; // reset retry counter
              end_if;
            _DiagInfo:
              if StandardResponse.SDOHeader.Cmd = SDO_COMMAND_GET_DIAG_INFO then
                _memcpy(ptr1 := #DiagVars.UserGetDiagInfoResp, 
                        ptr2 := #StandardResponse.aData + SIZEOF(USINT), 
                        cntr := sizeof(SafetyDiagInfo) );
                DiagVars.UserDiagInfoReady  := TRUE;
                DiagVars.UserWantsDiagInfo  := FALSE;
                LastRequest                 := _NoOpenRequest;
                ud_AsyComRetryCounter       := 0; // reset retry counter
              end_if;
            
            _ErrorChannelInfo:
            //if we did read command, then save the value to corresponding server
              if StandardResponse.SDOHeader.Cmd = SDO_COMMAND_READ then
                // if returncode is 0 read succeeded
                if StandardResponse.aData[0] = 0 then
                  // check if length is correct
                  if StandardResponse.aData[1] <> 0  then                  
                    _memcpy(ptr1 := #aErrorMem[actoffset], 
                            ptr2 := #StandardResponse.aData[2], 
                            cntr := StandardResponse.aData[1]);
                    if remainingPacketlength = 0 then
                      remainingPacketlength := StandardResponse.aData[2] - StandardResponse.aData[1];
                      actoffset := StandardResponse.aData[1];
                    else
                      remainingPacketlength -= StandardResponse.aData[1];
                      actoffset += StandardResponse.aData[1];
                    end_if; 
                    
                    // delete request
                    LastRequest := _NoOpenRequest;
                    if remainingPacketlength <= 0  then
                      //Finish reset variables
                      DiagVars.UserErrorInfoReady := TRUE;
                      DiagVars.UserWantsErrorInfo := FALSE;
                      ud_AsyComRetryCounter := 0; // reset retry counter   
                      remainingPacketlength := 0; //reset remainingPacketlength
                      actoffset := 0; //reset offset
                    end_if;                                          
                  end_if;                
                end_if;            
              end_if;  
          else
            LogError("@ZZZZ (SafetyCDIAS_Base::UpDataCY) SDO Receive: Invalid standard frame response");
          end_case;

          // 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("@ZZZZ (SafetyCDIAS_Base::UpDataCY) SDO Receive: Invalid sequence number in Standard SDO response");
          LogValue("expected: {0} / received: {1}", Value:=(StandardSeqNr OR 16#80), Value2:=StandardResponse.SDOHeader.SeqNr);
        end_if;
      else
        LogError("@ZZZZ (SafetyCDIAS_Base::UpDataCY) SDO Receive: Invalid frametype in Standard SDO response");
      end_if;

      // dont let the CDIAS-modules start before the master-slave configuation has finished (don´t forward the GetState to itself)
      if (p_ReceiveObj = this) & (b_ManagerInitialisationFinished = FALSE) then
        case ud_MyModuleID of
          CSCP01x_ID,
          CSDI16x_ID,
          CSTO08x_ID:
            // set some flags to ignore the SDO
            p_ReceiveObj    := NIL;
            IsStandardResp  := TRUE;
        end_case;
      end_if;

      //if there is no object, the message will be lost
      if ( p_ReceiveObj ) then
      
        //send SDO to receiver object
        MyPara.uiCmd    := CMD_SM_ADD_SDO_TO_BUFFER;
        MyPara.aPara[0] := p_SDOOutputBuffer$DINT;
        MyPara.aPara[1] := us_SDO_length;
        sd_retval$iprStates := p_ReceiveObj^.NewInst(#MyPara, #MyResult);    

//        sd_retval := p_ReceiveObj^.AddSDOToBuffer(p_us_Message := p_SDOOutputBuffer$^USINT, us_length := us_SDO_length);
        
        if sd_retval then         
          // generate error message with returncode (add to logfile and debugger trace)
          LogValue("@ZZZZ (SafetyCDIAS_Base::UpDataCY) AddSDOToBuffer failed: Returncode: -0x{0}", Value:=(0-sd_retval)$UDINT);
        end_if;
      
      elsif IsStandardResp = FALSE then

        if pSafetyManagerThis & us_SDO_length then
#ifdef DO_DEBUG
          DOCheck(pFrame:=(p_SDOOutputBuffer)$^SDOStdHeader, pCheckStruct:=#SDORead);
#endif

          MyPara.uiCmd    := CMD_SM_SDO_TO_MANAGER;
          MyPara.aPara[0] := to_dint(us_SDO_length);
          MyPara.aPara[1] := p_SDOOutputBuffer$DINT;
          pSafetyManagerThis^.NewInst(#MyPara, #MyResult);    
        else
          //log not routable SDOs
          LogValue("@ZZZZ (SafetyCDIAS_Base::UpDataCY) Safety module {0}: SDO not routed to receiver {1}", SafetyNumber$UDINT, p_SDOOutputBuffer^.SDOHeader.DstAdr$UDINT);
        end_if;
      end_if;

    elsif (LastRequest <> _NoOpenRequest) & (ud_TransfertimePerPackage > 0) then
      // count up for timeout
      ud_UnsafeTimeoutCounter += 1;
            
      if ( ud_UnsafeTimeoutCounter ) > ( 50 * ud_TransfertimePerPackage ) then
        CASE UnsafeScheduler OF

          UnsafeSchedulerSetBusReady:
            LogError("@ZZZZ (SafetyCDIAS_Base::UpdateCy) Timeout on setting bus ready");

          UnsafeSchedulerGetDiagVars:
            IF LastRequest = _ReadData THEN
              LogError("@ZZZZ (SafetyCDIAS_Base::UpdateCy) Timeout requesting DiagVars");
            END_IF;
            UnsafeScheduler       := UnsafeSchedulerGetCRC;
            DiagVars.SavingLogSSW := GetLogFileBlocks;
            
          UnsafeSchedulerGetCRC:
            LogError("@ZZZZ (SafetyCDIAS_Base::UpdateCy) Timeout requesting CRC");
            UnsafeScheduler       := UnsafeSchedulerWriteData;
            
          UnsafeSchedulerWriteData:
            LogError("@ZZZZ (SafetyCDIAS_Base::UpdateCy) Timeout writing Data 'Unsafe Input'");
            UnsafeScheduler       := UnsafeSchedulerReadData;
            UnsafeWriteTransNr    := 0;
            
          UnsafeSchedulerReadData:
            LogError("@ZZZZ (SafetyCDIAS_Base::UpdateCy) Timeout reading Data 'Unsafe Output'");
            UnsafeScheduler       := UnsafeSchedulerDiagState;
            UnsafeReadTransNr     := 0;
            
          UnsafeSchedulerDiagState:
            LogError("@ZZZZ (SafetyCDIAS_Base::UpdateCy) Timeout on reading DiagState");
            UnsafeScheduler       := UnsafeSchedulerDiagInfo;
            
          UnsafeSchedulerDiagInfo:
            LogError("@ZZZZ (SafetyCDIAS_Base::UpdateCy) Timeout on reading DiagInfo");
            UnsafeScheduler       := UnsafeSchedulerChannelError;
            
          UnsafeSchedulerChannelError:
            LogError("@ZZZZ (SafetyCDIAS_Base::UpdateCy) Timeout on reading ChannelError");
            UnsafeScheduler       := UnsafeSchedulerGetDiagVars;
          
          
        END_CASE;
        
        // we only increase the retry counter if the module is running
        if RunState then
          ud_AsyComRetryCounter += 1;        
        end_if;

        if ud_AsyComRetryCounter >= SDO_MAX_TRIES then
          ClassState := _AsyncComError;
          LogError("@ZZZZ (SafetyCDIAS_Base::UpdateCy) Too many consecutive asynchronous commands failed! Please contact Sigmatek Support!");
        else
          LastRequest := _NoOpenRequest;
          // if request is deleted, increase sequence number to set next request
          if StandardSeqNr < 16#7F then
            StandardSeqNr += 1;
          else
            StandardSeqNr := 0;
          end_if;
        end_if;
      end_if;
       
    end_if;

    //write to hardware from other module received SDO
    if ( ui_cnt_SDOInputBuffer > 0 ) & p_SDOInputBuffer then
      
      //set pointer to first SDO in the SDO list
      p_SDO_act     := p_SDOInputBuffer$^SDOHeader;
          
      //calculate length of SDO (CRC + data length)
      us_SDO_length := sizeof (SDOHeader.StdHeader.CRC) + p_SDO_act^.StdHeader.Len;
          
      //check, if buffer is empty
      if ( p_Handle_SDO_Write^.us_Status = SAFETY_SDO_NO_DATA ) then
      
#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
  RecordFrame(p_SDO_act$^DINT, 1);
#endif

        //copy SDO into write-buffer
        To_StdLib.MemCpy(dest := #p_Handle_SDO_Write^.SDOStructure, source := p_SDO_act, size := us_SDO_length);
        
        //mark SDO data as valid
        p_Handle_SDO_Write^.us_Status := SAFETY_SDO_DATA_VALID;
                   
        //decrement amount of SDOs 
        ui_cnt_SDOInputBuffer -= 1;
          
        //if there is at least 1 SDO left, copy the remaining memory over the actual SDO
        if ( ui_cnt_SDOInputBuffer > 0 ) then
                   
          //remove first entry in the SDO list
          _memmove(p_SDOInputBuffer, (p_SDOInputBuffer + SDO_MAX_LENGTH), (ui_cnt_SDOInputBuffer * SDO_MAX_LENGTH));
        end_if;
      end_if;
    end_if;

    // Start of scheduler; we need to share the time between reading, writing and diagnosis
    us_UnsafeSchedulerRun := 0;

    if ( ClassState <> _ReinitConfig ) & ( p_Handle_SDO_Write^.us_Status = SAFETY_SDO_NO_DATA ) then

      // Check actions until we find somthing we need to do
      // all 6 action-steps must be walked through during one cycle to make sure new data is fetched as fast as possible
      // SetBusReady is an exception: this step is only performed once on bootup!
      while (us_UnsafeSchedulerRun < 6) & (LastRequest = _NoOpenRequest) do
        us_UnsafeSchedulerRun   += 1;
        ud_UnsafeTimeoutCounter := 0; //No active request: we can reset the timeout-counter
        case UnsafeScheduler of

       (* ***************************************** *)
          UnsafeSchedulerSetBusReady:
       (* ***************************************** *)
       
          //Set Bus Ready has to be done one time after the manager initialisation was finished
          //Other steps of the scheduler can be executed before the manager initialisation is finished (diag steps)
          if b_ManagerInitialisationFinished = TRUE then
       
            case us_SetBusReadyState of
            
            //-------------------------------------------------------------------------------------------------------------
              WaitPDOsSyncron: 
              
                EverythingSynchron := TRUE;
                
                // it's possible that all PDOs are coming from a different domain, then we have no inputbuffer
                if ui_cnt_PDOInputBuffer then
                  p_PDOInBufferAct := #aPDOInputBuffer[0];
                  for i := 0 to (ui_cnt_PDOInputBuffer-1) do
                    if p_PDOInBufferAct^.b_TimeSynchron = FALSE then
                      // we're still not synchron with this module. if it's optional it is probably not connected
                      if p_PDOInBufferAct^.b_IsOptional then
                        if (ops.tAbsolute - ud_OptionalTimeoutStart) <= OPTIONAL_MODULE_SYNC_TIMEOUT then
                          // if timeout not exceeded => not sychron (otherwise the variable will stay on it's old value)
                          EverythingSynchron  := FALSE;
                          exit;
                        else
                          TRACE("Synchronisation timeout for optional module exceeded => assume it's synchon");
                        end_if;
                      else
                        EverythingSynchron    := FALSE;
                        exit;
                      end_if;
                    end_if;
                  
                    p_PDOInBufferAct +=  sizeof(PDOInputBuffer);
                  end_for;              
                  
                  if EverythingSynchron & (ModuleSyncNo > 0) then
                    ModuleSyncNo -= 1;

  #ifdef SAFETY_DEBUG_LOGGING_ACTIVATED
  //                  case ud_MyModuleID of
  //                    CSCP01x_ID:
  //                      TRACE("ModuleSyncNo wurde dekrementiert von: CSCP");
  //                      
  //                    CSDI16x_ID:
  //                      TRACE("ModuleSyncNo wurde dekrementiert von: CSDI");
  //                      
  //                    CSTO08x_ID:
  //                      TRACE("ModuleSyncNo wurde dekrementiert von: CSTO");
  //                  end_case;
  #endif
                  end_if;
  #ifdef SAFETY_DEBUG_LOGGING_ACTIVATED
  //              elsif EverythingSynchron then
  //                  case ud_MyModuleID of
  //                    CSCP01x_ID:
  //                      TRACE("ModuleSyncNo wurde nicht verändert von: CSCP");
  //                      
  //                    CSDI16x_ID:
  //                      TRACE("ModuleSyncNo wurde nicht verändert von: CSDI");
  //                      
  //                    CSTO08x_ID:
  //                      TRACE("ModuleSyncNo wurde nicht verändert von: CSTO");
  //                  end_case;
  #endif
                end_if;
                
                if EverythingSynchron then
                  us_SetBusReadyState := WaitAllModulesSyncron;
                end_if;

            //-------------------------------------------------------------------------------------------------------------
              WaitAllModulesSyncron:              
                // wait for other modules to be synchron with each other
                if (ModuleSyncNo = 0) & b_ManagerInitialisationFinished then
                  us_SetBusReadyState := SendSetBusReady;              
                end_if;
              
            //-------------------------------------------------------------------------------------------------------------
              SendSetBusReady:              
                // send the bus-ready command
                SDORequestBuffer.StdHeader.CRC  := 0;                                                   // CRC is always 0 in Std communication
                SDORequestBuffer.StdHeader.Cmd  := SDO_COMMAND_SET_BUS_READY;                           // set bus ready command
                SDORequestBuffer.StdHeader.Typ  := FRM_TYPECODE_STD;                                    // standard frame type
                SDORequestBuffer.StdHeader.SeqNr:= StandardSeqNr OR 16#80;                              // sequence number
                SDORequestBuffer.StdHeader.Len  := 4;                                                   // header
            
                LastRequest := _SetBusReady;

  #ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
    RecordFrame((#SDORequestBuffer)$^DINT, 1);
  #endif

                //copy SDO into write-buffer
                To_StdLib.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;
                
            //-------------------------------------------------------------------------------------------------------------
              SetBusReadyFinished:
                // all ok, nothing to do here
                
            end_case;
            us_UnsafeSchedulerRun := 16#FF; //make sure we don't repeat the while-loop until we have sent the bus-ready command

          else
            UnsafeScheduler := UnsafeSchedulerGetDiagVars;  //go on with next step
          end_if;


       (* ***************************************** *)
          UnsafeSchedulerGetDiagVars:
       (* ***************************************** *)

          //check, if buffer is empty and we got some unsafe data to get/set and crc check is finished
          if (DiagVars.SavingLogSSW = GetLogFileBlocks) then

            // check if more than blocksize to get
            if DiagVars.LogMemToGet > LOG_DATA_BLOCK_SIZE then
              // get a complete block
              DiagVars.BytesToGet := LOG_DATA_BLOCK_SIZE;
            else
              // get only the last bytes
              DiagVars.BytesToGet := DiagVars.LogMemToGet$USINT;
            end_if;

            StandardRequest.SDOHeader.Cmd   := SDO_COMMAND_READ;                            // read command
            StandardRequest.SDOHeader.Typ   := FRM_TYPECODE_STD;                            // standard frame type
            StandardRequest.SDOHeader.SeqNr := StandardSeqNr OR 16#80;                      // sequence number is in special area
            StandardRequest.SDOHeader.Len   := 4 + 4 + 1;                                   // header + destination address + length of data
            StandardRequest.aData[0]$UDINT  := DiagVars.ReadBaseAdr + (DiagVars.LogHeader.LogMemSize - DiagVars.LogMemToGet);// destination address
            StandardRequest.aData[4]        := DiagVars.BytesToGet$USINT;                   // length of data
                  
            LastRequest := _ReadData;

#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
  RecordFrame((#StandardRequest)$^DINT, 1);
#endif

            //copy SDO into write-buffer
            To_StdLib.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;
          else
            UnsafeScheduler := UnsafeSchedulerGetCRC;
          end_if;

          
       (* ***************************************** *)
          UnsafeSchedulerGetCRC:
       (* ***************************************** *)
          
          // every 5 secs check for a new safety project inside the cpu 
          if b_CheckCRC & ((ops.tAbsolute - ud_LastCrcCheck) > CRC_CHECK_TIME ) then

            SDORequestBuffer.StdHeader.CRC  := 0;                                                   // CRC is always 0 in Std communication
            SDORequestBuffer.StdHeader.Cmd  := SDO_COMMAND_READ;                                    // read command
            SDORequestBuffer.StdHeader.Typ  := FRM_TYPECODE_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     := SDO_ADDRESS_CONFIG_DATA + SDO_OFFSET_CONFIG_CRC_ALL; // address of crc
            SDORequestBuffer.us_Length      := 4;                                                   // length of crc

            LastRequest := _GetCRC;

#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
  RecordFrame((#SDORequestBuffer)$^DINT, 1);
#endif

            //copy SDO into write-buffer
            To_StdLib.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;

            ud_LastCrcCheck := ops.tAbsolute;
          else
            if RunState & us_SetBusReadyState = SetBusReadyFinished then
              // in operational (and SetbusReady is finished) also get unsafe-variables
              UnsafeScheduler := UnsafeSchedulerWriteData;
            else
              // not operational, we must skip the unsave vars
              UnsafeScheduler := UnsafeSchedulerDiagState;
              us_UnsafeSchedulerRun += 2;
            end_if;
          end_if;

       (* ***************************************** *)
          UnsafeSchedulerWriteData:
       (* ***************************************** *)

          if IsOptimizedCPU() then
            if ui_CntUnsafeInputs then
              // if we have finished checking through all variables the last time => check from beginning (otherwise the pointer is on the element where we have to continue)
              if pUnsafeInElement = NIL then
                pUnsafeInElement := p_UnsafeInputsTable;
              end_if;
              
              // we check if we have to write any of the unsafe input variables (only until our message is full)
              UnsafeWrPackageNo := 0;
              BDINTWriteVars    := 0; // limit number of bdint write variables to 3 to ensure constant load of firmware
              while pUnsafeInElement & (UnsafeWrPackageNo < MAX_UNSAFE_WRITE_PACKAGES) & (BDINTWriteVars < MAX_UNSAFE_BDINTS_PER_WRITE) do

                // we have to check if we add this one
                GotNewUnsafeValue := FALSE;

                // if the type is normal we can read the actual value from the server
                if pUnsafeInElement^.UnsafeType = NormalUnsafe then
                  // check if pointer to server is valid
                  if pUnsafeInElement^.ud_Thisp then
                    // get the actual value from the server
                    TmpVal := RD((pUnsafeInElement^.ud_Thisp)$^void);

                    // we remember to update this if it's necessary
                    GotNewUnsafeValue := TRUE;                 
                  else
                    if bd_LogOnceMarker.NoThisForUnsafeIn = FALSE then
                      bd_LogOnceMarker.NoThisForUnsafeIn        := TRUE;
                      bd_AlreadyLoggedMarker.NoThisForUnsafeIn  := TRUE;
                      LogError("@ZZZZ (SafetyCDIAS_Base::UpdateCy) [SL] No thispointer available for Server of local unsafe input variable");
                    end_if;
                  end_if;
                elsif pUnsafeInElement^.UnsafeType = ExternalInput then
                  // check if we already have a valid value there
                  if pUnsafeInElement^.b_IsValid then
                    // get the actual value from the element
                    TmpVal := pUnsafeInElement^.sd_NewValue4External;
                    
                    // we remember to update this if it's necessary
                    GotNewUnsafeValue := TRUE;
                  end_if;
                else
                  if bd_LogOnceMarker.WrongUnsafeVarType = FALSE then
                    bd_LogOnceMarker.WrongUnsafeVarType       := TRUE;
                    bd_AlreadyLoggedMarker.WrongUnsafeVarType := TRUE;
                    LogError("@ZZZZ (SafetyCDIAS_Base::UpdateCy) [SL] Wrong unsafe variable type in unsafe input list");              
                  end_if;
                end_if;
                
                // if we have a new valid unsafe value => check if we have to send it
                if GotNewUnsafeValue then
                  // if it hasn't been sent yet
                  if (pUnsafeInElement^.b_AlreadyTransmitted = FALSE) then
                    // remember that we sent this already
                    pUnsafeInElement^.b_AlreadyTransmitted := TRUE;
                    
                    // add this one
                    AddUnsafePackage := TRUE;
                  elsif TmpVal <> pUnsafeInElement^.sd_OldValue then
                    // if there were any changes on this value
                    
                    // add this one
                    AddUnsafePackage := TRUE;                
                  else
                    // don't add this one
                    AddUnsafePackage := FALSE;
                  end_if;                  

                  // if it is ready to be added => add it to send buffer
                  if AddUnsafePackage then
                    // add a package to send
                    aUnsafeWrPackages[UnsafeWrPackageNo].ud_Address := pUnsafeInElement^.ud_Address;
                    aUnsafeWrPackages[UnsafeWrPackageNo].Value      := TmpVal;
                    UnsafeWrPackageNo += 1;

                    // if it has a bitmask it's an unsafe bdint input variable
                    if pUnsafeInElement^.BitMask then
                      BDINTWriteVars += 1;
                    end_if;

                    // remember the actual as old value
                    pUnsafeInElement^.sd_OldValue := TmpVal;
                  end_if;
                end_if;

                pUnsafeInElement := pUnsafeInElement^.pNext;
              end_while;

              if UnsafeWrPackageNo then
                DataLen := UnsafeWrPackageNo * sizeof(UnsafeWritePackage);
              
                StandardRequest.SDOHeader.Cmd                 := SDO_COMMAND_WRITE_VALUES;       // write values command
                StandardRequest.SDOHeader.Typ                 := FRM_TYPECODE_STD;               // standard frame type     
                StandardRequest.SDOHeader.SeqNr               := StandardSeqNr OR 16#80;         // sequence number is in special area
                StandardRequest.SDOHeader.Len                 := 4 + 4 + 1 + DataLen;            // header + destination address + length of data + data
                StandardRequest.aData[0]                      := UnsafeWrPackageNo;              // number of packages
                StandardRequest.aData[1]$UnsafeWritePackages  := aUnsafeWrPackages;              // packages

                LastRequest := _WriteValues;

#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
  RecordFrame((#StandardRequest)$^DINT, 1);
#endif

                //copy SDO into write-buffer
                To_StdLib.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;
              else
                UnsafeScheduler := UnsafeSchedulerReadData;
              end_if;
            else
              UnsafeScheduler   := UnsafeSchedulerReadData;
            end_if;
          else
            // on CSCP011 the SDO_COMMAND_WRITE_VALUES didn't exist
            if ui_CntUnsafeInputs & WriteFramesNeeded then
              // if writing is not active, check if it's necessary to activate it
              if (UnsafeWritingActive = FALSE) then
                pUnsafeInElement := p_UnsafeInputsTable;

                for i := 0 to (ui_CntUnsafeInputs - 1) do
                  if pUnsafeInElement^.ud_Thisp then
                    sd_retval := RD((pUnsafeInElement^.ud_Thisp)$^void);        // data
                    if pUnsafeInElement^.sd_OldValue <> sd_retval then
                      UnsafeWritingActive := TRUE;
                      pUnsafeInElement^.sd_OldValue := sd_retval;
                    end_if;
                  end_if;
                  pUnsafeInElement += sizeof(UnsafeIORoutingElement);
                end_for;
              end_if;

              // check if writing is already active
              if UnsafeWritingActive then
                // pointer to the right unsafe input
                pUnsafeInElement := p_UnsafeInputsTable + (UnsafeWriteTransNr * MaxVarsPerWritePackage * sizeof(UnsafeIORoutingElement));

                // get length of data we write
                if (UnsafeWriteTransNr < (WriteFramesNeeded-1)) | ((ui_CntUnsafeInputs MOD MaxVarsPerWritePackage) = 0) then
                  DataLen := MaxVarsPerWritePackage * sizeof(DINT);
                else
                  DataLen := (ui_CntUnsafeInputs MOD MaxVarsPerWritePackage)$USINT * sizeof(DINT);
                end_if;

                StandardRequest.SDOHeader.Cmd   := SDO_COMMAND_WRITE;                           // write command
                StandardRequest.SDOHeader.Typ   := FRM_TYPECODE_STD;                            // standard frame type     
                StandardRequest.SDOHeader.SeqNr := StandardSeqNr OR 16#80;                      // sequence number is in special area
                StandardRequest.SDOHeader.Len   := 4 + 4 + 1 + DataLen;                         // header + destination address + length of data + data
                StandardRequest.aData[0]$UDINT  := pUnsafeInElement^.ud_Address;                // destination address
                StandardRequest.aData[4]        := DataLen;                                     // length of data
                
                // depending on length we do different number of server read-methods to get the data we write
                for i := 0 to (DataLen/sizeof(DINT)) - 1 do
                  if pUnsafeInElement^.ud_Thisp then
                    StandardRequest.aData[5 + (i * sizeof(DINT))]$DINT := pUnsafeInElement^.sd_OldValue;
                  else
                    // this server doesn't exist in lasal => always send 0
                    StandardRequest.aData[5 + (i * sizeof(DINT))]$DINT := 0;
                  end_if;

                  pUnsafeInElement += sizeof(UnsafeIORoutingElement);
                end_for;

                LastRequest := _WriteValues;

#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
  RecordFrame((#StandardRequest)$^DINT, 1);
#endif

                //copy SDO into write-buffer
                To_StdLib.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;
              else
                UnsafeScheduler := UnsafeSchedulerReadData;
              end_if;      
            else
              UnsafeScheduler   := UnsafeSchedulerReadData;
            end_if;
          end_if;

       (* ***************************************** *)
          UnsafeSchedulerReadData:
       (* ***************************************** *)
          if ui_CntUnsafeOutputs & ReadFramesNeeded then
            //check, if buffer is empty and we got some unsafe data to get/set and crc check is finished
            if (UnsafeReadTransNr < ReadFramesNeeded) //then
             & ( ((UnsafeReadTransNr = 0) & ( ops.tAbsolute - LastUnsafeUpdate > ud_ServerUpdateTime ) ) | (UnsafeReadTransNr <> 0) )then
              // here we request directly the unsafe IOs
              
              // sequence number is in special area
              StandardRequest.SDOHeader.SeqNr := StandardSeqNr OR 16#80;
              
              // we get an output
              pUnsafeOutElement := p_UnsafeOutputsTable + (UnsafeReadTransNr * MaxVarsPerReadPackage * sizeof(UnsafeIORoutingElement));
              
              // get length of data we read
              if (UnsafeReadTransNr < (ReadFramesNeeded - 1)) | ((ui_CntUnsafeOutputs MOD MaxVarsPerReadPackage) = 0) then
                UnsafeRdPackageNo := MaxVarsPerReadPackage;
              else
                UnsafeRdPackageNo := (ui_CntUnsafeOutputs MOD MaxVarsPerReadPackage)$USINT;
              end_if;
              
              DataLen := UnsafeRdPackageNo * sizeof(DINT);

              // create buffer with addresses of values to read
              pHelpUnsafe := pUnsafeOutElement;
              for i := 0 to (UnsafeRdPackageNo-1) do
                aUnsafeRdPackages[i] := pHelpUnsafe^.ud_Address;
                pHelpUnsafe += sizeof(UnsafeIORoutingElement);
              end_for;

              StandardRequest.SDOHeader.Cmd               := SDO_COMMAND_READ_VALUES;                     // read values command
              StandardRequest.SDOHeader.Typ               := FRM_TYPECODE_STD;                            // standard frame type
              StandardRequest.SDOHeader.SeqNr             := StandardSeqNr OR 16#80;                      // sequence number is in special area
              StandardRequest.SDOHeader.Len               := 4 + 1 + DataLen;                             // header + size + length of data
              StandardRequest.aData[0]                    := UnsafeRdPackageNo;                           // number of values to get
              StandardRequest.aData[1]$UnsafeReadPackages := aUnsafeRdPackages;                           // read addresses
                    
              LastRequest := _ReadValues;

#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
  RecordFrame((#StandardRequest)$^DINT, 1);
#endif

              //copy SDO into write-buffer
              To_StdLib.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;

            elsif (UnsafeReadTransNr >= ReadFramesNeeded) then
              // We have finished all read data, go on with the next step
              UnsafeScheduler := UnsafeSchedulerDiagState;
              LastUnsafeUpdate := ops.tAbsolute;
              UnsafeReadTransNr := 0;
            else
              // time until read is not yet over - go on
              UnsafeScheduler := UnsafeSchedulerDiagState;
            end_if;
          else
            UnsafeScheduler   := UnsafeSchedulerDiagState;
          end_if;

       (* ***************************************** *)
          UnsafeSchedulerDiagState:
       (* ***************************************** *)
          // get the diag state (on user demand)
          if DiagVars.UserWantsDiagState then
            
            // get state via SDO communication                                  
            SDORequestBuffer.StdHeader.CRC  := 0;                                                   // CRC is always 0 in Std communication
            SDORequestBuffer.StdHeader.Cmd  := SDO_COMMAND_GET_STATE;                               // get-state command
            SDORequestBuffer.StdHeader.Typ  := FRM_TYPECODE_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;

#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
  RecordFrame((#SDORequestBuffer)$^DINT, 1);
#endif

            //copy SDO into write-buffer
            To_StdLib.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;
          else
            UnsafeScheduler := UnsafeSchedulerDiagInfo;
          end_if;

       (* ***************************************** *)
          UnsafeSchedulerDiagInfo:
       (* ***************************************** *)
       
          // get the diag info (on user demand)
          if DiagVars.UserWantsDiagInfo then
            
            // get state via SDO communication                               
            StandardRequest.SDOHeader.CRC   := 0;                                                   // CRC is always 0 in Std communication
            StandardRequest.SDOHeader.Cmd   := SDO_COMMAND_GET_DIAG_INFO;                           // read command
            StandardRequest.SDOHeader.Typ   := FRM_TYPECODE_STD;                                    // standard frame type
            StandardRequest.SDOHeader.SeqNr := StandardSeqNr OR 16#80;                              // sequence number
            StandardRequest.SDOHeader.Len   := 4 + 1;                                               // header + µC-selection
            StandardRequest.aData[0]        := DiagVars.ucChoiceDiagInfo;

            LastRequest := _DiagInfo;

#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
  RecordFrame((#StandardRequest)$^DINT, 1);
#endif

            //copy SDO into write-buffer
            To_StdLib.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;
            
          else
            UnsafeScheduler := UnsafeSchedulerChannelError;            
          end_if;

       (* ***************************************** *)
          UnsafeSchedulerChannelError:
       (* ***************************************** *)
          
          if DiagVars.UserWantsErrorInfo  then            
            SDORequestBuffer.StdHeader.CRC  := 0;                                                      // CRC is always 0 in Std communication
            SDORequestBuffer.StdHeader.Cmd  := 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     := SDO_ADDRESS_ERROR_MEM;                                  // address of error memory
            SDORequestBuffer.us_Length      := SDO_LENGTH_ERROR_MESSAGE;                               // length of data (first byte contains number of following values + number of channels)                                              
            if remainingPacketlength <> 0 then
              // set offset if more than one package
              SDORequestBuffer.ud_Address     := (SDO_ADDRESS_ERROR_MEM + actoffset);                  // address of error memory
              // set new length for next package
              if remainingPacketlength > SDO_LENGTH_ERROR_MESSAGE then
                SDORequestBuffer.us_Length      := SDO_LENGTH_ERROR_MESSAGE;                              
              else
                SDORequestBuffer.us_Length      := remainingPacketlength$USINT;                                    
              end_if;
            end_if;                                               

            LastRequest := _ErrorChannelInfo; 
            
            
#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
  RecordFrame((#StandardRequest)$^DINT, 1);
#endif

            //copy SDO into write-buffer
            To_StdLib.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;
                      
          else
            UnsafeScheduler := UnsafeSchedulerGetDiagVars; 
          end_if;          
          

        else
          if bd_LogOnceMarker.InvalidSchedulerState = FALSE then
            bd_LogOnceMarker.InvalidSchedulerState := TRUE;
            bd_AlreadyLoggedMarker.InvalidSchedulerState := TRUE;
            LogError("@ZZZZ (SafetyCDIAS_Base::UpdateCy) [SL] Undefined Scheduler-State");
          end_if;
        end_case;
      
      end_while;
    end_if;
  end_if;

  // at the first run we write all variables independent of any changes
  if RunState > OldRunState then
    SendAllUnsafeValues();
  end_if;
  OldRunState := RunState;

//============================ Profiler start======================================================
#ifdef  DM_Profiler								
  StopTimeMeasurement(usMode := DMTIME_CY);
#endif	
//============================ Profiler end========================================================

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyCDIAS_Base::GetModuleType
	VAR_OUTPUT
		ui_ModuleType 	: UINT;
	END_VAR

  ui_ModuleType := TYPE_SAFETY_MODULE;
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::AddModuleToSafetyTask
	VAR_OUTPUT
		sd_retval 	: DINT;
	END_VAR
  
  //register module as safety module in OS and receive pointers on SDO buffers
  sd_retval := SAFETY_iAddModuleToSafetyTask( uiMaster  := 0
                                            , pucNode   := p_ObjectPath
                                            , pucRdSDO  := ( #p_Handle_SDO_Read )$^UDINT
                                            , pucWrSDO  := ( #p_Handle_SDO_Write )$^UDINT
                                            );
  
  //look for an error
	if ( sd_retval ) then
    State.uiIO_Flags				          := 0;
		State.uiIO_Flags.NoCalibration	  := 1;			
		State.uiIO_Flags.PhysicAccessOff  := 1;
    
    LogError("@ZZZZ (SafetyCDIAS_Base::AddModuleToSafetyTask) Module not added to Safety Communication Task");
    
	end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::GetModuleID
	VAR_OUTPUT
		ud_ModuleID 	: UDINT;
	END_VAR

  // no module
  ud_ModuleID := 16#ff;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyCDIAS_Base::Init
  VAR
		MyPara 	  : CmdStruct;
		MyResult	: results;
  END_VAR

//============================ Profiler start======================================================
#ifdef DM_Profiler 
  InitTimeMeasurement(usMode := DMTIME_RT);
  InitTimeMeasurement(usMode := DMTIME_CY);
  InitTimeMeasurement(usMode := DMTIME_RTPOSTSCAN);
#endif
//============================ Profiler end========================================================

#ifdef DEACTIVATED_LSL
  IF Place.Read() = DEACTIVATED_LSL THEN
    State.uiIO_Flags                  := 0;
    State.uiIO_Flags.NoHW             := 1;
    State.uiIO_Flags.PhysicAccessOff  := 1;
    return;
  END_IF;
#endif

  case InitStep of
    0:
      // initialize HwBaseCDIAS
      if InitSafetyBase() then
        InitStep += 1;
      else
        //Remember flag that init failed, we must not try again otherwise the local var pSafetyManagerThis gets overwritten with nil if it already has been initialized
        InitStep := -1;
      end_if;
    
    1:
      // add update tasks in dependence on priority (prio 1 is added when us_FirstScan = 2, prio 2 @ us_FirstScan = 3...)
      if ( ( us_FirstScan - 1 ) = GetTaskPriority() ) then
      
        AddSafetyTask();

        InitStep += 1;

      end_if;    
   
   2:
      // initialize safety module specific data (cpu, input, output) in last init and send OK to CPU

      if ((us_FirstScan = 10) & ((State.uiIO_Flags = 0 | DelayedStartup = 1))) then
              
        // log in to safety manager, if there is one
        if pSafetyManagerThis then
          MyPara.uiCmd    := CMD_SM_ADD_MODULE;
          MyPara.aPara[0] := ud_MyModuleID$DINT;
          MyPara.aPara[1] := THIS$DINT;
          pSafetyManagerThis^.NewInst(#MyPara, #MyResult);

          // check if quit error is avaialble
          MyPara.uiCmd    := CMD_SM_QUIT_ERROR_AVAILABLE;
          MyPara.aPara[0] := THIS$DINT;
          pSafetyManagerThis^.NewInst(#MyPara, #MyResult);

          // if the DLL has been found and the version shows that CDIAS safety is supported
          b_QuitErrorAvailable := (MyResult.aData[0]$DINT <> 0) & (MyResult.aData[4]$UDINT >= SAFETY_DLL_VERSION_CDIAS_QE);

          // give the manager more details about the module (if it didn't work at the first time and the safety number is valid)
          if (b_SafetyInfoOK = FALSE & ((DelayedStartup = 0) | ((DelayedStartup = 1 & SafetyNumber)))) then
          
            MyPara.uiCmd    := CMD_SM_ADD_MODULE_INFO;
            MyPara.aPara[0] := THIS$DINT;
            MyPara.aPara[1] := SafetyNumber$DINT;
            MyPara.aPara[2] := FW_Version$DINT;
            MyPara.aPara[3] := FPGA_Version$DINT;
            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);
            b_SafetyInfoOK := MyResult.aData[0];
          end_if;          
        else
          // if there is no manager, we don't have to wait in cywork until the initialisation is finished
          b_ManagerInitialisationFinished := TRUE;
          b_ManagerReadyForSDO            := TRUE;
        end_if;

        InitSafeModule();
      end_if;
      
    -1: 
      //Error, nothing to do here, states are set before
            
  end_case;

  us_FirstScan += 1;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::GetTaskPriority
	VAR_OUTPUT
		us_TaskPriority 	: USINT;
	END_VAR

  // highest = default-priority (no change in update order)
  us_TaskPriority := 0;
  
END_FUNCTION


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

  sd_retval := 0;
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::StartDO
  VAR
  	i : DINT;
  END_VAR
  
  if b_PayloadSupport = FALSE then
    //set right address of do
    MasterConnect.SetNewDOAddressRd( p_data := pPDOReadData$^DINT, ud_address:= ( ui_MyPlace + OFFSET_SPDO_DATA ) );
  end_if;
  
  //start data object
  MasterConnect.ResetDO( p_data_object := p_HandlePDORead$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := MaxLengthPDORead );

  // only for modules with outputs
  if Kennung <> CSDI16x_ID then
    if b_PayloadSupport = FALSE then
      //set right address of do
      MasterConnect.SetNewDOAddressWr( p_data := pPDOWriteData$^DINT, ud_address:= ( ui_MyPlace + OFFSET_SPDO_DATA ) );
    end_if;
    //start data object
    MasterConnect.ResetDO( p_data_object := p_HandlePDOWrite$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := MaxLengthPDOWrite);

    if (AdditionalSPDOs > 0) then      
      for i := 0 to (AdditionalSPDOs-1) do
        if b_PayloadSupport = FALSE then
          //set right address of do
          MasterConnect.SetNewDOAddressWr( p_data := aAdditionalPDOs[i].pPDOWriteData$^DINT, ud_address:= ( ui_MyPlace + OFFSET_SPDO_DATA ) );
        end_if;
        //start data object
        MasterConnect.ResetDO( p_data_object := aAdditionalPDOs[i].p_HandlePDOWrite$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := MaxLengthPDOWrite);
      end_for;
    end_if;
  end_if;
  
  if b_PayloadSupport = FALSE then
    //set right address of do
    MasterConnect.SetNewDOAddressRd(p_data := p_us_Handle_TDO_Read$^DINT, ud_address := ui_MyPlace + OFFSET_STDO_DATA);
        
    //set right address of do
    MasterConnect.SetNewDOAddressWr(p_data := p_us_Handle_TDO_Write$^DINT, ud_address := ui_MyPlace + OFFSET_STDO_DATA);
        
    //set right address of do
    MasterConnect.SetNewDOAddressRd(p_data := p_ud_Handle_LED$^DINT, ud_address := ui_MyPlace + OFFSET_LED );
  end_if;	
			
	//start data object
  MasterConnect.ResetDO( p_data_object := p_HandleTDORead$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := STDO_LENGTH );
  
  //start data object
  MasterConnect.ResetDO( p_data_object := p_HandleTDOWrite$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := STDO_LENGTH );
  
	//start data object
	MasterConnect.ResetDO( p_data_object := p_HandleLED$^DINT, us_state := VARAN_DO_CONT_RUN, ud_bytes := 15 );

  // only for modules with outputs
  if Kennung <> CSDI16x_ID then
    if b_PayloadSupport = FALSE then
      //set right address of do
      MasterConnect.SetNewDOAddressWr(p_data := p_ui_UnsafeOutWrite$^DINT, ud_address := ui_MyPlace + OFFSET_UNSAFE_VAR);
    end_if;   
    //start data object
    MasterConnect.ResetDO( p_data_object := p_HandleUnsafeOutWrite$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := UNSAFE_OUT_LENGTH );
  end_if;

  // fast unsafe variables (only if activated)
  if ActivateFastUnsafeIOs then
    if b_PayloadSupport = FALSE then
      //set right address of do
      MasterConnect.SetNewDOAddressRdWr(p_data:=p_us_Handle_FastUnsafeInputs$^DINT, ud_address_read:=ui_MyPlace + OFFSET_FAST_UNSAFE_IOS, ud_address_write:=ui_MyPlace + OFFSET_FAST_UNSAFE_IOS);
    end_if;
    //start data object
    MasterConnect.ResetDO( p_data_object := p_HandleFastUnsafeIOs$^DINT, us_state := VARAN_DO_CONT_RUN, ud_bytes := 1 );
  end_if;

  if b_PayloadSupport = FALSE then
    //set right address of do
    MasterConnect.SetNewDOAddressWr(p_data := p_us_Handle_TimeSyncHS_Write$^DINT, ud_address := ui_MyPlace + OFFSET_TIMESYNC_HANDSHAKE);
  end_if;
  //start data object
  MasterConnect.ResetDO( p_data_object := p_Handle_TimeSyncHS_Write$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := 1 );

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::StopDO
  VAR
  	i : DINT;
  END_VAR

  // stop data objects
	MasterConnect.ResetDO( p_data_object := p_HandlePDORead$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := MaxLengthPDORead);

  // only for modules with outputs
  if Kennung <> CSDI16x_ID then

    MasterConnect.ResetDO( p_data_object := p_HandlePDOWrite$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := MaxLengthPDOWrite);

    if (AdditionalSPDOs > 0) then      
      for i := 0 to (AdditionalSPDOs-1) do
        if b_PayloadSupport = FALSE then
          //set right address of do
          MasterConnect.SetNewDOAddressWr( p_data := aAdditionalPDOs[i].pPDOWriteData$^DINT, ud_address:= ( ui_MyPlace + OFFSET_SPDO_DATA ) );
        end_if;
        //start data object
        MasterConnect.ResetDO( p_data_object := aAdditionalPDOs[i].p_HandlePDOWrite$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := MaxLengthPDOWrite);
      end_for;
    end_if;
  end_if;

	MasterConnect.ResetDO( p_data_object := p_HandleTDORead$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := STDO_LENGTH );
  b_DOIsRunningTDORead          := 0;

	MasterConnect.ResetDO( p_data_object := p_HandleTDOWrite$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := STDO_LENGTH );
  b_DOIsRunningTDOWrite         := 0;

  MasterConnect.ResetDO( p_data_object := p_HandleLED$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := 15 );
  
  MasterConnect.ResetDO( p_data_object := p_Handle_TimeSyncHS_Write$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := 1 );
  b_DOIsRunning_TimeSyncHS      := 0;

  // only for modules with outputs
  if Kennung <> CSDI16x_ID then
    MasterConnect.ResetDO( p_data_object := p_HandleUnsafeOutWrite$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := UNSAFE_OUT_LENGTH );
    b_DOIsRunningUnsafeOutWrite := 0;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::InitBuffers
	VAR_OUTPUT
		sd_retval 	: DINT;
	END_VAR

  sd_retval := -1;
  
  //allocate memory for outgoing SDO (one SDO possible)
  p_SDOOutputBuffer$^void := To_StdLib.Malloc(size := SDO_MAX_LENGTH);
  
  if ( p_SDOOutputBuffer = NIL ) then
    State.uiIO_Flags				          := 0;
		State.uiIO_Flags.PhysicAccessOff  := 1;
    ClassState := _MemAllocFailed;
    return;
  end_if;

  //allocate memory for incoming SDO list (number of SDO is dynamical) 
  //following elements will be added dynamical
  
  //allocate list
  InputBufferAllocatedNo := SDO_BUFFER_ALLOC_BLOCK;
  p_SDOInputBuffer$^void := To_StdLib.Malloc(size := InputBufferAllocatedNo * SDO_MAX_LENGTH);
  
  if ( p_SDOInputBuffer = NIL ) then
    State.uiIO_Flags				          := 0;
		State.uiIO_Flags.PhysicAccessOff  := 1;
    ClassState := _MemAllocFailed;
    return;
  end_if;

  //all buffers initialized
  sd_retval := 0;
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::GetSafetyNumber
	VAR_OUTPUT
		sd_retval 	: DINT;
	END_VAR
  VAR
  	TempPathInfo: PathInfoType;
		MyPara 	    : CmdStruct;
		MyResult	  : results;
  END_VAR

  sd_retval := SDOStdRequ ( us_Command      := SDO_COMMAND_GET_SAFENBR
                          , p_us_RespData   := ( #SafetyNumber )$^USINT
                          , us_RespLength   := sizeof(SafetyNumber)
                          );
  
  if ( sd_retval <> 0 ) then
    State.uiIO_Flags				          := 0;
		State.uiIO_Flags.PhysicAccessOff  := 1;
    
    LogError("@ZZZZ (SafetyCDIAS_Base::GetSafetyNumber) No Safety Number available!");
  elsif pConfigMem then
    // store safety number in config memory
    pConfigMem^$HDINT := SafetyNumber;    
  end_if;

  sd_retval := SDOStdRequ ( us_Command      := SDO_COMMAND_GET_FW_VERSION
                          , p_us_RespData   := ( #FirmwareVersion )$^USINT
                          , us_RespLength   := sizeof(FirmwareVersionType)
                          );
  
  if ( sd_retval = 0 ) then
    FW_Version := FirmwareVersion.RevMinor OR (FirmwareVersion.RevMajor SHL 16);
    
    // Minor Versions starting with 9xxx mark Bootloader versions
    if (FirmwareVersion.RevMinor >= 9000) & (FirmwareVersion.RevMinor < 10000) then
      LogError("@ZZZZ (SafetyCDIAS_Base::GetSafetyNumber) Bootloader version of safety firmware detected! Download a firmware or contact Sigmatek Support!");
    end_if;
   
    // if we are connected over mover maybe the second try to read the fw version succeeds after the first failed
    if (sd_VaranType = 2) & (ClassState = _ReadFWVerFailed) then
      ClassState := _WaitForSynchronicity;
    end_if;
  else
    State.uiIO_Flags				          := 0;
    State.uiIO_Flags.PhysicAccessOff  := 1;
    ClassState := _ReadFWVerFailed;
    LogError("@ZZZZ (SafetyCDIAS_Base::GetSafetyNumber) No Firmware Version available!");
  end_if;

  InitPathInfo(#TempPathInfo);
  
  // add own safety number to routing table
  sd_retval := AddRoutingElement( ud_SafeNumber       := SafetyNumber
                                , ud_thisp            := this$UDINT
                                , pObject             := #TempPathInfo
                                );

  // give the manager more details about the module
  if pSafetyManagerThis then
    if ((SafetyNumber & DelayedStartup = 1) | DelayedStartup = 0) then
      MyPara.uiCmd    := CMD_SM_ADD_MODULE_INFO;
      MyPara.aPara[0] := THIS$DINT;
      MyPara.aPara[1] := SafetyNumber$DINT;
      MyPara.aPara[2] := FW_Version$DINT;
      MyPara.aPara[3] := FPGA_Version$DINT;
      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);
      b_SafetyInfoOK := MyResult.aData[0];
    end_if;
  else
    // if there is no safety manager, it can only work if old modules are being used (new need the time sync token)

    // if the FPGA Version is lower than 1.4 or the minor firmware version is lower than 100 everything is fine
    if (FPGA_Version < 16#14) | (FW_Version$UINT < 100) then
      // new classes with old modules and without safety manager (hwcontrol) => no problem
    else
      // new classes with new modules and without safety manager (hwcontrol) => problem: noone there to pass on the time sync token
      LogError("@ZZZZ (SafetyCDIAS_Base::GetSafetyNumber) For new safety modules an object of HwControl is needed for time synchronisation!");
    end_if;
  end_if;

END_FUNCTION


FUNCTION SafetyCDIAS_Base::SafetyCDIAS_Base
	VAR_OUTPUT
		ret_code 	: ConfStates;
	END_VAR

#ifdef HWC_LogInit
  HWC_LogInit();
#endif

  //get interface for safety functions
  if ( OS_CILGET(INTERFACE_SAFETY, #pISafety)) then
    pISafety := NIL;
		
    LogError("@ZZZZ (SafetyCDIAS_Base::SafetyCDIAS_Base) No Safety Interface found!");
    
  end_if;

  // initialize it with FALSE, if there is anything on local CDIAS it will change to TRUE
  b_SafetyOnLocalCDIAS := FALSE;

  // initialize module count with 0
  ModuleSyncNo := 0;
  
  ret_code := C_OK;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyCDIAS_Base::UpDateRT
	VAR_INPUT
		Handle 	      : UDINT;
	END_VAR
  VAR
    PDOLength     : USINT;
    p_ReceiveObj  : pVirtualBase;
    p_addressRd   : ^VaranDOSettingsRd;
    i             : DINT;
		MyPara 	      : CmdStruct;
		MyResult	    : results;
    bValidTDO     : BOOL;
  END_VAR

//============================ Profiler start======================================================
#ifdef  DM_Profiler								
  StartTimeMeasurement(usMode := DMTIME_RT);
#endif	
//============================ Profiler end========================================================

  // do tdo/pdo communication only, if module has been found and initialized correctly and if there are some LEDs on (else a FW-Update is running)
  if ( State.uiIO_Flags = 0 ) & 
     (( ClassState = _SafetyClassOK ) | ( ClassState = _WaitForSynchronicity ) | ( ClassState = _ReinitConfig ) | ( ClassState = _ModFromCfgNotFound ) | ( ClassState = _UnknownCfgError ) | ( ClassState = _UnsafeVarNotFound )) then

    if StartRtDOs then
      if StartRtDOs = 2 then
        //start DOs
        StartDO();
      else
        if b_PayloadSupport = FALSE then
          //set right address of do
          MasterConnect.SetNewDOAddressRd( p_data := pPDOReadData$^DINT, ud_address:= ( ui_MyPlace + OFFSET_SPDO_DATA ) );
        end_if;
        
        //start data object
        MasterConnect.ResetDO( p_data_object := p_HandlePDORead$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := MaxLengthPDORead );
      end_if;

      StartRtDOs := 0;
      return;
    end_if;

    // get I/O state, runstate, error
    UpDateNotStd(calloption:=CALL_OPTION_RT_PRESCAN);

    // wait until the safetymanager has initialized everything
    if b_ManagerInitialisationFinished = FALSE then
      return;
    end_if;

    // if any LED is active, then firmware update is not active and we can do our work
    if (VoltageOK | RunState | ServiceMode | Error) then    
      // first check if there is a TDO to fetch
#ifdef SAFETY_OVER_DIAS
      if ( b_im ) then
        // Read Length of TDO
        TDOInfo := p_us_Handle_TDOReadLen^;

        // check msb (= new data) and length of frame
        if (TDOInfo AND 16#80) & ((TDOInfo AND 16#7F) = STDO_LENGTH) then
        
          //copy TDO word by word
          for i := 0 to (((TDOInfo AND 16#7F)/2)-1) by 1 do 
              
            ( (#TDOFrame)$^UINT + ( i * 2 ) )^ := ( a_Handle_TDO_Read[i] )$^UINT^;
            
          end_for;

          // check length inside TDO Frame (must be 20)
          if TDOFrame.StdHeader.Len = 20 then
            
            // check who needs the TDO and give it the right addressee
            
            //search this-pointer of receiver with safety number
            p_ReceiveObj := ( GetRoutingPointerByNumber(ud_SafeNumber := TDOFrame.DstAdr))$pVirtualBase;
            
            if p_ReceiveObj <> NIL then
              MyPara.uiCmd := CMD_SM_WRITE_TDO_TO_MODULE;
              MyPara.aPara[0] := (#TDOFrame)$DINT;
              p_ReceiveObj^.NewInst(#MyPara, #MyResult);    

  //                p_ReceiveObj^.WriteTDO2Module(#TDOFrame);
            end_if;
          else
            if bd_AlreadyLoggedMarker.TdoLenInvalid = FALSE then
              bd_LogOnceMarker.TdoLenInvalid := TRUE;
            end_if;
          end_if;
        end_if;
      else
#endif

        if NewHandShakeValue then

          p_us_Handle_TimeSyncHS_Write^ := p_us_Handle_TimeSyncHS_Read^ OR NewHandShakeValue;
          if b_VaranAvailable then
          
            if b_PayloadSupport then
              if sd_VaranType = 2 then 
                p_Handle_TimeSyncHS_WriteEnable^ := VARAN_MOVER_DO_CONT_RUN;
                TimeSyncHSSingleRunActive := 2;
              else
                b_DOIsRunning_TimeSyncHS.StartRequest := true;
              end_if;
            else
              if sd_VaranType = 2 then 
                (p_Handle_TimeSyncHS_Write$^USINT )^ := VARAN_MOVER_DO_CONT_RUN;
                TimeSyncHSSingleRunActive := 2;
              else
                MasterConnect.ResetDO( p_data_object := p_Handle_TimeSyncHS_Write$^DINT, us_state := VARAN_DO_SINGLE_RUN, ud_bytes := 1 );
              end_if;
            end_if;
          
          end_if;
          
          // if the time synchonisation is active we send 2 different bits in 2 successive cycles, so the µC can detect the cycle time
          if NewHandShakeValue = 2#011 then
            NewHandShakeValue := 2#111;
            if sd_VaranType = 1 then 
              // start DO at this point to ensure 1 cycle delay, from request to response
              if b_PayloadSupport then
                EnableDO(ud_DOHandle := p_HandleTDORead$UDINT);
                b_DOIsRunningTDORead.ContRun := true;
              else
                p_HandleTDORead^.ucCtrlStat := VARAN_DO_CONT_RUN;
              end_if;
              
            end_if;
            TimeSyncDOActive.OwnSyncActive := 1;
          else
            NewHandShakeValue := 0;
          end_if;
        elsif b_TimeSyncActive then
          // on input or output module we wait until the time synchronisation is finished
          if ((p_us_Handle_TimeSyncHS_Read^ AND 2#110) = 0) & (TimeSyncHSSingleRunActive = 0) then
            b_TimeSyncActive := FALSE;
            TimeSyncDOActive.OwnSyncActive := 0;            
            
            // if we have no mover and no external request is pending => stop the read DO
            if (sd_VaranType = 1) & (TimeSyncDOActive$DINT = 0) then
              
              if b_PayloadSupport then
                
                if b_DOIsRunningTDORead = 0 then
                  if bd_AlreadyLoggedMarker.TdoLenInvalid = FALSE then
                    bd_LogOnceMarker.TdoLenInvalid := TRUE;
                  end_if;
                end_if;
                DisableDO(ud_DOHandle := p_HandleTDORead$UDINT);
                b_DOIsRunningTDORead := 0; 
                
              else
              
                if p_HandleTDORead^.ucCtrlStat AND 0x03 = VARAN_DO_NO_RUN then
                  if bd_AlreadyLoggedMarker.TdoLenInvalid = FALSE then
                    bd_LogOnceMarker.TdoLenInvalid := TRUE;
                  end_if;
                end_if;
                p_HandleTDORead^.ucCtrlStat := VARAN_DO_NO_RUN; 
                
              end_if;
              
            end_if;
            MyPara.uiCmd := CMD_SM_TIME_SYNC_FINISHED;
            pSafetyManagerThis^.NewInst(#MyPara, #MyResult); // thispointer doesn't have to be checked here; NewHandShakeValue gets set via SafetyManager
          end_if;
        end_if;

        // Read Length of TDO
        TDOInfo := p_us_Handle_TDO_Read_Length^;

        // check msb (= new data) and length of frame
        bValidTDO := (TDOInfo AND 16#80) & ((TDOInfo AND 16#7F) = STDO_LENGTH);
        
        if b_VaranAvailable then

          if (sd_VaranType = 1) then // ----------------------------------------------------------------------

            if b_NewSyncMode then
              if bValidTDO then
                if b_PayloadSupport then
                  
                // check if data-DO is running already
                  if b_DOIsRunningTDORead.ContRun then
                    TDOTransStarted := TRUE;      
                  else
                    // we didn´t expect this, so read out and ignore (maybe its an old frame)
                    b_DOIsRunningTDORead.StartRequest := true;
                    bValidTDO := FALSE;
                  end_if;
                  
                else
                    
                    // check if data-DO is running already
                  if (p_HandleTDORead^.ucCtrlStat AND 16#03) = VARAN_DO_CONT_RUN then
                    TDOTransStarted := TRUE;      
                  else
                    // we didn´t expect this, so read out and ignore (maybe its an old frame)
                    p_HandleTDORead^.ucCtrlStat := VARAN_DO_SINGLE_RUN;
                    bValidTDO := FALSE;
                  end_if;
                  
                end_if;                
              end_if;
            end_if;

            // if we got the TDO Data, copy them
            if TDOTransStarted then

              //copy whole TDO
              To_StdLib.MemCpy(dest := #TDOFrame, source := p_us_Handle_TDO_Read, size := sizeof(TDOType));

#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
  RecordFrame((#TDOFrame)$^DINT, 0);
#endif

              // check length inside TDO Frame (must be 20)
              if TDOFrame.StdHeader.Len = (STDO_LENGTH - sizeof(TDOType.StdHeader.CRC)) then
                TDOTransStarted := FALSE;
                
                // if our own timesynchronisation is not running => stop the read DO
                if b_NewSyncMode & (TimeSyncDOActive$DINT = 0) then
                  if b_PayloadSupport then
                    DisableDO(ud_DOHandle := p_HandleTDORead$UDINT);  // we got data, so stop DO
                    b_DOIsRunningTDORead := 0;
                  else
                    p_HandleTDORead^.ucCtrlStat := VARAN_DO_NO_RUN; // we got data, so stop DO
                  end_if;                  
                end_if;
                // check who needs the TDO and give it the right addressee
                
                //search this-pointer of receiver with safety number
                p_ReceiveObj := ( GetRoutingPointerByNumber(ud_SafeNumber := TDOFrame.DstAdr))$pVirtualBase;
                
                if p_ReceiveObj <> NIL then
#ifdef DO_DEBUG
                  DOCheck(pFrame:=(#TDOFrame)$^SDOStdHeader, pCheckStruct:=#TDORead);
#endif
                  
                  MyPara.uiCmd    := CMD_SM_WRITE_TDO_TO_MODULE;
                  MyPara.aPara[0] := (#TDOFrame)$DINT;
                  p_ReceiveObj^.NewInst(#MyPara, #MyResult);    

  //                p_ReceiveObj^.WriteTDO2Module(#TDOFrame);
                elsif pSafetyManagerThis then
#ifdef DO_DEBUG
                  DOCheck(pFrame:=(#TDOFrame)$^SDOStdHeader, pCheckStruct:=#TDORead);
#endif

                  //passing the TDO to another domain
                  MyPara.uiCmd    := CMD_SM_TDO_TO_MANAGER;
                  MyPara.aPara[0] := STDO_LENGTH;
                  MyPara.aPara[1] := (#TDOFrame)$DINT;
                  pSafetyManagerThis^.NewInst(#MyPara, #MyResult);                      
                end_if;
              elsif TDOFrame.StdHeader.Len > 0 then
                if bd_AlreadyLoggedMarker.TdoLenInvalid = FALSE then
                  bd_LogOnceMarker.TdoLenInvalid := TRUE;
                end_if;
              end_if;
            end_if;

            if (b_NewSyncMode = FALSE) & (TDOInfo AND 16#80) then
              if ((TDOInfo AND 16#7F) = STDO_LENGTH) then

                // if so, start DO and remember to use info next time
                if b_PayloadSupport then
                  b_DOIsRunningTDORead.StartRequest := true;
                else
                  p_HandleTDORead^.ucCtrlStat := VARAN_DO_SINGLE_RUN;
                end_if;                
                
                if ((TDOFrame.StdHeader.Typ AND SSDO_MASK_RESPONSE) = 0) & (udTDORdCnt < 2) then
                  udTDORdCnt += 1;
                else
                  TDOTransStarted := TRUE;                
                end_if;
              end_if;
            end_if;
          else  // Mover active ----------------------------------------------------------------------
            if TimeSyncHSSingleRunActive then
              TimeSyncHSSingleRunActive -= 1;
              if TimeSyncHSSingleRunActive = 0 then
                if b_PayloadSupport then
                  p_Handle_TimeSyncHS_WriteEnable^      := VARAN_DO_NO_RUN;
                else
                  (p_Handle_TimeSyncHS_Write$^USINT )^  := VARAN_DO_NO_RUN;
                end_if;                
              end_if;
            end_if;
          
            if bValidTDO then
          
              //copy whole TDO
              To_StdLib.MemCpy(dest := #TDOFrame, source := p_us_Handle_TDO_Read, size := sizeof(TDOType));

#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
RecordFrame((#TDOFrame)$^DINT, 0);
#endif

              // check length inside TDO Frame (must be 20)
              if TDOFrame.StdHeader.Len = (STDO_LENGTH - sizeof(TDOType.StdHeader.CRC)) then
                
                // check who needs the TDO and give it the right addressee
                
                //search this-pointer of receiver with safety number
                p_ReceiveObj := ( GetRoutingPointerByNumber(ud_SafeNumber := TDOFrame.DstAdr))$pVirtualBase;
                
                if p_ReceiveObj <> NIL then
#ifdef DO_DEBUG
                  DOCheck(pFrame:=(#TDOFrame)$^SDOStdHeader, pCheckStruct:=#TDORead);
#endif
                      
                  MyPara.uiCmd    := CMD_SM_WRITE_TDO_TO_MODULE;
                  MyPara.aPara[0] := (#TDOFrame)$DINT;
                  p_ReceiveObj^.NewInst(#MyPara, #MyResult);    

      //                p_ReceiveObj^.WriteTDO2Module(#TDOFrame);
                elsif pSafetyManagerThis then
#ifdef DO_DEBUG
                  DOCheck(pFrame:=(#TDOFrame)$^SDOStdHeader, pCheckStruct:=#TDORead);
#endif

                  //passing the TDO to another domain
                  MyPara.uiCmd    := CMD_SM_TDO_TO_MANAGER;
                  MyPara.aPara[0] := STDO_LENGTH;
                  MyPara.aPara[1] := (#TDOFrame)$DINT;
                  pSafetyManagerThis^.NewInst(#MyPara, #MyResult);                      
                end_if;
              elsif TDOFrame.StdHeader.Len > 0 then
                if bd_AlreadyLoggedMarker.TdoLenInvalid = FALSE then
                  bd_LogOnceMarker.TdoLenInvalid := TRUE;
                end_if;
              elsif TDOFrame.StdHeader.Len = 0 then
                if bd_AlreadyLoggedMarker.TdoLen0 = FALSE then
                  bd_LogOnceMarker.TdoLen0 := TRUE;
                end_if;
              end_if;
            end_if;
          end_if; // --------------------------------------------------------------------------------------
        else  // if b_VaranAvailable then
          if bValidTDO then

            //copy whole TDO
            To_StdLib.MemCpy(dest := #TDOFrame, source := p_us_Handle_TDO_Read, size := sizeof(TDOType));
            
#ifdef DO_DEBUG
            DOCheck(pFrame:=(#TDOFrame)$^SDOStdHeader, pCheckStruct:=#TDORead);
#endif

#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
  RecordFrame((#TDOFrame)$^DINT, 0);
#endif

            // check length inside TDO Frame (must be 20)
            if TDOFrame.StdHeader.Len = (STDO_LENGTH - sizeof(TDOType.StdHeader.CRC)) then
              
              // check who needs the TDO and give it the right addressee
              
              //search this-pointer of receiver with safety number
              p_ReceiveObj := ( GetRoutingPointerByNumber(ud_SafeNumber := TDOFrame.DstAdr))$pVirtualBase;
              
              if p_ReceiveObj <> NIL then
                if ((TDOFrame.StdHeader.Typ AND SSDO_MASK_RESPONSE) = 0) & (udTDORdCnt < 2) then
                  udTDORdCnt += 1;
                else
#ifdef DO_DEBUG
                  DOCheck(pFrame:=(#TDOFrame)$^SDOStdHeader, pCheckStruct:=#TDORead);
#endif
                  
                  MyPara.uiCmd    := CMD_SM_WRITE_TDO_TO_MODULE;
                  MyPara.aPara[0] := (#TDOFrame)$DINT;
                  p_ReceiveObj^.NewInst(#MyPara, #MyResult);    

      //                p_ReceiveObj^.WriteTDO2Module(#TDOFrame);
                end_if;
              elsif pSafetyManagerThis then
#ifdef DO_DEBUG
                DOCheck(pFrame:=(#TDOFrame)$^SDOStdHeader, pCheckStruct:=#TDORead);
#endif

                //passing the TDO to another domain
                MyPara.uiCmd    := CMD_SM_TDO_TO_MANAGER;
                MyPara.aPara[0] := STDO_LENGTH;
                MyPara.aPara[1] := (#TDOFrame)$DINT;
                pSafetyManagerThis^.NewInst(#MyPara, #MyResult);                      
              end_if;
            else
              if bd_AlreadyLoggedMarker.TdoLenInvalid = FALSE then
                bd_LogOnceMarker.TdoLenInvalid := TRUE;
              end_if;
            end_if;
          end_if;
        end_if;
        
        if bValidTDO then
          // if it's a response, reset the flag
          if TDOFrame.StdHeader.Typ AND 16#80 then            
            TimeSyncDOActive.Wait4ResponseNo -= 1;
          end_if;
        end_if;

#ifdef SAFETY_OVER_DIAS
      end_if;
#endif

      // if we are in run state
      if RunState then
      
        // we have to start the DOs here because it's the right task for this
        if b_StartDOs then
          b_StartDOs := FALSE;
          if sd_VaranType = 1 then
            if b_PayloadSupport = FALSE then
              //set right address of do
              MasterConnect.SetNewDOAddressWr( p_data := pPDOWriteData$^DINT, ud_address:= ( ui_MyPlace + OFFSET_SPDO_DATA ) );
            end_if;

            MasterConnect.ResetDO( p_data_object := p_HandlePDOWrite$^DINT, us_state := VARAN_DO_CONT_RUN, ud_bytes := MaxLengthPDOWrite);

            if AdditionalSPDOs & (ui_cnt_PDOInputBuffer > 1) then
              if AdditionalSPDOs > (ui_cnt_PDOInputBuffer-1) then
                AdditionalSPDOs := ui_cnt_PDOInputBuffer-1;
              end_if;

              for i := 0 to (AdditionalSPDOs-1) do
                if b_PayloadSupport = FALSE then
                  //set right address of do
                  MasterConnect.SetNewDOAddressWr( p_data := aAdditionalPDOs[i].pPDOWriteData$^DINT, ud_address:= ( ui_MyPlace + OFFSET_SPDO_DATA ) );
                end_if;

                MasterConnect.ResetDO( p_data_object := aAdditionalPDOs[i].p_HandlePDOWrite$^DINT, us_state := VARAN_DO_CONT_RUN, ud_bytes := MaxLengthPDOWrite);
              end_for;
            end_if;
          else        
            
            if b_PayloadSupport then
              p_HandlePDOWriteEnable^     := VARAN_MOVER_DO_CONT_RUN; // = VARAN_DO_SINGLE_RUN 
            else
              (p_HandlePDOWrite$^USINT )^ := VARAN_MOVER_DO_CONT_RUN; // is continous at the mover
            end_if;
            
            if AdditionalSPDOs & (ui_cnt_PDOInputBuffer > 1) then
              if AdditionalSPDOs > (ui_cnt_PDOInputBuffer-1) then
                AdditionalSPDOs := ui_cnt_PDOInputBuffer-1;
              end_if;

              for i := 0 to (AdditionalSPDOs-1) do
                if b_PayloadSupport then
                  aAdditionalPDOs[i].p_HandlePDOWriteEnable^    := VARAN_MOVER_DO_CONT_RUN; // = VARAN_DO_SINGLE_RUN 
                else
                  (aAdditionalPDOs[i].p_HandlePDOWrite$^USINT )^:= VARAN_MOVER_DO_CONT_RUN; // is continous at the mover
                end_if;
              end_for;
            end_if;
          end_if;
        end_if;    
        
        if b_MoveCommandOutputActive <> _Active then
          if PDOSingleRunActive then
            PDOSingleRunActive -= 1;
            if PDOSingleRunActive = 0 then
            
              if b_PayloadSupport then  // ---------------------------------
              
                if (sd_VaranType = 1) then  // Payload Without Mover +++++++
                  DisableDO(ud_DOHandle := p_HandlePDOWrite$UDINT);
                  
                  if AdditionalSPDOs then             
                    for i := 0 to (AdditionalSPDOs-1) do
                      DisableDO(ud_DOHandle := aAdditionalPDOs[i].p_HandlePDOWrite$UDINT );                      
                    end_for;
                  end_if;   
                
                else  // Payload With Mover ++++++++++++++++++++++++++++++++
                  p_HandlePDOWriteEnable^ := VARAN_DO_NO_RUN;
                  
                  if AdditionalSPDOs then             
                    for i := 0 to (AdditionalSPDOs-1) do
                      (aAdditionalPDOs[i].p_HandlePDOWriteEnable)^ := VARAN_DO_NO_RUN;
                    end_for;
                  end_if;
                end_if; // +++++++++++++++++++++++++++++++++++++++++++++++++
              
              else  // No Payload Wih Mover --------------------------------
                (p_HandlePDOWrite$^USINT )^ := VARAN_DO_NO_RUN;
                
                if AdditionalSPDOs then             
                  for i := 0 to (AdditionalSPDOs-1) do
                    (aAdditionalPDOs[i].p_HandlePDOWrite$^USINT )^ := VARAN_DO_NO_RUN;
                  end_for;
                end_if;
              end_if; // ---------------------------------------------------
              
            end_if;
          end_if;

          //read PDO from hardware, only if PDO is needed by other moduls
          if ( PDOOutputIsUsed ) then
#ifdef SAFETY_OVER_DIAS          
            if ( b_im ) then
              
              PDOLength := p_us_Handle_PDOReadLen^;
              
              // only if length is bigger than minimum and smaller than maximum
              if ( PDOLength > PDOType.Length ) & ( PDOLength <= SPDO_MAX_LENGTH) then
                //copy PDO word by word
                for i := 0 to ((PDOLength/2)-1) by 1 do 
                    
                  ( p_PDOOutputBuffer$^UINT + ( i * 2 ) )^ := ( a_Handle_PDO_Read[i] )$^UINT^;
                  
                end_for;
              end_if;
            else
#endif

              PDOLength := pPDOReadLengthData^;

              if b_VaranAvailable & (sd_VaranType = 1) then

                // if "pdo length" matches the length of Varan-PDO data object
                if PDOLength = PDOReadLen then
                  // only if length is bigger than minimum and smaller than maximum
                  if ( PDOLength > PDOType.Length ) & ( PDOLength <= SPDO_MAX_LENGTH) then
                    //copy whole PDO
                    To_StdLib.MemCpy(dest := #PDOOutputBuffer, source := pPDOReadData, size := PDOLength);

#ifdef DO_DEBUG
                    DOCheck(pFrame:=(#PDOOutputBuffer)$^SDOStdHeader, pCheckStruct:=#PDORead);
#endif

#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
//if ClassState = _SafetyClassOK then
  RecordFrame((#PDOOutputBuffer)$^DINT, 0);
//end_if;
#endif

                  end_if;
                else
                
                  if b_PayloadSupport then
                  // correct size of data object to PDOLength
                    ChangeDOLengthOffset( ud_DOHandle     := p_HandlePDORead$UDINT
                                        , ud_length_read  := PDOLength
                                        );
                    PDOReadLen              := PDOLength;
                    EnableDO(ud_DOHandle    := p_HandlePDORead$UDINT);
                  else
                    // correct size of data object to PDOLength
                    p_addressRd             := pPDOReadData - sizeof(VaranDOSettingsRd);
                    p_addressRd^.us_ByteCnt := PDOLength;
                    p_HandlePDORead^.usLengthofExpAnswer := sizeof(VaranDOSettingsRd.us_Command) + to_uint(PDOLength);

                    PDOReadLen := PDOLength;

                    MasterConnect.ResetDO( p_data_object := p_HandlePDORead$^DINT, us_state := VARAN_DO_CONT_RUN, ud_bytes := PDOLength );
                  end_if;
                    
                end_if;
              else
                // only if length is bigger than minimum and smaller than maximum
                if ( PDOLength > PDOType.Length ) & ( PDOLength <= SPDO_MAX_LENGTH) then
                  //copy whole PDO
                  To_StdLib.MemCpy(dest := #PDOOutputBuffer, source := pPDOReadData, size := PDOLength);

#ifdef DO_DEBUG
                  DOCheck(pFrame:=(#PDOOutputBuffer)$^SDOStdHeader, pCheckStruct:=#PDORead);
#endif

#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
//if ClassState = _SafetyClassOK then
  RecordFrame((#PDOOutputBuffer)$^DINT, 0);
//end_if;
#endif

                end_if;
              end_if;
#ifdef SAFETY_OVER_DIAS
            end_if;
#endif
          end_if;
        else
          PDOLength := pPDOReadLengthData^;

          // if "pdo length" doesn't match the length of Varan-PDO data object
          if (PDOLength <> PDOReadLen) & (sd_VaranType = 1) & ( PDOLength > PDOType.Length ) & ( PDOLength <= SPDO_MAX_LENGTH) then
          
            if b_PayloadSupport then
            // correct size of data object to PDOLength
              ChangeDOLengthOffset( ud_DOHandle     := p_HandlePDORead$UDINT
                                  , ud_length_read  := PDOLength
                                  );

              PDOReadLen := PDOLength;
              
              EnableDO(ud_DOHandle := p_HandlePDORead$UDINT);
            else
              // correct size of data object to PDOLength
              p_addressRd := pPDOReadData - sizeof(VaranDOSettingsRd);
              p_addressRd^.us_ByteCnt := PDOLength;
              p_HandlePDORead^.usLengthofExpAnswer := sizeof(VaranDOSettingsRd.us_Command) + to_uint(PDOLength);

              PDOReadLen := PDOLength;
          
              if b_PayloadSupport = FALSE then
                //set right address of do
                MasterConnect.SetNewDOAddressRd( p_data := pPDOReadData$^DINT, ud_address:= ( ui_MyPlace + OFFSET_SPDO_DATA ) );
              end_if;

              MasterConnect.ResetDO( p_data_object := p_HandlePDORead$^DINT, us_state := VARAN_DO_CONT_RUN, ud_bytes := PDOLength );
            end_if;
            
          end_if;

#ifdef DO_DEBUG
          DOCheck(pFrame:=pPDOReadData$^SDOStdHeader, pCheckStruct:=#PDORead);
#endif
        end_if;
      end_if;
    end_if;
  end_if;
  
  if b_PayloadSupport & (sd_VaranType = 1) then 
      
    // s_DO_AcyRd xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    case b_DOIsRunning_TimeSyncHS of
      
      SR_STATE_ENABLE_ME :  // DO is not running and start request is set ----------------------------------------
        EnableDO(ud_DOHandle := p_Handle_TimeSyncHS_Write$UDINT);        
        b_DOIsRunning_TimeSyncHS := SR_STATE_DISABLE_ME;
        
      SR_STATE_DISABLE_ME : // DO is running and start request is not set ----------------------------------------
        DisableDO(ud_DOHandle:= p_Handle_TimeSyncHS_Write$UDINT);
        b_DOIsRunning_TimeSyncHS := SR_STATE_NOTHING;
        
      SR_STATE_LEAVE_ME_ENABLED : // DO is running and another start request is set ------------------------------
        b_DOIsRunning_TimeSyncHS := SR_STATE_DISABLE_ME;
        
    end_case;
      
  end_if;
    
#ifndef CALL_OPTION_RT_POSTSCAN
  UpDateRTPostScan(Handle);
#endif 

//============================ Profiler start======================================================
#ifdef  DM_Profiler								
  StopTimeMeasurement(usMode := DMTIME_RT);
#endif	
//============================ Profiler end========================================================

END_FUNCTION

#pragma warning(disable:0073);
FUNCTION VIRTUAL SafetyCDIAS_Base::UpDateNotStd
	VAR_INPUT
		calloption 	: UDINT;
	END_VAR

END_FUNCTION
#pragma warning(default:0073);


FUNCTION VIRTUAL SafetyCDIAS_Base::ReadSDOConfig
	VAR_INPUT
		p_SDORequestBuffer 	          : ^SDORequReadConfig;
		p_SDOResponseBuffer 	        : ^SDORespReadConfig;
		pModule 	                    : ^PathInfoType;
		pListHeader 	                : ^PathInfoType;
	END_VAR
	VAR_OUTPUT
		sd_retval 	                  : DINT;
	END_VAR
  VAR
    ud_Address                    : UDINT;
    ud_ListLength_Address         : UDINT;
    ud_ListLength                 : UDINT;
    ud_TmpCnt                     : UDINT;
    i                             : UDINT;
    ud_ModulePathLen_Max          : UDINT;
    ud_ModulePathCompLen_Max      : UDINT;
    ud_ListHeaderPathLen_Max      : UDINT;
    ud_ListHeaderPathCompLen_Max  : UDINT;
    us_DataLength_Max             : USINT;
    ud_ListBaseAddress            : UDINT;
    ud_ListAddressMax             : UDINT;
    ud_CntUnsafeOutputs           : UDINT;
    ud_CntUnsafeInputs            : UDINT;
    ud_ActAddress                 : UDINT;  // actual offset in application memory (where to find the values in run mode)
    ud_UnsafeBDINT_Offset         : UDINT;  // actual offset in application memory (where to find the unsafe variables in run mode)
    ud_ActBlockType               : UDINT;
    ud_TmpAddress                 : UDINT;
    ud_TmpStrLen                  : UDINT;
    p_TmpBlockedData              : ^void;
    ud_ActStrLen                  : UDINT;
    us_BlockedTransferLength      : USINT;
    BoolOuts                      : UDINT;
    DintOuts                      : UDINT;    
    TempModuleConfig              : t_ModuleCfg;
    pChar                         : ^CHAR;
    TempPath                      : ARRAY [0..99] OF USINT;
    PathOfThisCPU                 : ARRAY [0..99] OF USINT;
    GotOwnPath                    : BOOL;
    TempPdoConfig                 : t_PdoCfg;
    pBitMasks                     : ^BDINT;
    ActBitMask                    : BDINT;
    ud_skipLength                 : UDINT; //++pr
    b_CfgTypeV2                   : BOOL; // FALSE means there is no support of new time synchronisation/new general purpose register
    TmpCRC                        : HDINT;
    ud_ContainerBlockType         : UDINT;
    b_CfgTypeV3                   : BOOL;
    ud_ConfigLength               : UDINT;
    hd_DynParaVersion             : UDINT;
  END_VAR

  // Initialize the variables with invalid if we are located on VARAN. If any module to communicate with is not located on VARAN, it will change to inactive. (ConfigSafetyInput/Output)
  if b_VaranAvailable then
    b_MoveCommandInputActive    := _Invalid;
    b_MoveCommandOutputActive   := _Invalid;
  else
    // if no VARAN, we can't move the PDOs
    b_MoveCommandInputActive    := _Inactive;
    b_MoveCommandOutputActive   := _Inactive;
  end_if;
    
  //minimum length of path: 2 bytes length, 1 byte domain info, 1 byte bus type and 1 byte port
  ud_ModulePathLen_Max          := 5;
  ud_ModulePathCompLen_Max      := 5;
  ud_ListHeaderPathLen_Max      := 5;
  ud_ListHeaderPathCompLen_Max  := 5;
  
  NewConfigType                 := ConfigState_NotInitialized;
  
  //initialize header-data for request
  
  //calculate length without crc
  p_SDORequestBuffer^.StdHeader.Len := sizeof(SDORequReadConfig) - sizeof(SDOHeader.StdHeader.CRC);
  
  //type
  p_SDORequestBuffer^.StdHeader.Typ := SDO_STD;
  
  //command for reading config data
  p_SDORequestBuffer^.StdHeader.Cmd := SDO_COMMAND_READ;
  
  
  //read crc of whole config data
  
  //send request and receive data
  sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                              , p_SDOResponseBuffer := p_SDOResponseBuffer
                              , ud_Address          := SDO_ADDRESS_CONFIG_DATA + SDO_OFFSET_CONFIG_CRC_ALL
                              , us_Length           := 4
                              );

  //no response
  if ( sd_retval <> 0 ) then
    LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Error reading CRC of config data");
    return;
  end_if;
  
  // save crc and remember the time
  ud_ConfigCRC          := p_SDOResponseBuffer^.ud_Data;
  //Show CRC on Server
  DesignerPrjConfigCRC  := ud_ConfigCRC;  
  ud_LastCrcCheck       := ops.tAbsolute;
  b_CheckCRC            := TRUE;
  
  //read length of whole config data
  
  //send request and receive data
  sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                              , p_SDOResponseBuffer := p_SDOResponseBuffer
                              , ud_Address          := SDO_ADDRESS_CONFIG_DATA + SDO_OFFSET_CONFIG_LEN_ALL
                              , us_Length           := 4
                              );

  //no response
  if ( sd_retval <> 0 ) then
    LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Error reading length of config data");
    return;
  end_if;
  
  //no config data available
  if ( p_SDOResponseBuffer^.ud_Data = 16#FFFF_FFFF ) then
    LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: No config data available.");
    return;
  end_if;
  
  ud_ConfigLength := p_SDOResponseBuffer^.ud_Data;
  
  
  // get BlockType
  //send request and receive data
  sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                              , p_SDOResponseBuffer := p_SDOResponseBuffer
                              , ud_Address          := SDO_ADDRESS_CONFIG_DATA + SDO_OFFSET_CONFIG_BLOCKTYPE
                              , us_Length           := 4
                              );
  //no response, error
  if ( sd_retval <> 0 ) then
    LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Error getting the block type of the header");
    return;
  end_if;  

  ud_ContainerBlockType := p_SDOResponseBuffer^.ud_Data;

  // check if it's a new version of the configuration
  if (ud_ContainerBlockType = BLKTYPE_CFG_CONTAINER_V3)       |
     (ud_ContainerBlockType = BLKTYPE_CFG_CONTAINER_V3_SLAVE)     |
     (ud_ContainerBlockType = BLKTYPE_CFG_CONTAINER_V3_SLAVE_OPTIONAL) then

    //read dynamic header length (how many data are attached to the header)
    
    //send request and receive data
    sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                , p_SDOResponseBuffer := p_SDOResponseBuffer
                                , ud_Address          := SDO_ADDRESS_CONFIG_DATA + SDO_OFFSET_CONFIG_LEN_HEAD
                                , us_Length           := 4
                                );

    //no response
    if ( sd_retval <> 0 ) then
      LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Error reading length of dynamic header data");
      return;
    end_if;

    // plausibility check for data length
    if p_SDOResponseBuffer^.ud_Data > 1000 then
      sd_retval := -1;
      LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Invalid length of dynamic header data");
      return;
    end_if;


    // the length info contains: size of length info + size of time info + size of additional data

    //start address of first list: address of dynamic length + length according to length info
    ud_ListBaseAddress := SDO_ADDRESS_CONFIG_DATA + SDO_OFFSET_CONFIG_LEN_HEAD + p_SDOResponseBuffer^.ud_Data;
    
    // if we got at least 4 byte additional header data, it's the version of the dynamic parameters => read it
    if p_SDOResponseBuffer^.ud_Data >= 12 then
      //send request and receive data
      sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                  , p_SDOResponseBuffer := p_SDOResponseBuffer
                                  , ud_Address          := SDO_ADDRESS_CONFIG_DATA + SDO_OFFSET_CONFIG_LEN_HEAD + 8
                                  , us_Length           := 4
                                  );

      //no response
      if ( sd_retval <> 0 ) then
        LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Error reading length of dynamic header data");
        return;
      end_if;
      
      hd_DynParaVersion := p_SDOResponseBuffer^.ud_Data;
    else
      LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Data structure error in config! No bytes for the dynamic parameter version (according to length info)!");
      return;
    end_if;
  else
    // old version => no dynamic header, the first list starts where the dynamic header length would be

    //start address of first list: address of time info + size of time info
    ud_ListBaseAddress := SDO_ADDRESS_CONFIG_DATA + SDO_OFFSET_CONFIG_LEN_HEAD + sizeof(UDINT);
  end_if;

  GotOwnPath := FALSE;
  
  //highest address for config data
  ud_ListAddressMax := SDO_ADDRESS_CONFIG_DATA + SDO_OFFSET_CONFIG_LEN_ALL + ud_ConfigLength;

  //max. length of data to read with one request
  us_DataLength_Max := SDO_MAX_LENGTH - sizeof(SDORespReadConfig) + sizeof(SDORespReadConfig.ud_Data);
  
  
  while ( ud_ListBaseAddress < ud_ListAddressMax ) do
    
    //first read length of path in list-header     
      
    //read path in list-header
    sd_retval := ReadModulePath ( p_SDORequestBuffer          := p_SDORequestBuffer
                                , p_SDOResponseBuffer         := p_SDOResponseBuffer
                                , p_ud_Address                := #ud_ListBaseAddress
                                , pModule                     := pListHeader
                                , p_ud_ModulePathLen_Max      := #ud_ListHeaderPathLen_Max
                                , p_ud_ModulePathCompLen_Max  := #ud_ListHeaderPathCompLen_Max
                                , us_SDOMaxDataSize           := us_DataLength_Max
                                );

    //no response, error
    if ( sd_retval <> 0 ) then
      LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Error reading module path out of config data");
      return;
    end_if;

    // remember our own uncompressed path (first listheader path in the memory)
    if pListHeader^.p_us_Path & (GotOwnPath = FALSE) then
      GotOwnPath := TRUE;

      // remember the path
      _memcpy(ptr1:=#PathOfThisCPU[0], ptr2:=pListHeader^.p_us_Path, cntr:=(pListHeader^.p_us_Path$^UINT)^ + 2);      
    end_if;

    //read length of download data in list-header (=LengthOverall) and save address
    //to calculate later the address of next list-header
    //address = last address + 4 byte (CRC)
    ud_ListLength_Address := ud_ListBaseAddress + 4;
    
    //send request and receive data
    sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                , p_SDOResponseBuffer := p_SDOResponseBuffer
                                , ud_Address          := ud_ListLength_Address
                                , us_Length           := 4
                                );

    //no response
    if ( sd_retval <> 0 ) then
      LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Failed to read out the length of the download data within the configuration");
      return;
    end_if;
    
    //save length of list
    ud_ListLength := p_SDOResponseBuffer^.ud_Data;
    
    //read first opcode in interpreter list
    
    //                                                   v
    //address of LengthOverall + 4 bytes (LengthOverall, BlockType, ModuleID)
    ud_Address := ud_ListLength_Address + 4;

    // get BlockType
    //send request and receive data
    sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                , p_SDOResponseBuffer := p_SDOResponseBuffer
                                , ud_Address          := ud_Address
                                , us_Length           := 4
                                );
    //no response, error
    if ( sd_retval <> 0 ) then
      LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Error getting the block type");
      return;
    end_if;  

    ud_ActBlockType := p_SDOResponseBuffer^.ud_Data;

    case ud_ActBlockType of
//**********************************************************************************************************************************************************
      BLKTYPE_CFG_CPU, 
      BLKTYPE_CFG_CPU_OPTIONAL , // if we don't need data from an external cpu
      BLKTYPE_CFG_MASTER_CPU: 
        //add other CPUs to routing table
  
        // if there is a valid module path
        if pListHeader^.p_us_Path <> NIL then
          //add module to routing tabs
          sd_retval := AddModuleToRoutingTabs ( pModule       := pListHeader
                                              , pListHeader   := pListHeader
                                              , b_IsOptional  := (ud_ActBlockType = BLKTYPE_CFG_CPU_OPTIONAL)
                                              );
          
          if (sd_retval <> 0 ) then
            if ( ClassState <> _ModFromCfgNotFound ) then
              LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Failed to add cpu module to routing tabs");
              return;
            end_if;
          end_if;
        end_if;

//**********************************************************************************************************************************************************
      BLKTYPE_CFG_SLAVE_COMPR, 
      BLKTYPE_CFG_SLAVE_COMPR_OPTIONAL: //Blocktyp der über die komprimierte Gesamtkonfiguration einer Slave-CPU gegeben wird
        //add other CPUs to routing table

        // if there is a valid module path
        if pListHeader^.p_us_Path <> NIL then
          //add module to routing tabs
          sd_retval := AddModuleToRoutingTabs ( pModule       := pListHeader
                                              , pListHeader   := pListHeader
                                              , b_IsOptional  := (ud_ActBlockType = BLKTYPE_CFG_SLAVE_COMPR_OPTIONAL)
                                              );
          
          if (sd_retval <> 0 ) then
            if ( ClassState <> _ModFromCfgNotFound ) then
              LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Slave Config Read Error: Failed to add cpu module to routing tabs");
              return;
            end_if;
          end_if;
          
          // we skip the config till we get to the interface information of this slave (if it's the source of an interface frame we have to remember it)

          //address of LengthOverall + 3 * 4 bytes (LengthOverall, BlockType, ModuleID) => now the address points to FUB offset
          ud_Address := ud_ListLength_Address + 12;
          
          //skip FUB offset
          ud_Address += 4;
          
          // get no of FUB´s
          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );
          //no response, error
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Slave Config Read Error: Error getting the FUB number");
            return;
          end_if;  

          ud_TmpCnt := p_SDOResponseBuffer^.ud_Data;
          
          // skip no of FUB´s and FUB´s
          ud_Address += (4 + (ud_TmpCnt * 4));

          // get length of path
          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );
          //no response, error
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Slave Config Read Error: Error getting the path length");
            return;
          end_if;  

          ud_TmpCnt := p_SDOResponseBuffer^.ud_Data;
          
          // skip length of path and the path
          ud_Address += (4 + ud_TmpCnt);

          // get length of comp path
          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );
          //no response, error
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Slave Config Read Error: Error getting the comp path length");
            return;
          end_if;  

          ud_TmpCnt := p_SDOResponseBuffer^.ud_Data;
          
          // skip length of comp path and the comp path
          ud_Address += (4 + ud_TmpCnt);

          // skip CRC and LengthOverall to get to the Blocktyp (Modul-Downloaddaten)
          ud_Address += 8;

          // get the block type
          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );
          //no response, error
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Slave Config Read Error: Error getting the block type of a slave config");
            return;
          end_if;  

          ud_TmpCnt := p_SDOResponseBuffer^.ud_Data;

          // check if it's a new version of the configuration
          if (ud_TmpCnt = BLKTYPE_CFG_CONTAINER_V3)       |
             (ud_TmpCnt = BLKTYPE_CFG_CONTAINER_V3_SLAVE)     |
             (ud_TmpCnt = BLKTYPE_CFG_CONTAINER_V3_SLAVE_OPTIONAL) then

            // skip blocktype to get to the dynamic header length (how many data are attached to the header)
            ud_Address += 4;

            //send request and receive data
            sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                        , p_SDOResponseBuffer := p_SDOResponseBuffer
                                        , ud_Address          := ud_Address
                                        , us_Length           := 4
                                        );

            //no response
            if ( sd_retval <> 0 ) then
              LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Error reading length of dynamic header data of a slave config");
              return;
            end_if;

            // plausibility check for data length
            if p_SDOResponseBuffer^.ud_Data > 1000 then
              sd_retval := -1;
              LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Invalid length of dynamic header data of a slave config");
              return;
            end_if;


            // the length info contains: size of length info + size of time info + size of additional data
            
            // skip the additional data to get to the path length
            ud_Address += p_SDOResponseBuffer^.ud_Data;
          else
            // old version => no dynamic header, so we skip only blocktype and time info
            ud_Address += 8;
          end_if;

          // get the path length
          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );
          //no response, error
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Slave Config Read Error: Error getting the path length");
            return;
          end_if;  

          ud_TmpCnt := p_SDOResponseBuffer^.ud_Data;

          // skip length of path and the path
          ud_Address += (4 + ud_TmpCnt);

          // get length of comp path
          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );
          //no response, error
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Slave Config Read Error: Error getting the comp path length");
            return;
          end_if;  

          ud_TmpCnt := p_SDOResponseBuffer^.ud_Data;

          // skip length of comp path and the comp path
          ud_Address += (4 + ud_TmpCnt);

          // skip CRC, LengthOverall, Blocktyp (Modul-Downloaddaten), ModuleID
          ud_Address += 16;
          
          // get the InterfaceCRC
          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );
          //no response, error
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Slave Config Read Error: Error getting the Inteface-CRC");
            return;
          end_if;  

          TmpCRC := p_SDOResponseBuffer^.ud_Data;

          
          //add slave information to config
          AddSlaveToCfg ( pModule       := pListHeader
                        , b_IsOptional  := (ud_ActBlockType = BLKTYPE_CFG_SLAVE_COMPR_OPTIONAL)
                        , b_IsInterface := (TmpCRC <> 0)
                        , InterfaceCRC  := TmpCRC
                        );

        end_if;

//**********************************************************************************************************************************************************
      BLKTYPE_CFG_REV: // revision
        
        // check if the list is long enough for a String (more bytes than just the header)
        if ud_ListLength > 12 then
        
          //address of LengthOverall + 3 * 4 bytes (LengthOverall, BlockType, ModuleID) => now the address points to the revision string
          ud_Address := ud_ListLength_Address + 12;
          
          //read out the string (length = LengthOverall - length header)
          
          // get memory for the string
          if pPrjNameStr = NIL then
            PrjNameMemLen := ud_ListLength$USINT - 12;
            pPrjNameStr$^void := To_StdLib.Malloc(size := PrjNameMemLen + 1);
          else
            if PrjNameMemLen <> (ud_ListLength$USINT - 12) then
              PrjNameMemLen := ud_ListLength$USINT - 12;
              pPrjNameStr$^void := To_StdLib.ReAlloc(mptr:=pPrjNameStr, newsize:=PrjNameMemLen + 1);
            end_if;
          end_if;

          // check if we got a memory
          if pPrjNameStr then

            _memset(dest:=pPrjNameStr, usByte:=0, cntr:=PrjNameMemLen+1);
           
            ud_ActStrLen  := ud_TmpStrLen := PrjNameMemLen;
            ud_TmpAddress := ud_Address;        
            
            IF p_BlockedTransferMemory = NIL THEN
              sd_retval   := -100;
              ClassState  := _MemAllocFailed;
              RETURN;
            END_IF;
            
            IF ud_BlockedTransferMemorySize < (ud_TmpStrLen + 1) THEN
              p_BlockedTransferMemory := To_StdLib.ReAlloc(mptr:=p_BlockedTransferMemory, newsize:=(ud_TmpStrLen + 1));
              IF p_BlockedTransferMemory = NIL THEN
                ud_BlockedTransferMemorySize  := 0;
                sd_retval                     := -100;
                ClassState                    := _MemAllocFailed;
                RETURN;
              ELSE
                ud_BlockedTransferMemorySize  := (ud_TmpStrLen + 1);
              END_IF;
            END_IF;

            To_StdLib.MemSet(dest:=p_BlockedTransferMemory, value:=0, size:=ud_BlockedTransferMemorySize);

            p_TmpBlockedData := p_BlockedTransferMemory;
                    
            us_BlockedTransferLength := BlockedTransferLength(ud_Datalength:=ud_TmpStrLen, us_MaxBlocklength:=60);
            
            while us_BlockedTransferLength do
            
              // get name
              sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                          , p_SDOResponseBuffer := p_SDOResponseBuffer
                                          , ud_Address          := ud_TmpAddress
                                          , us_Length           := us_BlockedTransferLength
                                          );
              //no response
              if ( sd_retval <> 0 ) then
                LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Revision Read Error: Reading Revision failed");
                return;
              end_if;

              To_StdLib.MemCpy(dest   := p_TmpBlockedData, 
                               source := #p_SDOResponseBuffer^.ud_Data, 
                               size   := us_BlockedTransferLength);
              
              p_TmpBlockedData  += us_BlockedTransferLength;
              ud_TmpAddress     += us_BlockedTransferLength;
              ud_TmpStrLen      -= us_BlockedTransferLength;
              
              us_BlockedTransferLength := BlockedTransferLength(ud_Datalength:=ud_TmpStrLen, us_MaxBlocklength:=60);
            
            end_while;
            
            To_StdLib.MemCpy(dest   := pPrjNameStr, 
                             source := p_BlockedTransferMemory, 
                             size   := PrjNameMemLen+1);

            b_GotNewRevision  := TRUE;

            // string is formed by: project name {TAB} project revision   => search for the tab
            pPrjRevStr        := pPrjNameStr; // initialize pointer, because maybe there is no content in the projectname
            pChar             := pPrjNameStr;
            while pChar^ do
              // check for tab sign
              if pChar^ = 9 then
                // at the next character our revision starts
                pPrjRevStr    := pChar + sizeof(CHAR);
                
                // we change the tab to a string termination
                pChar^        := 0;
                
                // save the length of the name and the length of the project revision
                PrjNameStrLen := pChar$UDINT - pPrjNameStr$UDINT;
                PrjRevStrLen  := PrjNameMemLen - PrjNameStrLen - sizeof(CHAR);
                exit;
              end_if;
              
              pChar += sizeof(CHAR);
            end_while;
            
            ShowProjectRevision();
          end_if;
        end_if;
        
//**********************************************************************************************************************************************************
      BLKTYPE_CFG_CRC: // CRC from Safety Application and HW-Tree
        
        // check if the list is long enough for a String (more bytes than just the header)
        if ud_ListLength > 12 then
        
          //address of LengthOverall + 3 * 4 bytes (LengthOverall, BlockType, ModuleID) => now the address points to the CRC values
          ud_Address := ud_ListLength_Address + 12;
          
          //read out the CRCs (length = 2 * 4 bytes)

          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 2*sizeof(HDINT)
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@0797 (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading CRC info of the safety designer project failed.");
            return;
          end_if;

          CRCInfo := p_SDOResponseBuffer^.ud_Data$t_CRCInfo;
          
          ApplCRC := CRCInfo.ApplCRC;
          HwCRC   := CRCInfo.HwCRC;
        end_if;    
        
//**********************************************************************************************************************************************************
      BLKTYPE_CFG_INTERFACE, 
      BLKTYPE_CFG_INTERFACE_OPTIONAL: // interface frame

        //address of LengthOverall + 3 * 4 bytes (LengthOverall, BlockType, Module ID) => points to interface CRC
        ud_Address := ud_ListLength_Address + 12;
   

//*****************************************************************************
//**   INTERFACE CRC                                                         **
//*****************************************************************************

        //send request and receive data
        sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                    , p_SDOResponseBuffer := p_SDOResponseBuffer
                                    , ud_Address          := ud_Address
                                    , us_Length           := 4
                                    );

        //no response
        if ( sd_retval <> 0 ) then
          LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Interface Config Read Error: Reading interface CRC of interface frame block failed");
          return;
        end_if;

        TempPdoConfig.InterfaceCRC := p_SDOResponseBuffer^.ud_Data;

        // skip interface crc
        ud_Address += 4;
        
        
//*****************************************************************************
//**   LENGTH OF TOPOLOGY PATH OF INTERFACE FRAME                            **
//*****************************************************************************

        //send request and receive data
        sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                    , p_SDOResponseBuffer := p_SDOResponseBuffer
                                    , ud_Address          := ud_Address
                                    , us_Length           := 4
                                    );

        //no response
        if ( sd_retval <> 0 ) then
          LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Interface Config Read Error: Reading length of topology path of interface frame block failed");
          return;
        end_if;


        // skip path length
        ud_Address += 4;
        
        us_BlockedTransferLength := p_SDOResponseBuffer^.ud_Data$USINT;


//*****************************************************************************
//**   TOPOLOGY PATH OF INTERFACE FRAME                                      **
//*****************************************************************************

        //send request and receive data
        sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                    , p_SDOResponseBuffer := p_SDOResponseBuffer
                                    , ud_Address          := ud_Address
                                    , us_Length           := us_BlockedTransferLength
                                    );

        //no response
        if ( sd_retval <> 0 ) then
          LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Interface Config Read Error: Reading topology path of interface frame block failed");
          return;
        end_if;


        // remember the destination path
        _memcpy(ptr1:=#TempPath[0], ptr2:=#p_SDOResponseBuffer^.ud_Data, cntr:=us_BlockedTransferLength);


        // skip path
        ud_Address += us_BlockedTransferLength;
        

//*****************************************************************************
//**   LENGTH OF COMPRESSED TOPOLOGY PATH OF INTERFACE FRAME                 **
//*****************************************************************************

        //send request and receive data
        sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                    , p_SDOResponseBuffer := p_SDOResponseBuffer
                                    , ud_Address          := ud_Address
                                    , us_Length           := 4
                                    );

        //no response
        if ( sd_retval <> 0 ) then
          LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Interface Config Read Error: Reading length of compressed topology path of interface frame block failed");
          return;
        end_if;


        // skip path length
        ud_Address += 4;
        
        us_BlockedTransferLength := p_SDOResponseBuffer^.ud_Data$USINT;
        

//*****************************************************************************
//**   COMPRESSED TOPOLOGY PATH OF INTERFACE FRAME                           **
//*****************************************************************************

        //send request and receive data
        sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                    , p_SDOResponseBuffer := p_SDOResponseBuffer
                                    , ud_Address          := ud_Address
                                    , us_Length           := us_BlockedTransferLength
                                    );

        //no response
        if ( sd_retval <> 0 ) then
          LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Interface Config Read Error: Reading compressed topology path of interface frame block failed");
          return;
        end_if;

        // skip path and maximum cycle time
        ud_Address += us_BlockedTransferLength + 4;


  // here starts the data area (before we read only the list header

//*****************************************************************************
//**   INTERFACE CRC                                                         **
//*****************************************************************************

        //send request and receive data
        sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                    , p_SDOResponseBuffer := p_SDOResponseBuffer
                                    , ud_Address          := ud_Address
                                    , us_Length           := 4
                                    );

        //no response
        if ( sd_retval <> 0 ) then
          LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Interface Config Read Error: Reading CRC of interface frame block failed");
          return;
        end_if;

        TempPdoConfig.InterfaceCRC := p_SDOResponseBuffer^.ud_Data;
        
        // skip interface CRC
        ud_Address += 4;


//*****************************************************************************
//**   NUMBER OF BOOL INTERFACE VARIABLES IN THE PDO                         **
//*****************************************************************************

        //send request and receive data
        sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                    , p_SDOResponseBuffer := p_SDOResponseBuffer
                                    , ud_Address          := ud_Address
                                    , us_Length           := 4
                                    );

        //no response
        if ( sd_retval <> 0 ) then
          LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Interface Config Read Error: Reading number of bool variables in the interface frame failed");
          return;
        end_if;

        BoolOuts := p_SDOResponseBuffer^.ud_Data;

        // skip bool variables
        ud_Address += 4;

//*****************************************************************************
//**   NUMBER OF DINT INTERFACE VARIABLES IN THE PDO                         **
//*****************************************************************************

        //send request and receive data
        sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                    , p_SDOResponseBuffer := p_SDOResponseBuffer
                                    , ud_Address          := ud_Address
                                    , us_Length           := 4
                                    );

        //no response
        if ( sd_retval <> 0 ) then
          LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Interface Config Read Error: Reading number of dint variables in the interface frame failed");
          return;
        end_if;

        // skip bool variables
        ud_Address += 4;

        DintOuts := p_SDOResponseBuffer^.ud_Data;

        // if there are interface variables
        if BoolOuts | DintOuts then
          // calculate the length of the interface frame
          TempPdoConfig.PdoLen              := CalcPDOLength(BoolOuts, DintOuts);

          // this is the source of the interface frame
          TempPdoConfig.SourcePathLen       := TempPath[0]$UINT + 2; 
          TempPdoConfig.pSourcePath         := #TempPath[0];

          // and the destination
          TempPdoConfig.DestPathLen         := PathOfThisCPU[0]$UINT + 2;
          TempPdoConfig.pDestPath           := #PathOfThisCPU[0];

          TempPdoConfig.Info                := 0;
          TempPdoConfig.Info.IsInterfacePDO := TRUE;
          TempPdoConfig.Info.IsOptional     := (ud_ActBlockType = BLKTYPE_CFG_INTERFACE_OPTIONAL);

          // add the interface PDO to the list
          AddPdoToCfg(TempPdoConfig);
        else
          LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Interface Config Read Error: No interface variables found in interface blocktype");
          return;
        end_if;

//**********************************************************************************************************************************************************
      BLKTYPE_CFG_MODULE, 
      BLKTYPE_CFG_MODULE_V2, 
      BLKTYPE_CFG_MODULE_OPTIONAL, 
      BLKTYPE_CFG_CONTAINER_SLAVE, 
      BLKTYPE_CFG_CONTAINER_SLAVE_OPTIONAL,
      BLKTYPE_CFG_MODULE_V3,
      BLKTYPE_CFG_MODULE_V3_OPTIONAL,
      BLKTYPE_CFG_CONTAINER_V3_SLAVE,
      BLKTYPE_CFG_CONTAINER_V3_SLAVE_OPTIONAL:      // module configurations  
        TempModuleConfig.Info               := 0;
        TempModuleConfig.DestCRCNo          := 0;
        TempModuleConfig.pDestCRCs          := NIL;
        if ud_ActBlockType = BLKTYPE_CFG_MODULE_OPTIONAL then
          TempModuleConfig.Info.IsOptional  := TRUE;
        else
          TempModuleConfig.Info.IsOptional  := FALSE;
        end_if;
       
        b_CfgTypeV2 := (ud_ActBlockType <> BLKTYPE_CFG_MODULE);

        // check if it's a V3 config, because the structure of the IO List is different
        if (ud_ActBlockType = BLKTYPE_CFG_MODULE_V3) | 
           (ud_ActBlockType = BLKTYPE_CFG_MODULE_V3_OPTIONAL) |
           (ud_ActBlockType = BLKTYPE_CFG_CONTAINER_V3_SLAVE) |
           (ud_ActBlockType = BLKTYPE_CFG_CONTAINER_V3_SLAVE_OPTIONAL) then
          b_CfgTypeV3 := TRUE;
        else
          b_CfgTypeV3 := FALSE;
        end_if;

        // if it's our own path, remember the type of module configuration
        if (PathOfThisCPU[0]$UINT = (pListHeader^.p_us_Path$^UINT)^) & (To_StdLib.MemCmp(#PathOfThisCPU[0], pListHeader^.p_us_Path, PathOfThisCPU[0]$UINT + 2) = 0) then
          // if config is already "old" dont change to "new". (can be set by block BLKTYPE_OLD_MODE_FLAG)
          if NewConfigType <> ConfigState_Old then
            NewConfigType := (b_CfgTypeV2$USINT + 1)$t_ConfigStateType;
          end_if;
        end_if;

        BoolOuts := 0;
        DintOuts := 0;

        // Remember the path (uncompressed and compressed)
        TempModuleConfig.PathLen      := pListHeader^.p_us_Path^$UINT + 2;
        TempModuleConfig.pPath        := pListHeader^.p_us_Path;

        TempModuleConfig.CompPathLen  := pListHeader^.ui_PathCompLen;
        TempModuleConfig.pCompPath    := pListHeader^.p_us_PathComp;


//*****************************************************************************
//**   LIST HEADER                                                           **
//*****************************************************************************


        //address of LengthOverall + 3 * 4 bytes (LengthOverall, BlockType, ModuleID)
        ud_Address := ud_ListLength_Address + 12;

        // only available at new modules
        if b_CfgTypeV2 then          

//*****************************************************************************
//**   INTERFACE CRC                                                         **
//*****************************************************************************

          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading interface CRC of interface frame block failed");
            return;
          end_if;

          TempPdoConfig.InterfaceCRC := p_SDOResponseBuffer^.ud_Data;

          // skip interface crc
          ud_Address += 4;
          
          
//*****************************************************************************
//**   LENGTH OF TOPOLOGY PATH OF INTERFACE FRAME                            **
//*****************************************************************************

          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading length of topology path of interface frame block failed");
            return;
          end_if;


          // skip path length
          ud_Address += 4;
          
          us_BlockedTransferLength := p_SDOResponseBuffer^.ud_Data$USINT;


//*****************************************************************************
//**   TOPOLOGY PATH OF INTERFACE FRAME                                      **
//*****************************************************************************

          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := us_BlockedTransferLength
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading topology path of interface frame block failed");
            return;
          end_if;

          // remember the destination path
          _memcpy(ptr1:=#TempPath[0], ptr2:=#p_SDOResponseBuffer^.ud_Data, cntr:=us_BlockedTransferLength);
          

          // skip path
          ud_Address += us_BlockedTransferLength;
          

//*****************************************************************************
//**   LENGTH OF COMPRESSED TOPOLOGY PATH OF INTERFACE FRAME                 **
//*****************************************************************************

          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading length of compressed topology path of interface frame block failed");
            return;
          end_if;


          // skip path length
          ud_Address += 4;
          
          us_BlockedTransferLength := p_SDOResponseBuffer^.ud_Data$USINT;
          

//*****************************************************************************
//**   COMPRESSED TOPOLOGY PATH OF INTERFACE FRAME                           **
//*****************************************************************************

          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := us_BlockedTransferLength
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading compressed topology path of interface frame block failed");
            return;
          end_if;

          ud_Address += us_BlockedTransferLength;

          // skip max. cycle time
          ud_Address += 4;        
        end_if;

        // on first 4 bytes is fix the system time
        ud_ActAddress := 4; 

        // address in memory for unsafe BDINT variables
        ud_UnsafeBDINT_Offset := 0;

//*****************************************************************************
//**   INTERPRETER CODE                                                      **
//*****************************************************************************

        //read til end-command is reached
        while ( 1 ) do
          
          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );
          //no response, error
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading next command failed");
            return;
          end_if;
          
          //end-command found
          if ( p_SDOResponseBuffer^.ud_Data = SDO_CONFIG_END_CMD ) then
            exit;
          end_if;
          
          //read next opcode
          //length of one command = 4 x 4 bytes
          ud_Address += 16;
          
          //if there is no end-command found, the returncode of response will be <> OK, when the end of config data is missed
          //In this case the loop ends with returncode <> 0.
        end_while;

        //list of I/Os starts at last address + 16 (length of end command = 4x4 bytes)
        ud_Address += 16;


//*****************************************************************************
//**   LOCAL BOOL INPUTS                                                     **
//*****************************************************************************

        //read number of local bool inputs
        
        //send request and receive data
        sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                    , p_SDOResponseBuffer := p_SDOResponseBuffer
                                    , ud_Address          := ud_Address
                                    , us_Length           := 4
                                    );

        //no response
        if ( sd_retval <> 0 ) then
          LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of local inputs failed");
          return;
        end_if;

        // remember the number
        BoolOuts += p_SDOResponseBuffer^.ud_Data;
      
        // get offset in application memory
        ud_ActAddress += p_SDOResponseBuffer^.ud_Data * 4;

        //++pr
        ud_skipLength := 4; // Anzahl Einträge
        // only available at new modules
        if b_CfgTypeV2 then          
          ud_skipLength += 12 * p_SDOResponseBuffer^.ud_Data; // QSE, Filtertime, Modulkennung(SDIAS)
        else
          ud_skipLength += 8 * p_SDOResponseBuffer^.ud_Data; // QSE, Filtertime
        end_if;

//*****************************************************************************
//**   LOCAL BOOL OUTPUTS AS INPUTS                                          **
//*****************************************************************************

        // get number of safe outputs as inputs

        //send request and receive data
        sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                    , p_SDOResponseBuffer := p_SDOResponseBuffer
                                    , ud_Address          := p_SDORequestBuffer^.ud_Address + ud_skipLength // ++pr
                                    , us_Length           := 4
                                    );

        //no response
        if ( sd_retval <> 0 ) then
          LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of safe outputs as inputs failed");
          return;
        end_if;

        // remember the number
        BoolOuts += p_SDOResponseBuffer^.ud_Data;

        // get offset in application memory
        ud_ActAddress += p_SDOResponseBuffer^.ud_Data * 4;


//*****************************************************************************
//**   SAFE BOOL OUTPUT VARIABLES                                            **
//*****************************************************************************

        // get number of safe bool output vars

        //send request and receive data
        sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                    , p_SDOResponseBuffer := p_SDOResponseBuffer
                                    , ud_Address          := p_SDORequestBuffer^.ud_Address + 4
                                    , us_Length           := 4
                                    );

        //no response
        if ( sd_retval <> 0 ) then
          LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of safe bool output vars failed");
          return;
        end_if;

        // remember the number
        BoolOuts += p_SDOResponseBuffer^.ud_Data;

        // get offset in application memory
        ud_ActAddress += p_SDOResponseBuffer^.ud_Data * 4;


        // the new container has some additional content here
        if b_CfgTypeV3 then

//*****************************************************************************
//**   LOCAL DINT INPUTS                                                     **
//*****************************************************************************

          //read number of local dint inputs
          
          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := p_SDORequestBuffer^.ud_Address + 4
                                      , us_Length           := 4
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of local DINT inputs failed");
            return;
          end_if;
          
          // remember the number
          DintOuts += p_SDOResponseBuffer^.ud_Data;
        
          // get offset in application memory
          ud_ActAddress += p_SDOResponseBuffer^.ud_Data * 4;


//*****************************************************************************
//**   LOCAL DINT OUTPUTS AS INPUTS                                          **
//*****************************************************************************

          // get number of safe dint outputs as inputs

          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := p_SDORequestBuffer^.ud_Address + 4 + 12 * p_SDOResponseBuffer^.ud_Data
                                      , us_Length           := 4
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of safe DINT outputs as inputs failed");
            return;
          end_if;

          // remember the number
          DintOuts += p_SDOResponseBuffer^.ud_Data;

          // get offset in application memory
          ud_ActAddress += p_SDOResponseBuffer^.ud_Data * 4;


        end_if;

//*****************************************************************************
//**   SAFE DINT OUTPUT VARIABLES                                            **
//*****************************************************************************

        // get number of safe dint output vars

        //send request and receive data
        sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                    , p_SDOResponseBuffer := p_SDOResponseBuffer
                                    , ud_Address          := p_SDORequestBuffer^.ud_Address + 4
                                    , us_Length           := 4
                                    );

        //no response
        if ( sd_retval <> 0 ) then
          LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of safe dint output vars failed");
          return;
        end_if;

        // only when there is a manager
        if pSafetyManagerThis then
          // remember the number
          DintOuts += p_SDOResponseBuffer^.ud_Data;

          // now we're ready to determine the PDO size of this module
          TempModuleConfig.PdoOutLen := CalcPDOLength(BoolOuts, DintOuts);
          
          // if it's our own path, remember the PDO length
          if (PathOfThisCPU[0]$UINT = (pListHeader^.p_us_Path$^UINT)^) & (To_StdLib.MemCmp(#PathOfThisCPU[0], pListHeader^.p_us_Path, PathOfThisCPU[0]$UINT + 2) = 0) then       
            MyPDOSize := TempModuleConfig.PdoOutLen;
          end_if;
        end_if;

        // get offset in application memory
        ud_ActAddress += p_SDOResponseBuffer^.ud_Data * 4;


        // special unsafe variables (not supported by old modules)
        if b_CfgTypeV2 then          

//*****************************************************************************
//**   FAST UNSAFE OUTPUT VARIABLES                                          **
//*****************************************************************************
            
          // get number of fast unsafe output vars (should be 8 or 0)

          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := p_SDORequestBuffer^.ud_Address + 4
                                      , us_Length           := 4
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of fast unsafe output vars failed");
            return;
          end_if;

          // get offset in application memory
          ud_ActAddress += p_SDOResponseBuffer^.ud_Data * 4;

          // if it's our own path, remember the fast unsafe settings
          if (PathOfThisCPU[0]$UINT = (pListHeader^.p_us_Path$^UINT)^) & (To_StdLib.MemCmp(#PathOfThisCPU[0], pListHeader^.p_us_Path, PathOfThisCPU[0]$UINT + 2) = 0) then       
            if (p_SDOResponseBuffer^.ud_Data <> 0) & (p_SDOResponseBuffer^.ud_Data <> 8) then
              b_FastUnsafeOutputsActive:= FALSE;
              
              // invalid number of fast unsafe output variables
              LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Invalid number of fast unsafe output vars (only 8 or 0 possible)");
            elsif (p_SDOResponseBuffer^.ud_Data = 8) then
              // if the client wasn't activated, we can't send anything
              if ActivateFastUnsafeIOs = 0 then
                b_FastUnsafeOutputsActive := FALSE;
                LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Configuration Error: Fast unsafe outputs configured in safety designer but not activated at hardware class");
              else
                // otherwise we remember that we found the configuration and the client is set
                b_FastUnsafeOutputsActive := TRUE;
              end_if;
            else
              // no fast outputs configured via safety designer
              b_FastUnsafeOutputsActive := FALSE;
            end_if;
          end_if;
        end_if;
        
//*****************************************************************************
//**   UNSAFE BOOL OUTPUT VARIABLES                                          **
//*****************************************************************************

        //read number of unsafe output vars
           
        //send request and receive data
        sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                    , p_SDOResponseBuffer := p_SDOResponseBuffer
                                    , ud_Address          := p_SDORequestBuffer^.ud_Address + 4
                                    , us_Length           := 4
                                    );

        //no response
        if ( sd_retval <> 0 ) then
          LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of unsafe bool output vars failed");
          return;
        end_if;

        ud_CntUnsafeOutputs := p_SDOResponseBuffer^.ud_Data;
        
        ud_Address := p_SDORequestBuffer^.ud_Address + 4;

        // skip the names of unsafe outputs
        for i := 1 to ud_CntUnsafeOutputs do
        
          // get length of Name
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );
          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading length of unsafe bool output name failed");
            return;
          end_if;

          // prepare address to get name
          ud_Address    += 4;
          
          ud_TmpStrLen  := p_SDOResponseBuffer^.ud_Data;
          ud_ActStrLen  := ud_TmpStrLen;
          ud_TmpAddress := ud_Address;        
          
          IF p_BlockedTransferMemory = NIL THEN
            sd_retval   := -100;
            ClassState  := _MemAllocFailed;
            RETURN;
          END_IF;
          
          IF ud_BlockedTransferMemorySize < (ud_TmpStrLen + 1) THEN
            p_BlockedTransferMemory := To_StdLib.ReAlloc(mptr:=p_BlockedTransferMemory, newsize:=(ud_TmpStrLen + 1));
            IF p_BlockedTransferMemory = NIL THEN
              ud_BlockedTransferMemorySize := 0;
              sd_retval   := -100;
              ClassState  := _MemAllocFailed;
              RETURN;
            ELSE
              ud_BlockedTransferMemorySize := (ud_TmpStrLen + 1);
            END_IF;
          END_IF;

          To_StdLib.MemSet(dest:=p_BlockedTransferMemory, value:=0, size:=ud_BlockedTransferMemorySize);

          p_TmpBlockedData := p_BlockedTransferMemory;
                  
          us_BlockedTransferLength := BlockedTransferLength(ud_Datalength:=ud_TmpStrLen, us_MaxBlocklength:=60);
          
          while us_BlockedTransferLength do
            
            // get name
            sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                        , p_SDOResponseBuffer := p_SDOResponseBuffer
                                        , ud_Address          := ud_TmpAddress
                                        , us_Length           := us_BlockedTransferLength
                                      );
            //no response
            if ( sd_retval <> 0 ) then
              LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading unsafe bool output name failed");
              return;
            end_if;

            To_StdLib.MemCpy(dest   := p_TmpBlockedData, 
                             source := #p_SDOResponseBuffer^.ud_Data, 
                             size   := us_BlockedTransferLength);
            
            p_TmpBlockedData  += us_BlockedTransferLength;
            ud_TmpAddress     += us_BlockedTransferLength;
            ud_TmpStrLen      -= us_BlockedTransferLength;
            
            us_BlockedTransferLength := BlockedTransferLength(ud_Datalength:=ud_TmpStrLen, us_MaxBlocklength:=60);
          
          end_while;
          
          sd_retval := AddUnsafeRoutElement(pRoutTable      := #p_UnsafeOutputsTable, 
                                            pRoutElementsNo := #ui_CntUnsafeOutputs, 
                                            ud_Address      := ud_ActAddress,
                                            ui_NameLen      := ud_ActStrLen$UINT, 
                                            pNameNewElement := p_BlockedTransferMemory$^CHAR);

          // if unsafe component not found (sd_retval <> 0), it's not problem for whole safe application

          // get offset in application memory
          ud_ActAddress += 4;

          // prepare address for next unsafe output or for number of safe inputs
          ud_Address += ud_ActStrLen;

        end_for;


        // special unsafe variables (not supported by old modules)
        if b_CfgTypeV2 then          

//*****************************************************************************
//**   UNSAFE BDINT OUTPUT VARIABLES                                         **
//*****************************************************************************

          //read number of unsafe BDINT output vars
             
          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of unsafe BDINT output vars failed");
            return;
          end_if;

          ud_CntUnsafeOutputs := p_SDOResponseBuffer^.ud_Data;
          
          ud_Address := p_SDORequestBuffer^.ud_Address + 4;
          
          if ud_CntUnsafeOutputs then
            
            //SDO request for this command has 5 bytes additional data
            pBitMasks$^void := To_StdLib.Malloc(size := ud_CntUnsafeOutputs * sizeof(BDINT));
            
            if ( pBitMasks = NIL ) then
              sd_retval  := -100;
              ClassState := _MemAllocFailed;
              LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Failed to allocate memory for the BDINT variable bitmasks");
              return;
            end_if;
            

            // get the bitmasks for the BDINT variables
            for i := 1 to ud_CntUnsafeOutputs do
            
              // get bitmask
              sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                          , p_SDOResponseBuffer := p_SDOResponseBuffer
                                          , ud_Address          := ud_Address
                                          , us_Length           := 4
                                          );
              //no response
              if ( sd_retval <> 0 ) then
                LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading bit mask of unsafe BDINT output failed");
                return;
              end_if;

              // prepare address for the next one
              ud_Address += 4;
              
              // save the bitmask for adding the rout element
              (pBitMasks + (i-1) * sizeof(BDINT))^ := p_SDOResponseBuffer^.ud_Data;
            end_for;
            
            // skip the names of unsafe outputs
            for i := 1 to ud_CntUnsafeOutputs do
            
              // get length of Name
              sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                          , p_SDOResponseBuffer := p_SDOResponseBuffer
                                          , ud_Address          := ud_Address
                                          , us_Length           := 4
                                          );
              //no response
              if ( sd_retval <> 0 ) then
                LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading length of unsafe BDINT output name failed");
                return;
              end_if;

              // prepare address to get name
              ud_Address += 4;
              
              ud_TmpStrLen  := p_SDOResponseBuffer^.ud_Data;
              ud_ActStrLen  := ud_TmpStrLen;
              ud_TmpAddress := ud_Address;        
              
              IF p_BlockedTransferMemory = NIL THEN
                sd_retval   := -100;
                ClassState  := _MemAllocFailed;
                RETURN;
              END_IF;
              
              IF ud_BlockedTransferMemorySize < (ud_TmpStrLen + 1) THEN
                p_BlockedTransferMemory := To_StdLib.ReAlloc(mptr:=p_BlockedTransferMemory, newsize:=(ud_TmpStrLen + 1));
                IF p_BlockedTransferMemory = NIL THEN
                  ud_BlockedTransferMemorySize := 0;
                  sd_retval := -100;
                  ClassState:= _MemAllocFailed;
                  RETURN;
                ELSE
                  ud_BlockedTransferMemorySize := (ud_TmpStrLen + 1);
                END_IF;
              END_IF;

              To_StdLib.MemSet(dest:=p_BlockedTransferMemory, value:=0, size:=ud_BlockedTransferMemorySize);

              p_TmpBlockedData := p_BlockedTransferMemory;
                      
              us_BlockedTransferLength := BlockedTransferLength(ud_Datalength:=ud_TmpStrLen, us_MaxBlocklength:=60);
              
              while us_BlockedTransferLength do
                
                // get name
                sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                            , p_SDOResponseBuffer := p_SDOResponseBuffer
                                            , ud_Address          := ud_TmpAddress
                                            , us_Length           := us_BlockedTransferLength
                                          );
                //no response
                if ( sd_retval <> 0 ) then
                  LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading unsafe BDINT output name failed");
                  return;
                end_if;

                To_StdLib.MemCpy(dest   := p_TmpBlockedData, 
                                 source := #p_SDOResponseBuffer^.ud_Data, 
                                 size   := us_BlockedTransferLength);
                
                p_TmpBlockedData          += us_BlockedTransferLength;
                ud_TmpAddress             += us_BlockedTransferLength;
                ud_TmpStrLen              -= us_BlockedTransferLength;
                
                us_BlockedTransferLength  := BlockedTransferLength(ud_Datalength:=ud_TmpStrLen, us_MaxBlocklength:=60);
              
              end_while;
              
              ActBitMask := (pBitMasks + (i-1) * sizeof(BDINT))^;
              
              sd_retval := AddUnsafeRoutElement(pRoutTable      := #p_UnsafeOutputsTable, 
                                                pRoutElementsNo := #ui_CntUnsafeOutputs, 
                                                ud_Address      := ud_UnsafeBDINT_Offset,
                                                ui_NameLen      := ud_ActStrLen$UINT, 
                                                pNameNewElement := p_BlockedTransferMemory$^CHAR,
                                                BitMask         := ActBitMask);

              // if unsafe component not found (sd_retval <> 0), it's not problem for whole safe application
              
              // get offset in application memory
              ud_ActAddress         += CountBits(ActBitMask) * sizeof(DINT);
              ud_UnsafeBDINT_Offset += sizeof(DINT);


              // prepare address for next unsafe output or for number of safe inputs
              ud_Address            += ud_ActStrLen;

            end_for;
            
            // free the bitmasks
            To_StdLib.Free(mptr:=pBitMasks);
          end_if;
        end_if;

//*****************************************************************************
//**   SAFE INPUT VARIABLES                                                  **
//*****************************************************************************

        // get number of safe inputs
        sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                    , p_SDOResponseBuffer := p_SDOResponseBuffer
                                    , ud_Address          := ud_Address
                                    , us_Length           := 4
                                    );

        //no response
        if ( sd_retval <> 0 ) then
          LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of safe inputs failed");
          return;
        end_if;

        //number of safe inputs
        ud_TmpCnt     := p_SDOResponseBuffer^.ud_Data;

        // get offset in application memory
        ud_ActAddress += ud_TmpCnt * 4;

        //address of path length of first safe input
        ud_Address    := p_SDORequestBuffer^.ud_Address + 4;
        
        //read path of all safe inputs and add them to routing lists
        for i := 1 to ud_TmpCnt do
          
          //read path
          sd_retval := ReadModulePath ( p_SDORequestBuffer          := p_SDORequestBuffer
                                      , p_SDOResponseBuffer         := p_SDOResponseBuffer
                                      , p_ud_Address                := #ud_Address
                                      , pModule                     := pModule
                                      , p_ud_ModulePathLen_Max      := #ud_ModulePathLen_Max
                                      , p_ud_ModulePathCompLen_Max  := #ud_ModulePathCompLen_Max
                                      , us_SDOMaxDataSize           := us_DataLength_Max
                                      );
          
          //no response, error
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading path of safe input failed");
            return;
          end_if;
          
          // if there is a valid module path
          if pModule^.p_us_Path <> NIL then
            //add module to routing tabs
            sd_retval := AddModuleToRoutingTabs ( pModule       := pModule
                                                , pListHeader   := pListHeader
                                                , b_IsOptional  := TempModuleConfig.Info.IsOptional
                                                );
            
            if (sd_retval <> 0 ) then
              if ( ClassState <> _ModFromCfgNotFound ) then
                LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Failed to add safe input module to routing tabs");
                return;
              end_if;
            end_if;
          end_if;
          
          //address of path length = last address + 2 * 4 bytes ( RemoteIndex + MaxAge)
          ud_Address += 8;
        
        end_for;

        if b_CfgTypeV3 then

//*****************************************************************************
//**   SAFE DINT INPUT VARIABLES                                             **
//*****************************************************************************

          // get number of safe DINT inputs
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of safe DINT inputs failed");
            return;
          end_if;

          //number of safe inputs
          ud_TmpCnt     := p_SDOResponseBuffer^.ud_Data;

          // get offset in application memory
          ud_ActAddress += ud_TmpCnt * 4;

          //address of path length of first safe input
          ud_Address    := p_SDORequestBuffer^.ud_Address + 4;
          
          //read path of all safe inputs and add them to routing lists
          for i := 1 to ud_TmpCnt do
            
            //read path
            sd_retval := ReadModulePath ( p_SDORequestBuffer          := p_SDORequestBuffer
                                        , p_SDOResponseBuffer         := p_SDOResponseBuffer
                                        , p_ud_Address                := #ud_Address
                                        , pModule                     := pModule
                                        , p_ud_ModulePathLen_Max      := #ud_ModulePathLen_Max
                                        , p_ud_ModulePathCompLen_Max  := #ud_ModulePathCompLen_Max
                                        , us_SDOMaxDataSize           := us_DataLength_Max
                                        );
            
            //no response, error
            if ( sd_retval <> 0 ) then
              LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading path of safe DINT input failed");
              return;
            end_if;
            
            // if there is a valid module path
            if pModule^.p_us_Path <> NIL then
              //add module to routing tabs
              sd_retval := AddModuleToRoutingTabs ( pModule       := pModule
                                                  , pListHeader   := pListHeader
                                                  , b_IsOptional  := TempModuleConfig.Info.IsOptional
                                                  );
              
              if (sd_retval <> 0 ) then
                if ( ClassState <> _ModFromCfgNotFound ) then
                  LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Failed to add safe DINT input module to routing tabs");
                  return;
                end_if;
              end_if;
            end_if;
            
            //address of path length = last address + 2 * 4 bytes ( RemoteIndex + MaxAge)
            ud_Address += 8;
          
          end_for;
        end_if;


        // only available at new modules
        if b_CfgTypeV2 then          

//*****************************************************************************
//**   SAFE INTERFACE INPUT VARIABLES                                        **
//*****************************************************************************

          // get number of safe interface input vars
          
          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of safe interface input variables failed");
            return;
          end_if;

          // skip the number
          ud_Address += 4;

          //number of safe inputs
          ud_TmpCnt := p_SDOResponseBuffer^.ud_Data;

          // get offset in application memory
          ud_ActAddress += ud_TmpCnt * 4;

          if ud_TmpCnt then
            
            for i := 0 to (ud_TmpCnt-1) do
              // get length of the uncompressed path
              
              //send request and receive data
              sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                          , p_SDOResponseBuffer := p_SDOResponseBuffer
                                          , ud_Address          := ud_Address
                                          , us_Length           := 4
                                          );

              //no response
              if ( sd_retval <> 0 ) then
                LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading length of uncompressed interface topology path failed");
                return;
              end_if;

              // skip length of top path
              ud_Address += 4;

              // skip top path
              ud_Address += p_SDOResponseBuffer^.ud_Data;

              // read length of compressed topology path

              //send request and receive data
              sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                          , p_SDOResponseBuffer := p_SDOResponseBuffer
                                          , ud_Address          := ud_Address
                                          , us_Length           := 4
                                          );

              //no response
              if ( sd_retval <> 0 ) then
                LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading length of compressed interface topology path failed");
                return;
              end_if;

              // skip length of compressed top path
              ud_Address += 4;

              // skip compressed top path and remote index and maximum age
              ud_Address += p_SDOResponseBuffer^.ud_Data + 4 + 4;            
            end_for;
          end_if;

(*
 4 Byte Anzahl
 4 Byte Länge vom Pfad, Pfad (vorne Pfad ":" dann CRC für da Interface dann bis auf 4 Byte aufgefüllt)
 4 Byte Länge vom komprimierten Pfad, komprimierter Pfad (vorne Pfad ":" dann CRC für da Interface dann bis auf 4 Byte aufgefüllt)
 4 Byte RemoteIndex
 4 Byte Maximales Alter
*)

        end_if;
        


        // only available at new containers
        if b_CfgTypeV3 then          

//*****************************************************************************
//**   SAFE DINT INTERFACE INPUT VARIABLES                                   **
//*****************************************************************************

          // get number of safe DINT interface input vars
          
          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of safe DINT interface input variables failed");
            return;
          end_if;

          // skip the number
          ud_Address += 4;

          //number of safe inputs
          ud_TmpCnt := p_SDOResponseBuffer^.ud_Data;

          // get offset in application memory
          ud_ActAddress += ud_TmpCnt * 4;

          if ud_TmpCnt then
            
            for i := 0 to (ud_TmpCnt-1) do
              // get length of the uncompressed path
              
              //send request and receive data
              sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                          , p_SDOResponseBuffer := p_SDOResponseBuffer
                                          , ud_Address          := ud_Address
                                          , us_Length           := 4
                                          );

              //no response
              if ( sd_retval <> 0 ) then
                LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading length of uncompressed interface topology path failed at safe DINT input variables");
                return;
              end_if;

              // skip length of top path
              ud_Address += 4;

              // skip top path
              ud_Address += p_SDOResponseBuffer^.ud_Data;

              // read length of compressed topology path

              //send request and receive data
              sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                          , p_SDOResponseBuffer := p_SDOResponseBuffer
                                          , ud_Address          := ud_Address
                                          , us_Length           := 4
                                          );

              //no response
              if ( sd_retval <> 0 ) then
                LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading length of compressed interface topology path failed at safe DINT input variables");
                return;
              end_if;

              // skip length of compressed top path
              ud_Address += 4;

              // skip compressed top path and remote index and maximum age
              ud_Address += p_SDOResponseBuffer^.ud_Data + 4 + 4;            
            end_for;
          end_if;

(*
 4 Byte Anzahl
 4 Byte Länge vom Pfad, Pfad (vorne Pfad ":" dann CRC für da Interface dann bis auf 4 Byte aufgefüllt)
 4 Byte Länge vom komprimierten Pfad, komprimierter Pfad (vorne Pfad ":" dann CRC für da Interface dann bis auf 4 Byte aufgefüllt)
 4 Byte RemoteIndex
 4 Byte Maximales Alter
*)

        end_if;
        
        
//*****************************************************************************
//**   FAST UNSAFE INPUT VARIABLES                                           **
//*****************************************************************************

        // only available at new modules
        if b_CfgTypeV2 then          
            
          // get number of fast unsafe intput vars (should be 8 or 0)

          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of fast unsafe intput vars failed");
            return;
          end_if;

          ud_Address += 4;

          // get offset in application memory
          ud_ActAddress += p_SDOResponseBuffer^.ud_Data * 4;

          // if it's our own path, remember the fast unsafe settings
          if (PathOfThisCPU[0]$UINT = (pListHeader^.p_us_Path$^UINT)^) & (To_StdLib.MemCmp(#PathOfThisCPU[0], pListHeader^.p_us_Path, PathOfThisCPU[0]$UINT + 2) = 0) then       
            if (p_SDOResponseBuffer^.ud_Data <> 0) & (p_SDOResponseBuffer^.ud_Data <> 8) then
              b_FastUnsafeInputsActive := FALSE;
              
              // invalid number of fast unsafe intput variables
              LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Invalid number of fast unsafe intput vars (only 8 or 0 possible)");
            elsif (p_SDOResponseBuffer^.ud_Data = 8) then
              // if the client wasn't activated, we can't send anything
              if ActivateFastUnsafeIOs = 0 then
                b_FastUnsafeInputsActive := FALSE;
                LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Configuration Error: Fast unsafe inputs configured in safety designer but not activated at hardware class");
              else
                // otherwise we remember that we found the configuration and the client is set
                b_FastUnsafeInputsActive := TRUE;
              end_if;
            else
              // no fast inputs configured via safety designer
              b_FastUnsafeInputsActive := FALSE;
              
              if (b_FastUnsafeOutputsActive = FALSE) & ActivateFastUnsafeIOs then
                LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Configuration Error: Fast unsafe outputs not configured in safety designer but activated at hardware class");
              end_if;
            end_if;
          end_if;
        end_if;

//*****************************************************************************
//**   UNSAFE BOOL INPUT VARIABLES                                           **
//*****************************************************************************

        // here we go for unsafe bool input vars
        
        // get number of unsafe input vars
        sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                    , p_SDOResponseBuffer := p_SDOResponseBuffer
                                    , ud_Address          := ud_Address
                                    , us_Length           := 4
                                    );

        //no response
        if ( sd_retval <> 0 ) then
          LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Failed to read number of unsafe input vars");
          return;
        end_if;


        ud_CntUnsafeInputs := p_SDOResponseBuffer^.ud_Data;
        
        ud_Address := p_SDORequestBuffer^.ud_Address + 4;

        // skip the names of unsafe inputs
        for i := 1 to ud_CntUnsafeInputs do
        
          // get length of Name
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );
          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading length of unsafe input name failed");
            return;
          end_if;

          // prepare address to get name
          ud_Address    += 4;
          
          ud_TmpStrLen  := p_SDOResponseBuffer^.ud_Data;
          ud_ActStrLen  := ud_TmpStrLen;
          ud_TmpAddress := ud_Address;        
          
          IF p_BlockedTransferMemory = NIL THEN
            sd_retval   := -100;
            ClassState  := _MemAllocFailed;
            RETURN;
          END_IF;
          
          IF ud_BlockedTransferMemorySize < (ud_TmpStrLen + 1) THEN
            p_BlockedTransferMemory := To_StdLib.ReAlloc(mptr:=p_BlockedTransferMemory, newsize:=(ud_TmpStrLen + 1));
            IF p_BlockedTransferMemory = NIL THEN
              ud_BlockedTransferMemorySize  := 0;
              sd_retval                     := -100;
              ClassState                    := _MemAllocFailed;
              RETURN;
            ELSE
              ud_BlockedTransferMemorySize := (ud_TmpStrLen + 1);
            END_IF;
          END_IF;

          To_StdLib.MemSet(dest:=p_BlockedTransferMemory, value:=0, size:=ud_BlockedTransferMemorySize);

          p_TmpBlockedData          := p_BlockedTransferMemory;
                  
          us_BlockedTransferLength  := BlockedTransferLength(ud_Datalength:=ud_TmpStrLen, us_MaxBlocklength:=60);
          
          while us_BlockedTransferLength do
          
          // get name
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_TmpAddress
                                      , us_Length           := us_BlockedTransferLength
                                      );
          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading unsafe input name failed");
            return;
          end_if;

            To_StdLib.MemCpy(dest   := p_TmpBlockedData, 
                             source := #p_SDOResponseBuffer^.ud_Data, 
                             size   := us_BlockedTransferLength);
            
            p_TmpBlockedData += us_BlockedTransferLength;
            ud_TmpAddress += us_BlockedTransferLength;
            ud_TmpStrLen -= us_BlockedTransferLength;
            
            us_BlockedTransferLength := BlockedTransferLength(ud_Datalength:=ud_TmpStrLen, us_MaxBlocklength:=60);
          
          end_while;
          
          sd_retval := AddUnsafeRoutElement(pRoutTable      := #p_UnsafeInputsTable, 
                                            pRoutElementsNo := #ui_CntUnsafeInputs, 
                                            ud_Address      := ud_ActAddress,
                                            ui_NameLen      := ud_ActStrLen$UINT, 
                                            pNameNewElement := p_BlockedTransferMemory$^CHAR);

          // if unsafe component not found (sd_retval <> 0), it's not problem for whole safe application

          // get offset in application memory
          ud_ActAddress += 4;

          // prepare address for next unsafe input
          ud_Address    += ud_ActStrLen;

        end_for;


        // only available at new modules
        if b_CfgTypeV2 then          

//*****************************************************************************
//**   UNSAFE BDINT INPUT VARIABLES                                          **
//*****************************************************************************

          // here we go for unsafe BDINT input vars
          
          // get number of unsafe input vars
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Failed to read number of unsafe BDINT input vars");
            return;
          end_if;


          ud_CntUnsafeInputs := p_SDOResponseBuffer^.ud_Data;
          
          ud_Address := p_SDORequestBuffer^.ud_Address + 4;

          if ud_CntUnsafeInputs then
            
            //SDO request for this command has 5 bytes additional data
            pBitMasks$^void := To_StdLib.Malloc(size := ud_CntUnsafeInputs * sizeof(BDINT));
            
            if ( pBitMasks = NIL ) then
              sd_retval                         := -100;
              ClassState := _MemAllocFailed;
              LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Failed to allocate memory for the BDINT variable bitmasks");
              return;
            end_if;
            

            // get the bitmasks for the BDINT variables
            for i := 1 to ud_CntUnsafeInputs do
            
              // get bitmask
              sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                          , p_SDOResponseBuffer := p_SDOResponseBuffer
                                          , ud_Address          := ud_Address
                                          , us_Length           := 4
                                          );
              //no response
              if ( sd_retval <> 0 ) then
                LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading bit mask of unsafe BDINT input failed");
                return;
              end_if;

              // prepare address for the next one
              ud_Address += 4;
              
              // save the bitmask for adding the rout element
              (pBitMasks + (i-1) * sizeof(BDINT))^ := p_SDOResponseBuffer^.ud_Data;
            end_for;
            
            // get the names of unsafe inputs
            for i := 1 to ud_CntUnsafeInputs do
            
              // get length of Name
              sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                          , p_SDOResponseBuffer := p_SDOResponseBuffer
                                          , ud_Address          := ud_Address
                                          , us_Length           := 4
                                          );
              //no response
              if ( sd_retval <> 0 ) then
                LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading length of unsafe BDINT input name failed");
                return;
              end_if;

              // prepare address to get name
              ud_Address += 4;
              
              ud_TmpStrLen := p_SDOResponseBuffer^.ud_Data;
              ud_ActStrLen := ud_TmpStrLen;
              ud_TmpAddress := ud_Address;        
              
              IF p_BlockedTransferMemory = NIL THEN
                sd_retval := -100;
                ClassState := _MemAllocFailed;
                RETURN;
              END_IF;
              
              IF ud_BlockedTransferMemorySize < (ud_TmpStrLen + 1) THEN
                p_BlockedTransferMemory := To_StdLib.ReAlloc(mptr:=p_BlockedTransferMemory, newsize:=(ud_TmpStrLen + 1));
                IF p_BlockedTransferMemory = NIL THEN
                  ud_BlockedTransferMemorySize  := 0;
                  sd_retval                     := -100;
                  ClassState                    := _MemAllocFailed;
                  RETURN;
                ELSE
                  ud_BlockedTransferMemorySize := (ud_TmpStrLen + 1);
                END_IF;
              END_IF;

              To_StdLib.MemSet(dest:=p_BlockedTransferMemory, value:=0, size:=ud_BlockedTransferMemorySize);

              p_TmpBlockedData          := p_BlockedTransferMemory;
                      
              us_BlockedTransferLength  := BlockedTransferLength(ud_Datalength:=ud_TmpStrLen, us_MaxBlocklength:=60);
              
              while us_BlockedTransferLength do
                
                // get name
                sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                            , p_SDOResponseBuffer := p_SDOResponseBuffer
                                            , ud_Address          := ud_TmpAddress
                                            , us_Length           := us_BlockedTransferLength
                                          );
                //no response
                if ( sd_retval <> 0 ) then
                  LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading unsafe BDINT input name failed");
                  return;
                end_if;

                To_StdLib.MemCpy(dest   := p_TmpBlockedData, 
                                 source := #p_SDOResponseBuffer^.ud_Data, 
                                 size   := us_BlockedTransferLength);
                
                p_TmpBlockedData          += us_BlockedTransferLength;
                ud_TmpAddress             += us_BlockedTransferLength;
                ud_TmpStrLen              -= us_BlockedTransferLength;
                
                us_BlockedTransferLength  := BlockedTransferLength(ud_Datalength:=ud_TmpStrLen, us_MaxBlocklength:=60);
              
              end_while;
              
              ActBitMask := (pBitMasks + (i-1) * sizeof(BDINT))^;
              
              sd_retval := AddUnsafeRoutElement(pRoutTable      := #p_UnsafeInputsTable, 
                                                pRoutElementsNo := #ui_CntUnsafeInputs, 
                                                ud_Address      := ud_UnsafeBDINT_Offset,
                                                ui_NameLen      := ud_ActStrLen$UINT, 
                                                pNameNewElement := p_BlockedTransferMemory$^CHAR,
                                                BitMask         := ActBitMask);

              // if unsafe component not found (sd_retval <> 0), it's not problem for whole safe application

              // get offset in application memory
              ud_ActAddress         += CountBits(ActBitMask) * sizeof(DINT);
              ud_UnsafeBDINT_Offset += sizeof(DINT);

              // prepare address for next unsafe output or for number of constants
              ud_Address += ud_ActStrLen;

            end_for;
            
            // free the bitmasks
            To_StdLib.Free(mptr:=pBitMasks);
          end_if;


//*****************************************************************************
//**   CONSTANTS                                                             **
//*****************************************************************************

          // constants

          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of constants failed");
            return;
          end_if;

          // skip number of constants
          ud_Address += 4;

          // skip constants
          ud_Address += p_SDOResponseBuffer^.ud_Data * 4;

          
          if b_CfgTypeV3 then
          
//*****************************************************************************
//**   DINT CONSTANTS                                                        **
//*****************************************************************************

            // constants

            //send request and receive data
            sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                        , p_SDOResponseBuffer := p_SDOResponseBuffer
                                        , ud_Address          := ud_Address
                                        , us_Length           := 4
                                        );

            //no response
            if ( sd_retval <> 0 ) then
              LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of DINT constants failed");
              return;
            end_if;

            // skip number of dint constants
            ud_Address += 4;

            // skip constants (8 byte per DINT constant)
            ud_Address += p_SDOResponseBuffer^.ud_Data * 8;

          end_if;

//*****************************************************************************
//**   LOCAL OUTPUTS                                                         **
//*****************************************************************************

          // local outputs
          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of local outputs failed");
            return;
          end_if;

          // skip number of local outputs
          ud_Address += 4;

          // skip local outputs
          //++pr
          // only available at new modules
          if b_CfgTypeV2 then          
            ud_Address += p_SDOResponseBuffer^.ud_Data * 8; // Used-Flag, Modulkennung(SDIAS)
          else
            ud_Address += p_SDOResponseBuffer^.ud_Data * 4; // Used-Flag
          end_if;
          
          
          if b_CfgTypeV3 then
          
//*****************************************************************************
//**   LOCAL DINT OUTPUTS                                                    **
//*****************************************************************************

            // local outputs
            //send request and receive data
            sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                        , p_SDOResponseBuffer := p_SDOResponseBuffer
                                        , ud_Address          := ud_Address
                                        , us_Length           := 4
                                        );

            //no response
            if ( sd_retval <> 0 ) then
              LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of local outputs failed");
              return;
            end_if;

            // skip number of local outputs
            ud_Address += 4;

            // skip local outputs
            //++pr
            // only available at new modules
            if b_CfgTypeV2 then          
              ud_Address += p_SDOResponseBuffer^.ud_Data * 8; // Used-Flag, Modulkennung(SDIAS)
            else
              ud_Address += p_SDOResponseBuffer^.ud_Data * 4; // Used-Flag
            end_if;
            
          end_if;


//*****************************************************************************
//**   SAFE BOOL INTERFACE OUTPUT VARIABLES                                  **
//*****************************************************************************

          // safe bool interface output vars
          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of safe BOOL interface output variables failed");
            return;
          end_if;

          // skip safe BOOL interface output variables
          ud_Address += 4;

          // count the interface output variables
          BoolOuts := p_SDOResponseBuffer^.ud_Data;


//*****************************************************************************
//**   SAFE DINT INTERFACE OUTPUT VARIABLES                                  **
//*****************************************************************************

          // safe dint interface output vars
          //send request and receive data
          sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                      , p_SDOResponseBuffer := p_SDOResponseBuffer
                                      , ud_Address          := ud_Address
                                      , us_Length           := 4
                                      );

          //no response
          if ( sd_retval <> 0 ) then
            LogError("@ZZZZ (SafetyCDIAS_Base::ReadSDOConfig) Config Read Error: Reading number of safe DINT interface output variables failed");
            return;
          end_if;

          // skip number of safe dint interface output vars
          ud_Address += 4;

          // count the interface output variables
          DintOuts := p_SDOResponseBuffer^.ud_Data;
          
          if b_CfgTypeV3 then

//*****************************************************************************
//**   DYNAMIC PARAMETERS (e.g. for SSI Module)                              **
//*****************************************************************************
(*
Version of Parameters is saved in hd_DynParaVersion
if it's 16#0001, then we read out the number of parameters which will follow
*)
          end_if;

          // if there are interface variables
          if BoolOuts | DintOuts then
            // calculate the length of the interface frame
            TempPdoConfig.PdoLen := CalcPDOLength(BoolOuts, DintOuts);

            TempPdoConfig.Info                := 0;
            TempPdoConfig.Info.IsInterfacePDO := TRUE;
            TempPdoConfig.Info.IsOptional     := (ud_ActBlockType = BLKTYPE_CFG_MODULE_OPTIONAL);
            
            // if it's a broadcast => mark it
            if (TempPath[0]$UINT = 2) & (TempPath[0]$HDINT = INTERFACE_FRAME_BROADCAST) then
              TempPdoConfig.Info.IFBroadCast  := TRUE;
            end_if;
            
            // this is the source of the interface frame
            TempPdoConfig.SourcePathLen := pListHeader^.p_us_Path^$UINT + 2;
            TempPdoConfig.pSourcePath   := pListHeader^.p_us_Path;

            // and the destination
            TempPdoConfig.DestPathLen   := TempPath[0]$UINT + 2;
            TempPdoConfig.pDestPath     := #TempPath[0];

            // add the interface PDO to the list
            AddPdoToCfg(TempPdoConfig);
            
            TempModuleConfig.Info.IsInterfaceSource := TRUE;
            TempModuleConfig.Info.IsInterfaceDest   := FALSE;
            TempModuleConfig.InterfaceCRC := TempPdoConfig.InterfaceCRC;
          else
            TempModuleConfig.Info.IsInterfaceSource := FALSE;
            TempModuleConfig.Info.IsInterfaceDest   := FALSE;
            TempModuleConfig.InterfaceCRC           := 0;
          end_if;
        else
          TempModuleConfig.Info.IsInterfaceSource   := FALSE;
          TempModuleConfig.Info.IsInterfaceDest     := FALSE;
          TempModuleConfig.InterfaceCRC             := 0;
        end_if;

        // if it's our own path, remember the safety number
        if (PathOfThisCPU[0]$UINT = (pListHeader^.p_us_Path$^UINT)^) & (To_StdLib.MemCmp(#PathOfThisCPU[0], pListHeader^.p_us_Path, PathOfThisCPU[0]$UINT + 2) = 0) then       
          TempModuleConfig.SafetyNbr := SafetyNumber;
        else
          TempModuleConfig.SafetyNbr := 0;
        end_if;

        // only when there is a manager
        if pSafetyManagerThis then
          AddModuleToCfg(TempModuleConfig);
        end_if;

//**********************************************************************************************************************************************************
      BLKTYPE_OLD_MODE_FLAG: // flag fore FW to use old config-mode
        // we need the old TimeSync config-type
        NewConfigType := ConfigState_Old;

//**********************************************************************************************************************************************************
      BLKTYPE_CFG_XML: // configuration for uploading the project to the safetydesigner (network placement information, names of bits,...)
        // no useful information here for us
        
//**********************************************************************************************************************************************************
    else
      // skip it = do nothing
//      TRACE("Found unhandled Blocktype in configuration");
//**********************************************************************************************************************************************************
    end_case;

    ud_ListBaseAddress := ud_ListLength_Address + ud_ListLength;
  end_while;
  
  if ( ( sd_retval = 0 ) & ( ClassState = _ModFromCfgNotFound ) ) then
    sd_retval := -1;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::SDOReadCfgRequ
	VAR_INPUT
		p_SDORequestBuffer 	  : ^SDORequReadConfig;
		p_SDOResponseBuffer 	: ^SDORespReadConfig;
		ud_Address 	          : UDINT;
		us_Length 	          : USINT;
	END_VAR
	VAR_OUTPUT
		sd_retval 	          : DINT;
	END_VAR

  //sequence number
  p_SDORequestBuffer^.StdHeader.SeqNr := us_CntSequNr;
  
  //increase counter for sequence number
  if us_CntSequNr < 16#7F then
    us_CntSequNr += 1;
  else
    us_CntSequNr := 0;
  end_if;
  
  //address 
  p_SDORequestBuffer^.ud_Address    := ud_Address;
  
  //length of expected data
  p_SDORequestBuffer^.us_Length     := us_Length;
  
  //calculate CRC (starting with length of data until the end of command)
  p_SDORequestBuffer^.StdHeader.CRC := 0;
  
  //send request
  sd_retval := SAFETY_iSendRequest( uiMaster    := 0
                                  , pucNode     := p_ObjectPath
                                  , uiInLength  := sizeof(SDORequReadConfig)
                                  , pucInput    := p_SDORequestBuffer$^USINT
                                  , uiOutLength := sizeof(SDORespReadConfig) - sizeof(SDORespReadConfig.ud_Data) + us_Length
                                  , pucOutput   := p_SDOResponseBuffer$^USINT
                                  );
                                  
  //no response
  if ( sd_retval <> 0 ) then
    LogError("@ZZZZ (SafetyCDIAS_Base::SDOReadCfgRequ) SAFETY_iSendRequest failed");
    
    // we remember to retry in a few seconds
    b_ReadConfigFailed := TRUE;
    return;
  end_if;

  //check sequence number to exclude a possible wrong response
  if ( p_SDORequestBuffer^.StdHeader.SeqNr <> p_SDOResponseBuffer^.StdHeader.SeqNr ) then
    // we remember to retry in a few seconds
    b_ReadConfigFailed := TRUE;
    //log not routable SDOs
    LogValue("@ZZZZ (SafetyCDIAS_Base::SDOReadCfgRequ) Invalid Sequence number in SDO Standard Response. Got {0} instead of expected {1}", to_udint(p_SDOResponseBuffer^.StdHeader.SeqNr), to_udint(p_SDORequestBuffer^.StdHeader.SeqNr));
    return;
  end_if;
    
  //check returncode of SDO
  if ( p_SDOResponseBuffer^.us_Returncode <> SDO_RETCODE_OK ) then
    //log not routable SDOs
    LogValue("@ZZZZ (SafetyCDIAS_Base::SDOReadCfgRequ) Safety module {0}: Retcode of SDO Standard Response was invalid. Retcode: {1}", SafetyNumber$UDINT, to_udint(p_SDOResponseBuffer^.us_Returncode));
    
//    // when reading fails because safety designer is writing at the same moment
//    if p_SDOResponseBuffer^.us_Returncode = SDO_MICROCTRL_DIFFER then
      // we remember to retry in a few seconds
      b_ReadConfigFailed := TRUE;
//    end_if;
    
    return;
  end_if;
    
  //check length of read data
  if ( p_SDOResponseBuffer^.us_Length = 0 ) then
    LogError("@ZZZZ (SafetyCDIAS_Base::SDOReadCfgRequ) Response length is 0");
    sd_retval := -104;
    return;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::GetRoutingData
	VAR_OUTPUT
		sd_retval 	            : DINT;
	END_VAR
	VAR
		p_SDORequestBuffer 	    : ^SDORequReadConfig;
		p_SDOResponseBuffer 	  : ^SDORespReadConfig;
    Module                  : PathInfoType;
    ListHeader              : PathInfoType;
    NotAvailableStr         : ARRAY [0..99] OF CHAR;
    Time1, Time2            : UDINT;
	END_VAR

  InitPathInfo(#Module);
  InitPathInfo(#ListHeader);

  //SDO request for this command has 5 bytes additional data
  p_SDORequestBuffer$^void := To_StdLib.Malloc(size := sizeof(SDORequReadConfig));
  
  if ( p_SDORequestBuffer = NIL ) then
    State.uiIO_Flags				          := 0;
		State.uiIO_Flags.PhysicAccessOff  := 1;
    sd_retval                         := -100;
    ClassState                        := _MemAllocFailed;
    return;
  end_if;
  
  //SDO response for this command can have maximum additional data
  p_SDOResponseBuffer$^void := To_StdLib.Malloc(size := SDO_MAX_LENGTH);
  
  if ( p_SDOResponseBuffer = NIL ) then
    
    To_StdLib.Free(mptr := p_SDORequestBuffer);
    
    State.uiIO_Flags				          := 0;
		State.uiIO_Flags.PhysicAccessOff  := 1;
    sd_retval                         := -100;
    ClassState                        := _MemAllocFailed;
    return;
  end_if;

  //alloc memory for path of input-safety-module
  Module.p_us_Path$^void := To_StdLib.Malloc(size := 5);
  
  if ( Module.p_us_Path = NIL ) then
    
    To_StdLib.Free(mptr := p_SDORequestBuffer);
    To_StdLib.Free(mptr := p_SDOResponseBuffer);
    
    State.uiIO_Flags				          := 0;
		State.uiIO_Flags.PhysicAccessOff  := 1;
    sd_retval                         := -100;
    ClassState                        := _MemAllocFailed;
    return;
  end_if;

  //alloc memory for compressed path of input-safety-module
  Module.p_us_PathComp$^void := To_StdLib.Malloc(size := 5);
  
  if ( Module.p_us_PathComp = NIL ) then
    
    To_StdLib.Free(mptr := p_SDORequestBuffer);
    To_StdLib.Free(mptr := p_SDOResponseBuffer);
    To_StdLib.Free(mptr := Module.p_us_Path);

    State.uiIO_Flags				          := 0;
		State.uiIO_Flags.PhysicAccessOff  := 1;
    sd_retval                         := -100;
    ClassState                        := _MemAllocFailed;
    return;
  end_if;

  //alloc memory for path in list header
  ListHeader.p_us_Path$^void := To_StdLib.Malloc(size := 5);
  
  if ( ListHeader.p_us_Path = NIL ) then
    
    To_StdLib.Free(mptr := p_SDORequestBuffer);
    To_StdLib.Free(mptr := p_SDOResponseBuffer);
    To_StdLib.Free(mptr := Module.p_us_Path);
    To_StdLib.Free(mptr := Module.p_us_PathComp);
    
    State.uiIO_Flags				          := 0;
		State.uiIO_Flags.PhysicAccessOff  := 1;
    sd_retval                         := -100;
    ClassState                        := _MemAllocFailed;
    return;
  end_if;

  //alloc memory for path in list header
  ListHeader.p_us_PathComp$^void := To_StdLib.Malloc(size := 5);
  
  if ( ListHeader.p_us_PathComp = NIL ) then
    
    To_StdLib.Free(mptr := p_SDORequestBuffer);
    To_StdLib.Free(mptr := p_SDOResponseBuffer);
    To_StdLib.Free(mptr := Module.p_us_Path);
    To_StdLib.Free(mptr := Module.p_us_PathComp);
    To_StdLib.Free(mptr := ListHeader.p_us_Path);
    
    State.uiIO_Flags				          := 0;
		State.uiIO_Flags.PhysicAccessOff  := 1;
    sd_retval                         := -100;
    ClassState                        := _MemAllocFailed;
    return;
  end_if;
  
  b_ReadConfigFailed := FALSE;
  
  // if there is a revision in the configuration this variable changes to TRUE
  b_GotNewRevision := FALSE;

Time1 := OS_READMICROSEC();
  //read config data via SDOs and add safety modules to routing lists
  sd_retval := ReadSDOConfig( p_SDORequestBuffer      := p_SDORequestBuffer
                            , p_SDOResponseBuffer     := p_SDOResponseBuffer
                            , pModule                 := #Module
                            , pListHeader             := #ListHeader
                            );
Time2 := OS_READMICROSEC();
ud_ConfigReadTime := Time2 - Time1;

  // if there is no revision in the configuration => clear it
  if (b_GotNewRevision = FALSE) then

    // free memory, if available  
    if pPrjNameStr & pPrjRevStr then
      To_StdLib.Free(pPrjNameStr);
    end_if;

    // use local memory to show "not available"
    _strcpy(dest:=#NotAvailableStr[0], src:="<not available>");
    PrjNameMemLen := _strlen(src:=#NotAvailableStr[0]);
    PrjNameStrLen := PrjRevStrLen := PrjNameMemLen - 1;
    pPrjNameStr   := pPrjRevStr := #NotAvailableStr[0];

    // write the strings to the string objects
    ShowProjectRevision();

    // there is no memory, so reset the pointer and length informations
    pPrjNameStr   := NIL;
    pPrjRevStr    := NIL;

    PrjNameMemLen := 0;
    PrjNameStrLen := 0;
    PrjRevStrLen  := 0;
  end_if;
  
  // if reading failed, because designer is writing at the same time => we try again in a few seconds
  if b_ReadConfigFailed then
  
    // next time we check for the configured state of the cpu
    b_CheckConfigured   := TRUE;

    // check again in background
    ClassState          := _ReinitConfig;
    
    // and wait at least 3 secs
    ud_LastCheckConfig  := ops.tAbsolute;
  
  // error in configuration -> no work
  elsif ( sd_retval <> 0 ) & (ClassState <> _ReinitConfig) then
    State.uiIO_Flags                  := 0;
  
    if ClassState = _WaitForSynchronicity then
      ClassState := _UnknownCfgError;
    end_if;
  
    LogError("@ZZZZ (SafetyCDIAS_Base::GetRoutingData) Reading Safety Configuration failed!");
  else    
    // if it's still invalid, moving is possible and none of the connected modules has any reason to deactivate it (otherwise it would be inactive)
    if (b_MoveCommandInputActive = _Invalid) & (b_SafetyOnLocalCDIAS = FALSE) then
      b_MoveCommandInputActive := _Active;
    end_if;
    
    // we start the data object for continous writing to the module after we know that there is an input for this module and the move command is active
    if b_MoveCommandInputActive = _Active then
      b_StartDOs := TRUE;
      
      WalkThroughPDOMoverList(pList := #pPDOMoverListInputs, _Active);
    else
      if b_VaranAvailable & (sd_VaranType = 1) then
        MasterConnect.ResetDO( p_data_object := p_HandlePDOWrite$^DINT, us_state := VARAN_DO_NO_RUN, ud_bytes := MaxLengthPDOWrite);
      end_if;
      // tell all modules which think we can communicate via pdo mover, that this is not the case any more
      // for all module which are configured as safety inputs for this module
      // delete list with modules where communication (input) with pdo mover is defined
      WalkThroughPDOMoverList(pList := #pPDOMoverListInputs, _Inactive);
    end_if;

    if pPDOMoverListInputs then
      CleanupPDOMoverList(pList := #pPDOMoverListInputs);
    end_if;

    // if it's still invalid, moving is possible and none of the connected modules has any reason to deactivate it (otherwise it would be inactive)
    if (b_MoveCommandOutputActive = _Invalid) & (b_SafetyOnLocalCDIAS = FALSE) then
      b_MoveCommandOutputActive := _Active;
    end_if;

    // we start the data object for continous writing to the module after we know that there is an input for this module and the move command is active
    if b_MoveCommandOutputActive = _Active then
      // if the mover is active we have to activate the data objects for continous run
      if sd_VaranType = 1 then
        if b_PayloadSupport = FALSE then
          //set right address of do
          MasterConnect.SetNewDOAddressRd( p_data := pPDOReadData$^DINT, ud_address:= ( ui_MyPlace + OFFSET_SPDO_DATA ) );
        end_if;
        
        MasterConnect.ResetDO( p_data_object := p_HandlePDORead$^DINT, us_state := VARAN_DO_CONT_RUN, ud_bytes := MaxLengthPDORead);
      end_if;
      WalkThroughPDOMoverList(pList := #pPDOMoverListInputs, _Active);//ZoePat 27.12.2012 14:31  PRÜFEN OB DAS RICHTIG IST!!??!! evtl. muss Outputs hier hin...
    else
      // tell all modules which think we can communicate via pdo mover, that this is not the case any more
      // for all module which are configured as safety outputs for this module
      // delete list with modules where communication (output) with pdo mover is defined
      WalkThroughPDOMoverList(pList := #pPDOMoverListOutputs, _Inactive);
    end_if;

    if pPDOMoverListOutputs then
      CleanupPDOMoverList(pList := #pPDOMoverListOutputs);
    end_if;

    // read config succeeded, check update cycle of unsafe variables
    CheckUnsafeUpdateCycle();
    
    // last thing to do is to start realtime and cyclic work (they do nothing in _ReinitConfig state
    if ud_UnsafeVarsNotFound then
      ClassState            := _UnsafeVarNotFound;
      ud_UnsafeVarsNotFound := 0;
    else
      if us_SetBusReadyState = SetBusReadyFinished then
        // we're already synchron from a former configuration phase
        ClassState          := _SafetyClassOK;
      else
        ClassState          := _WaitForSynchronicity;
      end_if;
    end_if;
    
    // check for interface frame destination modules and mark them
    GetDestinationCRCs();
    
    // if there is a safety manager create a configuration message and send it to the safety manager
    if pSafetyManagerThis then
      CreateAndSendCfg();
    end_if;
  end_if;

  // free temporary configuration lists if there were any
  FreeCfgLists();

  //free allocated buffers
  To_StdLib.Free(mptr := p_SDORequestBuffer);
  To_StdLib.Free(mptr := p_SDOResponseBuffer);
  To_StdLib.Free(mptr := Module.p_us_Path);
  To_StdLib.Free(mptr := Module.p_us_PathComp);
  
  // maybe the listheader pointers have been already freed by ReadModulePath
  if ListHeader.p_us_Path then
    To_StdLib.Free(mptr := ListHeader.p_us_Path);
  end_if;
  if ListHeader.p_us_PathComp then
    To_StdLib.Free(mptr := ListHeader.p_us_PathComp);
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::ReadModulePath
	VAR_INPUT
		p_SDORequestBuffer 	        : ^SDORequReadConfig;
		p_SDOResponseBuffer 	      : ^SDORespReadConfig;
		p_ud_Address 	              : ^UDINT;
		pModule 	                  : ^PathInfoType;
		p_ud_ModulePathLen_Max 	    : ^UDINT;
		p_ud_ModulePathCompLen_Max 	: ^UDINT;
		us_SDOMaxDataSize 	        : USINT;
	END_VAR
	VAR_OUTPUT
		sd_retval 	                : DINT;
	END_VAR
  VAR
    ud_ModulePathLen_Act      : UDINT;
    p_ud_ModulePath_Act       : ^UDINT;
  END_VAR

  //read length of module path
      
  //send request and receive data
  sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                              , p_SDOResponseBuffer := p_SDOResponseBuffer
                              , ud_Address          := p_ud_Address^
                              , us_Length           := 4
                              );

  //no response
  if ( sd_retval <> 0 ) then
    LogError("@ZZZZ (SafetyCDIAS_Base::ReadModulePath) Failed to read length of module path");
    return;
  end_if;
  
  //length of module path
  ud_ModulePathLen_Act := p_SDOResponseBuffer^.ud_Data;
  
  //length is zero, check compressed path
  if ( ud_ModulePathLen_Act > 0 ) then
        
    //resize buffer for path, if it's too small
    if ( ud_ModulePathLen_Act > p_ud_ModulePathLen_Max^ ) then
        
      pModule^.p_us_Path$^void := To_StdLib.ReAlloc(mptr := pModule^.p_us_Path$^void, newsize := ud_ModulePathLen_Act);
         
      if ( pModule^.p_us_Path = NIL ) then
            
        State.uiIO_Flags				          := 0;
        State.uiIO_Flags.PhysicAccessOff  := 1;
        sd_retval                         := -100;
        ClassState                        := _MemAllocFailed;
        return;
      end_if;
        
      //increase max. path length
      p_ud_ModulePathLen_Max^ := ud_ModulePathLen_Act;
          
    end_if;
        
    //read path
        
    //address of first byte of path
    p_ud_Address^ += 4;
        
    //set pointer to first byte of target buffer
    p_ud_ModulePath_Act := ( pModule^.p_us_Path )$^UDINT;
        
    //read path block by block, if path is longer than max. length
    while ( ud_ModulePathLen_Act > us_SDOMaxDataSize ) do
          
      //send request and receive data
      sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                  , p_SDOResponseBuffer := p_SDOResponseBuffer
                                  , ud_Address          := p_ud_Address^
                                  , us_Length           := us_SDOMaxDataSize
                                  );

      //no response
      if ( sd_retval <> 0 ) then
        LogError("@ZZZZ (SafetyCDIAS_Base::ReadModulePath) Failed to read block of module path");
        return;
      end_if;
          
      //copy part of path
      To_StdLib.MemCpy(dest := p_ud_ModulePath_Act , source := #p_SDOResponseBuffer^.ud_Data, size := us_SDOMaxDataSize);
            
      //rest of path to be read
      ud_ModulePathLen_Act -= us_SDOMaxDataSize;
          
      //address of next block
      p_ud_Address^ += us_SDOMaxDataSize;
          
      //set pointer to next free byte of target buffer
      p_ud_ModulePath_Act += us_SDOMaxDataSize;
          
    end_while;

    //read last bytes of path
      
    //send request and receive data
    sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                , p_SDOResponseBuffer := p_SDOResponseBuffer
                                , ud_Address          := p_ud_Address^
                                , us_Length           := ud_ModulePathLen_Act$USINT
                                );

    //no response
    if ( sd_retval <> 0 ) then
      LogError("@ZZZZ (SafetyCDIAS_Base::ReadModulePath) Failed to read last bytes of module path");
      return;
    end_if;
          
    To_StdLib.MemCpy(dest := p_ud_ModulePath_Act, source := #p_SDOResponseBuffer^.ud_Data, size := ud_ModulePathLen_Act);

    //address of next byte after path
    //address of last block + length of last read block
    p_ud_Address^ += ud_ModulePathLen_Act;
  else

    if pModule^.p_us_Path <> NIL then
      To_StdLib.Free(mptr := pModule^.p_us_Path);
      pModule^.p_us_Path := NIL;
    end_if;
    
    //address of compressed path
    p_ud_Address^ += 4;
  end_if;

// ============================================================================================================================

  // compressed module path starts here

  // read length of module path
      
  // send request and receive data
  sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                              , p_SDOResponseBuffer := p_SDOResponseBuffer
                              , ud_Address          := p_ud_Address^
                              , us_Length           := 4
                              );

  //no response
  if ( sd_retval <> 0 ) then
    LogError("@ZZZZ (SafetyCDIAS_Base::ReadModulePath) Failed to read length of compressed module path");
    return;
  end_if;
  
  //length of module path
  ud_ModulePathLen_Act := p_SDOResponseBuffer^.ud_Data;
  
  pModule^.ui_PathCompLen := to_uint(ud_ModulePathLen_Act);
  
  //if length is zero, leave method
  if ( ud_ModulePathLen_Act = 0 ) then
    if pModule^.p_us_PathComp <> NIL then
      To_StdLib.Free(mptr := pModule^.p_us_PathComp);
      pModule^.p_us_PathComp := NIL;
    end_if;

    // address of CRC
    p_ud_Address^ += 4;

    return;
  end_if;

  //resize buffer for path, if it's too small
  if ( ud_ModulePathLen_Act > p_ud_ModulePathCompLen_Max^ ) then
      
    pModule^.p_us_PathComp$^void := To_StdLib.ReAlloc(mptr := pModule^.p_us_PathComp$^void, newsize := ud_ModulePathLen_Act);
       
    if ( pModule^.p_us_PathComp = NIL ) then
          
      State.uiIO_Flags				          := 0;
      State.uiIO_Flags.PhysicAccessOff  := 1;
      sd_retval                         := -100;
      ClassState                        := _MemAllocFailed;
      return;
    end_if;
      
    //increase max. path length
    p_ud_ModulePathCompLen_Max^ := ud_ModulePathLen_Act;
        
  end_if;
      
  //read path
      
  //address of first byte of path
  p_ud_Address^ += 4;

  //set pointer to first byte of target buffer
  p_ud_ModulePath_Act := pModule^.p_us_PathComp$^UDINT;

  //read path block by block, if path is longer than max. length
  while ( ud_ModulePathLen_Act > us_SDOMaxDataSize ) do
        
    //send request and receive data
    sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                                , p_SDOResponseBuffer := p_SDOResponseBuffer
                                , ud_Address          := p_ud_Address^
                                , us_Length           := us_SDOMaxDataSize
                                );

    //no response
    if ( sd_retval <> 0 ) then
      LogError("@ZZZZ (SafetyCDIAS_Base::ReadModulePath) Failed to read block of compressed module path");
      return;
    end_if;
        
    //copy part of path
    To_StdLib.MemCpy(dest := p_ud_ModulePath_Act , source := #p_SDOResponseBuffer^.ud_Data, size := us_SDOMaxDataSize);
          
    //rest of path to be read
    ud_ModulePathLen_Act -= us_SDOMaxDataSize;
        
    //address of next block
    p_ud_Address^ += us_SDOMaxDataSize;
        
    //set pointer to next free byte of target buffer
    p_ud_ModulePath_Act += us_SDOMaxDataSize;
        
  end_while;

  //read last bytes of path
    
  //send request and receive data
  sd_retval := SDOReadCfgRequ ( p_SDORequestBuffer  := p_SDORequestBuffer
                              , p_SDOResponseBuffer := p_SDOResponseBuffer
                              , ud_Address          := p_ud_Address^
                              , us_Length           := ud_ModulePathLen_Act$USINT
                              );

  //no response
  if ( sd_retval <> 0 ) then
    LogError("@ZZZZ (SafetyCDIAS_Base::ReadModulePath) Failed to read last bytes of compressed module path");
    return;
  end_if;
        
  To_StdLib.MemCpy(dest := p_ud_ModulePath_Act, source := #p_SDOResponseBuffer^.ud_Data, size := ud_ModulePathLen_Act);

  //address of next byte after path
  //address of last block + length of last read block
  p_ud_Address^ += ud_ModulePathLen_Act;
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::AddModuleToRoutingTabs
	VAR_INPUT
		pModule 	                : ^PathInfoType;
		pListHeader 	            : ^PathInfoType;
    b_IsOptional              : BOOL;
	END_VAR
	VAR_OUTPUT
		sd_retval 	              : DINT;
	END_VAR
  VAR
    p_TargetObject            : pVirtualBase;
    p_SafetyBase              : pVirtualBase;
    ud_IO_SafeNumber          : HDINT;
    ud_PDO_Buffer             : UDINT;
    pMoveCommandInputActive   : ^PDOMoveState;
    pMoveCommandOutputActive  : ^PDOMoveState;
    ud_MoveSourceDOHandle     : UDINT;
    ud_MoveSourceAddr         : UDINT;
    ud_MoveSourceOffset       : UDINT;
    MyPara 	                  : CmdStruct;
    MyResult                  : results;
  END_VAR

  // if the cpu is connected via varan there is a chance to activate the Move Command (only if all inputs for the cpu are also connected via VARAN)
  if b_VaranAvailable & (b_SafetyOnLocalCDIAS = FALSE) then
    pMoveCommandInputActive   := #b_MoveCommandInputActive;    
    pMoveCommandOutputActive  := #b_MoveCommandOutputActive;
  else
    pMoveCommandInputActive   := NIL;
    pMoveCommandOutputActive  := NIL;
  end_if;
  
  // initialize with invalid value
  ud_MoveSourceAddr := 0;

  sd_retval         := -1;
    
  //get this-pointer of object in network that is located with transfered path
  p_TargetObject    := ( MasterConnect.GetObjectThisp(p_us_ObjectPath := pModule^.p_us_Path) )$pVirtualBase;

  //this-pointer found
  if ( p_TargetObject ) then
    
    //add output module
    
    //If found this-pointer equals the own this-pointer, then the module has to be added to output-list.
    //This module (CPU) provides the safety input values for the output module (path in list-header).
    if ( p_TargetObject = this ) then

      //the output module is addressed by the ListHeaderPath     
      //get this-pointer of object in network that is located with transfered path
      p_TargetObject := ( MasterConnect.GetObjectThisp(p_us_ObjectPath := pListHeader^.p_us_Path) )$pVirtualBase;
      
      //this-pointer found
      if ( p_TargetObject ) then
      
        MyPara.uiCmd := CMD_SM_GET_MODULE_TYPE;
        sd_retval$iprStates := p_TargetObject^.NewInst(#MyPara, #MyResult);    

        //check if it's a safety module
        if ( MyResult.aData[0]$UDINT = SM_TYPE_SAFETY_MODULE ) then        
      
          //object is based on SafetyBase
          p_SafetyBase    := ( p_TargetObject )$pVirtualBase;
      
          //get pointer on PDO output buffer
          ud_PDO_Buffer   := GetPointer2PDOBuffer();

          //configure safety output module and receive safety number
          //inform the output module about safety number and object path of the safe CPU
          MyPara.uiCmd    := CMD_SM_CONFIG_SAFETY_OUTPUT;
          MyPara.aPara[0] := SafetyNumber$DINT;
          MyPara.aPara[1] := this$DINT;
          MyPara.aPara[2] := (GetPointer2PDOBuffer())$DINT;
          MyPara.aPara[3] := pModule$DINT;
          MyPara.aPara[4] := pMoveCommandOutputActive$DINT;
          MyPara.aPara[5] := ud_LocalMoveSourceAddr$DINT;
          MyPara.aPara[6] := b_IsOptional;
          if sd_VaranType = 1 then
            MyPara.aPara[7] := p_HandlePDORead$DINT;
          else
            MyPara.aPara[7] := ud_HandlePDOReadMoverDO$DINT;
          end_if;
    
          MyPara.aPara[8]     := 0$DINT;
          
          sd_retval$iprStates := p_SafetyBase^.NewInst(#MyPara, #MyResult);    

          ud_IO_SafeNumber    := MyResult.aData[0]$UDINT;
          
//          //configure safety output module and receive safety number
//          //inform the output module about safety number and object path of the safe CPU
//          ud_IO_SafeNumber := p_SafetyBase^.ConfigSafetyOutput  ( ud_SafeNrCPU    := SafetyNumber
//                                                                , ud_thisp        := this$UDINT
//                                                                , ud_p_PDOBuffer  := GetPointer2PDOBuffer()
//                                                                , pObject         := pModule
//                                                                , pMoveActive     := pMoveCommandOutputActive
//                                                                , ud_HandleSourceDO := p_HandlePDORead$UDINT  // LanSte 28.05.2013 Payload support
//                                                                , ud_MoveSourceAddr := ud_LocalMoveSourceAddr
//                                                                , ud_MoveSourceOffset:= 0 //LanSte 28.05.2013 Payload support
//                                                                , b_IsOptional := b_IsOptional
//                                                                );
    
          //output module successfully configured
          if ( ud_IO_SafeNumber <> 0 ) then

            // add thispointer to list of modules which are configured to communicate via pdo mover (output)
            if pMoveCommandOutputActive & (pMoveCommandOutputActive^ <> _Inactive) then
              AddToPDOMoverList(p_SafetyBase, #pPDOMoverListOutputs);
            end_if;

            //add module to routing table
            sd_retval := AddRoutingElement( ud_SafeNumber       := ud_IO_SafeNumber
                                          , ud_thisp            := p_SafetyBase$UDINT
                                          , pObject             := pListHeader
                                          );
          else
            sd_retval := 0; // could be an optional module
          end_if;
        else
          LogError("@ZZZZ (SafetyCDIAS_Base::AddModuleToRoutingTabs) Config Read Error: Output module: Trying to add a non-safety module to safety routing table");
          LogHWPath("HW-Path of Module: {0}", pListHeader^.p_us_Path);
        end_if;
      else
        LogError("@ZZZZ (SafetyCDIAS_Base::AddModuleToRoutingTabs) Config Read Error: Output module: No Object of HW-class found for module to be added to safety routing table");
        LogHWPath("HW-Path of Module: {0}", pListHeader^.p_us_Path);
      end_if;



    //add other cpu module

    elsif pModule = pListHeader then
    
      //the output module is addressed by the ListHeaderPath     
      //get this-pointer of object in network that is located with transfered path
      p_TargetObject := ( MasterConnect.GetObjectThisp(p_us_ObjectPath := pListHeader^.p_us_Path) )$pVirtualBase;
      
      //this-pointer found
      if ( p_TargetObject ) then
      
        //check if it's a safety module
        MyPara.uiCmd := CMD_SM_GET_MODULE_TYPE;
        sd_retval$iprStates := p_TargetObject^.NewInst(#MyPara, #MyResult);    

        if ( MyResult.aData[0]$UDINT = SM_TYPE_SAFETY_MODULE ) then        
      
          //object is based on SafetyBase
          p_SafetyBase := ( p_TargetObject )$pVirtualBase;
          
          //get safety number
          MyPara.uiCmd := CMD_SM_CONFIG_SAFETY_CPU;
          
          sd_retval$iprStates := p_SafetyBase^.NewInst(#MyPara, #MyResult);    

          ud_IO_SafeNumber := MyResult.aData[0]$UDINT;

//          ud_IO_SafeNumber := p_SafetyBase^.ConfigSafetyCpu();
    
          if ( ud_IO_SafeNumber <> 0 ) then
            
            //add module to routing table
            sd_retval := AddRoutingElement( ud_SafeNumber       := ud_IO_SafeNumber
                                          , ud_thisp            := p_SafetyBase$UDINT
                                          , pObject             := pListHeader
                                          );
          else
            LogError("@ZZZZ (SafetyCDIAS_Base::AddModuleToRoutingTabs) Config Read Error: CPU module: 0 is an invalid safety number");            
            LogHWPath("HW-Path of Module: {0}", pListHeader^.p_us_Path);

            b_ReInitMarker := TRUE;
          end_if;
        else
          LogError("@ZZZZ (SafetyCDIAS_Base::AddModuleToRoutingTabs) Config Read Error: CPU module: Trying to add a non-safety module to safety routing table");          
          LogHWPath("HW-Path of Module: {0}", pListHeader^.p_us_Path);
        end_if;
      else
        LogError("@ZZZZ (SafetyCDIAS_Base::AddModuleToRoutingTabs) Config Read Error: CPU module: No Object of HW-class found for module to be added to safety routing table");
        LogHWPath("HW-Path of Module: {0}", pListHeader^.p_us_Path);
      end_if;
      
    
    //add input module
    
    else
      //It's a safety input module, so it has to be added to safety input list.
      //check if found object represents a safety module
      MyPara.uiCmd := CMD_SM_GET_MODULE_TYPE;
      sd_retval$iprStates := p_TargetObject^.NewInst(#MyPara, #MyResult);    
      if ( MyResult.aData[0]$UDINT = SM_TYPE_SAFETY_MODULE ) then
      
        //object is based on SafetyBase
        p_SafetyBase := p_TargetObject;

        //configure safety input module and receive pointer on PDO-Buffer and safety number
        MyPara.uiCmd    := CMD_SM_CONFIG_SAFETY_INPUT;
        MyPara.aPara[0] := SafetyNumber$DINT;
        MyPara.aPara[1] := this$DINT;
        MyPara.aPara[2] := (#ud_PDO_Buffer)$DINT;
        MyPara.aPara[3] := pMoveCommandInputActive$DINT;
        MyPara.aPara[4] := (#ud_MoveSourceAddr)$DINT;
        MyPara.aPara[5] := (#ud_MoveSourceDOHandle)$DINT;
        MyPara.aPara[6] := (#ud_MoveSourceOffset)$DINT;  
        sd_retval$iprStates := p_SafetyBase^.NewInst(#MyPara, #MyResult);    

        ud_IO_SafeNumber := MyResult.aData[0]$UDINT;

//      //configure safety input module and receive pointer on PDO-Buffer and safety number
//      ud_IO_SafeNumber := p_SafetyBase^.ConfigSafetyInput ( ud_SafeNrCPU          := SafetyNumber
//                                                          , ud_thisp              := this$UDINT
//                                                          , p_PDOBuffer           := #ud_PDO_Buffer
//                                                          , pMoveActive           := pMoveCommandInputActive
//                                                          , p_ud_HandleSourceDO   := #ud_MoveSourceDOHandle
//                                                          , p_ud_MoveSourceAddr   := #ud_MoveSourceAddr
//                                                          , p_ud_MoveSourceOffset := #ud_MoveSourceOffset
//                                                          );
        //input module successfully configured
        if ( ud_IO_SafeNumber <> 0 ) then
          // only if the configuration affects our cpu, we add something to our PDO input buffer
          p_TargetObject := ( MasterConnect.GetObjectThisp(p_us_ObjectPath := pListHeader^.p_us_Path) )$pVirtualBase;

          //this-pointer found              
          if ( p_TargetObject = this ) then         

            // add thispointer to list of modules which are configured to communicate via pdo mover (input)
            if pMoveCommandInputActive & (pMoveCommandInputActive^ <> _Inactive) then
              AddToPDOMoverList(p_SafetyBase, #pPDOMoverListInputs);
            end_if;
          
            //add pointer on PDO output buffer of input module to list of incoming PDOs
          //add pointer on PDO output buffer of input module to list of incoming PDOs
          sd_retval := AddPDOToInputBuffer( ud_p2Buffer         := ud_PDO_Buffer
                                          , ud_HandleSourceDO   := ud_MoveSourceDOHandle //LanSte 28.05.2013 Payload support
                                          , ud_MoveSourceAddr   := ud_MoveSourceAddr
                                          , ud_MoveSourceOffset := ud_MoveSourceOffset //LanSte 28.05.2013 Payload support
                                          , ud_SafetyNr         := ud_IO_SafeNumber
                                          , b_IsOptional        := b_IsOptional);          else
            sd_retval := 0;
          end_if;
          
          if ( sd_retval = 0 ) then
            
            //add module to routing table
            sd_retval := AddRoutingElement( ud_SafeNumber       := ud_IO_SafeNumber
                                          , ud_thisp            := p_SafetyBase$UDINT
                                          , pObject             := pModule
                                          );
        
          else
            LogError("@ZZZZ (SafetyCDIAS_Base::AddModuleToRoutingTabs) Config Read Error: Input module: Failed to add module to input buffer");            
            LogHWPath("HW-Path of Module: {0}", pListHeader^.p_us_Path);
          end_if;
        else
          // module in configuration, which is not physically available but hw-class is placed
          sd_retval := 0; // could be an optional module
        end_if;
      else
        LogError("@ZZZZ (SafetyCDIAS_Base::AddModuleToRoutingTabs) Config Read Error: Input module: Trying to add a non-safety module to safety routing table");          
        LogHWPath("HW-Path of Module: {0}", pModule^.p_us_Path);
      end_if;
    end_if;
  else
    // module in configuration, which is not physically available and no hw-class is placed
    LogError("@ZZZZ (SafetyCDIAS_Base::AddModuleToRoutingTabs) Config Read Error: Module in safety configuration, where no HW-Class is placed (maybe optional module)");
    LogHWPath("HW-Path of Module: {0}", pModule^.p_us_Path);
    sd_retval := 0;
  end_if;  

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::GetRoutingElementByThis
	VAR_INPUT
		ud_thisp 	        : UDINT;
	END_VAR
	VAR_OUTPUT
		p_RoutElement 	  : ^RoutElement;
	END_VAR
  VAR
  	i1                : UINT;
    p_RoutElement_Act : ^RoutElement;
  END_VAR

  p_RoutElement := NIL;
  
  //set pointer on first routing element
  p_RoutElement_Act := p_RoutTable;
  
  //check each element
  for i1 := 0 to ui_CntRoutElements - 1 do 
  
    //if searched this is found, pointer on routing element is returned
    if ( p_RoutElement_Act^.ud_Thisp = ud_thisp ) then
      p_RoutElement := p_RoutElement_Act;
      return;
    end_if;
    
    //set pointer to next element
    p_RoutElement_Act += sizeof ( RoutElement );
  
  end_for;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::SDOStdRequ
	VAR_INPUT
		us_Command 	        : USINT;
		p_us_RespData 	    : ^USINT;
		us_RespLength 	    : USINT;
	END_VAR
	VAR_OUTPUT
		sd_retval 	        : DINT;
	END_VAR
  VAR
  	pSDORequestBuffer   : ^SDOStdHeader;
    pSDOResponseBuffer  : ^SDOStdResp;
    RespBuffer          : ARRAY [0..127] OF USINT;
    RequBuffer          : ARRAY [0..127] OF USINT;
    us_OutLength        : USINT;
  END_VAR

  //SDO requests for this commands don't have any further data
  pSDORequestBuffer$^void   := #RequBuffer[0];
  pSDOResponseBuffer$^void  := #RespBuffer[0];
  
  //SDO response buffer (length header + rc + data)
  us_OutLength := sizeof(SDOStdHeader) + 1 + us_RespLength;
  
  //calculate length without crc
  pSDORequestBuffer^.len    := sizeof(SDOStdHeader) - sizeof(SDOStdHeader.CRC);
  
  //type
  pSDORequestBuffer^.typ    := FRM_TYPECODE_STD;
  
  //sequence number
  pSDORequestBuffer^.SeqNr  := us_CntSequNr;
  
  //increase counter for sequence number
  if us_CntSequNr < 16#7F then
    us_CntSequNr += 1;
  else
    us_CntSequNr := 0;
  end_if;
  
  //command to inform CPU about initializing classes is ok
  pSDORequestBuffer^.cmd := us_Command;
  
  //set CRC-field to 0
  pSDORequestBuffer^.CRC := 0;
  
  //send request
  sd_retval := SAFETY_iSendRequest( uiMaster    := 0
                                  , pucNode     := p_ObjectPath
                                  , uiInLength  := sizeof(SDOStdHeader)
                                  , pucInput    := pSDORequestBuffer$^USINT
                                  , uiOutLength := us_OutLength
                                  , pucOutput   := pSDOResponseBuffer$^USINT
                                  );

  

  //no response
  if ( sd_retval = 0 ) then

    //check sequence number to exclude a possible wrong response
    if ( pSDORequestBuffer^.SeqNr <> pSDOResponseBuffer^.StdHeader.SeqNr ) then
      sd_retval := -102;
      //log not routable SDOs
      LogValue("@ZZZZ (SafetyCDIAS_Base::SDOStdRequ) Invalid Sequence number in SDO Standard Response. Got {0} instead of expected {1}", to_udint(pSDOResponseBuffer^.StdHeader.SeqNr), to_udint(pSDORequestBuffer^.SeqNr));
      
    //check returncode of SDO
    elsif ( pSDOResponseBuffer^.us_Returncode <> SDO_RETCODE_OK ) then
      //log not routable SDOs
      LogValue("@ZZZZ (SafetyCDIAS_Base::SDOStdRequ) Safety module {0}: Retcode of SDO Standard Response was invalid. Retcode: {1}", SafetyNumber$UDINT, to_udint(pSDOResponseBuffer^.us_Returncode));
      sd_retval := -103;
    end_if;
  else
    //log not routable SDOs
    LogValue("@ZZZZ (SafetyCDIAS_Base::SDOStdRequ) SAFETY_iSendRequest failed with retcode: -{0}", to_udint(ABS(sd_retval)));
  end_if;
  
  //return response
  if ( ( sd_retval = 0 ) & ( p_us_RespData <> NIL )) then
  
    To_StdLib.MemCpy(dest := p_us_RespData, source := #pSDOResponseBuffer^.us_Data, size := us_RespLength);
  
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::GetPDOInputBuffer
	VAR_INPUT
		ud_p2Buffer 	    : UDINT;
	END_VAR
	VAR_OUTPUT
		p_InputBuffer 	  : ^PDOInputBuffer;
	END_VAR
  VAR
  	i1                : UINT;
    p_InputBuffer_Act : ^PDOInputBuffer;
  END_VAR

  p_InputBuffer := NIL;
  
  if ui_cnt_PDOInputBuffer then
  
    //set pointer on first input buffer element
    p_InputBuffer_Act := #aPDOInputBuffer[0];
    
    //check each element
    for i1 := 0 to (ui_cnt_PDOInputBuffer-1) do 
    
      //if searched pointer is found, pointer on input buffer element is returned
      if ( p_InputBuffer_Act^.ud_p2Buffer = ud_p2Buffer ) then
        p_InputBuffer := p_InputBuffer_Act;
        return;
      end_if;
      
      //set pointer to next element
      p_InputBuffer_Act += sizeof ( PDOInputBuffer );
    
    end_for;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::GetThisViaServerName
	VAR_INPUT
		pObjectDotServer 	: ^CHAR;
	END_VAR
	VAR_OUTPUT
		ThisPtr 	        : pVoid;
	END_VAR
  VAR
    ChannelMode       : CHMODE;
  END_VAR
  
  ThisPtr := NIL;

  if pObjectDotServer = NIL then
    return;
  end_if;
  
  // get thispointer to server via name
  ChannelMode := _LookUpEmbed_C(pObjectDotServer, #ThisPtr, NIL);

  // check if it's a server
  case ChannelMode of
    _CH_CMD,
    _CH_SVR:
    
  else
    ThisPtr := NIL;
    LogError("@ZZZZ (SafetyCDIAS_Base::GetThisViaServerName) Couldn't get thispointer of server:");
    LogError(e_msg:=pObjectDotServer);
    ud_UnsafeVarsNotFound += 1;
  end_case;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::AddUnsafeRoutElement
	VAR_INPUT
		pRoutTable 	      : ^pUnsafeIORoutingElement;
		pRoutElementsNo 	: ^UINT;
		ud_Address 	      : UDINT;
		ui_NameLen 	      : UINT;
		pNameNewElement 	: ^CHAR;
		BitMask 	        : BDINT;
	END_VAR
	VAR_OUTPUT
		sd_retval 	      : DINT;
	END_VAR
  VAR
  	p_RoutElement     : ^UnsafeIORoutingElement;
    RemoteDomain      : USINT;
    LinearMemory      : BOOL;
  END_VAR 

  sd_retval := -1;

  // check parameters
  if (ui_NameLen = 0) | (pNameNewElement = NIL) then
    LogError("@ZZZZ (SafetyCDIAS_Base::AddUnsafeRoutElement) Invalid call parameters for the variable name (invalid configuration in safety cpu)");
    return;
  end_if;

  // on CSCP011 the SDO_COMMAND_WRITE_VALUES didn't exist, so we have to make a difference here
  if (us_Variant = CSCP011_Preliminary) | (us_Variant = CSCP011_SERIES) | (pRoutTable = #p_UnsafeOutputsTable) then
    LinearMemory := TRUE;
  else
    LinearMemory := FALSE;
  end_if;


  // if there is a domain info attached
  if (pNameNewElement^ = '@') & ((pNameNewElement + 1)^ = 'D') then
    // check if it's in the actual domain
    if (pNameNewElement + 3)^ = ':' then
      // 1 digit domain number
      RemoteDomain := (pNameNewElement + 2)^ - '0';
    elsif (pNameNewElement + 4)^ = ':' then
      // 2 digits domain number
      RemoteDomain := ((pNameNewElement + 2)^ - '0') * 10 + (pNameNewElement + 3)^ - '0';
    else
      LogError("@ZZZZ (SafetyCDIAS_Base::AddUnsafeRoutElement) Invalid domain info at unsafe variable");      
      return;
    end_if;
    
    // prepare the string (remove the domain info)
    if RemoteDomain >= 10 then
      ui_NameLen      -= 5;
      pNameNewElement += 5;
    else
      ui_NameLen      -= 4;
      pNameNewElement += 4;
    end_if;
  end_if;


  //With the first element, the table must be positioned
  if ( pRoutTable^ = NIL ) then
  
    //allocate memory for first routing element
    pRoutTable^$^void := To_StdLib.Malloc(size := sizeof(UnsafeIORoutingElement));
  
    if ( pRoutTable^ = NIL ) then
  
      State.uiIO_Flags                  := 0;
      State.uiIO_Flags.PhysicAccessOff 	:= 1;
      sd_retval                         :=-1;
      ClassState                        := _MemAllocFailed;
      return;
      
    end_if;
    
    p_RoutElement := pRoutTable^;
    
  else
    
    //add new element
    
    //add space for one element to table (linked list element for inputs and linear data area for outputs)
    if LinearMemory = FALSE then
    // search for a place
      p_RoutElement := pRoutTable^;
      while p_RoutElement^.pNext do
        p_RoutElement := p_RoutElement^.pNext;
      end_while;
      p_RoutElement^.pNext$^void := To_StdLib.Malloc(sizeof(UnsafeIORoutingElement));

      if ( p_RoutElement^.pNext = NIL ) then
      
        State.uiIO_Flags                  := 0;
        State.uiIO_Flags.PhysicAccessOff 	:= 1;
        sd_retval                         :=-1;
        ClassState                        := _MemAllocFailed;
        return;
        
      end_if;

      // set pointer to new element
      p_RoutElement := p_RoutElement^.pNext;
    else
      pRoutTable^$^void := To_StdLib.ReAlloc(mptr := pRoutTable^, newsize := ( ( pRoutElementsNo^ + 1 ) * sizeof(UnsafeIORoutingElement)));

      if ( pRoutTable^ = NIL ) then
      
        State.uiIO_Flags                  := 0;
        State.uiIO_Flags.PhysicAccessOff 	:= 1;
        sd_retval                         :=-1;
        ClassState                        := _MemAllocFailed;
        return;
        
      end_if;
      
      //set pointer to empty element on last position
      p_RoutElement := pRoutTable^ + ( pRoutElementsNo^ ) * sizeof(UnsafeIORoutingElement);
    end_if;
  end_if;  

  if p_RoutElement then
    //allocate memory for name
    p_RoutElement^.pName$^void := To_StdLib.Malloc(size := ui_NameLen);
  
    if ( p_RoutElement^.pName = NIL ) then
  
      State.uiIO_Flags                  := 0;
      State.uiIO_Flags.PhysicAccessOff 	:= 1;
      sd_retval                         :=-1;
      ClassState                        := _MemAllocFailed;
      return;
      
    end_if;

    p_RoutElement^.NameLength := ui_NameLen;
    _memcpy(ptr1:=p_RoutElement^.pName, ptr2:=pNameNewElement, cntr:=ui_NameLen);

    // unsafe bdint variables are localized in a different memory area
    if BitMask then
      p_RoutElement^.ud_Address         := SDO_ADDRESS_UNSAFE_BDINT + ud_Address;
    else
      p_RoutElement^.ud_Address         := SDO_ADDRESS_APP_DATA + ud_Address;
    end_if;
    
    p_RoutElement^.BitMask              := BitMask;
    
    // initialize with invalid
    p_RoutElement^.b_IsValid            := FALSE;
    p_RoutElement^.sd_OldValue          := (16#80000000)$DINT;
    p_RoutElement^.sd_NewValue4External := (16#80000000)$DINT;

    // remember that we haven't transmitted this value so far
    p_RoutElement^.b_AlreadyTransmitted := FALSE;

    // initialize next pointer
    p_RoutElement^.pNext                := NIL;
    
    //increase counter
    pRoutElementsNo^                    += 1;
  
    // check if name exists in PLC
    p_RoutElement^.ud_Thisp             := GetThisViaServerName(pNameNewElement)$UDINT;
    if (pRoutTable = #p_UnsafeOutputsTable) & p_RoutElement^.BitMask then
      p_RoutElement^.UnsafeType         := BDINTOutput;
    else
      p_RoutElement^.UnsafeType         := NormalUnsafe;
    end_if;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::InitPathInfo
	VAR_INPUT
		pPathInfo 	: ^PathInfoType;
	END_VAR

  pPathInfo^.p_us_Path      := NIL;
  pPathInfo^.p_us_PathComp  := NIL;
  pPathInfo^.ui_PathCompLen := 0;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::WriteTDO2Module
	VAR_INPUT
		pTDO 	: ^TDOType;
	END_VAR
#ifdef SAFETY_OVER_DIAS
  VAR
    i : DINT;
  END_VAR
#endif

  if ( State.uiIO_Flags = 0 ) then

  #ifdef SAFETY_OVER_DIAS
    #pragma message("TDO-Handling over DIAS has to be reworked!")
    if ( b_im ) then
      //copy TDO word by word
      for i := 0 to (((TDOInfo AND 16#7F)/2)-1) by 1 do 
          
        ( a_Handle_TDO_Write[i] )$^UINT^ := ( (pTDO)$^UINT + ( i * 2 ) )^;
        
      end_for;
    else
  #endif

      // responses into response buffer, request into requestbuffer (only enough place for 1)
      if pTDO^.StdHeader.Typ AND SSDO_MASK_RESPONSE then
        IF ( s_TDORingbuffer.ud_entries < ( SIZEOF( TDORingbuffer.Entry ) / SIZEOF( TDOType ) ) ) THEN
          s_TDORingbuffer.Entry[s_TDORingbuffer.ud_WritePos] :=  pTDO^;
          s_TDORingbuffer.ud_WritePos       := ( s_TDORingbuffer.ud_WritePos + 1 ) mod ( SIZEOF( TDORingbuffer.Entry ) / SIZEOF( TDOType ) );
          s_TDORingbuffer.ud_Entries        += 1;
          s_TDORingbuffer.b_ErrorTriggered  := FALSE;
        ELSIF ( s_TDORingbuffer.b_ErrorTriggered = FALSE ) THEN
          LogError("@ZZZZ (SafetyCDIAS_Base::WriteTDO2Module) [SL] Buffer for TDO-Messages is full!");
          s_TDORingbuffer.b_ErrorTriggered  := TRUE;
        END_IF;

        IF s_TDORingbuffer.ud_Entries > s_TDORingbuffer.ud_maxEntries THEN
          s_TDORingbuffer.ud_maxEntries     := s_TDORingbuffer.ud_Entries;
        END_IF;
      else
        s_TDORingbuffer.RequestTDO          := pTDO^;
        s_TDORingbuffer.b_RequestAvailable  := TRUE;
      end_if;

  #ifdef SAFETY_OVER_DIAS
    end_if;
  #endif
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::ResetConfig
  VAR
    p_SafetyBase        : pVirtualBase;
  	p_RoutElement       : ^RoutElement;
    p_UnsafeRoutElement : ^UnsafeIORoutingElement;
    i                   : UINT;
    ii                  : DINT;
		MyPara 	            : CmdStruct;
		MyResult	          : results;
  END_VAR
  
  // tell all modules, which are connected to this cpu (through the old configuration) that they should delete the cpu from their routing table
  // must be more than 1, because 1st is always own entry
  if p_RoutTable & (ui_CntRoutElements > 1) then
    //set pointer on 2nd routing element
    p_RoutElement := p_RoutTable + sizeof(RoutElement);
    for i := 1 to (ui_CntRoutElements - 1) do
      // clear everything except this object (done after the for loop)
      if p_RoutElement^.ud_Thisp <> THIS$UDINT then
        // get thispointer of routing element
        p_SafetyBase := (p_RoutElement^.ud_Thisp)$pVirtualBase;
        
        // call other safety-class to remove the safetynumber from the routing table
        MyPara.uiCmd := CMD_SM_REMOVE_CPU_FROM_TABLE;
        MyPara.aPara[0] := SafetyNumber$DINT;
        
        p_SafetyBase^.NewInst(#MyPara, #MyResult);    

//        p_SafetyBase^.RemoveCPUFromTable(ud_SafetyNr := SafetyNumber);        
      end_if;

      // free memory of compressed path
      if p_RoutElement^.p_CompressedPath then
        To_StdLib.Free(mptr:=p_RoutElement^.p_CompressedPath);
      end_if;

      // set pointer on next routing element
      p_RoutElement += sizeof(RoutElement);
    end_for;
    
    // reduce local routing table to the cpu's own entry
    ui_CntRoutElements := 1;
  end_if;

  // on CSCP011 the SDO_COMMAND_WRITE_VALUES didn't exist, so we have to make a difference here
  if (us_Variant <> CSCP011_Preliminary) & (us_Variant <> CSCP011_Preliminary) then
    while p_UnsafeInputsTable do
      p_UnsafeRoutElement := p_UnsafeInputsTable;
      p_UnsafeInputsTable := p_UnsafeInputsTable^.pNext;
      
      To_StdLib.Free(mptr:=p_UnsafeRoutElement^.pName);
      To_StdLib.Free(mptr:=p_UnsafeRoutElement);
    end_while;
  else
    // free list of unsafe elements
    if p_UnsafeInputsTable then
      To_StdLib.Free(mptr:=p_UnsafeInputsTable);
      p_UnsafeInputsTable := NIL;
    end_if;    
  end_if;
  ui_CntUnsafeInputs    := 0;

  // unsafe outputs are always in linear memory
  if p_UnsafeOutputsTable then
    To_StdLib.Free(mptr:=p_UnsafeOutputsTable);
    p_UnsafeOutputsTable := NIL;
  end_if;
  ui_CntUnsafeOutputs   := 0;
  
  // reset no of SDO input buffer
  ui_cnt_SDOInputBuffer := 0;
  
  // if the old configuration is reset, check for the configured state of the cpu
  b_CheckConfigured     := TRUE;

  if b_VaranAvailable then
    // by default the mover is invalid. it will be initialized when reading the configuration
    b_MoveCommandInputActive  := _Invalid;
    b_MoveCommandOutputActive := _Invalid;

    if b_PayloadSupport then
      
      DisableDO(ud_DOHandle := InputMovHandle$UDINT);
    
      if AdditionalSPDOs then
        for ii := 0 to (AdditionalSPDOs-1) do
          DisableDO(ud_DOHandle := aAdditionalPDOs[ii].InputMovHandle$UDINT);
        end_for;
      end_if;
    else
      
      if InputMovHandle then
        InputMovHandle^.ucCtrlStat := VARAN_DO_NO_RUN;
      end_if;
      
      if AdditionalSPDOs then
        for ii := 0 to (AdditionalSPDOs-1) do
          aAdditionalPDOs[ii].InputMovHandle^.ucCtrlStat := VARAN_DO_NO_RUN;
        end_for;
      end_if;    
    end_if;
    
  else
    // if no VARAN, we can't move the PDOs
    b_MoveCommandInputActive  := _Inactive;
    b_MoveCommandOutputActive := _Inactive;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyCDIAS_Base::MyBackground
  VAR
  	sd_retval         : DINT;
    GetStateResp      : GetStateResponseType;
    LastWriteCounter  : UDINT;
    FileHandle        : DINT;
		MyPara 	          : CmdStruct;
		MyResult	        : results;
  END_VAR

  // if any LED is active, then firmware update is not active and we can do our work
  if (VoltageOK | RunState | ServiceMode | Error) then    

    // if a quit error is pending
    if QuitComError = 2 then
      MyPara.uiCmd := CMD_SM_QUIT_ERROR_VIA_OS;
      MyPara.aPara[0] := THIS$DINT;
      MyPara.aPara[1] := SafetyNumber$DINT;
      pSafetyManagerThis^.NewInst(#MyPara, #MyResult);
  
      QuitComError := MyResult.aData[0]$DINT;
    end_if;

    if (ClassState = _ReinitConfig) then
     
      // check every second if the cpu is configured
      if b_CheckConfigured & ((ops.tAbsolute - ud_LastCheckConfig) > 3000) then
        // get state via SDO communication
        sd_retval := SDOStdRequ ( us_Command      := SDO_COMMAND_GET_STATE
                                , p_us_RespData   := ( #GetStateResp )$^USINT
                                , us_RespLength   := sizeof(GetStateResponseType)
                                );
        
        // the cpu is configured, load the new configuration
        if ( sd_retval = 0 ) & 
           (GetStateResp.ConfigState <> CFG_STATE_UNKNOWN) &
           (GetStateResp.ConfigState <> CFG_STATE_INVALID) &
           (GetStateResp.ConfigState <> CFG_STATE_NOT_CONFIGURED) then
          
          b_CheckConfigured := FALSE;
          b_GetNewConfiguration := TRUE;
        end_if;
        
        // remember the last time we checked for configurated cpu
        ud_LastCheckConfig := ops.tAbsolute;
      end_if;
        
      // if there is a new configuration => get it
      if b_GetNewConfiguration then
      
        //get configuration from safe CPU and build routing tables
        sd_retval := GetRoutingData();
        if sd_retval = 0 then
          b_GetNewConfiguration := FALSE;
          
          SendAllUnsafeValues();
        else
          LogError("@ZZZZ (SafetyCDIAS_Base::MyBackground) FAILED TO REINIT THE SAFECPU: ");
        end_if;
      end_if;
    end_if;

    // here we save the log file from the module to the harddrive (started by user)
    if DiagVars.SavingLogInProgress then
    
      case DiagVars.SavingLogSSW of

  // ********************************************************************************************************************************************
        GetLogHeader:     // get log header from module (contains size of log memory and write counter)

          // get log header via SDO communication
          sd_retval := SDORequ ( us_Command      := SDO_COMMAND_GET_LOG_HDR
                               , p_us_RequData   := #DiagVars.ucChoiceSaveLog
                               , us_RequLength   := 1
                               , p_us_RespData   := ( #DiagVars.LogHeader)$^USINT
                               , us_RespLength   := sizeof(DiagStructType.LogHeader)
                               );
          
          if ( sd_retval = 0 ) then
            DiagVars.LogMemToGet := DiagVars.LogHeader.LogMemSize;
            DiagVars.pLogFileMem$pVoid := To_StdLib.Malloc(size:=DiagVars.LogHeader.LogMemSize);
            //_memset(dest:=DiagVars.pLogFileMem$pVoid, usByte:=0, cntr:=DiagVars.LogHeader.LogMemSize);
            if DiagVars.ucChoiceSaveLog = 0 then
              DiagVars.ReadBaseAdr  := SDO_ADDRESS_LOG_UC1;
            else
              DiagVars.ReadBaseAdr  := SDO_ADDRESS_LOG_UC2;
            end_if;
            DiagVars.SavingLogSSW   := GetLogFileBlocks;
            
          end_if;

  // ********************************************************************************************************************************************
        GetLogFileBlocks: // get the log memory from the application memory of the module (every cycle only a little bit to prevent runtime error in module)
          
          // we wait here until UpdateCy finishes our work
        
  // ********************************************************************************************************************************************
        GetLogHeader2:    // get log header from module again. if write counter changed, 
                          // we repeat GetLogFileBlocks. otherwise we continue to save the file
        
          LastWriteCounter := DiagVars.LogHeader.WriteCounter;
        
          // get LogHeader
          sd_retval := SDORequ ( us_Command      := SDO_COMMAND_GET_LOG_HDR
                               , p_us_RequData   := #DiagVars.ucChoiceSaveLog
                               , us_RequLength   := 1
                               , p_us_RespData   := ( #DiagVars.LogHeader)$^USINT
                               , us_RespLength   := sizeof(DiagStructType.LogHeader)
                               );
          
          if ( sd_retval = 0 ) then
          
            // if write counter is different, repeat last step
            if DiagVars.LogHeader.WriteCounter <> LastWriteCounter then
              DiagVars.SavingLogSSW := GetLogFileBlocks;

              DiagVars.LogMemToGet := DiagVars.LogHeader.LogMemSize;
              
              // realloc memory (maybe it's a different size)
              To_StdLib.Free(mptr:=DiagVars.pLogFileMem$pVoid);
              DiagVars.pLogFileMem$pVoid := To_StdLib.Malloc(size:=DiagVars.LogHeader.LogMemSize);
            else
              // write counter is equal. continue to last step
              DiagVars.SavingLogSSW := SaveLogFile;
            end_if;
          end_if;
        
  // ********************************************************************************************************************************************
        SaveLogFile:      // save the memory to the specified file (DPNE)
          // open file (create/overwrite always)
          FileHandle := FileSys.FileOpen(filename:=#DiagVars.DPNE[0], attributes:=ATT_CREATE_ALWAYS);
          
          DiagVars.SavingLogSuccessful := 1;
          
          if FileHandle >= 0 then
            
            // save content to it
            if FileSys.FileWrite(handle:=FileHandle, buffer:=DiagVars.pLogFileMem, length:=DiagVars.LogHeader.LogMemSize) <> DiagVars.LogHeader.LogMemSize$DINT then
              // failed to write to file
              LogError("@ZZZZ (SafetyCDIAS_Base::MyBackground) Failed to write to binary LogFile");
              DiagVars.SavingLogSuccessful := -1;
            end_if;

            // close file
            FileSys.FileClose(handle:=FileHandle);
          else
            // failed to open file
            LogError("@ZZZZ (SafetyCDIAS_Base::MyBackground) Failed to open binary LogFile");
            DiagVars.SavingLogSuccessful := -1;            
          end_if;
          
          To_StdLib.Free(mptr:=DiagVars.pLogFileMem$pVoid);
          DiagVars.pLogFileMem := NIL;
          
          DiagVars.SavingLogSSW         := GetLogHeader;
          DiagVars.SavingLogInProgress  := FALSE;
        
      end_case;  
    end_if;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::RemoveCPUFromTable
	VAR_INPUT
		ud_SafetyNr 	  : HDINT;
	END_VAR
  VAR
  	p_RoutElement   : ^RoutElement;
    i               : UDINT;
    FoundIndex      : UDINT;
    pPDOInputBuffer : ^PDOInputBuffer;
    Found : BOOL;
  END_VAR

  // if we are a cpu, do nothing
  if b_CheckCRC then
    return;
  end_if;
  
  //check each element (must be more than 1, because 1st is always own entry)
  if p_RoutTable & (ui_CntRoutElements > 1) then
    //set pointer on 2nd routing element
    p_RoutElement := p_RoutTable + sizeof(RoutElement);
    for i := 1 to (ui_CntRoutElements - 1) do
    
      // if we found safenumber, delete element from table
      if ( p_RoutElement^.ud_SafeNumber = ud_SafetyNr ) then
      
        // at last element we don't need to copy data, just decrease buffersize
        if i <> (ui_CntRoutElements - 1) then
          _memcpy(p_RoutElement, p_RoutElement + sizeof(RoutElement), sizeof(RoutElement) * (ui_CntRoutElements - 1 - i));
        end_if;
        
        // free 1 element and decrease element counter
        ui_CntRoutElements -= 1;

        exit;
      end_if;
      
      // set pointer on next routing element
      p_RoutElement += sizeof(RoutElement);
    end_for;
  end_if;  
    
  // reset no of SDO input buffer
  ui_cnt_SDOInputBuffer := 0;

  if b_VaranAvailable then
    // by default the mover is invalid. it will be initialized when reading the configuration
    b_MoveCommandInputActive  := _Invalid;
    b_MoveCommandOutputActive := _Invalid;

    if InputMovHandle then    
      if b_PayloadSupport then
        DisableDO(ud_DOHandle := InputMovHandle$UDINT);
      
        if AdditionalSPDOs then
          for i := 0 to (AdditionalSPDOs-1)$UDINT do
            DisableDO(ud_DOHandle := aAdditionalPDOs[i].InputMovHandle$UDINT);
          end_for;
        end_if;
      else
        InputMovHandle^.ucCtrlStat := VARAN_DO_NO_RUN;

        if AdditionalSPDOs then
          for i := 0 to (AdditionalSPDOs-1)$UDINT do
            aAdditionalPDOs[i].InputMovHandle^.ucCtrlStat := VARAN_DO_NO_RUN;
          end_for;
        end_if;
          
      end_if;
    end_if;
  else
    // if no VARAN, we can't move the PDOs
    b_MoveCommandInputActive  := _Inactive;
    b_MoveCommandOutputActive := _Inactive;
  end_if;

  // check if we received a PDO from this CPU => if so, delete it from the PDO input buffer
  if ui_cnt_PDOInputBuffer then   
    // search for the PDO
    Found := FALSE;
    pPDOInputBuffer := #aPDOInputBuffer[0];
    for FoundIndex := 0 to (ui_cnt_PDOInputBuffer-1) do
      if pPDOInputBuffer^.ud_SafetyNr = ud_SafetyNr then
        Found := TRUE;
        exit;
      end_if;
      
      pPDOInputBuffer += sizeof(PDOInputBuffer);
    end_for;

    // if we found the PDO => remove it from memory (move the memory behind the found PDO over the place of the found PDO)
    if Found then
      // if it's last entry (no entries have to be moved) => we only have to copy some memory if it's not the last
      if FoundIndex < (ui_cnt_PDOInputBuffer-1) then
        for i := FoundIndex to (ui_cnt_PDOInputBuffer-2) do
          aPDOInputBuffer[i] := aPDOInputBuffer[i+1];
        end_for;
      end_if;
      ui_cnt_PDOInputBuffer -= 1;
    end_if;
  end_if;  

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::CheckUnsafeUpdateCycle

  // we can only use 56 byte pay load (instead of 64) because fw drops the 8 byte used for addresses in safe SDO

  if ui_CntUnsafeOutputs then
  // maximum of read variables in 1 frame is 15 (56 Bytes pay load - 1 Byte Returncode - 1 Byte Length = 54 Bytes => 13x4Bytes = 52)
    MaxVarsPerReadPackage := (SDO_MAX_LENGTH - (sizeof(SDOHeader) - sizeof(SDOHeader.SessId)) - sizeof(SDORespReadConfig.us_Returncode) - sizeof(SDORespReadConfig.us_Length)) / sizeof(DINT);
    ReadFramesNeeded := ((ui_CntUnsafeOutputs - 1) / MaxVarsPerReadPackage) + 1;
  else
    ReadFramesNeeded := 0;
  end_if;

  if ui_CntUnsafeInputs then
  // maximum of write variables in 1 frame is 14 (56 Bytes pay load - 4 Byte Address - 1 Byte Length = 51 Bytes => 12x4Bytes = 48)
    MaxVarsPerWritePackage := (SDO_MAX_LENGTH - (sizeof(SDOHeader) - sizeof(SDOHeader.SessId)) - sizeof(SDORequReadConfig.ud_Address) - sizeof(SDORequReadConfig.us_Length)) / sizeof(DINT);
    WriteFramesNeeded := ((ui_CntUnsafeInputs - 1) / MaxVarsPerWritePackage) + 1;
  else
    WriteFramesNeeded := 0;
  end_if;

  // check if user has given us enough time
  if b_VaranAvailable then
    if sd_VaranType = 2 then
      ud_TransfertimePerPackage := SDO_TRANSFERTIME_MOVER;
    else
      ud_TransfertimePerPackage := SDO_TRANSFERTIME_VARAN;
    end_if;
  else
    ud_TransfertimePerPackage := SDO_TRANSFERTIME_CDIAS;
#ifdef SAFETY_OVER_DIAS
    #pragma message("Transfer time for DIAS must be defined!")
#endif
  end_if;
  
  if ( (WriteFramesNeeded + ReadFramesNeeded) * ud_TransfertimePerPackage ) > ServerUpdateTime then
    ServerUpdateTime    := ( WriteFramesNeeded + ReadFramesNeeded ) * ud_TransfertimePerPackage;
    ServerUpdateTime.Write(input:=ServerUpdateTime);
    ud_ServerUpdateTime := ( ReadFramesNeeded ) * ud_TransfertimePerPackage;
  end_if;  

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyCDIAS_Base::FetchDiagState

  DiagVars.UserDiagStateReady := FALSE;
  DiagVars.UserWantsDiagState := TRUE;

END_FUNCTION

FUNCTION VIRTUAL GLOBAL SafetyCDIAS_Base::GetDiagState
	VAR_INPUT
		pDiagState 	: ^SafetyDiagState;
	END_VAR
	VAR_OUTPUT
		StateReady 	: BOOL;
	END_VAR
  
  StateReady                        := DiagVars.UserDiagStateReady;
  
  // if data ready, we save it into user structure
  if StateReady then
    pDiagState^.RunState            := DiagVars.UserGetStateResp.RuntimeState;
    pDiagState^.ConfigState         := DiagVars.UserGetStateResp.ConfigState;
    pDiagState^.LoginLevel          := DiagVars.UserGetStateResp.LoginLevel;
    pDiagState^.ErrorCounterIOState := DiagVars.UserGetStateResp.ErrorCount;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyCDIAS_Base::FetchDiagInfo
	VAR_INPUT
		ucChoice 	: USINT;
	END_VAR

  DiagVars.ucChoiceDiagInfo  := ucChoice;
  DiagVars.UserDiagInfoReady := FALSE;
  DiagVars.UserWantsDiagInfo := TRUE;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyCDIAS_Base::GetDiagInfo
	VAR_INPUT
		pDiagInfo 	: ^SafetyDiagInfo;
	END_VAR
	VAR_OUTPUT
		StateReady 	: BOOL;
	END_VAR
  
  StateReady    := DiagVars.UserDiagInfoReady;
  
  // if data ready, we save it into user structure
  if StateReady then
    pDiagInfo^  := DiagVars.UserGetDiagInfoResp;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::SDORequ
	VAR_INPUT
		us_Command 	        : USINT;
		p_us_RequData 	    : ^USINT;
		us_RequLength 	    : USINT;
		p_us_RespData 	    : ^USINT;
		us_RespLength 	    : USINT;
	END_VAR
	VAR_OUTPUT
		sd_retval 	        : DINT;
	END_VAR
  VAR
  	pSDORequestBuffer   : ^SDOStdHeader;
    pSDOResponseBuffer  : ^SDOStdResp;
    RespBuffer          : ARRAY [0..127] OF USINT;
    RequBuffer          : ARRAY [0..127] OF USINT;
    us_InLength         : USINT;
    us_OutLength        : USINT;
  END_VAR

  //SDO requests for this commands don't have any further data
  pSDORequestBuffer$^void   := #RequBuffer[0];
  pSDOResponseBuffer$^void  := #RespBuffer[0];  
   
  //SDO request buffer (length header + data)
  us_InLength               := sizeof(SDOStdHeader) + us_RequLength;
  
  //SDO response buffer (length header + rc + data)
  us_OutLength              := sizeof(SDOStdHeader) + 1 + us_RespLength;
  
  //calculate length without crc
  pSDORequestBuffer^.len    := sizeof(SDOStdHeader) - sizeof(SDOStdHeader.CRC) + us_RequLength;
  
  //type
  pSDORequestBuffer^.typ    := FRM_TYPECODE_STD;
  
  //sequence number
  pSDORequestBuffer^.SeqNr  := us_CntSequNr;

  _memcpy(ptr1:=pSDORequestBuffer + sizeof(SDOStdHeader), ptr2:=p_us_RequData, cntr:=us_RequLength);

  //increase counter for sequence number
  if us_CntSequNr < 16#7F then
    us_CntSequNr += 1;
  else
    us_CntSequNr := 0;
  end_if;
  
  //command to inform CPU about initializing classes is ok
  pSDORequestBuffer^.cmd := us_Command;
  
  //set CRC-field to 0
  pSDORequestBuffer^.CRC := 0;
  
  //send request
  sd_retval := SAFETY_iSendRequest( uiMaster    := 0
                                  , pucNode     := p_ObjectPath
                                  , uiInLength  := us_InLength
                                  , pucInput    := pSDORequestBuffer$^USINT
                                  , uiOutLength := us_OutLength
                                  , pucOutput   := pSDOResponseBuffer$^USINT
                                  );

  //no response
  if ( sd_retval = 0 ) then

    //check sequence number to exclude a possible wrong response
    if ( pSDORequestBuffer^.SeqNr <> pSDOResponseBuffer^.StdHeader.SeqNr ) then
      sd_retval := -102;
      
    //check returncode of SDO
    elsif ( pSDOResponseBuffer^.us_Returncode <> SDO_RETCODE_OK ) then
      sd_retval := -103;
    end_if;
  
  end_if;
  
  //return response
  if ( ( sd_retval = 0 ) & ( p_us_RespData <> NIL )) then
    To_StdLib.MemCpy(dest := p_us_RespData, source := #pSDOResponseBuffer^.us_Data, size := us_RespLength);
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyCDIAS_Base::SaveLog
	VAR_INPUT
		ucChoice  : USINT;
		pDPNE 	  : ^CHAR;
	END_VAR
	VAR_OUTPUT
		Success 	: DINT;
	END_VAR

  if DiagVars.SavingLogInProgress = FALSE then
    DiagVars.SavingLogInProgress  := TRUE;

    DiagVars.SavingLogSuccessful  := FALSE; //Reset Value
    
    DiagVars.ucChoiceSaveLog      := ucChoice;
  
    _memcpy(ptr1:=#DiagVars.DPNE, ptr2:=pDPNE, cntr:=_strlen(pDPNE));
    
    Success := TRUE;
  else
    Success := FALSE;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyCDIAS_Base::SaveLogActive
	VAR_OUTPUT
		InProgress 	: BOOL;
	END_VAR
  
  InProgress := DiagVars.SavingLogInProgress;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::BlockedTransferLength
	VAR_INPUT
		ud_Datalength 	    : UDINT;
		us_MaxBlocklength 	: USINT;
	END_VAR
	VAR_OUTPUT
		us_ActBlocklength 	: USINT;
	END_VAR

  IF ud_Datalength > to_UDINT(us_MaxBlocklength) THEN
    us_ActBlocklength := us_MaxBlocklength;
  ELSE
    us_ActBlocklength := to_USINT(ud_Datalength);
  END_IF;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::AddToPDOMoverList
	VAR_INPUT
		pThis 	: pVirtualBase;
		pList 	: ^pPDOMoverList;
	END_VAR
  VAR
    pHelp : ^PDOMoverList;
  END_VAR

  if pList^ = NIL then
    pList$^pvoid^ := To_StdLib.Malloc(size:=sizeof(PDOMoverList));
    //Graphic.Memory((#pList)$^pVoid, sizeof(PDOMoverList));
    pHelp := pList^;
  else
    pHelp := pList^;
    if pHelp^.pThis = pThis then
      // this pointer already in buffer => leave function
      return;
    end_if;
    while pHelp^.pNext <> NIL do
      if pHelp^.pThis <> pThis then
        pHelp := pHelp^.pNext;
      else
        // this pointer already in buffer => leave function
        return;
      end_if;
    end_while;
    pHelp^.pNext$pvoid := To_StdLib.Malloc(size:=sizeof(PDOMoverList));
    pHelp := pHelp^.pNext;
  end_if;
  
  if pHelp <> NIL then
    pHelp^.pThis := pThis;
    pHelp^.pNext := NIL;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::WalkThroughPDOMoverList
	VAR_INPUT
		pList 	  : ^pPDOMoverList;
		NewState 	: PDOMoveState;
	END_VAR
  VAR
  	pAct      : ^PDOMoverList;
    pFree     : ^void;
		MyPara 	  : CmdStruct;
		MyResult  : results;
  END_VAR

  // get pointer on first element of list
  pAct := pList^;

  // if we have entries left we walk on
  WHILE pAct DO
#pragma warning(disable:137 )
    // set state of corresponding PDOMover to off
    IF pList = #pPDOMoverListInputs THEN
      if NewState = _Inactive then

        MyPara.uiCmd    := CMD_SM_DEACTIVATE_MOVE_CMD;
        MyPara.aPara[0] := 0;
        pAct^.pThis^.NewInst(#MyPara, #MyResult);    
        
//        pAct^.pThis^.b_MoveCommandOutputActive := _Inactive;
      end_if;
    ELSE
      if NewState = _Inactive then

        MyPara.uiCmd    := CMD_SM_DEACTIVATE_MOVE_CMD;
        MyPara.aPara[0] := 1;
        pAct^.pThis^.NewInst(#MyPara, #MyResult);    

//        pAct^.pThis^.b_MoveCommandInputActive := _Inactive;
      end_if;
    END_IF;
#pragma warning(default:137 )    
    
    //go to next entry and get rid of the allocated memory
    pFree := pAct;
    pAct  := pAct^.pNext;
    To_StdLib.Free(mptr:=pFree);
  END_WHILE;
  
  // we got rid of the memory above - to make sure nobody will use this data again we clear the list entry
  pList^ := NIL;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::CleanupPDOMoverList
	VAR_INPUT
		pList 	: ^pPDOMoverList;
	END_VAR
  VAR
  	pAct    : ^PDOMoverList;
    pFree   : ^void;
  END_VAR

  // get pointer on first element of list
  pAct := pList^;

  // if we have entries left we walk on
  WHILE pAct DO    
    //go to next entry and get rid of the allocated memory
    pFree := pAct;
    pAct  := pAct^.pNext;
    To_StdLib.Free(mptr:=pFree);
  END_WHILE;
  
  // we got rid of the memory above - to make sure nobody will use this data again we clear the list entry
  pList^ := NIL;
  
END_FUNCTION

#pragma warning(disable: 73)
FUNCTION VIRTUAL SafetyCDIAS_Base::AddFrame
	VAR_INPUT
		pFrame 	        : ^SafetyCDIAS_Base::SDOStdHeader;
		FrameState 	    : DINT;
		CallerSafetyNr 	: HDINT;
	END_VAR

END_FUNCTION
#pragma warning(default: 73)

FUNCTION VIRTUAL SafetyCDIAS_Base::RecordFrame
	VAR_INPUT
		pFrame 	    : ^DINT;
		FrameState 	: DINT;
	END_VAR
  VAR
    ThisBackup  : pVoid;
    TempSafetyNr: HDINT;
  END_VAR

  if pAnalyzerThis & pAnalyzerMethod then
    
    TempSafetyNr  := SafetyNumber;
  
    ThisBackup    := THIS;
    
    THIS          := pAnalyzerThis$^SafetyCDIAS_Base;
    pAnalyzerMethod$AddFrame(pFrame$^SDOStdHeader, FrameState, TempSafetyNr);
    
    THIS          := ThisBackup$^SafetyCDIAS_Base;
  end_if;

END_FUNCTION

#pragma warning(disable: 73)
FUNCTION VIRTUAL GLOBAL SafetyCDIAS_Base::UpDateRTPostScan
	VAR_INPUT
		Handle 	          : UDINT;
	END_VAR
  VAR
  	i                 : UDINT;
    TempSafetyNr      : HDINT;
    p_PDOInBufferAct  : ^PDOInputBuffer;
  END_VAR

//============================ Profiler start======================================================
#ifdef  DM_Profiler								
  StartTimeMeasurement(usMode := DMTIME_RTPOSTSCAN);
#endif	
//============================ Profiler end========================================================

  // do tdo/pdo communication only, if module has been found and initialized correctly and if there are some LEDs on (else a FW-Update is running)
  if ( State.uiIO_Flags = 0 ) & 
     (( ClassState = _SafetyClassOK ) | ( ClassState = _WaitForSynchronicity ) | ( ClassState = _ModFromCfgNotFound ) | ( ClassState = _UnknownCfgError ) | ( ClassState = _UnsafeVarNotFound )) then



    // if any LED is active, then firmware update is not active and we can do our work
    if (VoltageOK | RunState | ServiceMode | Error) then
    
      // write unsafe I/Os
      UpDateNotStd(calloption:=CALL_OPTION_RT_POSTSCAN);

      // TDO Handling with mover
      if TDOSingleRunActive then
        TDOSingleRunActive := FALSE;
        if b_PayloadSupport then
          p_HandleTDOWriteEnable^     := VARAN_DO_NO_RUN;
        else
          ( p_HandleTDOWrite$^USINT )^  := VARAN_DO_NO_RUN;
        end_if;        
      end_if;

      // check if we may send a TDO (TDO-Status-Register MSB must be zero)
      if (( p_us_Handle_TDO_Status_Write^ AND 16#80 ) = 0) then

        // check for a TDO Request => if there is one, send it
        if s_TDORingbuffer.b_RequestAvailable then

          To_StdLib.MemCpy(dest := p_us_Handle_TDO_Write, source := #s_TDORingbuffer.RequestTDO, size := sizeof(TDOType));

          TimeSyncDOActive.Wait4ResponseNo += 1;
#ifdef DO_DEBUG
          DOCheck(pFrame:=(#s_TDORingbuffer.RequestTDO)$^SDOStdHeader, pCheckStruct:=#TDOWrite);
#endif

#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
  RecordFrame((#s_TDORingbuffer.RequestTDO)$^DINT, 1);
#endif

          s_TDORingbuffer.b_RequestAvailable := FALSE;

          if b_VaranAvailable then
            if (sd_VaranType = 1) then
              
              if b_PayloadSupport then  // Payload, No Mover ---------------------------------------------------------------------
                
                if b_DOIsRunningTDOWrite.StartRequest then  // Check if the startrequest has been set somewhere else, probably not the same check as without payload. 
                  TDOErrorDetectedCnt += 1;
                end_if;
                
                b_DOIsRunningTDOWrite.StartRequest := true;

                if b_NewSyncMode then
                  // start DO at this point to ensure 1 cycle delay, from request to response
                  EnableDO(ud_DOHandle := p_HandleTDORead$UDINT);
                  b_DOIsRunningTDORead.ContRun := true; // Important! This flag is checked in UpdataRT
                end_if;
                
              else  // No Payload, No Mover -------------------------------------------------------------------------------------------
                
                if p_HandleTDOWrite^.ucCtrlStat AND VARAN_DO_SINGLE_RUN then
                  TDOErrorDetectedCnt += 1;
                end_if;

                p_HandleTDOWrite^.ucCtrlStat  := VARAN_DO_SINGLE_RUN;
                
                if b_NewSyncMode then
                  // start DO at this point to ensure 1 cycle delay, from request to response
                  p_HandleTDORead^.ucCtrlStat := VARAN_DO_CONT_RUN;
                end_if;
                  
              end_if;
              
            else  // Mover
            
              if b_PayloadSupport then  // Payload, Mover ---------------------------------------------------------------------
                  
                if p_HandleTDOWriteEnable^ AND VARAN_MOVER_DO_SINGLE_RUN then
                  TDOErrorDetectedCnt += 1;
                end_if;
                  p_HandleTDOWriteEnable^ := VARAN_MOVER_DO_SINGLE_RUN;
                TDOSingleRunActive := TRUE;

              else  // No Payload, Mover -------------------------------------------------------------------------------------------
                
                if ( p_HandleTDOWrite$^USINT )^ AND VARAN_MOVER_DO_SINGLE_RUN then
                  TDOErrorDetectedCnt += 1;
                end_if;
                ( p_HandleTDOWrite$^USINT )^ := VARAN_MOVER_DO_SINGLE_RUN;        
                TDOSingleRunActive := TRUE;
                
              end_if;
            end_if;
          end_if;

        // Send entries of TDO-Buffer (only responses)
        elsif ( s_TDORingbuffer.ud_Entries > 0 ) THEN

          To_StdLib.MemCpy(dest := p_us_Handle_TDO_Write, source := #s_TDORingbuffer.Entry[s_TDORingbuffer.ud_ReadPos], size := sizeof(TDOType));

#ifdef DO_DEBUG
          DOCheck(pFrame:=(#s_TDORingbuffer.Entry[s_TDORingbuffer.ud_ReadPos])$^SDOStdHeader, pCheckStruct:=#TDOWrite);
#endif

#ifdef SAFETY_PROTOCOL_ANALYZER_ACTIVATED
  RecordFrame((#s_TDORingbuffer.Entry[s_TDORingbuffer.ud_ReadPos])$^DINT, 1);
#endif

          // in the startupphase we use the time synchronisation between modules to check if a module is synchron with all of his communication partners
          if (us_SetBusReadyState = WaitPDOsSyncron) & ui_cnt_PDOInputBuffer then
            TempSafetyNr := s_TDORingbuffer.Entry[s_TDORingbuffer.ud_ReadPos].SrcAdr;

            p_PDOInBufferAct := #aPDOInputBuffer[0];
            for i := 0 to (ui_cnt_PDOInputBuffer-1) do
              if p_PDOInBufferAct^.ud_SafetyNr = TempSafetyNr then
                p_PDOInBufferAct^.b_TimeSynchron := TRUE;
              end_if;

              p_PDOInBufferAct +=  sizeof(PDOInputBuffer);
            end_for;                        
          end_if;

          s_TDORingbuffer.ud_ReadPos := ( s_TDORingbuffer.ud_ReadPos + 1 ) mod ( SIZEOF( TDORingbuffer.Entry ) / SIZEOF( TDOType ) );
          s_TDORingbuffer.ud_Entries -= 1;

          if b_VaranAvailable then
            if (sd_VaranType = 1) then
            
              if b_PayloadSupport then   // Payload, No Mover ---------------------------------------------------------------------
                if b_DOIsRunningTDOWrite.StartRequest then // Check if the startrequest has been set somewhere else, probably not the same check as without payload. 
                  TDOErrorDetectedCnt += 1;
                end_if;
                
                b_DOIsRunningTDOWrite.StartRequest := true;
                
                if b_NewSyncMode then
                  // start DO at this point to ensure 1 cycle delay, from request to response
                  EnableDO(ud_DOHandle := p_HandleTDORead$UDINT);
                  b_DOIsRunningTDORead.ContRun := true; // Important! This flag is checked in UpdataRT
                end_if;
              
              else  // No Payload, No Mover -------------------------------------------------------------------------------------------
                  
                if p_HandleTDOWrite^.ucCtrlStat AND VARAN_DO_SINGLE_RUN then
                  TDOErrorDetectedCnt += 1;
                end_if;

                p_HandleTDOWrite^.ucCtrlStat  := VARAN_DO_SINGLE_RUN;

                if b_NewSyncMode then
                  // start DO at this point to ensure 1 cycle delay, from request to response
                  p_HandleTDORead^.ucCtrlStat := VARAN_DO_CONT_RUN;
                end_if;                
              
              end_if;
              
            else  // Mover
            
              if b_PayloadSupport then  // Payload, Mover ---------------------------------------------------------------------
                
                if p_HandleTDOWriteEnable^ AND VARAN_MOVER_DO_SINGLE_RUN then
                  TDOErrorDetectedCnt += 1;
                end_if;
                p_HandleTDOWriteEnable^ := VARAN_MOVER_DO_SINGLE_RUN;
                TDOSingleRunActive := TRUE;
  
              else  // No Payload, Mover -------------------------------------------------------------------------------------------
              
                if ( p_HandleTDOWrite$^USINT )^ AND VARAN_MOVER_DO_SINGLE_RUN then
                  TDOErrorDetectedCnt += 1;
                end_if;
                ( p_HandleTDOWrite$^USINT )^ := VARAN_MOVER_DO_SINGLE_RUN;        
                TDOSingleRunActive := TRUE;
              
              end_if;
              
            end_if;
          end_if;
        END_IF;
      else
        // can't write this time, if there is a request waiting => drop it
        if s_TDORingbuffer.b_RequestAvailable then
          s_TDORingbuffer.b_RequestAvailable := FALSE;
          RequestDropCounter += 1;
        end_if;
      end_if;
      
      if RunState & ((us_SetBusReadyState = SetBusReadyFinished) | b_ManualQuit) then
        //write PDO to hardware
        if ( ui_cnt_PDOInputBuffer > 0 ) then          
          WritePDO2Module();
        end_if;
      end_if;
    end_if;
  end_if;
  
  if b_PayloadSupport & (sd_VaranType = 1) then
      
    // p_HandleTDORead xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    case b_DOIsRunningTDORead of
    
      SR_STATE_ENABLE_ME :  // DO is not running and start request is set ----------------------------------------
        EnableDO(ud_DOHandle  := p_HandleTDORead$UDINT);        
        b_DOIsRunningTDORead  := SR_STATE_DISABLE_ME;
        
      SR_STATE_DISABLE_ME : // DO is running and start request is not set ----------------------------------------
        DisableDO(ud_DOHandle := p_HandleTDORead$UDINT);
        b_DOIsRunningTDORead  := SR_STATE_NOTHING;
        
      SR_STATE_LEAVE_ME_ENABLED : // DO is running and another start request is set ------------------------------
        b_DOIsRunningTDORead  := SR_STATE_DISABLE_ME;
        
    end_case;
    
    // p_HandleTDOWrite xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    case b_DOIsRunningTDOWrite of
    
      SR_STATE_ENABLE_ME :  // DO is not running and start request is set ----------------------------------------
        EnableDO(ud_DOHandle  := p_HandleTDOWrite$UDINT); 
        b_DOIsRunningTDOWrite := SR_STATE_DISABLE_ME;
        
      SR_STATE_DISABLE_ME : // DO is running and start request is not set ----------------------------------------
        DisableDO(ud_DOHandle := p_HandleTDOWrite$UDINT);
        b_DOIsRunningTDOWrite := SR_STATE_NOTHING;
        
      SR_STATE_LEAVE_ME_ENABLED : // DO is running and another start request is set ------------------------------
        b_DOIsRunningTDOWrite := SR_STATE_DISABLE_ME;
        
    end_case;
    
    // p_HandleUnsafeOutWrite xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    case b_DOIsRunningUnsafeOutWrite of
    
      SR_STATE_ENABLE_ME :  // DO is not running and start request is set ----------------------------------------
        EnableDO(ud_DOHandle  := p_HandleUnsafeOutWrite$UDINT); 
        b_DOIsRunningUnsafeOutWrite := SR_STATE_DISABLE_ME;
        
      SR_STATE_DISABLE_ME : // DO is running and start request is not set ----------------------------------------
        DisableDO(ud_DOHandle := p_HandleUnsafeOutWrite$UDINT);
        b_DOIsRunningUnsafeOutWrite := SR_STATE_NOTHING;
        
      SR_STATE_LEAVE_ME_ENABLED : // DO is running and another start request is set ------------------------------
        b_DOIsRunningUnsafeOutWrite := SR_STATE_DISABLE_ME;
        
    end_case;
    
  end_if;

//============================ Profiler start======================================================
#ifdef  DM_Profiler								
  StopTimeMeasurement(usMode := DMTIME_RTPOSTSCAN);
#endif	
//============================ Profiler end========================================================

END_FUNCTION
#pragma warning(default: 73)


FUNCTION VIRTUAL GLOBAL SafetyCDIAS_Base::State::NewInst
	VAR_INPUT
		pPara 	        : ^CmdStruct;
		pResult 	      : ^Results;
	END_VAR
	VAR_OUTPUT
		ret_code 	      : IprStates;
	END_VAR
  VAR
  	OldClassState   : SafetyConfigStateType;
    pPDOInputBuffer : ^PDOInputBuffer;
    i, j            : UINT;
    Found           : BOOL;
    sd_retval       : DINT;
    GetStateResp    : GetStateResponseType;
    
  	ptmpStr         : ^CHAR;
    ud_StrSize      : UDINT;
    us_temp         : USINT;    
    
  END_VAR

	ret_code := READY;

	CASE pPara^.uiCmd OF
//**********************************************************************************************************************************************************
		CMD_SM_SET_NEW_SYNC_MODE:
    
      b_NewSyncMode := pPara^.aPara[0]$BOOL; //TRUE;
    
      if b_NewSyncMode then
        NewHandShakeValue := 2#001;
      end_if;
            
//**********************************************************************************************************************************************************
    CMD_SM_START_TIME_SYNC:

      // set bit for starting timesync at the module (bit 2#100 is set later additionally so the firmware can detect our cycle time)
      NewHandShakeValue := 2#011;
      
      b_TimeSyncActive := TRUE;

//**********************************************************************************************************************************************************
    CMD_SM_INIT_FINISHED:
      // the safety manager has finished his administration work (e.g. connecting the domains)
      b_ManagerInitialisationFinished := TRUE;
      
      // optional modules may not be available
      ud_OptionalTimeoutStart := ops.tAbsolute;
      
      UnsafeScheduler := UnsafeSchedulerSetBusReady;      
      us_SetBusReadyState := WaitPDOsSyncron;            
      
//**********************************************************************************************************************************************************
    CMD_SM_FIRST_CONNECT_READY:
      // the safety manager has finished first time connecting the domains
      b_ManagerReadyForSDO := TRUE;

//**********************************************************************************************************************************************************
    CMD_SM_DISCONNECT:
      b_ManagerInitialisationFinished := FALSE;
      b_ManagerReadyForSDO := FALSE;

      // wait again to send bus ready signal
      if ClassState <> _ReinitConfig then
        ClassState := _WaitForSynchronicity;
      end_if;
      UnsafeScheduler := UnsafeSchedulerSetBusReady;      
      us_SetBusReadyState := WaitPDOsSyncron;

//**********************************************************************************************************************************************************
    CMD_SM_SDO_TO_MODULE:
#ifdef DO_DEBUG
      DOCheck(pFrame:=(pPara^.aPara[1])$^SDOStdHeader, pCheckStruct:=#SDOWrite);
#endif

      AddSDOToBuffer(p_us_Message := pPara^.aPara[1]$^USINT, us_length := pPara^.aPara[0]$USINT);
      
//**********************************************************************************************************************************************************
    CMD_SM_TDO_TO_MODULE:
      WriteTDO2Module(pTDO:=(pPara^.aPara[1])$^TDOType);
           
//**********************************************************************************************************************************************************
    CMD_SM_GET_SAFETY_NUMBER:
      // check if pointer is valid
      if pPara^.aPara[0] then
        ((pPara^.aPara[0])$^UDINT)^ := SafetyNumber;
      end_if;
//**********************************************************************************************************************************************************
    CMD_SM_ADD_INPUT_PDO:
      AddPDOToInputBuffer(ud_p2Buffer         := pPara^.aPara[0]$UDINT
                        , ud_HandleSourceDO   := pPara^.aPara[5]$UDINT
                        , ud_MoveSourceAddr   := pPara^.aPara[1]$UDINT
                        , ud_MoveSourceOffset := pPara^.aPara[6]$UDINT
                        , ud_SafetyNr         := pPara^.aPara[2]$UDINT
                        , b_IsOptional        := pPara^.aPara[4]$BOOL
                        , us_PdoLen           := pPara^.aPara[3]$USINT);
    
//**********************************************************************************************************************************************************
    CMD_SM_ADD_OUTPUT_PDO:      
      // if it's an interface frame, we return the pointer to the second PDO frame which is the interface pdo frame
      if pPara^.aPara[0] = 1 then
        // skip the first PDO
        pResult^.aData[0]$UDINT := GetPointer2PDOBuffer() + MyPDOSize;
        pResult^.aData[4]$UDINT := pPDOReadData$UDINT + MyPDOSize;
        pResult^.aData[8]$UDINT := p_HandlePDORead$UDINT; // Still the same DO Handle 
        pResult^.aData[12]$UDINT:= MyPDOSize$UDINT;       
        pResult^.aData[8]$UDINT := p_HandlePDORead$UDINT; // Still the same DO Handle 
        pResult^.aData[12]$UDINT:= MyPDOSize$UDINT;       
      else
        // otherwise just get the pointer to the PDO read data
        pResult^.aData[0]$UDINT := GetPointer2PDOBuffer();
        pResult^.aData[4]$UDINT := pPDOReadData$UDINT;
        pResult^.aData[8]$UDINT := p_HandlePDORead$UDINT;
        pResult^.aData[12]$UDINT:= 0$UDINT;
        pResult^.aData[8]$UDINT := p_HandlePDORead$UDINT;
        pResult^.aData[12]$UDINT:= 0$UDINT;
      end_if;
      
      // p_HandlePDORead

      pResult^.uiLng := 16;
      
//**********************************************************************************************************************************************************
    CMD_SM_REMOVE_INPUT_PDO:
      // we lost connection to other systems => we have to initialize again! remove old input PDOs
      
      if ui_cnt_PDOInputBuffer then
        // save the old state of the class and set it temporarily to "module not found" to prevent update rt from crashing
        OldClassState := ClassState;
        ClassState := _ModuleNotFound;
        
        // search for the PDO
        Found := FALSE;
        pPDOInputBuffer := #aPDOInputBuffer[0];
        for i := 0 to (ui_cnt_PDOInputBuffer-1) do
          if pPDOInputBuffer^.ud_p2Buffer = pPara^.aPara[0]$UDINT then
            Found := TRUE;
            exit;
          end_if;
          
          pPDOInputBuffer += sizeof(PDOInputBuffer);
        end_for;

        // if we found the PDO => remove it from memory (move the memory behind the found PDO over the place of the found PDO)
        if Found then
          // if it's last entry (no entries have to be moved) => we only have to copy some memory if it's not the last
          if i < (ui_cnt_PDOInputBuffer-1) then
            for j := i to (ui_cnt_PDOInputBuffer-2) do
              aPDOInputBuffer[j] := aPDOInputBuffer[j+1];
            end_for;
          end_if;
          ui_cnt_PDOInputBuffer -= 1;
        else
          LogError("@ZZZZ (SafetyCDIAS_Base::State::NewInst) CMD_SM_REMOVE_INPUT_PDO failed! Couldn't find specified PDO!");
        end_if;

        // restore old class state
        ClassState := OldClassState;
      else
        LogError("@ZZZZ (SafetyCDIAS_Base::State::NewInst) CMD_SM_REMOVE_INPUT_PDO failed! No input PDOs found!");
      end_if;

//*****************************************************************************
//** COMMANDS FROM OTHER SAFETYMODULES                                       **
//*****************************************************************************

//**********************************************************************************************************************************************************
    CMD_SM_ADD_SDO_TO_BUFFER:
      sd_retval := AddSDOToBuffer(p_us_message:=pPara^.aPara[0]$^USINT, us_length:=pPara^.aPara[1]$USINT);
      if sd_retval then
        ret_code := 1$IprStates; //means iprStates::ERROR but a server error also exists
      end_if;
      
      pResult^.aData[0]$DINT := sd_retval;
      
//**********************************************************************************************************************************************************
    CMD_SM_WRITE_TDO_TO_MODULE:
      WriteTDO2Module(pTDO:=pPara^.aPara[0]$^TDOType);

//**********************************************************************************************************************************************************
    CMD_SM_CONFIG_SAFETY_CPU:
      pResult^.aData[0]$UDINT := ConfigSafetyCpu();
      
//**********************************************************************************************************************************************************
    CMD_SM_CONFIG_SAFETY_INPUT:
      pResult^.aData[0]$UDINT := ConfigSafetyInput(ud_SafeNrCPU         := pPara^.aPara[0]$HDINT
                                                 , ud_thisp             := pPara^.aPara[1]$UDINT
                                                 , p_PDOBuffer          := pPara^.aPara[2]$^UDINT
                                                 , pMoveActive          := pPara^.aPara[3]$^PDOMoveState
                                                 , p_ud_HandleSourceDO  := pPara^.aPara[5]$^UDINT
                                                 , p_ud_MoveSourceAddr  := pPara^.aPara[4]$^UDINT
                                                 , p_ud_MoveSourceOffset:= pPara^.aPara[6]$^UDINT
                                                 );

//**********************************************************************************************************************************************************
    CMD_SM_CONFIG_SAFETY_OUTPUT:
      pResult^.aData[0]$UDINT := ConfigSafetyOutput(ud_SafeNrCPU        := pPara^.aPara[0]$HDINT
                                                  , ud_thisp            := pPara^.aPara[1]$UDINT
                                                  , ud_p_PDOBuffer      := pPara^.aPara[2]$UDINT
                                                  , pObject             := pPara^.aPara[3]$^PathInfoType
                                                  , pMoveActive         := pPara^.aPara[4]$^PDOMoveState
                                                  , ud_HandleSourceDO   := pPara^.aPara[7]$UDINT
                                                  , ud_MoveSourceAddr   := pPara^.aPara[5]$UDINT
                                                  , ud_MoveSourceOffset := pPara^.aPara[8]$UDINT
                                                  , b_IsOptional        := pPara^.aPara[6]$BOOL
                                                  );
                                                  
//**********************************************************************************************************************************************************
    CMD_SM_REMOVE_CPU_FROM_TABLE:
      RemoveCPUFromTable(ud_SafetyNr := pPara^.aPara[0]$HDINT);
      
//**********************************************************************************************************************************************************     
    CMD_SM_GET_MODULE_TYPE:
      pResult^.aData[0]$UDINT := SM_TYPE_SAFETY_MODULE;
      
//**********************************************************************************************************************************************************     
    CMD_SM_DEACTIVATE_MOVE_CMD:
      // check if it's for input (1) or output (0)
      if pPara^.aPara[0] then
        b_MoveCommandInputActive  := _Inactive;        
      else
        b_MoveCommandOutputActive := _Inactive;
      end_if;

//**********************************************************************************************************************************************************     
    CMD_SM_MODULE_REINIT:
      if b_ReInitMarker then
        if GetModuleID() = CSCP01x_ID then
        
          // delete request
          LastRequest := _NoOpenRequest;
          ud_AsyComRetryCounter := 0; // reset retry counter

          // remove the cpu from all classes, which use it
          ResetConfig();

          if UnsafeScheduler <> UnsafeSchedulerSetBusReady then
            us_SetBusReadyState := WaitPDOsSyncron;
            UnsafeScheduler := UnsafeSchedulerSetBusReady;
          end_if;

          MaxVarsPerReadPackage   := 0;
          ReadFramesNeeded        := 0;
          MaxVarsPerWritePackage  := 0;
          WriteFramesNeeded       := 0;        

          ClassState := _ReinitConfig;
          b_GetNewConfiguration := TRUE;
        end_if;

        b_ReInitMarker := FALSE;
      end_if;
      
//**********************************************************************************************************************************************************     
    CMD_SM_POST_INIT_FINISHED:
    
      b_PostInitPassed := TRUE;
      
      if ( State.uiIO_Flags = 0 ) then

        // get configuration if module is configured
        
        // get state via SDO communication
        sd_retval := SDOStdRequ ( us_Command      := SDO_COMMAND_GET_STATE
                                , p_us_RespData   := ( #GetStateResp )$^USINT
                                , us_RespLength   := sizeof(GetStateResponseType)
                                );
        
        // the cpu is configured, load the new configuration
        if ( sd_retval = 0 ) & 
           (GetStateResp.ConfigState <> CFG_STATE_UNKNOWN) &
           (GetStateResp.ConfigState <> CFG_STATE_INVALID) &
           (GetStateResp.ConfigState <> CFG_STATE_NOT_CONFIGURED) then
                      
          //get configuration from safe CPU and build routing tables
          GetRoutingData();
        else
          //get configuration from safe CPU and build routing tables later in background
          b_GetNewConfiguration := FALSE;
          
            // next time we check for the configured state of the cpu
          b_CheckConfigured     := TRUE;

          // check again in background
          ClassState            := _ReinitConfig;
        end_if;
      end_if;

//**********************************************************************************************************************************************************
  CMD_GET_HARDWARE_DIAGNOSIS:
    //Set Errors
    
    ret_code := 1$IprStates; //means iprStates::ERROR but a server error also exists
    
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.retcode           := _HWC_RETVAL_ERROR_CLASS_NOT_ONLINE;
    
    //Return State and Device ID and Kennung of placed module --------------------------------
    if State.uiIO_Flags.WrongHW = 1 then
      pResult^.aData$t_HWCGetHardwareDiagnosisOut.ClassState := _WrongHardware;
      pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_WRONG_HARDWARE;
    elsif State.uiIO_Flags.NoHW = 1 then
      pResult^.aData$t_HWCGetHardwareDiagnosisOut.ClassState := _NoHardware;
      pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_NO_HARDWARE;
    elsif State.uiIO_Flags.NoCalibration = 1 then
      pResult^.aData$t_HWCGetHardwareDiagnosisOut.ClassState := _NoCalibDataFound;
      pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_NO_CALIB_DATA_FOUND;        
    end_if;

    pResult^.aData$t_HWCGetHardwareDiagnosisOut.ud_DeviceID := GetModuleID();
    pResult^.aData$t_HWCGetHardwareDiagnosisOut.ud_Variante := GetKennung();
        
    //-----------------------------------------------------------------------------------------
    
    // Only respond if the class is online
    if State.uiIO_Flags = 0 then    
      pResult^.aData$t_HWCGetHardwareDiagnosisOut.ClassState := _ClassOk;
      ptmpStr := pPara^.aPara[0]$t_HWCGetHardwareDiagnosisIn.pStr_HardewareTreeEntry;
      
      // Check if position pointers strings are valid
      if ptmpStr & p_ObjectPath then
        
        // Length is 2 byte for ptmpStr and 1 byte for p_ObjectPath
        if (ptmpStr)$^UINT^ > 0 & (ptmpStr)$^UINT^ = (p_ObjectPath)$^USINT^ then // Check if length if positionstring is valid and equal
        
          if _memcmp(ptr1:=ptmpStr+2, ptr2:=p_ObjectPath+1, cntr:= (ptmpStr)$^UINT^) = 0 then  // Compare strings , 2 bytes length for ptmpStr, 1 byte length for p_ObjectPath
            
            ret_code := READY;
            pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.retcode           := _HWC_RETVAL_OK;
            pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pStr_DeviceName   := NIL;
            pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pStr_VendorName   := NIL;
            pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_VendorID       := 0;
            
            // Get Serialno -----------------------------------------------------------------------------------------
            ud_StrSize := SerialNoStr.GetLength() ;              
            pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pStr_SerialNo     := NIL;
            
            if ud_StrSize then

              if (ud_StrSize < sizeof(a_SerialNo)) then // < to account for 0 termination
                // Copy complete string
                SerialNoStr.GetDataAt(pData:=#a_SerialNo[0], udSize:=ud_StrSize, udAt:=0);
                a_SerialNo[ud_StrSize] := 0; // 0 termination
              else
                // Copy part string
                SerialNoStr.GetDataAt(pData:=#a_SerialNo[0], udSize:=sizeof(a_SerialNo)-1, udAt:=0);
                a_SerialNo[sizeof(a_SerialNo)-1] := 0; // 0 termination                
              end_if; 
              pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pStr_SerialNo     := #a_SerialNo[0];                
            end_if;   
            // ----------------------------------------------------------------------------------------------------------

            pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pStr_OrderingNo   := NIL;
            pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_LicenseNo      := 0;
            
            // Get Hardwareversion --------------------------------------------------------------------------------------
            pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.hd_HWVersion := 0; 
            if MasterConnect.I2CReadOneByte(AdressCDIAS:=(Place*16#100)$UINT+CDIAS_EEPROM_OFFSET_HWVERSION, pData:=#us_temp) = 0 then
              pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.hd_HWVersion := us_temp;                
            end_if;             
            
            // Get Variante --------------------------------------------------------------------------------------
              pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_Variante := 0; 
            if MasterConnect.I2CReadOneByte(AdressCDIAS:=(Place*16#100)$UINT+CDIAS_EEPROM_OFFSET_VARIANTE, pData:=#us_temp) = 0 then
              pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_Variante := us_temp;                
            end_if;      
            
            // Get FPGA Version -----------------------------------------------------------------------------------------
            pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.hd_FPGAVersion := FPGA_Version;
            
            //Get Safetynumber ------------------------------------------------------------------------------------------
            pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.hd_SafetyNumber := SafetyNumber;
            
            //Get FW Version --------------------------------------------------------------------------------------------
            GetFWVersion(pData:=#a_FWVersion[0],sizeof(a_FWVersion));
            pResult^.aData$t_HWCGetHardwareDiagnosisOut.pStr_FWVersion := #a_FWVersion[0];
            
            // -----------------------------------------------------------------------------------------------------------

            pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_Place          := Place;
            pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_reserved_size  := 0;
            pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pud_reserved      := NIL;
            pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_user_size      := 0;
            pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pud_user          := NIL;
            pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.p_DynExtList      := NIL;
          end_if;

        end_if;
      
      end_if; 
//      else
//        pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.retcode           := _HWC_RETVAL_ERROR_CLASS_NOT_ONLINE;
    end_if;
  
//**********************************************************************************************************************************************************
  else
    // needed for required handling
    ret_code := HwBaseCDIAS::NewInst(pPara, pResult);
//**********************************************************************************************************************************************************
  END_CASE;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::ShowProjectRevision
// to overload in cscp class
END_FUNCTION


FUNCTION SafetyCDIAS_Base::DOCheck
	VAR_INPUT
		pFrame 	      : ^SDOStdHeader;
		pCheckStruct 	: ^t_DataObjectCheck;
	END_VAR
  VAR
  	DOCheckHeader : SDOStdHeader;
    ActTime       : UDINT;
  END_VAR 
   
  // check if input parameters are correct
  if pFrame & pFrame^.Len & pCheckStruct then
    DOCheckHeader := pFrame^;
    
    // only if we got a different frame
    if DOCheckHeader <> pCheckStruct^.LastHeader then
      ActTime := OS_READMICROSEC();
      
      pCheckStruct^.TimeDiff := ActTime - pCheckStruct^.LastTime;
      
      if pCheckStruct^.TimeDiff > pCheckStruct^.TimeDiffMax then
        if pCheckStruct^.TimeDiffMax = 0 then
          pCheckStruct^.TimeDiffMax := 1;
        else
          pCheckStruct^.TimeDiffMax := pCheckStruct^.TimeDiff;
        end_if;
      end_if;

      if pCheckStruct^.TimeDiff < pCheckStruct^.TimeDiffMin then
        pCheckStruct^.TimeDiffMin := pCheckStruct^.TimeDiff;
      end_if;


      pCheckStruct^.LastTime := ActTime;      
    else
      // if it's the same frame again: problem!
      pCheckStruct^.SameFrameCnt += 1;
    end_if;
    pCheckStruct^.LastHeader := DOCheckHeader;
  end_if; 

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::CalcPDOLength
	VAR_INPUT
		BoolVarNo 	: UDINT;
		DintVarNo 	: UDINT;
	END_VAR
	VAR_OUTPUT
		PdoLen 	    : USINT;
	END_VAR
  VAR
    PayLoad     : USINT;
  END_VAR

  // we have at least the header
  PdoLen  := sizeof(PDOType) - sizeof(PDOType.DataAndCopy);
  PayLoad := 0;
  
  // now add some space for the needed data
  if BoolVarNo then
    // 1 byte (type + number of values) + 1 byte index + 2 bits for every value (4 per byte)
    PayLoad += 2 + ((BoolVarNo$USINT + 3) / 4);

    // make the it 2 byte aligned (if it isn't already) => only if no dint variables, otherwise it is done one at the DINT variables
    if (PayLoad MOD 2) & (DintVarNo = 0) then
      PayLoad := PayLoad + (2 - (PayLoad MOD 2)); //increase memory, up to a value, which could be divided by 2
    end_if;
  end_if;

  if DintVarNo then
    // 1 byte (type + number of values) + 1 byte index + 1 byte errorflags per 8 values + 4 byte for every value
    PayLoad += 2 + (((DintVarNo$USINT - 1 ) / 8) + 1) + DintVarNo$USINT * 4;
    
    // make the it 2 byte aligned (if it isn't already)
    if (PayLoad MOD 2) then
      PayLoad := PayLoad + (2 - (PayLoad MOD 2)); //increase memory, up to a value, which could be divided by 2
    end_if;
  end_if;

  // duplicate it
  PayLoad *= 2;

  // add it to the total length
  PdoLen += PayLoad; 

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::AddModuleToCfg
	VAR_INPUT
		ModuleCfg : t_ModuleCfg;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR
    pHelp     : ^t_ModuleListElem;
  END_VAR

  retcode := 0;

  if pFirstModuleCfg = NIL then
    pFirstModuleCfg$pVoid := To_StdLib.Malloc(size:=sizeof(t_ModuleListElem));
    pHelp := pFirstModuleCfg;
  else
    pHelp := pFirstModuleCfg;
    // if searched path has been found, we already got this module in our list
    if (ModuleCfg.PathLen = pHelp^.ModuleInfo.PathLen) & (To_StdLib.MemCmp(dest:= ModuleCfg.pPath, source:= pHelp^.ModuleInfo.pPath , size:= ModuleCfg.PathLen) = 0) then
      // already in buffer => leave function
      return;
    end_if;
    while pHelp^.pNext <> NIL do
      // if searched path has been found, we already got this module in our list
      if (ModuleCfg.PathLen = pHelp^.ModuleInfo.PathLen) & (To_StdLib.MemCmp(dest:= ModuleCfg.pPath, source:= pHelp^.ModuleInfo.pPath , size:= ModuleCfg.PathLen) = 0) then
        // already in buffer => leave function
        return;
      else
        pHelp := pHelp^.pNext;
      end_if;
    end_while;
    
    // if searched path has been found, we already got this module in our list
    if (ModuleCfg.PathLen = pHelp^.ModuleInfo.PathLen) & (To_StdLib.MemCmp(dest:= ModuleCfg.pPath, source:= pHelp^.ModuleInfo.pPath , size:= ModuleCfg.PathLen) = 0) then
      // already in buffer => leave function
      return;
    else
      pHelp^.pNext$pvoid := To_StdLib.Malloc(size:=sizeof(t_ModuleListElem));
      pHelp := pHelp^.pNext;
    end_if;
  end_if;
  
  if pHelp <> NIL then
    // allocate memory for the module path
    pHelp^.ModuleInfo.pPath$pVoid := To_StdLib.Malloc(size:=ModuleCfg.PathLen);
    if pHelp^.ModuleInfo.pPath = NIL then
      ClassState := _MemAllocFailed;
      retcode := -1;
      return;
    end_if;

    _memcpy(ptr1:=pHelp^.ModuleInfo.pPath, ptr2:=ModuleCfg.pPath, cntr:=ModuleCfg.PathLen);

    // allocate memory for the module path
    pHelp^.ModuleInfo.pCompPath$pVoid := To_StdLib.Malloc(size:=ModuleCfg.CompPathLen);
    if pHelp^.ModuleInfo.pCompPath = NIL then
      ClassState := _MemAllocFailed;

      retcode := -1;
      return;
    end_if;

    _memcpy(ptr1:=pHelp^.ModuleInfo.pCompPath, ptr2:=ModuleCfg.pCompPath, cntr:=ModuleCfg.CompPathLen);

    pHelp^.ModuleInfo.Info        := ModuleCfg.Info;
    pHelp^.ModuleInfo.SafetyNbr   := ModuleCfg.SafetyNbr;
    pHelp^.ModuleInfo.InterfaceCRC:= ModuleCfg.InterfaceCRC;
    pHelp^.ModuleInfo.DestCRCNo   := ModuleCfg.DestCRCNo;
    phelp^.ModuleInfo.pDestCRCs   := ModuleCfg.pDestCRCs;
    pHelp^.ModuleInfo.PathLen     := ModuleCfg.PathLen;
    pHelp^.ModuleInfo.CompPathLen := ModuleCfg.CompPathLen;
    pHelp^.ModuleInfo.PdoOutLen   := ModuleCfg.PdoOutLen;
    
    pHelp^.pNext                  := NIL;
    
    ModuleCfgNo += 1;
  else
    ClassState := _MemAllocFailed;
    retcode := -1;
    return;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::AddPdoToCfg
	VAR_INPUT
		PdoCfg 	: t_PdoCfg;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR
    pHelp : ^t_PdoListElem;
  END_VAR

  retcode := 0;

  if pFirstPdoCfg = NIL then
    pFirstPdoCfg$pVoid := To_StdLib.Malloc(size:=sizeof(t_PdoListElem));
    pHelp := pFirstPdoCfg;
  else
    pHelp := pFirstPdoCfg;
    // if searched path has been found, we already got this pdo in our list
    if (PdoCfg.SourcePathLen = pHelp^.PdoInfo.SourcePathLen) & (PdoCfg.DestPathLen = pHelp^.PdoInfo.DestPathLen) &
      (PdoCfg.InterfaceCRC = pHelp^.PdoInfo.InterfaceCRC) &
      (To_StdLib.MemCmp(dest:= PdoCfg.pSourcePath, source:= pHelp^.PdoInfo.pSourcePath , size:= PdoCfg.SourcePathLen) = 0) &
      (To_StdLib.MemCmp(dest:= PdoCfg.pDestPath,   source:= pHelp^.PdoInfo.pDestPath   , size:= PdoCfg.DestPathLen  ) = 0) then
      // already in buffer => leave function
      return;
    end_if;
    while pHelp^.pNext <> NIL do
      // if searched path has been found, we already got this pdo in our list
      if (PdoCfg.SourcePathLen = pHelp^.PdoInfo.SourcePathLen) & (PdoCfg.DestPathLen = pHelp^.PdoInfo.DestPathLen) &
        (PdoCfg.InterfaceCRC = pHelp^.PdoInfo.InterfaceCRC) &
        (To_StdLib.MemCmp(dest:= PdoCfg.pSourcePath, source:= pHelp^.PdoInfo.pSourcePath , size:= PdoCfg.SourcePathLen) = 0) &
        (To_StdLib.MemCmp(dest:= PdoCfg.pDestPath,   source:= pHelp^.PdoInfo.pDestPath   , size:= PdoCfg.DestPathLen  ) = 0) then
        // already in buffer => leave function
        return;
      else
        pHelp := pHelp^.pNext;
      end_if;
    end_while;
    
    // if searched path has been found, we already got this pdo in our list
    if (PdoCfg.SourcePathLen = pHelp^.PdoInfo.SourcePathLen) & (PdoCfg.DestPathLen = pHelp^.PdoInfo.DestPathLen) &
      (PdoCfg.InterfaceCRC = pHelp^.PdoInfo.InterfaceCRC) &
      (To_StdLib.MemCmp(dest:= PdoCfg.pSourcePath, source:= pHelp^.PdoInfo.pSourcePath , size:= PdoCfg.SourcePathLen) = 0) &
      (To_StdLib.MemCmp(dest:= PdoCfg.pDestPath,   source:= pHelp^.PdoInfo.pDestPath   , size:= PdoCfg.DestPathLen  ) = 0) then
      // already in buffer => leave function
      return;
    else
      pHelp^.pNext$pvoid := To_StdLib.Malloc(size:=sizeof(t_PdoListElem));
      pHelp := pHelp^.pNext;
    end_if;
  end_if;
  
  if pHelp <> NIL then
    // allocate memory for the module source path
    pHelp^.PdoInfo.pSourcePath$pVoid := To_StdLib.Malloc(size:=PdoCfg.SourcePathLen);
    if pHelp^.PdoInfo.pSourcePath = NIL then
      ClassState := _MemAllocFailed;
      retcode := -1;
      return;
    end_if;

    _memcpy(ptr1:=pHelp^.PdoInfo.pSourcePath, ptr2:=PdoCfg.pSourcePath, cntr:=PdoCfg.SourcePathLen);

    // allocate memory for the module source path
    pHelp^.PdoInfo.pDestPath$pVoid := To_StdLib.Malloc(size:=PdoCfg.DestPathLen);
    if pHelp^.PdoInfo.pDestPath = NIL then
      ClassState := _MemAllocFailed;
      retcode := -1;
      return;
    end_if;

    _memcpy(ptr1:=pHelp^.PdoInfo.pDestPath, ptr2:=PdoCfg.pDestPath, cntr:=PdoCfg.DestPathLen);

    pHelp^.PdoInfo.Info           := PdoCfg.Info;
    pHelp^.PdoInfo.InterfaceCRC   := PdoCfg.InterfaceCRC;
    pHelp^.PdoInfo.SourcePathLen  := PdoCfg.SourcePathLen;
    pHelp^.PdoInfo.DestPathLen    := PdoCfg.DestPathLen;
    // length is only zero for non-interface pdos
    if PdoCfg.Info.IsInterfacePDO = FALSE then
      pHelp^.PdoInfo.PdoLen       := 0;   // the length is determined later in method CreateAndSendCfg
    else
      pHelp^.PdoInfo.PdoLen       := PdoCfg.PdoLen;
    end_if;
    pHelp^.PdoInfo.PDO_ID         := 255; // the ID is assigned later by the safety manager of the master domain
    pHelp^.pNext                  := NIL;

    PdoCfgNo += 1;
  else
    ClassState  := _MemAllocFailed;
    retcode     := -1;
    return;
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::AddSlaveToCfg
	VAR_INPUT
		pModule 	    : ^PathInfoType;
		b_IsOptional 	: BOOL;
		b_IsInterface : BOOL;
		InterfaceCRC 	: HDINT;
	END_VAR
  VAR
    pHelp         : ^t_SlaveListElem;
  END_VAR

  if pFirstSlaveCfg = NIL then
    pFirstSlaveCfg$pVoid := To_StdLib.Malloc(size:=sizeof(t_SlaveListElem));
    pHelp := pFirstSlaveCfg;
  else
    pHelp := pFirstSlaveCfg;
    while pHelp^.pNext <> NIL do
      //if searched path is found, we already got this module in our list
      if (pModule^.ui_PathCompLen = pHelp^.SlaveInfo.CompPathLen) &
        (To_StdLib.MemCmp(dest:= pModule^.p_us_PathComp, source:= pHelp^.SlaveInfo.pCompPath , size:= pModule^.ui_PathCompLen) = 0) then
        // already in buffer => leave function
        return;
      else
        pHelp := pHelp^.pNext;
      end_if;
    end_while;

    //if searched path is found, we already got this module in our list
    if (pModule^.ui_PathCompLen = pHelp^.SlaveInfo.CompPathLen) &
      (To_StdLib.MemCmp(dest:= pModule^.p_us_PathComp, source:= pHelp^.SlaveInfo.pCompPath , size:= pModule^.ui_PathCompLen) = 0) then
      // already in buffer => leave function
      return;
    end_if;
    
    pHelp^.pNext$pvoid := To_StdLib.Malloc(size:=sizeof(t_SlaveListElem));
    pHelp := pHelp^.pNext;
  end_if;
  
  if pHelp <> NIL then
    // allocate memory for the module path
    pHelp^.SlaveInfo.PathLen := pModule^.p_us_Path^$UINT + 2;
    pHelp^.SlaveInfo.pPath$pVoid := To_StdLib.Malloc(size:=pHelp^.SlaveInfo.PathLen);
    if pHelp^.SlaveInfo.pPath = NIL then
      ClassState := _MemAllocFailed;
      LogError("@ZZZZ (SafetyCDIAS_Base::AddSlaveToCfg) Error: Failed to allocate memory for the module path");
      return;
    end_if;

    _memcpy(ptr1:=pHelp^.SlaveInfo.pPath, ptr2:=pModule^.p_us_Path, cntr:=pHelp^.SlaveInfo.PathLen);

    // allocate memory for the module path
    pHelp^.SlaveInfo.CompPathLen := pModule^.ui_PathCompLen;
    pHelp^.SlaveInfo.pCompPath$pVoid := To_StdLib.Malloc(size:=pHelp^.SlaveInfo.CompPathLen);
    if pHelp^.SlaveInfo.pCompPath = NIL then
      ClassState := _MemAllocFailed;
      LogError("@ZZZZ (SafetyCDIAS_Base::AddSlaveToCfg) Error: Failed to allocate memory for the compressed module path");
      return;
    end_if;

    _memcpy(ptr1:=pHelp^.SlaveInfo.pCompPath, ptr2:=pModule^.p_us_PathComp, cntr:=pHelp^.SlaveInfo.CompPathLen);

    pHelp^.SlaveInfo.Info             := 0;
    pHelp^.SlaveInfo.Info.IsOptional  := b_IsOptional;
    pHelp^.SlaveInfo.Info.IsInterface := b_IsInterface;

    pHelp^.SlaveInfo.InterfaceCRC     := InterfaceCRC;

    pHelp^.pNext                      := NIL;
    
    SlaveCfgNo += 1;
  else
    ClassState := _MemAllocFailed;
    LogError("@ZZZZ (SafetyCDIAS_Base::AddSlaveToCfg) Error: Failed to allocate memory for the new list-element");
    return;
  end_if;

END_FUNCTION

FUNCTION VIRTUAL SafetyCDIAS_Base::FreeCfgLists
  VAR
    pHelpModule : ^t_ModuleListElem;
    pHelpPdo    : ^t_PdoListElem;
    pHelpSlave  : ^t_SlaveListElem;
//    pHelpUnsafeVar : ^t_UnsafeVarListElem;
  END_VAR

  // while we got module cfgs 
  while pFirstModuleCfg do
    pHelpModule := pFirstModuleCfg;
    pFirstModuleCfg := pFirstModuleCfg^.pNext;
    
    if pHelpModule^.ModuleInfo.pDestCRCs then
      To_StdLib.Free(pHelpModule^.ModuleInfo.pDestCRCs);
    end_if;
    To_StdLib.Free(pHelpModule^.ModuleInfo.pPath);
    To_StdLib.Free(pHelpModule^.ModuleInfo.pCompPath);
    To_StdLib.Free(pHelpModule);
  end_while;
  pFirstModuleCfg := NIL;
  ModuleCfgNo     := 0;

  // while we got pdo cfgs
  while pFirstPdoCfg do
    pHelpPdo := pFirstPdoCfg;
    pFirstPdoCfg := pFirstPdoCfg^.pNext;
    
    To_StdLib.Free(pHelpPdo^.PdoInfo.pSourcePath);
    To_StdLib.Free(pHelpPdo^.PdoInfo.pDestPath);
    To_StdLib.Free(pHelpPdo);
  end_while;
  pFirstPdoCfg := NIL;
  PdoCfgNo := 0;

  // while we got slave cfgs 
  while pFirstSlaveCfg do
    pHelpSlave := pFirstSlaveCfg;
    pFirstSlaveCfg := pFirstSlaveCfg^.pNext;
    
    To_StdLib.Free(pHelpSlave^.SlaveInfo.pPath);
    To_StdLib.Free(pHelpSlave^.SlaveInfo.pCompPath);
    To_StdLib.Free(pHelpSlave);
  end_while;
  pFirstSlaveCfg := NIL;
  SlaveCfgNo := 0;

// memory is freed by safety manager
//  // while we got unsafevar cfgs
//  while pFirstUnsafeCfg do
//    pHelpUnsafeVar := pFirstUnsafeCfg;
//    pFirstUnsafeCfg := pFirstUnsafeCfg^.pNext;
//    
//    To_StdLib.Free(pHelpUnsafeVar^.UnsafeVarInfo.pName);
//    To_StdLib.Free(pHelpUnsafeVar);
//  end_while;
//  pFirstUnsafeCfg := NIL;
//  UnsafeCfgNo := 0;
  
  // reduze size of config mem used to 4 (only safety number of cpu module)
  ConfigMemSizeUsed := 4;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::CreateAndSendCfg
  VAR
    pHelpModule   : ^t_ModuleListElem;
    pHelpPdo      : ^t_PdoListElem;
    pHelpSlave    : ^t_SlaveListElem;
    pCfg          : ^void;
    TmpPathLen    : UINT;
		MyPara 	      : CmdStruct;
		MyResult	    : results;
    AddConfigSize : UDINT;
  END_VAR

(*
    Memory structure:
      4 Byte: SafetyNumber of CPU (is already there from initialisation in CSCP011_IM::InitSafeModule)
      1 Byte: Number of module configurations which are following
      for every module configuration (first is always the CPU itself)
        1 Byte: Info
        4 Byte: Interface Frame Source SafetyNumber (0 if it is no source for interface frames)
        4 Byte: Interface Frame CRC
        1 Byte: Number of destination inferface frame CRCs
        x Byte: Destination interface frame CRCs (number * sizeof(HDINT)
        2 Byte: Length of hardware path
        x Byte (depending on length in the 2 byte before): Hardwarepath
        2 Byte: Length of compressed hardware path
        x Byte (depending on length in the 2 byte before): Compressed Hardwarepath
        1 Byte: PDO out length for this module
      1 Byte: Number of pdo configurations which are following
      for every PDO configuration
        1 Byte: PDO length
        1 Byte: Interface frame info
        4 Byte: Interface CRC
        2 Byte: Length of source hardware path
        x Byte (depending on length in the 2 byte before): Hardwarepath of source
        2 Byte: Length of destination hardware path
        x Byte (depending on length in the 2 byte before): Hardwarepath of destination       
      1 Byte: Number of slave configurations which are following
      for every slave configuration
        1 Byte: Info
        4 Byte: InterfaceCRC
        2 Byte: Length of hardware path
        x Byte (depending on length in the 2 byte before): Hardwarepath
        2 Byte: Length of compressed hardware path
        x Byte (depending on length in the 2 byte before): Compressed Hardwarepath
*)

  // check if there is memory and if the only thing inside is the safety number
  if pConfigMem & (ConfigMemSizeUsed = 4) then
    // pCfg points to the next memory we have to write to => set it to the memory after the safety number
    pCfg := pConfigMem + ConfigMemSizeUsed;
        
    // add all module configurations to memory
    if pFirstModuleCfg then
      // add number of module configurations to memory (no need to check the memory here, because already 512 bytes are allocated)
      pCfg^$USINT       := ModuleCfgNo;
      pCfg              += sizeof(USINT);
      ConfigMemSizeUsed += sizeof(USINT);

      pHelpModule := pFirstModuleCfg;
      // go through list
      while pHelpModule do
        // add the elements
        
        // check if we have enough memory to add the next module
        AddConfigSize := sizeof(BSINT) + sizeof(HDINT) + sizeof(HDINT) + sizeof(UINT) + pHelpModule^.ModuleInfo.PathLen + sizeof(UINT) + pHelpModule^.ModuleInfo.CompPathLen + sizeof(USINT);
        if pHelpModule^.ModuleInfo.Info.IsInterfaceDest then
          AddConfigSize += sizeof(USINT) + pHelpModule^.ModuleInfo.DestCRCNo * sizeof(HDINT);
        end_if;

        pCfg := CheckConfigMemSize(AddConfigSize);
        if pCfg = NIL then
          // error message already logged by function
          return;
        end_if;

        // info
        pCfg^$BSINT := pHelpModule^.ModuleInfo.Info;
        pCfg              += sizeof(BSINT);
        ConfigMemSizeUsed += sizeof(BSINT);

        // safety number of interface frame source (if it is one)
        pCfg^$HDINT := pHelpModule^.ModuleInfo.SafetyNbr;
        pCfg              += sizeof(HDINT);
        ConfigMemSizeUsed += sizeof(HDINT);

        // interface CRC of interface frame
        pCfg^$HDINT := pHelpModule^.ModuleInfo.InterfaceCRC;
        pCfg              += sizeof(HDINT);
        ConfigMemSizeUsed += sizeof(HDINT);

        // if its also interface frame destination send the corresponding interface CRCs
        if pHelpModule^.ModuleInfo.Info.IsInterfaceDest then
          TmpPathLen := pHelpModule^.ModuleInfo.DestCRCNo; // save some time with this local variable
          pCfg^$USINT := TmpPathLen$USINT;
          pCfg              += sizeof(USINT);
          ConfigMemSizeUsed += sizeof(USINT);
       
          _memcpy(ptr1:=pCfg, ptr2:=pHelpModule^.ModuleInfo.pDestCRCs, cntr:=TmpPathLen * sizeof(HDINT));
          pCfg += TmpPathLen * sizeof(HDINT);
          ConfigMemSizeUsed += TmpPathLen * sizeof(HDINT);
        end_if;

        // uncompressed module path
        TmpPathLen := pHelpModule^.ModuleInfo.PathLen; // save some time with this local variable
        pCfg^$UINT := TmpPathLen;
        pCfg              += sizeof(UINT);
        ConfigMemSizeUsed += sizeof(UINT);
      
        _memcpy(ptr1:=pCfg, ptr2:=pHelpModule^.ModuleInfo.pPath, cntr:=TmpPathLen);
        pCfg += TmpPathLen;
        ConfigMemSizeUsed += TmpPathLen;

        // compressed module path
        TmpPathLen := pHelpModule^.ModuleInfo.CompPathLen; // save some time with this local variable
        pCfg^$UINT := TmpPathLen;
        pCfg              += sizeof(UINT);
        ConfigMemSizeUsed += sizeof(UINT);
      
        _memcpy(ptr1:=pCfg, ptr2:=pHelpModule^.ModuleInfo.pCompPath, cntr:=TmpPathLen);
        pCfg += TmpPathLen;
        ConfigMemSizeUsed += TmpPathLen;
      
        // PDO out length for this module (to assign the length to the pdo configurations)
        pCfg^$USINT := pHelpModule^.ModuleInfo.PdoOutLen;
        pCfg              += sizeof(USINT);
        ConfigMemSizeUsed += sizeof(USINT);
      
        pHelpModule := pHelpModule^.pNext;
      end_while;

      pCfg := CheckConfigMemSize(sizeof(USINT));
      if pCfg = NIL then
        // error message already logged by function
        return;
      end_if;

      // add number of pdo configurations to memory
      pCfg^$USINT := PdoCfgNo;
      pCfg              += sizeof(USINT);
      ConfigMemSizeUsed += sizeof(USINT);

      // add all pdo configurations to memory (module configs must be available, to find out the PDO length)
      if pFirstPdoCfg then
        pHelpPdo := pFirstPdoCfg;
        // go through list
        while pHelpPdo do
          // add the elements

          // check if we have enough memory to add the next module
          AddConfigSize := sizeof(USINT) + sizeof(BSINT) + sizeof(HDINT) + sizeof(UINT) + pHelpPdo^.PdoInfo.SourcePathLen + sizeof(UINT) + pHelpPdo^.PdoInfo.DestPathLen;
          pCfg := CheckConfigMemSize(AddConfigSize);
          if pCfg = NIL then
            // error message already logged by function
            return;
          end_if;

          // first of all we have to find out the pdo length of this element => search the module configurations until we find our source and copy the pdo length
          if pHelpPdo^.PdoInfo.PdoLen = 0 then
            pHelpModule := pFirstModuleCfg;
            // go through list
            while pHelpModule do
              // if the path of the source module matches, save the pdolength of this module
              if (pHelpPdo^.PdoInfo.SourcePathLen = pHelpModule^.ModuleInfo.PathLen) & (To_StdLib.MemCmp(dest:= pHelpPdo^.PdoInfo.pSourcePath, source:= pHelpModule^.ModuleInfo.pPath , size:= pHelpPdo^.PdoInfo.SourcePathLen) = 0) then
                pHelpPdo^.PdoInfo.PdoLen := pHelpModule^.ModuleInfo.PdoOutLen;
                exit;
              end_if;
              pHelpModule := pHelpModule^.pNext;
            end_while;
          end_if;

          
          // PDO Length
          pCfg^$USINT := pHelpPdo^.PdoInfo.PdoLen;
          pCfg              += sizeof(USINT);
          ConfigMemSizeUsed += sizeof(USINT);

          // info
          pCfg^$BSINT := pHelpPdo^.PdoInfo.Info;
          pCfg              += sizeof(BSINT);
          ConfigMemSizeUsed += sizeof(BSINT);

          // interface CRC
          pCfg^$HDINT := pHelpPdo^.PdoInfo.InterfaceCRC;
          pCfg              += sizeof(HDINT);
          ConfigMemSizeUsed += sizeof(HDINT);

          // Source Path Length
          TmpPathLen := pHelpPdo^.PdoInfo.SourcePathLen; // save some time with this local variable
          pCfg^$UINT := TmpPathLen;
          pCfg              += sizeof(UINT);
          ConfigMemSizeUsed += sizeof(UINT);
        
          // Source Path
          _memcpy(ptr1:=pCfg, ptr2:=pHelpPdo^.PdoInfo.pSourcePath, cntr:=TmpPathLen);
          pCfg += TmpPathLen;
          ConfigMemSizeUsed += TmpPathLen;

          // Destination Path Length
          TmpPathLen := pHelpPdo^.PdoInfo.DestPathLen; // save some time with this local variable
          pCfg^$UINT := TmpPathLen;
          pCfg              += sizeof(UINT);
          ConfigMemSizeUsed += sizeof(UINT);
        
          // Destination Path
          _memcpy(ptr1:=pCfg, ptr2:=pHelpPdo^.PdoInfo.pDestPath, cntr:=TmpPathLen);
          pCfg += TmpPathLen;
          ConfigMemSizeUsed += TmpPathLen;
        
          pHelpPdo := pHelpPdo^.pNext;
        end_while;
      end_if;

      pCfg := CheckConfigMemSize(sizeof(USINT));
      if pCfg = NIL then
        // error message already logged by function
        return;
      end_if;

      // add number of slave configurations to memory
      pCfg^$USINT       := SlaveCfgNo;
      pCfg              += sizeof(USINT);
      ConfigMemSizeUsed += sizeof(USINT);

      pHelpSlave := pFirstSlaveCfg;
      // go through list
      while pHelpSlave do
        // add the elements
        
        // check if we have enough memory to add the next module
        AddConfigSize := sizeof(BSINT) + sizeof(HDINT) + sizeof(UINT) + pHelpSlave^.SlaveInfo.PathLen + sizeof(UINT) + pHelpSlave^.SlaveInfo.CompPathLen;

        pCfg := CheckConfigMemSize(AddConfigSize);
        if pCfg = NIL then
          // error message already logged by function
          return;
        end_if;

        // info
        pCfg^$BSINT := pHelpSlave^.SlaveInfo.Info;
        pCfg              += sizeof(BSINT);
        ConfigMemSizeUsed += sizeof(BSINT);

        // InterfaceCRC
        pCfg^$HDINT := pHelpSlave^.SlaveInfo.InterfaceCRC;
        pCfg              += sizeof(HDINT);
        ConfigMemSizeUsed += sizeof(HDINT);

        // uncompressed Slave path
        TmpPathLen := pHelpSlave^.SlaveInfo.PathLen; // save some time with this local variable
        pCfg^$UINT := TmpPathLen;
        pCfg              += sizeof(UINT);
        ConfigMemSizeUsed += sizeof(UINT);
      
        _memcpy(ptr1:=pCfg, ptr2:=pHelpSlave^.SlaveInfo.pPath, cntr:=TmpPathLen);
        pCfg += TmpPathLen;
        ConfigMemSizeUsed += TmpPathLen;

        // compressed Slave path
        TmpPathLen := pHelpSlave^.SlaveInfo.CompPathLen; // save some time with this local variable
        pCfg^$UINT := TmpPathLen;
        pCfg              += sizeof(UINT);
        ConfigMemSizeUsed += sizeof(UINT);
      
        _memcpy(ptr1:=pCfg, ptr2:=pHelpSlave^.SlaveInfo.pCompPath, cntr:=TmpPathLen);
        pCfg += TmpPathLen;
        ConfigMemSizeUsed += TmpPathLen;
      
        pHelpSlave := pHelpSlave^.pNext;
      end_while;

    else
      // add number of module, pdo and slave configurations to memory (all as 0)
      
      // no module configs
      pCfg^$USINT := 0;
      pCfg              += sizeof(USINT);
      ConfigMemSizeUsed += sizeof(USINT);

      // no pdo configs
      pCfg^$USINT := 0;
      pCfg              += sizeof(USINT);
      ConfigMemSizeUsed += sizeof(USINT);

      // no slave configs
      pCfg^$USINT := 0;
      pCfg              += sizeof(USINT);
      ConfigMemSizeUsed += sizeof(USINT);
    end_if;    

    MyPara.uiCmd := CMD_SM_CPU_CFG_TO_MANAGER;
    MyPara.aPara[0] := ConfigMemSizeUsed$DINT;
    MyPara.aPara[1] := pConfigMem$DINT;
    if pSafetyManagerThis^.NewInst(#MyPara, #MyResult) = READY then
      // the manager takes care of our memory from now on
      pFirstSlaveCfg := NIL;
    end_if;    
    
    // now tell the manager, what kind of configuration we have
    MyPara.uiCmd := CMD_SM_NEW_CFG_TYPE;
    MyPara.aPara[0] := SafetyNumber$DINT;
    MyPara.aPara[1] := NewConfigType;
    pSafetyManagerThis^.NewInst(#MyPara, #MyResult);
  else
    LogError("@ZZZZ (SafetyCDIAS_Base::CreateAndSendCfg) No config memory or invalid memory size usage");
  end_if;

END_FUNCTION

#pragma warning(disable: 73)
FUNCTION VIRTUAL SafetyCDIAS_Base::CheckVariant
	VAR_INPUT
		us_ActVariant 	: USINT;
	END_VAR
	VAR_OUTPUT
		b_IsOK 	        : BOOL;
	END_VAR

  // if the overwritten methods are getting deleted, we already have a code for compatiblity here
  b_IsOK := TRUE; // FALSE;

END_FUNCTION
#pragma warning(default: 73)


FUNCTION SafetyCDIAS_Base::SendAllUnsafeValues
  VAR
  	pHelpUnsafeOut : ^UnsafeIORoutingElement;
  END_VAR

  // mark all unsafe values as not sent
  pHelpUnsafeOut := p_UnsafeInputsTable;
  while pHelpUnsafeOut do
    pHelpUnsafeOut^.b_AlreadyTransmitted := FALSE;
    
    pHelpUnsafeOut := pHelpUnsafeOut^.pNext;
  end_while;
  
  // reset the actual pointer
  pUnsafeInElement := NIL;

END_FUNCTION


FUNCTION SafetyCDIAS_Base::GetDestinationCRCs
  VAR
    pHelpModule : ^t_ModuleListElem;
    pHelpPdo    : ^t_PdoListElem;
  END_VAR

  // go through the module list
  pHelpModule := pFirstModuleCfg;
  while pHelpModule do
    pHelpPdo := pFirstPdoCfg;
    while pHelpPdo do
      // search in the PDOs if this module is an interface frame destination somewhere
      if pHelpPdo^.PdoInfo.Info.IsInterfacePDO then 
        if (pHelpPdo^.PdoInfo.DestPathLen = pHelpModule^.ModuleInfo.PathLen) &
         (To_StdLib.MemCmp(dest:= pHelpModule^.ModuleInfo.pPath, source:= pHelpPdo^.PdoInfo.pDestPath , size:= pHelpModule^.ModuleInfo.PathLen) = 0) then
          pHelpModule^.ModuleInfo.Info.IsInterfaceDest := TRUE;
          if pHelpModule^.ModuleInfo.DestCRCNo & pHelpModule^.ModuleInfo.pDestCRCs then
            pHelpModule^.ModuleInfo.pDestCRCs$^void := To_StdLib.ReAlloc(mptr:=pHelpModule^.ModuleInfo.pDestCRCs, newsize:=(pHelpModule^.ModuleInfo.DestCRCNo+1) * sizeof(HDINT));
          else
            pHelpModule^.ModuleInfo.pDestCRCs$^void := To_StdLib.Malloc(sizeof(HDINT));
          end_if;
          
          (pHelpModule^.ModuleInfo.pDestCRCs + pHelpModule^.ModuleInfo.DestCRCNo * sizeof(HDINT))^ := pHelpPdo^.PdoInfo.InterfaceCRC;
          
          pHelpModule^.ModuleInfo.DestCRCNo += 1;
        end_if;
      else
        // if this is module is optional and it's the source of the PDO => the pdo is also optional
        if pHelpModule^.ModuleInfo.Info.IsOptional & (pHelpPdo^.PdoInfo.SourcePathLen = pHelpModule^.ModuleInfo.PathLen) &
         (To_StdLib.MemCmp(dest:= pHelpModule^.ModuleInfo.pPath, source:= pHelpPdo^.PdoInfo.pSourcePath , size:= pHelpModule^.ModuleInfo.PathLen) = 0) then
          pHelpPdo^.PdoInfo.Info.IsOptional := TRUE;
        end_if;
      end_if;
          
      pHelpPdo := pHelpPdo^.pNext;
    end_while;
  
    pHelpModule := pHelpModule^.pNext;
  end_while;

END_FUNCTION


FUNCTION SafetyCDIAS_Base::CountBits
	VAR_INPUT
		BitMask 	: BDINT;
	END_VAR
	VAR_OUTPUT
		BitNo 	  : UDINT;
	END_VAR
  
  BitNo := 0;
  
  while BitMask do
    BitMask := BitMask AND (BitMask - 1);
    BitNo += 1;
  end_while;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::IsOptimizedCPU
	VAR_OUTPUT
		IsOptimized 	: DINT;
	END_VAR

  if us_Variant = CSCP012_SERIES then
    IsOptimized := TRUE;
  else
    IsOptimized := FALSE;
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::CheckConfigMemSize
	VAR_INPUT
		AddConfigSize 	: UDINT;
	END_VAR
	VAR_OUTPUT
		pCfg 	          : ^void;
	END_VAR
  VAR
  	pTempMem        : ^void;
  END_VAR

  pCfg := NIL;
  
  if ((ConfigMemSizeUsed + AddConfigSize) > ConfigMemSize) & (AddConfigSize <= CONFIG_MEMORY_BLOCK_SIZE) then
    // if there isn't enough memory => reallocate
    pTempMem := To_StdLib.ReAlloc(mptr:=pConfigMem, newsize:=ConfigMemSize + CONFIG_MEMORY_BLOCK_SIZE);
    IF pTempMem <> NIL THEN
      pConfigMem := pTempMem;
      ConfigMemSize += CONFIG_MEMORY_BLOCK_SIZE;
    ELSE
      ClassState := _MemAllocFailed;
      LogError("@ZZZZ (SafetyCDIAS_Base::CheckConfigMemSize) Failed to reallocate configuration memory!");
      return;
    END_IF;
  elsif (AddConfigSize > CONFIG_MEMORY_BLOCK_SIZE) then
    ClassState := _MemAllocFailed;
    LogError("@ZZZZ (SafetyCDIAS_Base::CheckConfigMemSize) The configuration of a single config element is too big to handle!");          
    return;
  end_if;

  pCfg := pConfigMem + ConfigMemSizeUsed;
          
END_FUNCTION


FUNCTION SafetyCDIAS_Base::DToH
	VAR_INPUT
		pt 	    : ^CHAR;
		value 	: DINT;
	END_VAR
  VAR
    val     : UDINT;
  END_VAR

  // this method converts a single byte into a zero-terminated hexstring like 0xA4 => "A4"
  val := value$UDINT;

  // zero termination
  (pt + 2)^ := 0;

  // start with the low nibble
  if (val AND 16#F) < 10 then
    (pt + 1)^ := (val AND 16#F)$USINT + '0';
  else
    (pt + 1)^ := (val AND 16#F)$USINT - 10 + 'A';
  end_if;

  // now get the high nibble
  val := val / 16;

  if (val AND 16#F) < 10 then
    pt^ := (val AND 16#F)$USINT + '0';
  else
    pt^ := (val AND 16#F)$USINT - 10 + 'A';
  end_if;
  
END_FUNCTION


FUNCTION SafetyCDIAS_Base::LogHWPath
	VAR_INPUT
		pString 	: ^CHAR;
		pHWPath 	: ^USINT;
	END_VAR
  VAR
    TempStr   : ARRAY [0..99] OF CHAR;
    TraceVal  : USINT;
    i         : UINT;
    MyMsg     : ARRAY [0..599] OF CHAR;
  END_VAR

  if pString & pHWPath then

    _strncpy(dest:=#MyMsg[0], src:=pString, max:=200);
  
    TraceVal := pHWPath^;
    if TraceVal then
      TraceVal  += 2; //show also the length
      i         := 0;
      while (TraceVal >= 1) & (i < 95) do
        DToH(#TempStr[i], pHWPath^$USINT);
        i         += 2; // 2 chars per byte
        TempStr[i]:= ' ';
        i         += 1;
        pHWPath   += 1;
        TraceVal  -= 1;
      end_while;
      TempStr[i] := 0;

      _strcat( dest:=#MyMsg[0], src:=#TempStr[0]);
    end_if;

#ifdef HWC_LogError
    HWC_LogError(this, #MyMsg[0]);
#endif
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyCDIAS_Base::QuitComError::Write
	VAR_INPUT
		input (EAX) 	: DINT;
	END_VAR
	VAR_OUTPUT
		result (EAX) 	: DINT;
	END_VAR

 	result := input;

  if b_QuitErrorAvailable then
    // remember to do it in next background
    QuitComError := 2;
  else
    // remember. that there has been a manual quit (for writing PDOs in PostScan)
    b_ManualQuit := TRUE;
    
    // remember to do it in next cyclic
    QuitComError := 1;
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::GetFWVersion
	VAR_INPUT
		pData 	: ^CHAR;
		length 	: DINT;
	END_VAR
  
  //Check pointer
  if pData then
    //Length of Firmwareversion (HDINT) -> 8Byte +1 byte zero termination
    if Length >= 9 then
      _itoa(udNumber:=FW_Version, pString:=pData);  
    else
      pData^ := 0;
    end_if; 
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyCDIAS_Base::GetDiagConnect::NewInst
	VAR_INPUT
		pPara 	  : ^CmdStruct;
		pResult 	: ^Results;
	END_VAR
	VAR_OUTPUT
		ret_code 	: IprStates;
	END_VAR
  
	ret_code := READY;

	CASE pPara^.uiCmd OF
  
    CMD_SM_DIAG_GET_INFO:
      
      //Subcommand
      case pPara^.aPara[0] of
//*****************************************************************************
        SBCMD_SM_DIAG_GET_INFO: 
          pResult^.aData[0] :=  GetDiagInfo(pDiagInfo:=(pPara^.aPara[1])$^SafetyDiagInfo);
               
//*****************************************************************************
        SBCMD_SM_DIAG_GET_STATE:
          pResult^.aData[0] :=  GetDiagState(pDiagState:=(pPara^.aPara[1])$^SafetyDiagState);
      
//*****************************************************************************
        SBCMD_SM_DIAG_FETCH_INFO:
          //Fetch Diag Info for uCx
          FetchDiagInfo(ucChoice:=pPara^.aPara[1]$USINT);          
    
//*****************************************************************************
        SBCMD_SM_DIAG_FETCH_STATE:
          FetchDiagState();
               
//*****************************************************************************
        SBCMD_SM_DIAG_IS_SAVE_LOG_ACTIVE:
          pResult^.aData[0] := SaveLogActive();
      
//*****************************************************************************
        SBCMD_SM_DIAG_SAVE_LOGFILE:
          pResult^.aData[0] := (SaveLog(ucChoice:=(pPara^.aPara[1])$USINT, pDPNE:=(pPara^.aPara[2])$^CHAR))$USINT;

//*****************************************************************************
        SBCMD_SM_DIAG_GET_SAVE_LOGFILE_STATE:
          pResult^.aData[0] := DiagVars.SavingLogSuccessful$USINT;
      
//*****************************************************************************
        SBCMD_SM_DIAG_GET_SAFETY_NUMBER:     
          pResult^.aData[0]$UDINT := SafetyNumber;
      
//*****************************************************************************
        SBCMD_SM_DIAG_GET_SAFETY_STATE:
          pResult^.aData[0] := ClassState$USINT;

//*****************************************************************************          
        SBCMD_SM_DIAG_IS_DIAGNOSE_AVAILABLE:          
          pResult^.aData[0] := TRUE;
          
//*****************************************************************************          
        SBCMD_SM_DIAG_GET_CHANNEL_INFO:
          pResult^.aData[0] := GetChannelInfo(pErrorMemUser:=(pPara^.aPara[1])$^UINT, pErrorMem:=#aErrorMem[1], ErrorDataLength:=aErrorMem[0] - 1);
          pResult^.aData[1] := aErrorMem[0] - 1;
 
//*****************************************************************************          
        SBCMD_SM_DIAG_FETCH_CHANNEL_INFO:
          FetchChannelInfo();
          
//*****************************************************************************          
        SBCMD_SM_DIAG_GET_ERRORCODE_OFFSET:
                    
          //Check for valid version
          if pPara^.aPara[1] = 0x01 then  //Version
            
            ret_code := READY;          
            pResult^.aData[0] := 0x01;  //return version
            pResult^.aData[1]$UDINT := GetDiagVisualOffsetErrorCode();
            
            pResult^.uiLng := 12;
            
          else
            
            //invalid version, return error
            ret_code := 1$IprStates; //means iprStates::ERROR but a server error also exists

            pResult^.aData[0] := 0x0;
            pResult^.uiLng    := 4;
            
          end_if;
          
      end_case;      
    else
      TRACE("(SafetyCDIAS_Base::GetDiagConnect::NewInst) Unknown command!");
      ret_code := 1$IprStates; //means iprStates::ERROR but a server error also exists
        
	END_CASE;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyCDIAS_Base::FetchChannelInfo

  DiagVars.UserErrorInfoReady := FALSE;
  DiagVars.UserWantsErrorInfo := TRUE;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::GetChannelInfo
	VAR_INPUT
		pErrorMemUser 	: ^UINT;
		pErrorMem 	: ^USINT;
		ErrorDataLength 	: INT;
	END_VAR
	VAR_OUTPUT
		StateReady 	: BOOL;
	END_VAR
  VAR
  	i   : INT;
  END_VAR
  
  
  StateReady := DiagVars.UserErrorInfoReady;
  
  if StateReady then
    //copy error values in UserArray
    for i := 0 to ErrorDataLength-1 do
      
      pErrorMemUser^ := pErrorMem^; 
      
      //set pointer to next entry     
      pErrorMemUser += sizeof(UINT);
      pErrorMem += sizeof(USINT);
    end_for;   
  end_if;

END_FUNCTION


FUNCTION VIRTUAL SafetyCDIAS_Base::GetDiagVisualOffsetErrorCode
	VAR_OUTPUT
		udOffset 	: UDINT;
	END_VAR
  
  //In the safety firmware for the CSCP and SCP there is only one byte for the errorcode
  //To have different errorcodes (between CSCP and SCP) the safetydesigner adds a fix offset of 1000 to the errorcodes of the SCP01x and SCP11x
  udOffset := 0;

END_FUNCTION
