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

(*!
<Class
	Name               = "HwControl"
	Revision           = "5.24"
	GUID               = "{4794F3F9-7ABA-4680-9933-0608225B5265}"
	RealtimeTask       = "false"
	DefRealtime        = "1 ms"
	DefRealtimeIndex   = "0"
	CyclicTask         = "false"
	DefCyclictime      = "1 ms"
	DefCyclicIndex     = "2147483392"
	BackgroundTask     = "false"
	Sigmatek           = "true"
	OSInterface        = "false"
	HighPriority       = "false"
	Automatic          = "false"
	UpdateMode         = "Prescan"
	IconPath           = ".\Class\HwControl\HwControl.ico"
	SharedCommandTable = "true"
	Objectsize         = "(646,120)"
	Comment            = "Class to handle VaranManager,  and the cooperation with DiasMasterC">
	<Channels>
		<Server Name="Control">
		</Server>
		<Server Name="DiasMaster" WriteProtected="false" Comment="connect to client &apos;to_HWControl&quot; of class DiasMasterC if used (if Server is 1 class is connected)&#13;&#10;">
		</Server>
		<Server Name="SafetyState" GUID="{7E088AB6-AB0A-450E-964A-E46FE15A0D4B}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Shows state of safety functionality initialisation&#13;&#10;&#13;&#10; 1..OK&#13;&#10; 0..not active or initializing&#13;&#10;-1..failed to allocate memory&#13;&#10;-2..invalid domain number set in this system&#13;&#10;-3..newer OS version required for domain number support&#13;&#10;-4..method to determine domain number not provided by lsl_st_hardwaretree.h&#13;&#10;-5..only 1 instance of safety manager allowed&#13;&#10;-6..a slave system can only have 1 master. check hw class configuration&#13;&#10;-7..invalid module type tried to log in&#13;&#10;-8..couldn&apos;t find InterfaceCRC which is requested by other domain. Check SafetyDesigner projects, most likely the interface variables doesn&apos;t match.&#13;&#10;-9..failed to add a new copy data object to varan manager&#13;&#10;-10..a non-optional module or domain is not available&#13;&#10;-11..timeout in initialisation (see debugger trace or logfile for further details)&#13;&#10;-13..the class safetymanager could not login into the class HwControl."/>
		<Client Name="HwcLogging" Required="true" Internal="true"/>
		<Client Name="HWRtPostScan" Required="true" Internal="true"/>
		<Client Name="InterfaceNo" Required="false" Internal="false" DefValue="1" Comment="If interface frames via IP address are used, this is the place to choose the interface number&#13;&#10;&#13;&#10;For example if you set the IP of interface 1 via autoexec.lsl setting SET IP 1 HOSTADDR x.x.x.x and this is what you want to use, you choose 1 for the interface number."/>
		<Client Name="RtTaskSync" Required="false" Internal="false" DefValue="0" Comment="With this setting the realtime task synchronization between more cores can be activated.&#13;&#10;If it is activated and not supported, the client is set to 0.&#13;&#10;As an initialization value. For further information look at library help.&#13;&#10;0 .. deactivated (default)&#13;&#10;1 .. activated&#13;&#10;&#13;&#10;"/>
		<Client Name="SafetyDomainTimeout" Required="false" Internal="false" Comment="[ms] the class has to wait for optional interface domains (leave 0 if none available)&#13;&#10;Set this client to 1 when using FlexCon functionality (without interface domains) where it&apos;s possible that not all participants are available at all times"/>
		<Client Name="SafetyManager" Required="true" Internal="true"/>
		<Client Name="UdpSafetyPort" Required="false" Internal="false" DefValue="10823" Comment="If interface frames via IP address are used, this is the place to choose the port.&#13;&#10;It&apos;s recommended to only change the port (all communication partners must use the same port!) if there would be a conflict with the default port 10823."/>
	</Channels>
	<Dependencies>
		<Files>
			<File Path=".\Class\VaranManager_Base\VaranManager_Base.h" Include="false"/>
			<File Path=".\Class\HwControl\HwControl.h" Include="true"/>
			<File Path=".\Class\HwControl\watchdog.h" Include="true"/>
			<File Path=".\Source\interfaces\lsl_st_sysinfo.h" Include="true"/>
			<File Path=".\Source\interfaces\lsl_st_systrace.h" Include="true"/>
			<File Path=".\Class\HwControl\_HWKScope.h" Include="true"/>
		</Files>
	</Dependencies>
	<RevDoku>
		<Owner Company="Sigmatek" Author="renste"/>
		<Dokumentation Revision="5.24" Date="13.12.2024" Author="LanSte" Company="Sigmatek" Description="Added support for Get Required Wait Time"/>
		<Dokumentation Revision="5.23" Date="27.09.2024" Author="RamAnd" Company="Sigmatek" Description="SafetyDomainTimeout now also sets the timeout to wait for optional UDP interface frames.&#13;&#10;Mapping of PDOs in the VBC/VMC memory could have been wrong which would prevent the routing of the safety PDOs.&#13;&#10;Prevented access to uninitialized pointer when an optional reading interface frame via VBC/VMC was not available that could have lead to a crash.&#13;&#10;Prevent sending the current interface frame configuration to the counterparts too fast which could cause problems with the SDO buffer.&#13;&#10;The startup of multiple stations connected via VBC/VMC has been reworked to speed up the connection establishment.&#13;&#10;The number of possible internal interface frames has been increased from 10 to 100.&#13;&#10;The maximum number of interface frame informations from other stations has been increased from 150 to 500."/>
		<Dokumentation Revision="5.22" Date="11.09.2024" Author="RamAnd" Company="Sigmatek" Description="Corrected collecting module information of safety interface frame communication partners that could have lead to a wrong restriction of the number of possible modules."/>
		<Dokumentation Revision="5.21" Date="30.09.2022" Author="RamAnd" Company="Sigmatek" Description="The busy state of the safety CPU wasn&apos;t detected correctly when establishing UDP connections."/>
		<Dokumentation Revision="5.20" Date="13.07.2022" Author="RamAnd" Company="Sigmatek" Description="Try again to establish a safety UDP connection if the attempt failed because the safe CPU was busy."/>
		<Dokumentation Revision="5.19" Date="22.03.2022" Author="RamAnd" Company="Sigmatek" Description="Added support for the new OS Interface to quit errors"/>
		<Dokumentation Revision="5.18" Date="17.01.2022" Author="EisMic" Company="Sigmatek" Description="Testversion: Forward the NewInst commando CMD_HWC_CONVERT_COMPRESSED_HWPATH to the SafetyManager class."/>
		<Dokumentation Revision="5.17" Date="30.11.2021" Author="EisMic" Company="Sigmatek" Description="Added global functions to determine the current operation system.&#13;&#10;Added global function HWC_IsPostInitFinished to determine if the postinit phase is finished or not."/>
		<Dokumentation Revision="5.16" Date="23.10.2020" Author="PieSte" Company="Sigmatek" Description="Added support for new blocktype and extended routing of FSoE data for this type.&#13;&#10;Corrected allocate of udp buffers at &quot;AddModule()&quot;.&#13;&#10;Don&apos;t Log AddDynSlave error if RetCode is zero at GetDestSafetyOfDO() Methode."/>
		<Dokumentation Revision="5.15" Date="18.12.2020" Author="RamAnd" Company="Sigmatek" Description="Removed CLI/STI occurances in internal time measurements"/>
		<Dokumentation Revision="5.14" Date="13.03.2020" Author="Berste1" Company="Sigmatek" Description="Registration for Pll readjustment added"/>
		<Dokumentation Revision="5.13" Date="08.04.2020" Author="PieSte" Company="Sigmatek" Description="Add client RtTaskSync for realtime synchronization if more than one core is used.&#13;&#10;Corrected nil pointer &quot;pStr_HWTreeEntry&quot; at newinst command &quot;CMD_GET_HARDWARE_DIAGNOSIS&quot;."/>
		<Dokumentation Revision="5.12" Date="02.03.2020" Author="FurDom" Company="Sigmatek" Description="Reworked to support newer CPUs (address space &gt; 0x80000000). Needs SafetyUDP class version &gt;= 1.4!"/>
		<Dokumentation Revision="5.11" Date="14.08.2019" Author="LanSte" Company="Sigmatek" Description="Added header file: _HWKScope.h for scope interface. "/>
		<Dokumentation Revision="5.10" Date="08.11.2019" Author="RamAnd" Company="Sigmatek" Description="Detached the logging functionality from HwControl into a new class HwcLogging which is used now as an embedded object in HwControl.&#13;&#10;Added more logging possibilities via new function _HwcLog_sprintfST."/>
		<Dokumentation Revision="5.9" Date="18.07.2019" Author="RamAnd" Company="Sigmatek" Description="Corrected that SDO forwarding would not work properly in some cases.&#13;&#10;Prevent writing to an invalid pointer when resetting UDP connections that could have lead to a crash."/>
		<Dokumentation Revision="5.8" Date="25.06.2019" Author="RamAnd" Company="Sigmatek" Description="Added support for FlexCon functionality."/>
		<Dokumentation Revision="5.7" Date="14.03.2019" Author="RamAnd" Company="Sigmatek" Description="Removed limitations of formerly unallowed safety topologies (since v4.0)"/>
		<Dokumentation Revision="5.6" Date="12.02.2019" Author="PieSte" Company="Sigmatek" Description="The Sequence Number in the SafetyManager class for Udp Safety communication has been extended from 1 to 4 bytes. This increases the availability of the Udp Safety connection. Furthermore two clients have been added at internal class SafetyManager to set the Request Cycle (Default 10) and the Response Timeout (Default 100ms) to optimize the Safety UDP bus load. This setting may only be changed after consultation with Sigmatek.  (SA43141)&quot;/&gt;"/>
		<Dokumentation Revision="5.5" Date="22.01.2019" Author="EisMic" Company="Sigmatek" Description="Corrected an error that the Realtime/Cyclic task of the class was called 2 times if the derivation of the class has a configured Realtime/Cyclic Task. (The error apperared since v5.0)"/>
		<Dokumentation Revision="5.4" Date="15.11.2018" Author="LanSte" Company="Sigmatek" Description="SafetyManager: Added support for custom FSoE Connections."/>
		<Dokumentation Revision="5.3" Date="27.08.2018" Author="PieSte" Company="Sigmatek" Description="Behaviour of safety udp communication when resetting the bSequenceCntReceived flag after maximum of retries corrected. (SafetyManager)"/>
		<Dokumentation Revision="5.2" Date="18.07.2018" Author="PieSte&#13;&#10;EisMic" Company="Sigmatek" Description="Added support for HGW1033-3. (in SafetyManager)&#13;&#10;Removed incorrect LogMessage. Corrected access exception in method CalculateTaskInfo.&#13;&#10;OS_AddTraceKeyVal is not used anymore with OS-Version between 9.1.0 and 9.3.0. Not supported with these versions."/>
		<Dokumentation Revision="5.1" Date="19.06.2018" Author="ZoePat" Company="Sigmatek" Description="Corrected a possible reboot of some CPUs (CCP512, CCP612, CP212, and similar). The error appeared since V5.0 if the SRAM was accessed via the cyclic-task of the HWControl."/>
		<Dokumentation Revision="5.0" Date="26.03.2018" Author="EisMic" Company="Sigmatek" Description="Added support for 2nd realtime.&#13;&#10;Added support for 2nd varanmanager.&#13;&#10;Removed task settings from object. Task-settings for realtime and cyclic task are now calculated depending on the connected hardware-classes. See documentation for more details.&#13;&#10;Extended the methods AddFirstCallHw and AddHwObject by some parameters to select a CPU-core and task-times.&#13;&#10;Added support for SmartIO modules."/>
		<Dokumentation Revision="4.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="4.14" Date="18.01.2018" Author="EisMic" Company="Sigmatek" Description="Added new NewInst command to get supported features by HwControl.&#13;&#10;The newinst cmd CMD_SET_POSTINIT_DONE will now be send to all connected classes instead of only to the DiasMaster."/>
		<Dokumentation Revision="4.13" Date="23.01.2018" Author="RamAnd" Company="Sigmatek" Description="Log messages have been standardized for easier maintenance, easier use in any class and to allow spam filtering. Code for the logging functions is now only located in HwControl."/>
		<Dokumentation Revision="4.12" Date="05.01.2018" Author="PieSte" Company="Sigmatek" Description="The safety UDP communication at &quot;SafetyManager&quot; class has been made more reliable. Now only new packages are allowed and old packages are discarded."/>
		<Dokumentation Revision="4.11" Date="18.09.2017" Author="LanSte" Company="Sigmatek" Description="Added NewInst Commands to check if the Post-Init is done."/>
		<Dokumentation Revision="4.10" Date="29.08.2017" Author="RamAnd" Company="Sigmatek" Description="The VaranManager can now tell the HwControl if it doesn&apos;t have any clients connected. In this case the HwControl is in charge of triggering the internal watchdog."/>
		<Dokumentation Revision="4.9" Date="22.08.2017" Author="RamAnd" Company="Sigmatek" Description="Fixed an error which prevented two SCP111s on the same PLC from exchanging interfaceframes in both directions."/>
		<Dokumentation Revision="4.8" 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="4.7" Date="22.06.2017" Author="RamAnd" Company="Sigmatek" Description="If a disconnect happens in a multi master system with safety communication (more than 2 systems connected and exchanging safety data) now the other masters are notified about it to reestablish the connection."/>
		<Dokumentation Revision="4.6" Date="01.03.2017" Author="EisMic" Company="Sigmatek" Description="Corrected an error in the handling of optional safety modules."/>
		<Dokumentation Revision="4.5" Date="14.02.2017" Author="ZoePat" Company="Sigmatek" Description="SdiasModules can now request to increase the PostInit timeout."/>
		<Dokumentation Revision="4.4" Date="21.09.2016" Author="PieSte" Company="Sigmatek" Description="Add methode &quot;AddFirstCallHW&quot; for objects which are called as first at HwControl Realtime. In the TraceView scope is the and of first object call as UserEvent0 with data = 1.215.775.599 marked. "/>
		<Dokumentation Revision="4.3" Date="28.01.2016" Author="RamAnd" Company="Sigmatek" Description="Support for FSoE via IP added."/>
		<Dokumentation Revision="4.2" Date="06.06.2016" Author="EisMic" Company="Sigmatek" Description="Corrected error if distributed safety modules are connected after the initialisation phase."/>
		<Dokumentation Revision="4.1" 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="4.0" Date="30.11.2015" Author="ZoePat&#13;&#10;LanSte" Company="Sigmatek" Description="Check for unallowed safety topology."/>
		<Dokumentation Revision="3.9" Date="21.10.2015" Author="RamAnd" Company="Sigmatek" Description="Support for MS012 added"/>
		<Dokumentation Revision="3.8" Date="19.05.2015" Author="RamAnd" Company="Sigmatek" Description="If two systems with FSoE safety were connected via VBC/VMC an error in the connection establishment could cause the FSoE connection to fail."/>
		<Dokumentation Revision="3.7" Date="15.04.2015" Author="RamAnd" Company="Sigmatek" Description="Added another step in initialisation to prevent watchdog error."/>
		<Dokumentation Revision="3.6" Date="16.10.2014&#13;&#10;25.03.2015" Author="RamAnd&#13;&#10;PieSte" Company="Sigmatek" Description="Support for SCP111 added.&#13;&#10;Support for SDD1300, SDD1400, SDD1500 and SDD1600 added."/>
		<Dokumentation Revision="3.5" Date="12.11.2014" Author="PieSte" Company="Sigmatek" Description="Removed trace message if watchdog interface is not available."/>
		<Dokumentation Revision="3.4" Date="28.10.2014" Author="RamAnd" Company="Sigmatek" Description="If an error has been reported to HwControl, it is now forwarded to the DiasMasterC object (if there is one)."/>
		<Dokumentation Revision="3.3" Date="10.10.2014" Author="PieSte" Company="Sigmatek" Description="Added Watchdog API and trigger watchdog in postscan task."/>
		<Dokumentation Revision="3.2" Date="18.06.2014" Author="EisMic" Company="Sigmatek" Description="Added support for reading hardware diagnosis via newinst cmd: CMD_GET_HARDWARE_DIAGNOSE "/>
		<Dokumentation Revision="3.1" Date="17.06.2014" Author="RamAnd" Company="Sigmatek" Description="Added possibility to start a quit error via OS interface."/>
		<Dokumentation Revision="3.0" Date="15.04.2014" Author="RamAnd" Company="Sigmatek" Description="Changed initialisation: &#13;&#10; - Activation of hardware classes realtime task as well as completing CDIAS/DIAS initialisation is now done in post init instead of last init&#13;&#10; - No realtime is running in the first initialisation of the modules&#13;&#10; - New second initialisation where realtime is running to check if the realtime data are valid"/>
		<Dokumentation Revision="2.0" Date="12.02.2014" Author="PieSte" Company="Sigmatek" Description="Improved description of CyWork method."/>
		<Dokumentation Revision="1.50" Date="06.12.2013" Author="LanSte&#13;&#10;RamAnd&#13;&#10;FucHer" Company="Sigmatek" Description="Ensured that he class is copatible with old loader versions that do not support the post init phase.&#13;&#10;Removed domain support&#13;&#10;Changed AWL code to Structured Text.&#13;&#10;If the task setting for cyclic task fails, the error wasn&apos;t displayed.&#13;&#10;The task setting for cyclic task didn&apos;t work (only required if existing object is updated)."/>
		<Dokumentation Revision="1.40" Date="01.08.2013" Author="RamAnd" Company="Sigmatek" Description="Corrected error, where the user classes are already called during SDIAS initialisation."/>
		<Dokumentation Revision="1.30" Date="18.07.2013" Author="RamAnd" Company="Sigmatek" Description="Added PostInit interface of loader, where after the last init the varan managers can initialize modules until they are ready."/>
		<Dokumentation Revision="1.20" Date="07.03.2013" Author="RamAnd" Company="Sigmatek" Description="Changed range of the safety NewInst commands. Range for HW-Classes: 0x8000-0x8FFF; Range for Safety HW-Classes: 0x8100-0x81FF"/>
		<Dokumentation Revision="1.15" Date="23.12.2011" Author="RamAnd" Company="Sigmatek" Description="Added support for the SafetyManager"/>
		<Dokumentation Revision="1.14" Date="14.02.2012" Author="RamAnd" Company="Sigmatek" Description="Watchdog is now also triggered if no VARAN/DIAS interface is available (needed for internal IOs of Edge ETVs)"/>
		<Dokumentation Revision="1.13" Date="25.05.2011" Author="RamAnd" Company="Sigmatek" Description="PostScan-Calls in Init-Phase are now done in HwControl instead of VaranManager."/>
		<Dokumentation Revision="1.12" Date="27.10.2010" Author="RamAnd" Company="Sigmatek" Description="Added RtPostScan support for special hardware like the IOs of an Edge ETV"/>
		<Dokumentation Revision="1.11" Date="13.08.2010" Author="BleErn" Company="Sigmatek" Description="Postscan calls were not stopped on error"/>
		<Dokumentation Revision="1.10" Date="22.07.2010" Author="WocPet" Company="Sigmatek" Description="New functionality added to display required error from diasmaster"/>
		<Dokumentation Revision="1.9" Date="13.07.2010" Author="BleErn" Company="Sigmatek" Description="Content of corresponding LASAL Hardware Description file (.lhd) which is necessary for the hardware editor has been corrected"/>
		<Dokumentation Revision="1.8" Date="03.03.2010" Author="BleErn" Company="Sigmatek" Description="Added Handling for DiasMaster RtPostScan"/>
		<Dokumentation Revision="1.7" Date="08.02.2010" Author="BleErn" Company="Sigmatek" Description="Added Baseclass for RtPostScan with DIAS/CDIAS/CTMS&#13;&#10;Caution: RtPostScan cannot be used together with RtDebug!"/>
		<Dokumentation Revision="1.6" Date="10.03.2010" Author="RamAnd" Company="Sigmatek" Description="Added Support for various IOs (e.g. ETV Edge IOs)"/>
		<Dokumentation Revision="1.5" Date="03.02.2009" Author="RamAnd" Company="Sigmatek" Description="Added Synchronity check if VMC is used."/>
	</RevDoku>
	<Network Name="HwControl">
		<!-- List of Components in this network -->
		<Components>
			<Object
				Name       = "_base"
				GUID       = "{4EF772E0-592A-4829-B661-2E7E0E1B8913}"
				Class      = "HwControlBase"
				Position   = "(218,120)"
				Visualized = "false"
				RealTime   = "1 ms">
				<Channels>
					<Server Name="Control"/>
					<Server Name="DiasMaster"/>
					<Server Name="State"/>
					<Client Name="RtDebug"/>
					<Client Name="To_StdLib"/>
					<Client Name="To_TaskObjectControl"/>
				</Channels>
			</Object>
			<Object
				Name       = "HwcLogging"
				GUID       = "{3532143A-BD06-42EA-B855-9758BF64895A}"
				Class      = "HwcLogging"
				Position   = "(150,540)"
				Visualized = "false">
				<Channels>
					<Server Name="ClassSvr"/>
					<Server Name="OverrideSpamProtection"/>
					<Client Name="To_SigCLib"/>
				</Channels>
			</Object>
			<Object
				Name       = "HWRtPostScan"
				GUID       = "{2898FBA7-3B52-4F51-87F4-0F7670C09C64}"
				Class      = "HWRtPostScan"
				Position   = "(150,930)"
				Visualized = "false"
				RealTime   = "1 ms"
				RealIndex  = "1073741824">
				<Channels>
					<Server Name="ClassSvr"/>
					<Client Name="toHwControlBase"/>
				</Channels>
			</Object>
			<Object
				Name       = "SafetyManager"
				GUID       = "{4545C840-4FB2-4C80-B150-345DF08208A7}"
				Class      = "SafetyManager"
				Position   = "(960,360)"
				Visualized = "true"
				CyclicTime = "10 ms">
				<Channels>
					<Server Name="ClassState"/>
					<Server Name="InitFault"/>
					<Server Name="InitSSM"/>
					<Server Name="LoginCnt"/>
					<Server Name="MaxSyncDuration"/>
					<Server Name="MinSyncDuration"/>
					<Server Name="sControl"/>
					<Server Name="sErrorCount"/>
					<Server Name="sLastErrorMessage"/>
					<Server Name="sLastErrorNoOS"/>
					<Server Name="sTReceive"/>
					<Server Name="SyncDuration"/>
					<Client Name="InterfaceNo" Value="1"/>
					<Client Name="SafetyDomainTimeout"/>
					<Client Name="To_HwControl"/>
					<Client Name="To_MultiTask"/>
					<Client Name="To_OSKernel"/>
					<Client Name="UdpSafetyPort" Value="10823"/>
					<Client Name="UdpSafetyRequestCycle" Value="UDP_MIN_REQUEST_TIME"/>
					<Client Name="UdpSafetyResponseTimeout" Value="UDP_MIN_RESPONSE_TIMEOUT"/>
				</Channels>
			</Object>
		</Components>
		<Comments>
		</Comments>
		<!-- List of Connections in this network -->
		<Connections>
			<Connection Source="this.Control" Destination="_base.Control" Vertices="(1794,210),(886,210),"/>
			<Connection Source="this.State" Destination="_base.State" Vertices="(1794,270),(886,270),"/>
			<Connection Source="this.DiasMaster" Destination="_base.DiasMaster" Vertices="(1794,330),(886,330),"/>
			<Connection Source="_base.RtDebug" Destination="this.RtDebug" Vertices="(218,330),(120,330),(120,210),(38,210),"/>
			<Connection Source="this.SafetyManager" Destination="SafetyManager.ClassState"/>
			<Connection Source="SafetyManager.To_HwControl" Destination="_base.Control" Vertices="(960,570),(930,570),(930,210),(886,210),"/>
			<Connection Source="SafetyManager.UdpSafetyPort" Destination="this.UdpSafetyPort" Vertices="(960,450),(38,450),"/>
			<Connection Source="SafetyManager.SafetyDomainTimeout" Destination="this.SafetyDomainTimeout" Vertices="(960,750),(930,750),(930,750),(120,750),(120,390),(38,390),"/>
			<Connection Source="SafetyManager.InterfaceNo" Destination="this.InterfaceNo" Vertices="(960,510),(38,510),"/>
			<Connection Source="this.SafetyState" Destination="SafetyManager.ClassState" Vertices="(1794,390),(1740,390),(1740,450),(1622,450),"/>
			<Connection Source="this.HWRtPostScan" Destination="HWRtPostScan.ClassSvr"/>
			<Connection Source="HWRtPostScan.toHwControlBase" Destination="_base.Control" Vertices="(150,1020),(120,1020),(120,870),(930,870),(930,210),(886,210),"/>
			<Connection Source="this.HwcLogging" Destination="HwcLogging.ClassSvr"/>
		</Connections>
		<!-- Headerfiles -->
		<Options>
		</Options>
	</Network>
</Class>
*)
#pragma using HwControlBase

HwControl : CLASS
: HwControlBase
	TYPE
	  pVaranManager : ^VaranManager;
	  t_DMFunctions : STRUCT
	    p_RtFunction : pVoid;
	    p_SendSync : pVoid;
	    p_FinishIMProg : pVoid;
	    p_LastInit : pVoid;
	    p_This : pVoid;
	    sd_PllTime : DINT;
	    ud_DiasTime : UDINT;
	    sd_RtDebug : DINT;
	    p_RtPostScanFunction : pVoid;
	    SafetyManagerThisPointer : ^pVirtualBase;
	  END_STRUCT;
	  t_DiasMaster : STRUCT
	    ud_Counter : UDINT;
	    p_Functions : ^t_DMFunctions;
	  END_STRUCT;
#pragma pack(push, 1)
	  t_HwObjectListCallFirst : STRUCT
	    pThis : pVirtualBase;
	    udLoggedInNumber : UDINT;
	    us_CoreSelect : USINT;
	    ud_RtTime_us : UDINT;
	    ud_CyTime_us : UDINT;
	    pNext : ^t_HwObjectListCallFirst;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_HwObjectListElement : STRUCT
	    pThis : pVirtualBase;
	    pRtPostScan : ^UDINT;  //! <Type Comment="used for EdgeETV IOs" Name="t_HwObjectListElement.pRtPostScan"/>
	    bdSettings : t_HwObjListSettings;
	    usEscSequence : USINT;  //! <Type Comment="Escapesequence that identifies the bustype." Name="t_HwObjectListElement.usEscSequence"/>
	    us_CoreSelect : USINT;
	    ud_RtTime_us : UDINT;
	    ud_CyTime_us : UDINT;
	    pNext : ^t_HwObjectListElement;
	  END_STRUCT;
#pragma pack(pop)
	  t_VMFunctions : STRUCT
	    p_This : pVaranManager;
	    ud_VaranTime : UDINT;
	    b_IsAlsoClient : BOOL;
	    ud_SuperiorTime : UDINT;
	    b_HWClassSynchron : BOOL;
	    b_OverrideFrameCheck : BOOL;
	    SafetyManagerThisPointer : ^pVirtualBase;
	    Reserved1 : DINT;
	    Reserved2 : DINT;
	  END_STRUCT;
	  t_OneVaranManager : STRUCT
	    ud_CounterRt : UDINT;
	    ud_CounterCy : UDINT;
	    ud_SuperiorSync : UDINT;
	    ud_SuperiorSyncActual : UDINT;
	    p_Functions : ^t_VMFunctions;
	    usOldFrameCnt : USINT;
	    usActFrameCnt : USINT;
	    usSyncCheck : USINT;
	    us_CoreSelect : USINT;
	    ud_RtTime_us : UDINT;
	    ud_CyTime_us : UDINT;
	  END_STRUCT;
#pragma pack(push, 1)
	  t_s_CallFirstObject : STRUCT
	    pThis : pVirtualBase;
	    us_CoreSelect : USINT;
	    ud_RtTime_us : UDINT;
	    ud_CyTime_us : UDINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_s_RtTaskControl : STRUCT
	    pvPreRtSyncTaskEvent : pVoid;
	    pvPostRtSyncTaskEvent : pVoid;
	    udPreRtCnt : UDINT;
	    udPostRtCnt : UDINT;
	    b_RtTaskControlActive : BOOL;
	    usCoresRtActive : USINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_s_TaskCoreInfo : STRUCT
	    us_CoreSelect : USINT;
	    ud_MyRtTaskTime_us : UDINT;  //! <Type Comment="tasktime of HwControl realtime task of the core" Name="t_s_TaskCoreInfo.ud_MyRtTaskTime_us"/>
	    ud_MyCyTaskTime_us : UDINT;  //! <Type Comment="tasktime of HwControl cyclic task of the core" Name="t_s_TaskCoreInfo.ud_MyCyTaskTime_us"/>
	    uiHwTimeStamp_us : UINT;
	    ud_FirstPostScanCall : UDINT;
	    ud_LastPostScanWorkCall : UDINT;
	    b_PostScanStarted : BOOL;
	  END_STRUCT;
#pragma pack(pop)
	END_TYPE
  //Servers:
	SafetyState 	: SvrCh_DINT;
  //Clients:
	SafetyManager 	: CltChCmd_SafetyManager;
	SafetyDomainTimeout 	: CltCh_UDINT;
	UdpSafetyPort 	: CltCh_UDINT;
	InterfaceNo 	: CltCh_UDINT;
	RtTaskSync 	: CltCh_DINT;
	HWRtPostScan 	: CltChCmd_HWRtPostScan;
	HwcLogging 	: CltChCmd_HwcLogging;
  //Variables:
		a_VaranManager : ARRAY [0..MAX_VARAN_MANAGERS-1] OF t_OneVaranManager;
			//! <Variable Comment="array of structures for VaranManager functions and settings" Name="a_VaranManager"/>
		s_DiasMaster 	: t_DiasMaster;			//! <Variable Comment="structure for DiasMaster functions and settings" Name="s_DiasMaster"/>
		us_Initcounter 	: USINT;			//! <Variable Comment="varaiable to count init steps" Name="us_Initcounter"/>
		p_DebugAPI 	: ^DEBUGAPI;			//! <Variable Comment="pointer to debug API (OS - Interface)" Name="p_DebugAPI"/>
		p_WatchdogAPI 	: ^LSLAPI_IWATCHDOG;
		pCallFirstObjects 	: ^t_HwObjectListCallFirst;
		sCallFirstObjects : ARRAY [0..HWCONTROL_MAX_FIRSTCALL_OBJECTS-1] OF t_s_CallFirstObject;

		bCallFirstObjects 	: BOOL;
		VaranManagersAvailable 	: USINT;
		pSCDW 	: ^LSL_CDIASWATCHDOG;
		pHwControlLogins 	: ^t_HwObjectListElement;
		b_PostInitInstalled 	: BOOL;
		pSystrace 	: ^OS_SYSTRACE;
		AdditionalPostInitTime 	: UDINT;
		SupportedFeatures 	: t_HWC_SupportedFeatureBits1;
		pLSLSysInfo 	: ^LSL_SYSINFO_TYPE;
		ud_CPUCoreCount 	: UDINT;			//! <Variable Comment="Shows the amount of CPU cores of the current CPU." Name="ud_CPUCoreCount"/>
		us_CPUsRtCyEnabled 	: USINT;
		aHwControl_Times : ARRAY [0..TASK_SELECT_COREMAX] OF t_HwControl_Times_SINGLE;
			//! <Variable Comment="Shows the measured times if the time measurement is activated in HwControl.h with the define HWCONTROL_TIME_MEASUREMENT." Name="aHwControl_Times"/>
		aTaskInfoCore : ARRAY [0..TASK_SELECT_COREMAX] OF t_s_TaskCoreInfo;
			//! <Variable Comment="Shows information of the supported cores." Name="aTaskInfoCore"/>
		sRtTaskControl 	: t_s_RtTaskControl;
		pSpecialObjects 	: ^t_HwObjectListElement;
		mt_api 	: ^LSL_MT_TYPE;
		b_SoftwareSyncActive 	: BOOL;
  //Functions:
				//! <Function Comment="[#ENGLISH]&#13;&#10;=================================================================================================&#13;&#10;Init for HwControl class&#13;&#10;=================================================================================================&#13;&#10;[clients] RtDebug    :R&#13;&#10;[members] us_InitCounter  :R/W :varaiable to count init steps&#13;&#10;   p_DebugAPI   :W  :pointer to debug API (OS - Interface)&#13;&#10;   s_DiasMaster  :R  :structure for DiasMaster functions and settings&#13;&#10;" Name="Init"/>
	FUNCTION VIRTUAL GLOBAL Init;
	
	FUNCTION VIRTUAL GLOBAL CyWork
		VAR_INPUT
			EAX 	: UDINT;
		END_VAR
		VAR_OUTPUT
			state (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL RtWork
		VAR_INPUT
			EAX 	: UDINT;
		END_VAR
		VAR_OUTPUT
			state (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION HwControl
		VAR_OUTPUT
			ret_code 	: ConfStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL UpdateRtPostScan;
				//! <Function Comment="no longer used." Name="AddSafetyManager"/>
	FUNCTION VIRTUAL GLOBAL AddSafetyManager
		VAR_INPUT
			pThis 	: pVirtualBase;
		END_VAR
		VAR_OUTPUT
			pFirstVM 	: pVirtualBase;
		END_VAR;
				//! <Function Comment="no longer used." Name="DisableSafetyManager"/>
	FUNCTION VIRTUAL GLOBAL DisableSafetyManager;
				//! <Function Comment="[#ENGLISH]&#13;&#10;=================================================================================================&#13;&#10;Class to call a function pointer&#13;&#10;=================================================================================================&#13;&#10;" Name="CallPtr"/>
	FUNCTION CallPtr
		VAR_INPUT
			p_function 	: pVoid;			//! <Variable Comment="pointer to function should be called" Name="CallPtr.p_function"/>
			p_this 	: pVoid;			//! <Variable Comment="thispointer of object" Name="CallPtr.p_this"/>
		END_VAR;
				//! <Function Comment="Function to get Tasktime of Hwcontrol class&#13;&#10;" Name="GetMyTaskTime"/>
	FUNCTION GLOBAL GetMyTaskTime
		VAR_INPUT
			us_CoreSelect 	: DINT := 0;			//! <Variable Comment="Coreselect 0 ... ud_task_time is realtime task time of core 0.&#13;&#10;Coreselect 1 ... ud_task_time is realtime task time of core 1." Name="GetMyTaskTime.us_CoreSelect"/>
		END_VAR
		VAR_OUTPUT
			ud_task_time 	: UDINT;			//! <Variable Comment="rt task time in ns" Name="GetMyTaskTime.ud_task_time"/>
		END_VAR;
				//! <Function Comment="Function to add a VaranManager to HwControl list" Name="AddVaranManager"/>
	FUNCTION GLOBAL AddVaranManager
		VAR_INPUT
			ud_manager_number 	: UDINT;			//! <Variable Comment="number of varan manager&#13;&#10;" Name="AddVaranManager.ud_manager_number"/>
			p_function_list 	: ^void;			//! <Variable Comment="pointer to function list and settings of VaranMaster" Name="AddVaranManager.p_function_list"/>
			us_CoreSelect 	: USINT := 0;			//! <Variable Comment="Selection on which core the manager should be called." Name="AddVaranManager.us_CoreSelect"/>
			ud_RtTime_us 	: UDINT := 0;			//! <Variable Comment="Realtime task time in µs.&#13;&#10;The time will be used in the calculation for the realtime task time of the selected core.&#13;&#10;The calculated time of the HwControl will be distributed to the logged in object with the newinst command CMD_POST_INIT_DISTRIBUTE_TASKTIMES.&#13;&#10;For more information about the task time settings look in the hardware class documentation." Name="AddVaranManager.ud_RtTime_us"/>
			ud_CyTime_us 	: UDINT := 0;			//! <Variable Comment="Cyclic task time in µs.&#13;&#10;The time will be used in the calculation for the cyclic task time of the selected core.&#13;&#10;The calculated time of the HwControl will be distributed to the logged in object with the newinst command CMD_POST_INIT_DISTRIBUTE_TASKTIMES.&#13;&#10;For more information about the task time settings look in the hardware class documentation." Name="AddVaranManager.ud_CyTime_us"/>
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;			//! <Variable Comment="Returncode of the function.&#13;&#10;0 ... OK&#13;&#10;&lt;&gt; 0 ... Error" Name="AddVaranManager.sd_retval"/>
		END_VAR;
				//! <Function Comment="Function to remove a Varanmanager from the HwControl list." Name="DisableVaranManager"/>
	FUNCTION GLOBAL DisableVaranManager
		VAR_INPUT
			ud_manager_number 	: UDINT;			//! <Variable Comment="number of varan manager" Name="DisableVaranManager.ud_manager_number"/>
			p_function_list 	: ^void;			//! <Variable Comment="pointer to function list and settings of VaranMaster" Name="DisableVaranManager.p_function_list"/>
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;			//! <Variable Comment="Returncode of the function.&#13;&#10;0 ... OK&#13;&#10;&lt;&gt; 0 ... Error" Name="DisableVaranManager.sd_retval"/>
		END_VAR;
				//! <Function Comment="Function sets Hardware off&#13;&#10;" Name="SetHardwareOff"/>
	FUNCTION GLOBAL SetHardwareOff
		VAR_INPUT
			e_error 	: t_e_VaranErrors;			//! <Variable Comment="reason why hardware is set off" Name="SetHardwareOff.e_error"/>
		END_VAR;
				//! <Function Comment="Function returns Debug State" Name="GetRtDebugState"/>
	FUNCTION GLOBAL GetRtDebugState
		VAR_OUTPUT
			sd_RtDebug 	: DINT;
		END_VAR;
				//! <Function Comment="function to add a special hw. &#13;&#10;function should only be used from hardware classes.&#13;&#10;Has to be called in initialisation phase.&#13;&#10;&#13;&#10;This object will be called in realtime and cyclic task from the HwControl. Only on core 0.&#13;&#10;&#13;&#10;Attention:&#13;&#10;To select a core on which the special hw should be called, please use the method AddHwObject." Name="AddSpecialHW"/>
	FUNCTION GLOBAL AddSpecialHW
		VAR_INPUT
			pThis 	: pVirtualBase;			//! <Variable Comment="Thispointer of object." Name="AddSpecialHW.pThis"/>
			pRtPostScan 	: ^UDINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION PostScanWork
		VAR_INPUT
			us_CoreSelect 	: USINT;
		END_VAR;
				//! <Function Comment="This function prototype is used to call functions via function pointers." Name="ObjectFunct"/>
	FUNCTION ObjectFunct;
				//! <Function Comment="function to login objects which are called as first objects in HwControl realtime.&#13;&#10;Has to be called in initialisation phase.&#13;&#10;&#13;&#10;Objects which are logged in at the HwControl via this function will get an NewInst call with the command CMD_POST_INIT_DISTRIBUTE_TASKTIMES at the beginning of the post init phase.&#13;&#10;The calculated tasktimes (realtime and cyclic) will be distributed to the classes. The data structure of the command can be seen at the definition of the NewInst command in the Headerfile HwControl.h." Name="AddFirstCallHW"/>
	FUNCTION GLOBAL AddFirstCallHW
		VAR_INPUT
			pThis 	: pVirtualBase;			//! <Variable Comment="pointer on object to call in RtWork" Name="AddFirstCallHW.pThis"/>
			udSelectPlace 	: UDINT;			//! <Variable Comment="Select order of first calls beginning from 0.&#13;&#10;Only one number per object possible.&#13;&#10;0 .. first object&#13;&#10;1 .. second object&#13;&#10;2 .. third object&#13;&#10;....&#13;&#10;max place .. last object" Name="AddFirstCallHW.udSelectPlace"/>
			us_CoreSelect 	: USINT := 0;			//! <Variable Comment="Selection from which core the object should be called.&#13;&#10;0 ... Core 0&#13;&#10;1 ... Core 1&#13;&#10;x ... Core x" Name="AddFirstCallHW.us_CoreSelect"/>
			ud_RtTime_us 	: UDINT := 0;			//! <Variable Comment="Realtime task time in µs.&#13;&#10;The time will be used in the calculation for the realtime task time of the selected core.&#13;&#10;The calculated time of the HwControl will be distributed to the logged in object with the newinst command CMD_POST_INIT_DISTRIBUTE_TASKTIMES.&#13;&#10;For more information about the task time settings look in the hardware class documentation." Name="AddFirstCallHW.ud_RtTime_us"/>
			ud_CyTime_us 	: UDINT := 0;			//! <Variable Comment="Cyclic task time in µs.&#13;&#10;The time will be used in the calculation for the cyclic task time of the selected core.&#13;&#10;The calculated time of the HwControl will be distributed to the logged in object with the newinst command CMD_POST_INIT_DISTRIBUTE_TASKTIMES.&#13;&#10;For more information about the task time settings look in the hardware class documentation." Name="AddFirstCallHW.ud_CyTime_us"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;			//! <Variable Comment="return value of function&#13;&#10; 0 .. ok&#13;&#10;-1  ... invalid place number&#13;&#10;-2  ... place already selected&#13;&#10;-3  ... object login is to late, it must be done before last init cycle&#13;&#10;-4  ... parameter us_CoreSelect is invalid. (see debugger trace for details)&#13;&#10;-5  ... multicore support not supported by LSL_ITASK interface.&#13;&#10;-6  ... HwControl does not support the number of parameter us_CoreSelect&#13;&#10;-7  ... parameter ud_RtTime_us is smaller than CPU maintimer.&#13;&#10;-8  ... parameter ud_RtTime_us is not a multiple of CPU maintimer.&#13;&#10;-9  ... parameter ud_CyTime_us is smaller than CPU maintimer.&#13;&#10;-10 ... parameter ud_RtTime_us is not a multiple of CPU maintimer." Name="AddFirstCallHW.retcode"/>
		END_VAR;
	
	FUNCTION InstallPostInitCB
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
	
	FUNCTION UpdateRtFirstCallObjects
		VAR_INPUT
			usCoreSelect 	: USINT;
		END_VAR;
	
	FUNCTION UpdateRtLoginObjects
		VAR_INPUT
			usCoreSelect 	: USINT;
		END_VAR;
	
	FUNCTION UpdateRtPostscanLoginObjects
		VAR_INPUT
			usCoreSelect 	: USINT;
		END_VAR;
	
	FUNCTION UpdateRtVaranManager
		VAR_INPUT
			usActiveCore 	: USINT;
		END_VAR;
	
	FUNCTION UpdateRtPostScanVaranManager
		VAR_INPUT
			usActiveCore 	: USINT;
		END_VAR;
				//! <Function Comment="function to add a hw object which will be called in the realtime and cyclic task on the selected core.&#13;&#10;function should only be used from hardware classes.&#13;&#10;Has to be called in initialisation phase." Name="AddHwObject"/>
	FUNCTION GLOBAL AddHwObject
		VAR_INPUT
			pThis 	: pVirtualBase;			//! <Variable Comment="Thispointer of object." Name="AddHwObject.pThis"/>
			Settings 	: t_HwObjListSettings;
			EscapeSequence 	: USINT := 0;
			us_CoreSelect 	: USINT := 0;			//! <Variable Comment="Selection from which core the object should be called.&#13;&#10;0 ... Core 0&#13;&#10;1 ... Core 1&#13;&#10;x ... Core x" Name="AddHwObject.us_CoreSelect"/>
			ud_RtTime_us 	: UDINT := 0;			//! <Variable Comment="Realtime task time in µs.&#13;&#10;The time will be used in the calculation for the realtime task time of the selected core.&#13;&#10;The calculated time of the HwControl will be distributed to the logged in object with the newinst command CMD_POST_INIT_DISTRIBUTE_TASKTIMES.&#13;&#10;For more information about the task time settings look in the hardware class documentation." Name="AddHwObject.ud_RtTime_us"/>
			ud_CyTime_us 	: UDINT := 0;			//! <Variable Comment="Cyclic task time in µs.&#13;&#10;The time will be used in the calculation for the cyclic task time of the selected core.&#13;&#10;The calculated time of the HwControl will be distributed to the logged in object with the newinst command CMD_POST_INIT_DISTRIBUTE_TASKTIMES.&#13;&#10;For more information about the task time settings look in the hardware class documentation." Name="AddHwObject.ud_CyTime_us"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;			//! <Variable Comment="return value of function&#13;&#10; 0 .. ok&#13;&#10;-1  ... failed to allocate memory for hw object&#13;&#10;-2  ... parameter pThis is invalid&#13;&#10;-4  ... parameter us_CoreSelect is invalid. (see debugger trace for details)&#13;&#10;-5  ... multicore support not supported by LSL_ITASK interface.&#13;&#10;-6  ... HwControl does not support the number of parameter us_CoreSelect&#13;&#10;-7  ... parameter ud_RtTime_us is smaller than CPU maintimer.&#13;&#10;-8  ... parameter ud_RtTime_us is not a multiple of CPU maintimer.&#13;&#10;-9  ... parameter ud_CyTime_us is smaller than CPU maintimer.&#13;&#10;-10 ... parameter ud_RtTime_us is not a multiple of CPU maintimer." Name="AddHwObject.retcode"/>
		END_VAR;
	
	FUNCTION CalcTimeMeasurementPreScan
		VAR_INPUT
			pHwControlTimes 	: ^t_HwControl_Times_SINGLE;
		END_VAR;
	
	FUNCTION CalcTimeMeasurementPostScan
		VAR_INPUT
			pHwControlTimes 	: ^t_HwControl_Times_SINGLE;
		END_VAR;
	
	FUNCTION CalcTimeMeasurementCyclic
		VAR_INPUT
			pHwControlTimes 	: ^t_HwControl_Times_SINGLE;
		END_VAR;
	
	FUNCTION CalculateTaskInfo
		VAR_INPUT
			us_CoreSelect 	: USINT;
			pTaskInfo 	: ^t_s_TaskCoreInfo;
		END_VAR;
	
	FUNCTION CalculateGGT
		VAR_INPUT
			Var1 	: UDINT;
			Var2 	: UDINT;
		END_VAR
		VAR_OUTPUT
			ggT 	: UDINT;
		END_VAR;
	
	FUNCTION RtPreScan_CoreX
		VAR_INPUT
			pCoreSelect 	: ^void;
		END_VAR;
	
	FUNCTION CyWork_CoreX
		VAR_INPUT
			pCoreSelect 	: ^void;
		END_VAR;
	
	FUNCTION RtPostScan_CoreX
		VAR_INPUT
			pCoreSelect 	: ^void;
		END_VAR;
				//! <Function Comment="Function which returns the ITASK Version of the OS." Name="Get_ITASK_Version"/>
	FUNCTION Get_ITASK_Version
		VAR_OUTPUT
			version 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL Control::NewInst
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
				//! <Function Comment="[#ENGLISH]&#13;&#10;=================================================================================================&#13;&#10;Write Function of DiasMaster&#13;&#10;=================================================================================================&#13;&#10;[server] State    :W  :server shows error state of HwControl class&#13;&#10;   DiasMaster   :W  :server which is connected to DiasMaster&#13;&#10;[members] s_DiasMaster  :W  :pointer to DiasMaster functions and settings&#13;&#10;" Name="DiasMaster.Write"/>
	FUNCTION VIRTUAL GLOBAL DiasMaster::Write
		VAR_INPUT
			input (EAX) 	: DINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL SafetyState::Read
		VAR_OUTPUT
			output (EAX) 	: DINT;
		END_VAR;
  //Tables:
	FUNCTION @STD
		VAR_OUTPUT
			ret_code	: CONFSTATES;
		END_VAR;
	FUNCTION GLOBAL TAB @CT_;
END_CLASS;

#pragma using HwcLogging
#pragma using HWRtPostScan
#pragma using SafetyManager


//}}LSL_DECLARATION


FUNCTION GLOBAL TAB HwControl::@CT_
0$UINT,
2#0100000000000000$UINT, //TY_HWCONTROL
5$UINT, 24$UINT, (SIZEOF(::HwControl))$UINT, 
1$UINT, 7$UINT, 0$UINT, 
TO_UDINT(2471641665), "HwControl", //Class
TO_UDINT(1193052171), "HwControlBase", 1$UINT, 10$UINT, //Baseclass
//Servers:
(::HwControl.SafetyState.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1504224158), "SafetyState", 
//Clients:
(::HwControl.SafetyManager.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000010$UINT, TO_UDINT(1799751072), "SafetyManager", TO_UDINT(1799751072), "SafetyManager", 2$UINT, 28$UINT, 
(::HwControl.SafetyDomainTimeout.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000100$UINT, TO_UDINT(1863305286), "SafetyDomainTimeout", 
(::HwControl.UdpSafetyPort.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000100$UINT, TO_UDINT(3294470351), "UdpSafetyPort", 
(::HwControl.InterfaceNo.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000100$UINT, TO_UDINT(2005113602), "InterfaceNo", 
(::HwControl.RtTaskSync.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(3691411803), "RtTaskSync", 
(::HwControl.HWRtPostScan.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000010$UINT, TO_UDINT(4260294091), "HWRtPostScan", TO_UDINT(4260294091), "HWRtPostScan", 1$UINT, 0$UINT, 
(::HwControl.HwcLogging.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000010$UINT, TO_UDINT(3078259981), "HwcLogging", TO_UDINT(3078259981), "HwcLogging", 1$UINT, 0$UINT, 
END_FUNCTION


#define USER_CNT_HwControl 3

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

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

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

	_memcpy((#vmt.CmdTable)$^USINT, HwControlBase::Control.pMeth, nCmdSize);
	vmt.CmdTable.nCmds		:= nSTDCMD + USER_CNT_HwControl;
	vmt.CmdTable.NewInstr		:= #Control::NewInst();
	vmt.CmdTable.Init		:= #Init();
	vmt.CmdTable.CyWork		:= #CyWork();
	vmt.CmdTable.RtWork		:= #RtWork();
#pragma warning (disable : 74)
	vmt.UserFcts[0]		:= #UpdateRtPostScan();

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

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

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

	IF HwControlBase::Control.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	DiasMaster.pMeth			:= StoreMethod( #M_RD_DIRECT(), #DiasMaster::Write() );
	IF DiasMaster.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	SafetyState.pMeth			:= StoreMethod( #SafetyState::Read(), #M_NO_F() );
	IF SafetyState.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	ret_code	:= HwControl();

END_FUNCTION

#pragma usingLtd VaranManager

//{{LSL_IMPLEMENTATION
#pragma using VaranManager_Base
#pragma using VaranManager

#include <lsl_st_xtimer.h>

(************************************************************************************
*
*	Class controlls timing of DiasMaster and VaranMaster (later for more VaranMasters)
*	Created : Sigmatek	/	SR	/	March-April 2006
*	Changes : 
*
*
*   FOR NEWER CHANGES SEE REVISION DOCUMENTATION OF CLASS
*
*
*		1.3 => 1.4 	/   30.06.2008 
*           - [DB 884]: prevent exception in method DiasMaster::Write
*		1.2 => 1.3  /   21.03.2008
*			- [DB 817]: set RtDebug-Flag in DiasMaster
*		1.1 => 1.2	/	29.02.2008
*			- [DB 770]:	add function to get Rt-Debug State
*		1.0 => 1.1	/	28.11.2006
*			first library version
*		0.2 => 1.0	/	09.10.2006
*			initial version
*		0.1 => 0.2	/	13.06.2006
*			second testversion 
*		0.0	=> 0.1	/	10.04.2006
*			first testversion for fair in Hannover
*
************************************************************************************)
VAR_PRIVATE
  HwControlThis             : ^void;
  bPostInitFinished         : BOOL;
END_VAR

#ifdef DiasMasterC_Profiler
  VAR_GLOBAL

    HWC_Time_RTPostscan		: STRUCT
        _min 	: udint;
        _max 	: udint;
        avg 	: udint;
        run 	: udint;
        sum 	: udint;
        start : udint;
        stop 	: udint;
        diff 	: udint;
        init	: udint;
        initfl: bool;

    END_STRUCT;
  END_VAR
#endif

//Has to be activated in HwControl.h
#ifdef HWCONTROL_TIME_MEASUREMENT
  #pragma message("***************************************")  
  #pragma message("HWCONTROL_TIME_MEASUREMENT is activated")
  #pragma message("***************************************")  
#endif

// Method define because we need poiner to method
FUNCTION GLOBAL LDR_InstallPostInitCB
  VAR_INPUT
    pThis       : ^VirtualBase;
    pCmdSvr     : ^SVRCHCMD;
    newInstCmd  : UINT;
  END_VAR;


FUNCTION HwControl::HwControl
  VAR_OUTPUT
    ret_code 	: ConfStates;
  END_VAR
  VAR
    i : USINT;
  END_VAR
    
  //Set supported features of HwControl (only for compatibility reasons)
  SupportedFeatures.PostInitDoneCmdCalled := TRUE;  //Flag which indicates, that the PostinitDone CMD will be called in PostInit for every logged in class
  SupportedFeatures.CalculateTaskInfo     := TRUE;  //Flag which indicates, that the HwControl calculate the task settings (RT,CY) for each core due to the logged in objects
  
  //Initialize us_CoreSelect
  for i:= 0 to TASK_SELECT_COREMAX do
    aTaskInfoCore[i].us_CoreSelect := i;
  end_for;

  //Store this pointer of HwControl
  HwControlThis := this;
  
  HWC_LogInit();

#ifdef HWC_ENABLE_SPAM_PROTECTION
  // pause spam protection to allow complete logging during init and post init phase
  HwcLogging.OverrideSpamProtection.Write(input:=1);
#endif
  
  //Initialize in constructor to be sure that flag is false also in the complete init phase
  bPostInitFinished := FALSE;

  ret_code := C_OK;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL HwControl::Init
  VAR
    MyPara          : CmdStruct;
    MyResult        : results;
    udFirstCallCnt  : UDINT;
    pHelp           : ^t_HwObjectListCallFirst;
    retcode         : DINT;
#ifdef HWCONTROL_TIME_MEASUREMENT
    i : USINT;
#endif    
  END_VAR

  //-------------------------------------------------------------------------------------------------------------
  //First Init - phase
  if ( us_InitCounter = 0 ) then    
        
    //set this pointer to Rt-Debug function
    if ( OS_CILGet( "DEBUGAPI", #p_DebugAPI ) = SYS_ERR_NONE ) then
      
      //look if realtime debug option is used (our Rt-task is running even if realtime of user is debugged)
      RtDebug := RtDebug.read();
      
    end_if;
    
     //get cil interface to trigger watchdog
    OS_CILGet( INTERFACE_WATCHDOG, #p_WatchdogAPI );
 
    //Get OS-Interface for system info (To get amount of CPU Cores)
    if OS_CILGET(INTERFACE_LSL_SYSINFO, #pLSLSysInfo) <> SYS_ERR_NONE then
      pLSLSysInfo := NIL;
      ud_CPUCoreCount := 1; //Standard
    else
      retcode$DINT := OS_SYSINFO_GET_PROP(pLSLSysInfo, LSL_SYSINFO_ID_CPU_COUNT, #ud_CPUCoreCount, sizeof(ud_CPUCoreCount));
      
      if retcode <> LSL_SYSINFO_ERR_NONE then
        ud_CPUCoreCount := 1; //Standard
      end_if;      
    end_if;
    
    //Get information if the use of the additional cores for Realtime and Cyclic is enabled
    
    //_Firstscan ... (*AT % M 0EB8*), _cpus_RtCyEnabled ... (*AT % M 0F21*)
    //Offset between these variables is 16#69
    
    //Use pointer instead of the name to be compatible with old Loader versions (old loader does not have this variable --> compiler error) 
    us_CPUsRtCyEnabled := ( ( #_Firstscan + 16#69 )$^USINT)^; //0... information not available, x ... number of core with enabled RT/CY threads
       
  end_if; 

  //-------------------------------------------------------------------------------------------------------------
  //in last init phase we call DiasMaster init functions, bring our realtime task to first position and start it
  if ( _Firstscan = TRUE ) then
    
    // tell the loader that we need a post init phase
    if InstallPostInitCB() <> 0 then
      HWC_LogError(this, "@014F (HwControl::Init) Failed to install post init callback!");
    end_if;

    //look if DiasMaster is also used
    if ( s_DiasMaster.p_Functions <> NIL ) then
      //make some initialization in DiasMaster before we can start our realtime task
      CallPtr	( p_function	:= s_DiasMaster.p_Functions^.p_FinishIMProg
              , p_this		  := s_DiasMaster.p_Functions^.p_This
              );
    end_if;

    // if there is no post init => we have to start the realtime from here
    if b_PostInitInstalled = FALSE then
      // Call own NewInst with CMD_POST_INIT_CALL. For sorting VaranDOs, starting RT task, init diasmaster")      
      MyPara.uiCmd := CMD_POST_INIT_CALL;
      Control.NewInst(pPara:=#MyPara, pResult:=#MyResult);      
    end_if;

    // if there is no varan manager and no diasmaster => we have to trigger the CDIAS watchdog for internal IOs (ETV Edge)
    if (VaranManagersAvailable = 0) & (s_DiasMaster.p_Functions = NIL) then
      OS_CILGET( "CDIASWATCHDOG", #pSCDW );
    end_if;

#ifdef HWCONTROL_TIME_MEASUREMENT
    OS_CILGet("SYSTRACE", #pSystrace$void);
    
    //AddTraceKeyVal is only supported with RTK and Salamander with the new kernel ( >= 9.3.0)
    //This function is supported for the CP731 but has caused problems with another PLC (WA042). 
    //Therefore this feature has been deactivated for versions 09.02.xxx.
      if ( _RtOSVersion < 16#9100 ) | ( _RtOSversion >= 0x9300 ) then
    
      //Add Trace key values for a better visualisation in trace view
      OS_AddTraceKeyVal(pSystrace, TRECGRP_USER0, HWCONTROL_SYSTRACE_RTPRESCAN_START,                    "HwControl - Prescan: Start Realtime");
      OS_AddTraceKeyVal(pSystrace, TRECGRP_USER0, HWCONTROL_SYSTRACE_RTPRESCAN_START_FIRST_CALL_OBJECTS, "HwControl - Prescan: Start First Call Objects");
      OS_AddTraceKeyVal(pSystrace, TRECGRP_USER0, HWCONTROL_SYSTRACE_RTPRESCAN_START_VARAN_MANAGERS,     "HwControl - Prescan: Start VARAN Manager");
      OS_AddTraceKeyVal(pSystrace, TRECGRP_USER0, HWCONTROL_SYSTRACE_RTPRESCAN_START_HW_OBJECTS,         "HwControl - Prescan: Start HW Objects (SDIAS,IOs)");
      OS_AddTraceKeyVal(pSystrace, TRECGRP_USER0, HWCONTROL_SYSTRACE_RTPRESCAN_START_DIAS_CDIAS_OTHER,   "HwControl - Prescan: Start other Objects (DIAS,SpecialHW)");
      OS_AddTraceKeyVal(pSystrace, TRECGRP_USER0, HWCONTROL_SYSTRACE_RTPRESCAN_FINISH,                   "HwControl - Prescan: Finished RtWork");
   
      OS_AddTraceKeyVal(pSystrace, TRECGRP_USER0, HWCONTROL_SYSTRACE_RTPOSTSCAN_START,                   "HwControl - Postscan: Start Postscan");
      OS_AddTraceKeyVal(pSystrace, TRECGRP_USER0, HWCONTROL_SYSTRACE_RTPOSTSCAN_START_VARAN_MANAGERS,    "HwControl - Postscan: Start VARAN Manager");
      OS_AddTraceKeyVal(pSystrace, TRECGRP_USER0, HWCONTROL_SYSTRACE_RTPOSTSCAN_START_HW_OBJECTS,        "HwControl - Postscan: Start HW Objects (SDIAS,IOs):");
      OS_AddTraceKeyVal(pSystrace, TRECGRP_USER0, HWCONTROL_SYSTRACE_RTPOSTSCAN_FINISH,                  "HwControl - Postscan: Finished RtPostScan");

      OS_AddTraceKeyVal(pSystrace, TRECGRP_USER0, HWCONTROL_SYSTRACE_CYWORK_START,                       "HwControl - Cywork: Start Cywork");
      OS_AddTraceKeyVal(pSystrace, TRECGRP_USER0, HWCONTROL_SYSTRACE_CYWORK_START_VARAN_MANAGERS,        "HwControl - Cywork: Start VARAN Manager");
      OS_AddTraceKeyVal(pSystrace, TRECGRP_USER0, HWCONTROL_SYSTRACE_CYWORK_START_HW_OBJECTS,            "HwControl - Cywork: Start HW Objects (SDIAS,IOs)");
      OS_AddTraceKeyVal(pSystrace, TRECGRP_USER0, HWCONTROL_SYSTRACE_CYWORK_FINISH,                      "HwControl - Cywork: Finished Cywork");
      
    end_if;

    //Initialize min values of time measurement
    for i:= 0 to TASK_SELECT_COREMAX-1 do
    
      aHwControl_Times[i].sRtPrescan_Total.MinTime          := 16#FFFF;
      aHwControl_Times[i].sRtPrescan_FirstCallHW.MinTime    := 16#FFFF;
      aHwControl_Times[i].sRtPrescan_HwObjects.MinTime      := 16#FFFF;
      aHwControl_Times[i].sRtPrescan_Varan.MinTime          := 16#FFFF;
      aHwControl_Times[i].sRtPrescan_Other.MinTime          := 16#FFFF;
      
      aHwControl_Times[i].sRtPostscan_Total.MinTime         := 16#FFFF;
      aHwControl_Times[i].sRtPostscan_HwObjects.MinTime     := 16#FFFF;
      aHwControl_Times[i].sRtPostscan_Varan.MinTime         := 16#FFFF;

      aHwControl_Times[i].sCyWork_Total.MinTime             := 16#FFFF;
      aHwControl_Times[i].sCyWork_HwObjects.MinTime         := 16#FFFF;
      aHwControl_Times[i].sCyWork_Varan.MinTime             := 16#FFFF;
    
    end_for;
    
#endif

    // if first call objects logged in arrange them to a daisy chain
    if bCallFirstObjects then     
      OS_CILGet("SYSTRACE", #pSystrace$void);  
      
      //AddTraceKeyVal is only supported with RTK and Salamander with the new kernel ( >= 9.3.0)
      if ( _RtOSVersion < 16#9100 ) | ( _RtOSversion >= 0x9300 ) then
        OS_AddTraceKeyVal(pSystrace, TRECGRP_USER0, HWCONTROL_SYSTRACE_RTPRESCAN_FINISHED_FIRST_CALL_OBJECTS, "HwControl - Prescan: Finished Call of First Call Objects");
      end_if;
      
      bCallFirstObjects := FALSE;
      for udFirstCallCnt := 0 to HWCONTROL_MAX_FIRSTCALL_OBJECTS-1 do
        if sCallFirstObjects[udFirstCallCnt].pThis <> NIL then 
          if bCallFirstObjects = FALSE then
            pCallFirstObjects$pVoid := To_StdLib.Malloc(size:=sizeof(t_HwObjectListCallFirst));
            pHelp                   := pCallFirstObjects;            
            bCallFirstObjects       := TRUE;   
          else          
            pHelp^.pNext$pVoid      := To_StdLib.Malloc(size:=sizeof(t_HwObjectListCallFirst));
            pHelp                   := pHelp^.pNext;
          end_if;                   
          pHelp^.pThis              := sCallFirstObjects[udFirstCallCnt].pThis;
          pHelp^.udLoggedInNumber   := udFirstCallCnt;
          pHelp^.us_CoreSelect      := sCallFirstObjects[udFirstCallCnt].us_CoreSelect;
          pHelp^.ud_RtTime_us       := sCallFirstObjects[udFirstCallCnt].ud_RtTime_us;
          pHelp^.ud_CyTime_us       := sCallFirstObjects[udFirstCallCnt].ud_CyTime_us;
          pHelp^.pNext              := NIL;
        end_if;
      end_for;  
      bCallFirstObjects := TRUE;
    end_if;    
  end_if;
  
  us_InitCounter += 1;		//increment init phase counter

//-------------------------------------Profiler Start----------------------------------------------
  //#WP001 start
  #ifdef DiasMasterC_Profiler	
    HWC_Time_RTPostscan.sum 	:= 0;
    HWC_Time_RTPostscan.run 	:= 0;
    HWC_Time_RTPostscan._max 	:= 0;
    HWC_Time_RTPostscan._min 	:= 16#ffffffff;
    HWC_Time_RTPostscan.init  := OS_readmicrosec();
  #endif
  //#WP001 end
//-------------------------------------Profiler End------------------------------------------------

END_FUNCTION //VIRTUAL GLOBAL HwControl::Init


FUNCTION VIRTUAL GLOBAL HwControl::RtWork
  VAR_INPUT
    EAX 	: UDINT;
  END_VAR
  VAR_OUTPUT
    state (EAX) 	: UDINT;
  END_VAR
  VAR
    us_CoreSelect : USINT;
    pHelp         : ^t_HwObjectListElement;
    udOldCnt      : UDINT;
#ifdef HWCONTROL_TIME_MEASUREMENT  
    udTimeMeasure1 : UDINT;
    udTimeMeasure2 : UDINT;
#endif
  END_VAR
  
  us_CoreSelect := TASK_SELECT_CORE0;  
    
#ifdef HWCONTROL_TIME_MEASUREMENT  
  OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_RTPRESCAN_START,us_CoreSelect);
#endif

  //if class is ok
  if ( HwControl::State = _ClassOk ) then

    // if interface is available trigger watchdog 
    //**********************************************************************************************************************************************************    
    if p_WatchdogAPI then
      OS_WD_TRIGGER(p_WatchdogAPI);
      
    // trigger watchdog (pointer only valid if no varan manager and diasmaster available)
    elsif pSCDW then
      SCDW_CDWTRIGGER();
    end_if;

    // special classes with first call priority, which are controlled by HwControl
    //**********************************************************************************************************************************************************
#ifdef HWCONTROL_TIME_MEASUREMENT    
    OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_RTPRESCAN_START_FIRST_CALL_OBJECTS,us_CoreSelect);
    udTimeMeasure1 := OS_READMICROSEC();  
#endif    

    UpdateRtFirstCallObjects(us_CoreSelect);

#ifdef HWCONTROL_TIME_MEASUREMENT    
    udTimeMeasure2 := OS_READMICROSEC();
    aHwControl_Times[us_CoreSelect].sRtPrescan_FirstCallHW.ActTime := udTimeMeasure2 - udTimeMeasure1;
#endif    
        
    //Increment timestamp for SmartIO modules        
    aTaskInfoCore[us_CoreSelect].uiHwTimeStamp_us += (aTaskInfoCore[us_CoreSelect].ud_MyRtTaskTime_us)$UINT;    
        
    //Send Sync for DiasMaster
    //**********************************************************************************************************************************************************
    if ( s_DiasMaster.p_Functions <> NIL ) then
      //if call time for dias master is reached
      if ( s_DiasMaster.ud_Counter = s_DiasMaster.p_Functions^.ud_DiasTime ) then

        CallPtr	( p_function	:= s_DiasMaster.p_Functions^.p_SendSync
                , p_this		  := s_DiasMaster.p_Functions^.p_This
                );
      end_if;
    end_if;
  
    //Update Realtime of all varanmanagers which are running on core 0
    //**********************************************************************************************************************************************************
#ifdef HWCONTROL_TIME_MEASUREMENT    
    OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_RTPRESCAN_START_VARAN_MANAGERS,us_CoreSelect);
    udTimeMeasure1 := OS_READMICROSEC();  
#endif    

    UpdateRtVaranManager(us_CoreSelect);    

#ifdef HWCONTROL_TIME_MEASUREMENT    
    udTimeMeasure2 := OS_READMICROSEC();
    aHwControl_Times[us_CoreSelect].sRtPrescan_Varan.ActTime := udTimeMeasure2 - udTimeMeasure1;
#endif

    //DiasMaster Call Rt
    //**********************************************************************************************************************************************************
#ifdef HWCONTROL_TIME_MEASUREMENT    
    OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_RTPRESCAN_START_DIAS_CDIAS_OTHER,us_CoreSelect);
    udTimeMeasure1 := OS_READMICROSEC();  
#endif       
    
    //Only call DIAS from core 0
    if ( s_DiasMaster.p_Functions <> NIL ) then
      //if call time for dias master is reached
      if ( s_DiasMaster.ud_Counter = s_DiasMaster.p_Functions^.ud_DiasTime ) then
    
        //set task time counter to HwControl task time
        s_DiasMaster.ud_Counter := aTaskInfoCore[us_CoreSelect].ud_MyRtTaskTime_us;

        CallPtr	( p_function	:= s_DiasMaster.p_Functions^.p_RtFunction
                , p_this		  := s_DiasMaster.p_Functions^.p_This
                );
    
      else
        //add task time to counter
        s_DiasMaster.ud_Counter += aTaskInfoCore[us_CoreSelect].ud_MyRtTaskTime_us;
      end_if;
    end_if;
    
    // special classes, which are controlled by HwControl (Modules which are added via AddSpecialHW)
    if pSpecialObjects then
      pHelp := pSpecialObjects;
      while pHelp <> NIL do
        pHelp^.pThis^.RtWork(0);
        pHelp := pHelp^.pNext;
      end_while;
    end_if;    

#ifdef HWCONTROL_TIME_MEASUREMENT    
    udTimeMeasure2 := OS_READMICROSEC();
    aHwControl_Times[us_CoreSelect].sRtPrescan_Other.ActTime := udTimeMeasure2 - udTimeMeasure1;
#endif

    // objects, which are controlled by HwControl
    //**********************************************************************************************************************************************************
#ifdef HWCONTROL_TIME_MEASUREMENT    
    OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_RTPRESCAN_START_HW_OBJECTS,us_CoreSelect);
    udTimeMeasure1 := OS_READMICROSEC();  
#endif    

    UpdateRtLoginObjects(usCoreSelect:= us_CoreSelect);

#ifdef HWCONTROL_TIME_MEASUREMENT    
    udTimeMeasure2 := OS_READMICROSEC();
    aHwControl_Times[us_CoreSelect].sRtPrescan_HwObjects.ActTime := udTimeMeasure2 - udTimeMeasure1;
#endif

    // if someone wants to debug realtime or we are in startup phase (only 1 rt object possible to start while init is running)
    //**********************************************************************************************************************************************************
    if RtDebug | (_FirstScan & (aTaskInfoCore[us_CoreSelect].b_PostScanStarted = FALSE)) then
      PostScanWork(us_CoreSelect);
      if (RtDebug = 0) then
        aTaskInfoCore[us_CoreSelect].ud_LastPostScanWorkCall := OS_READMICROSEC();
      end_if;
    else
      //check for active realtime synchronisation
      if sRtTaskControl.b_RtTaskControlActive = TRUE then      
      
        //increment finished counter for this rt prescan - counter is decrement after syncronizing
        udOldCnt := sigclib_atomic_incU32(pValue:=#sRtTaskControl.udPreRtCnt);
        
        //if old counter is all cores -1 then is the last prescan rt reached
        if udOldCnt >= sRtTaskControl.usCoresRtActive - 1 then
        
          //all rt tasks are finished -> free mutex
          OS_MT_SIGNAL(sRtTaskControl.pvPreRtSyncTaskEvent);
                
          sigclib_atomic_decU32(pValue:=#sRtTaskControl.udPreRtCnt);
                    
          //if the counter reached zero we know all other PreScans at Wait State are unlocked again
          while sigclib_atomic_getU32(pValue:=#sRtTaskControl.udPreRtCnt) <> 0 do
          
          end_while;
          
          //reset PreScan mutex
          OS_MT_RESETEVENT(sRtTaskControl.pvPreRtSyncTaskEvent);
        else
          //wait for other rt task to be finished
          OS_MT_WAIT(sRtTaskControl.pvPreRtSyncTaskEvent);
          sigclib_atomic_decU32(pValue:=#sRtTaskControl.udPreRtCnt);          
        end_if;        
      end_if;  
    end_if;    
  end_if;  
  
#ifdef HWCONTROL_TIME_MEASUREMENT 
  OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_RTPRESCAN_FINISH,us_CoreSelect);
  CalcTimeMeasurementPreScan(#aHwControl_Times[us_CoreSelect]);
#endif 

  state := READY;

END_FUNCTION


FUNCTION HwControl::RtPreScan_CoreX
  VAR_INPUT
    pCoreSelect 	: ^void;
  END_VAR
  VAR
    us_CoreSelect : USINT;
    udOldCnt : UDINT;
#ifdef HWCONTROL_TIME_MEASUREMENT  
    udTimeMeasure1 : UDINT;
    udTimeMeasure2 : UDINT;
#endif
  END_VAR
  
  this := HwControlThis$^HWControl;
  us_CoreSelect := pCoreSelect^$USINT;  
    
#ifdef HWCONTROL_TIME_MEASUREMENT  
  OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_RTPRESCAN_START,us_CoreSelect);
  udTimeMeasure1 := OS_READMICROSEC();
#endif

  //if class is ok
  if ( HwControl::State = _ClassOk ) then

    // special classes with first call priority, which are controlled by HwControl
    //**********************************************************************************************************************************************************
#ifdef HWCONTROL_TIME_MEASUREMENT    
    OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_RTPRESCAN_START_FIRST_CALL_OBJECTS,us_CoreSelect);
    udTimeMeasure1 := OS_READMICROSEC();  
#endif    

    UpdateRtFirstCallObjects(us_CoreSelect);

#ifdef HWCONTROL_TIME_MEASUREMENT    
    udTimeMeasure2 := OS_READMICROSEC();
    aHwControl_Times[us_CoreSelect].sRtPrescan_FirstCallHW.ActTime := udTimeMeasure2 - udTimeMeasure1;
#endif    
  
    aTaskInfoCore[us_CoreSelect].uiHwTimeStamp_us += (aTaskInfoCore[us_CoreSelect].ud_MyRtTaskTime_us)$UINT;      
  
    //Update Realtime of all varanmanagers which are running on core 0
    //**********************************************************************************************************************************************************
#ifdef HWCONTROL_TIME_MEASUREMENT    
    OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_RTPRESCAN_START_VARAN_MANAGERS,us_CoreSelect);
    udTimeMeasure1 := OS_READMICROSEC();  
#endif    

    UpdateRtVaranManager(us_CoreSelect);    

#ifdef HWCONTROL_TIME_MEASUREMENT    
    udTimeMeasure2 := OS_READMICROSEC();
    aHwControl_Times[us_CoreSelect].sRtPrescan_Varan.ActTime := udTimeMeasure2 - udTimeMeasure1;
#endif

    // objects, which are controlled by HwControl
    //**********************************************************************************************************************************************************
#ifdef HWCONTROL_TIME_MEASUREMENT    
    OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_RTPRESCAN_START_HW_OBJECTS,us_CoreSelect);
    udTimeMeasure1 := OS_READMICROSEC();  
#endif    

    UpdateRtLoginObjects(usCoreSelect:= us_CoreSelect);

#ifdef HWCONTROL_TIME_MEASUREMENT    
    udTimeMeasure2 := OS_READMICROSEC();
    aHwControl_Times[us_CoreSelect].sRtPrescan_HwObjects.ActTime := udTimeMeasure2 - udTimeMeasure1;
#endif

    // if someone wants to debug realtime or we are in startup phase (only 1 rt object possible to start while init is running)
    //**********************************************************************************************************************************************************
    if RtDebug | (_FirstScan & (aTaskInfoCore[us_CoreSelect].b_PostScanStarted = FALSE)) then
      PostScanWork(us_CoreSelect);
      if (RtDebug = 0) then
        aTaskInfoCore[us_CoreSelect].ud_LastPostScanWorkCall := OS_READMICROSEC();
      end_if;
    else    
      //check for active realtime synchronisation
      if sRtTaskControl.b_RtTaskControlActive = TRUE then      
      
        //increment finished counter for this rt prescan - counter is decrement after syncronizing
        udOldCnt := sigclib_atomic_incU32(pValue:=#sRtTaskControl.udPreRtCnt);
        
        //if old counter is all cores -1 then is the last prescan rt reached
        if udOldCnt >= sRtTaskControl.usCoresRtActive - 1 then
        
          //all rt tasks are finished -> free mutex
          OS_MT_SIGNAL(sRtTaskControl.pvPreRtSyncTaskEvent);
                
          sigclib_atomic_decU32(pValue:=#sRtTaskControl.udPreRtCnt);
                    
          //if the counter reached zero we know all other PreScans at Wait State are unlocked again
          while sigclib_atomic_getU32(pValue:=#sRtTaskControl.udPreRtCnt) <> 0 do
          
          end_while;
          //reset PreScan mutex
          OS_MT_RESETEVENT(sRtTaskControl.pvPreRtSyncTaskEvent);
        else
          //wait for other rt task to be finished
          OS_MT_WAIT(sRtTaskControl.pvPreRtSyncTaskEvent);
          sigclib_atomic_decU32(pValue:=#sRtTaskControl.udPreRtCnt);          
        end_if;        
      end_if;  
    end_if;
  end_if;
  
#ifdef HWCONTROL_TIME_MEASUREMENT 
  OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_RTPRESCAN_FINISH,us_CoreSelect);
  CalcTimeMeasurementPreScan(#aHwControl_Times[us_CoreSelect]);
#endif 
  
END_FUNCTION


FUNCTION HwControl::RtPostScan_CoreX
  VAR_INPUT
    pCoreSelect 	: ^void;
  END_VAR
  VAR
    us_CoreSelect : USINT;
    udOldCnt : UDINT;
  END_VAR

  this := HwControlThis$^HWControl;
  us_CoreSelect := pCoreSelect^$USINT;    
    
  if sRtTaskControl.b_RtTaskControlActive = TRUE then
     
    //increment PostScan start counter for this rt PostScan - counter is decrement after syncronizing
    udOldCnt := sigclib_atomic_incU32(pValue:=#sRtTaskControl.udPostRtCnt);
    
    //if old counter is all cores -1 then is the last postscan rt reached
    if udOldCnt >= sRtTaskControl.usCoresRtActive - 1 then
    
      //all PostScans tasks are reached -> free mutex
      OS_MT_SIGNAL(sRtTaskControl.pvPostRtSyncTaskEvent);
      
      sigclib_atomic_decU32(pValue:=#sRtTaskControl.udPostRtCnt);
      
      //if the counter reached zero we know all other PostScans at Wait State are unlocked again
      while sigclib_atomic_getU32(pValue:=#sRtTaskControl.udPostRtCnt) <> 0 do
      
      end_while;
      
      //reset PreScan mutex
      OS_MT_RESETEVENT(sRtTaskControl.pvPostRtSyncTaskEvent);
    else
      //wait for other rt task to be finished
      OS_MT_WAIT(sRtTaskControl.pvPostRtSyncTaskEvent);
      sigclib_atomic_decU32(pValue:=#sRtTaskControl.udPostRtCnt);
    end_if;
  end_if;

  // first time postscan is called by os
  if aTaskInfoCore[us_CoreSelect].b_PostScanStarted = FALSE then
    aTaskInfoCore[us_CoreSelect].b_PostScanStarted := TRUE;
    if p_WatchdogAPI then
      //turn of watchdogtask of os because we trigger it in application
      OS_WD_SETPROPERTY(p_WatchdogAPI, Property:=WD_PROP_APPL_WD, value:=1); // 1 to disable autotrigger
    end_if;   
    // if we've already done postscan work from prescan, don't do anything here
    aTaskInfoCore[us_CoreSelect].ud_FirstPostScanCall := OS_READMICROSEC();
    // check if already called in same cycle => my task time in ns recalculated to 80 percent of the task time in µs
    if (aTaskInfoCore[us_CoreSelect].ud_FirstPostScanCall - aTaskInfoCore[us_CoreSelect].ud_LastPostScanWorkCall) < ((aTaskInfoCore[us_CoreSelect].ud_MyRtTaskTime_us * 80) / 100) then
      return;
    end_if;
  end_if;

  PostScanWork(us_CoreSelect);
  
END_FUNCTION


FUNCTION HwControl::CyWork_CoreX
  VAR_INPUT
    pCoreSelect 	: ^void;
  END_VAR
  VAR
    us_CoreSelect : USINT;
    pHelp         : ^t_HwObjectListElement;
    pOneManager   : ^t_OneVaranManager;
    i             : USINT;
#ifdef HWCONTROL_TIME_MEASUREMENT  
    udTimeMeasure1 : UDINT;
    udTimeMeasure2 : UDINT;
#endif    
  END_VAR
  
  this := HwControlThis$^HWControl;

  us_CoreSelect := pCoreSelect^$USINT;  
  
#ifdef HWCONTROL_TIME_MEASUREMENT  
  OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_CYWORK_START,us_CoreSelect);  
#endif

  //Update cyclic of all varanmanagers
  //*****************************************************************************
#ifdef HWCONTROL_TIME_MEASUREMENT
  udTimeMeasure1 := OS_READMICROSEC();
  OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_CYWORK_START_VARAN_MANAGERS,us_CoreSelect);
#endif  
  
  pOneManager := #a_VaranManager[0];
  for i := 0 TO (MAX_VARAN_MANAGERS - 1) do    
    //Look for right core
    if pOneManager^.us_CoreSelect = us_CoreSelect then
      
      //Check for valid manager
      if pOneManager^.p_Functions <> NIL  then
        
        //Only call cywork if it is time to call it
        if pOneManager^.ud_CounterCy = pOneManager^.ud_CyTime_us then
          pOneManager^.ud_CounterCy := 0;
          pOneManager^.p_Functions^.p_This^.CyWork();
        end_if;
        
        pOneManager^.ud_CounterCy += aTaskInfoCore[us_CoreSelect].ud_MyCyTaskTime_us;
        
      end_if;
    end_if;
    pOneManager += SIZEOF(t_OneVaranManager);    
  end_for;
  
#ifdef HWCONTROL_TIME_MEASUREMENT    
  udTimeMeasure2 := OS_READMICROSEC();
  aHwControl_Times[us_CoreSelect].sCyWork_Varan.ActTime := udTimeMeasure2 - udTimeMeasure1;
#endif
  
  
  //Update cyclic of other objects
  //*****************************************************************************
#ifdef HWCONTROL_TIME_MEASUREMENT    
  OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_CyWORK_START_HW_OBJECTS,us_CoreSelect);
  udTimeMeasure1 := OS_READMICROSEC();  
#endif    

  if pHwControlLogins then
    pHelp := pHwControlLogins;
    while pHelp <> NIL do
      if pHelp^.bdSettings.Cyclic & pHelp^.us_CoreSelect = us_CoreSelect then
        pHelp^.pThis^.CyWork(0);
      end_if;
      pHelp := pHelp^.pNext;
    end_while;
  end_if;

#ifdef HWCONTROL_TIME_MEASUREMENT 
  udTimeMeasure2 := OS_READMICROSEC();
  aHwControl_Times[us_CoreSelect].sCyWork_HwObjects.ActTime := udTimeMeasure2 - udTimeMeasure1;

  OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_CYWORK_FINISH,us_CoreSelect);
  CalcTimeMeasurementCyclic(#aHwControl_Times[us_CoreSelect]);
#endif 

END_FUNCTION


FUNCTION GLOBAL HwControl::AddVaranManager
  VAR_INPUT
    ud_manager_number 	: UDINT;
    p_function_list 	  : ^void;
    us_CoreSelect 	    : USINT;(* := 0 *)
    ud_RtTime_us 	      : UDINT;(* := 0 *)
    ud_CyTime_us 	      : UDINT;(* := 0 *)
  END_VAR
  VAR_OUTPUT
    sd_retval 	: DINT;
  END_VAR

  // is class ok
  if ( State = _ClassOk ) then
    
    //Check if selected core is available at this CPU
    if ( us_CoreSelect > TASK_SELECT_CORE0 ) & (us_CoreSelect > (ud_CPUCoreCount-1)) then
      sd_retval := -4;    //Invalid Core selected
      HWC_LogValue2(this,"@0150 (HwControl::AddVaranManager) Invalid parameter us_CoreSelect 0x{0}. CPU only has 0x{1} core(s)", us_CoreSelect, ud_CPUCoreCount);
      return;
    
    //Check if the use of the additional cores for Realtime and Cyclic is enabled
    elsif ( us_CoreSelect > TASK_SELECT_CORE0 ) & (us_CoreSelect > (us_CPUsRtCyEnabled-1)) then
      sd_retval := 11;
      HWC_LogError(this, "@0151 (HwControl::AddVaranManager) Rt/Cy Tasks are not enabled for the additional cores. Please use <SET MULTICOREOBJS 1> in autoexec.lsl");
      return;

    //Check if the LSL_I_TASK Interface version supports multicore
    elsif ( us_CoreSelect > TASK_SELECT_CORE0 ) & ( Get_ITASK_Version() < LSL_ITASK_VERSION_MULTICORE_SUPPORT ) then
      sd_retval := -5;
      HWC_LogError(this, "@0152 (HwControl::AddVaranManager) Invalid CPU-Core selected for this CPU. Version of LSL_ITASK Interface doesn't support multicore");
      return;
      
    //Check if coreselect is supported by HwControl already     
    elsif ( us_CoreSelect > TASK_SELECT_COREMAX ) then
      sd_retval := -6; //Failed to install realtime task
      HWC_LogValue2(this, "@0153 (HwControl::AddVaranManager) Invalid parameter us_CoreSelect 0x{0}. Max. us_CoreSelect by HwControl is 0x{1}",us_CoreSelect,TASK_SELECT_COREMAX);
      return;
    end_if;
    
    //Check if Rt time is smaller than maintimer
    if ( ud_RtTime_us <> 0 ) & ( ud_RtTime_us < _ClockTicks ) then
      sd_retval := -7;
      HWC_LogError(this, "@0154 (HwControl::AddVaranManager) Parameter ud_RtTime_us is smaller than CPU maintimer!");
      return;
      
    //Check if Rt time is not a multiple of maintimer
    elsif ( ud_RtTime_us <> 0 ) & (ud_RtTime_us MOD _ClockTicks) <> 0 then
      sd_retval := -8;
      HWC_LogError(this, "@0155 (HwControl::AddVaranManager) Parameter ud_RtTime_us not a multiple of CPU maintimer!");
      return;
    end_if;
    
    //Check if Cy time is smaller than maintimer
    if ( ud_CyTime_us <> 0 ) & ud_CyTime_us < _ClockTicks then
      sd_retval := -9;
      HWC_LogError(this, "@0156 (HwControl::AddVaranManager) Parameter ud_CyTime_us is smaller than CPU maintimer!");
      return;
      
    //Check if CY time is not a multiple of maintimer          
    elsif ( ud_CyTime_us <> 0 ) & (ud_CyTime_us MOD _ClockTicks) <> 0 then
      sd_retval := -10;
      HWC_LogError(this, "@0157 (HwControl::AddVaranManager) Parameter ud_CyTime_us not a multiple of CPU maintimer!");
      return;
      
    end_if;
    
    // look if it is a correct VaranManager number
    if	(( ud_manager_number >= 0 ) & 
         ( ud_manager_number <= MAX_VARAN_MANAGERS - 1 )) then
  
      // look if the pointer is valid
      if p_function_list then
        
        //is this number already in use
        if ( a_VaranManager[ ud_manager_number ].p_Functions <> NIL ) then

          State											                      := _NotInitialized;		//Set to error state
          a_VaranManager[ ud_manager_number ].p_Functions	:= NIL;
          sd_retval 										                  := -6;

          HWC_LogError(this, "@0158 (HwControl::AddVaranManager) Multiple VaranManager number!");
          return;
        end_if;

        //load pointer to varan functions
        a_VaranManager[ ud_manager_number ].p_Functions$^void := p_function_list;
        
        //Save core to execute task from
        a_VaranManager[ ud_manager_number ].us_CoreSelect   := us_CoreSelect;
        
        //set counter to time to execute task at first realtime        
        if ud_RtTime_us <> 0 then
          a_VaranManager[ ud_manager_number ].ud_RtTime_us    := ud_RtTime_us;
          a_VaranManager[ ud_manager_number ].ud_CounterRt    := a_VaranManager[ ud_manager_number ].ud_RtTime_us;
        else
          a_VaranManager[ ud_manager_number ].ud_RtTime_us    := a_VaranManager[ ud_manager_number ].p_Functions^.ud_VaranTime / 1000;  //Convert from ns to µs
          a_VaranManager[ ud_manager_number ].ud_CounterRt    := a_VaranManager[ ud_manager_number ].p_Functions^.ud_VaranTime / 1000;  //Convert from ns to µs
        end_if;

        //set counter to time to execute task at first cyclic                
        if ud_CyTime_us <> 0 then
          a_VaranManager[ ud_manager_number ].ud_CyTime_us    := ud_CyTime_us;
          a_VaranManager[ ud_manager_number ].ud_CounterCy    := a_VaranManager[ ud_manager_number ].ud_CyTime_us;
        else
          a_VaranManager[ ud_manager_number ].ud_CyTime_us    := a_VaranManager[ ud_manager_number ].p_Functions^.ud_VaranTime / 1000;  //Convert from ns to µs       
          a_VaranManager[ ud_manager_number ].ud_CounterCy    := a_VaranManager[ ud_manager_number ].p_Functions^.ud_VaranTime / 1000;  //Convert from ns to µs
        end_if;
        
        sd_retval 	:= 0;
        
        // new varanmanager is avaliable
        VaranManagersAvailable += 1;
      else
        sd_retval := -3;			// pointer invalid
        HWC_LogError(this, "@0159 (HwControl::AddVaranManager) Invalid pointer!");
      end_if;
    else
      sd_retval := -2;			//manager number wrong
      HWC_LogError(this, "@015A (HwControl::AddVaranManager) Wrong VaranManagerNumber!");
    end_if;
  else
    sd_retval := -1; // class state not _ClassOk
    HWC_LogError(this, "@015B (HwControl::AddVaranManager) Class state is not ok!");
  end_if;

END_FUNCTION //GLOBAL HwControl::AddVaranManager


FUNCTION HwControl::CallPtr
  VAR_INPUT
    p_function	: pFct;
    p_this		  : pVoid;
  END_VAR
  VAR
    save_this   :^HwControl;
  END_VAR

  save_this := this;              // save this ptr
  this      := p_this$^HwControl; // load thispointer of object
  p_function$ObjectFunct();       // call function of object
  this      := save_this;         // restore this ptr

END_FUNCTION // HwControl::CallPtr


FUNCTION GLOBAL HwControl::GetMyTaskTime
  VAR_INPUT
    us_CoreSelect 	: DINT;(* := 0 *)
  END_VAR
  VAR_OUTPUT
    ud_task_time 	: UDINT;
  END_VAR
  
  //Check if we already have calculated a time for the Realtime
  ud_task_time := aTaskInfoCore[us_CoreSelect].ud_MyRtTaskTime_us * 1000;		//give back task time in ns  

END_FUNCTION // HwControl::GetMyTaskTime


FUNCTION GLOBAL HwControl::SetHardwareOff
  VAR_INPUT
    e_error		: t_e_VaranErrors;
  END_VAR
  VAR
    MyPara    : CmdStruct;
    MyResult  : results;
  END_VAR

  State := e_error;
    
  // if a diasmaster is available => tell him
  if s_DiasMaster.p_Functions then
    MyPara.uiCmd := CMD_HWC_ERROR_TO_DIASM;
    s_DiasMaster.p_Functions^.p_This$pVirtualBase^.NewInst(#MyPara,#MyResult);
  end_if;

END_FUNCTION //GLOBAL HwControl::SetHardwareOff


FUNCTION GLOBAL HwControl::GetRtDebugState
  VAR_OUTPUT
    sd_RtDebug		: DINT;
  END_VAR

  sd_RtDebug := RtDebug.read();

END_FUNCTION //GLOBAL HwControl::GetRtDebugState

 
FUNCTION VIRTUAL GLOBAL HwControl::DiasMaster::Write
  VAR_INPUT
    input (EAX) 	: DINT;
  END_VAR
  VAR_OUTPUT
    result (EAX) 	: DINT;
  END_VAR

  //is it a required error from dias master?
  if input = 0 then
    State := _RequiredError;
    return;
  end_if;                   

  //is class ok
  if ( State = _ClassOk ) then

    s_DiasMaster.p_Functions$DINT := input;		//load pointer to DiasMaster functions

    //look if DiasMaster time is faster as the maintimer
    if ( ( s_DiasMaster.p_Functions^.ud_DiasTime ) < (_ClockTicks) ) then

      State						          := _DiasTimeError;			//Set to error state
      s_DiasMaster.p_Functions	:= NIL;
      result 						        := -1;
      HWC_LogError(this, "@015C (HwControl::DiasMaster::Write) DiasMaster time is smaller than HwControl RT-Task!");
      return;
    //look if DiasMaster time is a multiple time of our task time
    elsif ( ( s_DiasMaster.p_Functions^.ud_DiasTime ) mod (_ClockTicks) <> 0 ) then

      State						          := _DiasTimeError;			//Set to error state
      s_DiasMaster.p_Functions	:= NIL;
      result						        := -1;
      HWC_LogError(this, "@015D (HwControl::DiasMaster::Write) DiasMaster time is not a multiple of HwControl RT-Task!");
      return;
    else
      //set counter to time to execute task at first realtime
      s_DiasMaster.ud_Counter := s_DiasMaster.p_Functions^.ud_DiasTime;
      result 					    := 0;
      DiasMaster := input := 1;				//Mark server as connected right
    end_if;

    //set RtDebug-Flag for DiasMaster
    s_DiasMaster.p_Functions^.sd_RtDebug := RtDebug.Read();
  else
    result := -1;
  end_if;

END_FUNCTION


FUNCTION GLOBAL HwControl::AddSpecialHW
  VAR_INPUT
    pThis 	      : pVirtualBase;
    pRtPostScan 	: ^UDINT;
  END_VAR
  VAR_OUTPUT
    retcode 	    : DINT;
  END_VAR
  VAR
    pHelp         : ^t_HwObjectListElement;
  END_VAR
  
  //Attention: This function does not provide core-selection and cycle time settings (these object will be called on core 0 every time and with the calculated time)
  //If you want to use this feature please use the method AddHwObject
  
  if pSpecialObjects = NIL then
    pSpecialObjects$pVoid := To_StdLib.Malloc(size:=sizeof(t_HwObjectListElement));
    pHelp := pSpecialObjects;
  else
    pHelp := pSpecialObjects;
    while pHelp^.pNext <> NIL do
      pHelp := pHelp^.pNext;
    end_while;
    pHelp^.pNext$pVoid := To_StdLib.Malloc(size:=sizeof(t_HwObjectListElement));
    pHelp := pHelp^.pNext;
  end_if;
  
  if pHelp <> NIL then
    pHelp^.pThis          := pThis;
    pHelp^.bdSettings     := 0;
    pHelp^.usEscSequence  := 0;
    pHelp^.us_CoreSelect  := 0;
    pHelp^.ud_RtTime_us   := 0;
    pHelp^.ud_CyTime_us   := 0;
    pHelp^.pRtPostScan    := pRtPostScan;
    pHelp^.pNext          := NIL;
    
    retcode               := 0;
  else
    retcode               := -1;
  end_if;

END_FUNCTION


FUNCTION GLOBAL HwControl::AddFirstCallHW
  VAR_INPUT
    pThis 	        : pVirtualBase;
    udSelectPlace 	: UDINT;
    us_CoreSelect 	: USINT;(* := 0 *)
    ud_RtTime_us 	  : UDINT;(* := 0 *)
    ud_CyTime_us 	  : UDINT;(* := 0 *)
  END_VAR
  VAR_OUTPUT
    retcode 	: DINT;
  END_VAR
  
  if udSelectPlace >= HWCONTROL_MAX_FIRSTCALL_OBJECTS then
    //place is not available
    retcode := -1;
    return;
  end_if;  
  
  if sCallFirstObjects[udSelectPlace].pThis <> NIL then
    //place is already used
    retcode := -2;
    return;
  end_if;
  
  if _FirstScan = TRUE then
    //object login is to late
    retcode := -3;
    return;
  end_if;
  
  //Check if the selected core is available on the CPU
  if ( us_CoreSelect > TASK_SELECT_CORE0 ) & (us_CoreSelect > (ud_CPUCoreCount-1)) then
    //CPU does not have the requested core
    HWC_LogValue2(this,"@0150 (HwControl::AddFirstCallHW) Invalid parameter us_CoreSelect 0x{0}. CPU only has 0x{1} core(s)", us_CoreSelect, ud_CPUCoreCount);
    retcode := -4;
    return;
    
  //Check if the use of the additional cores for Realtime and Cyclic is enabled
  elsif ( us_CoreSelect > TASK_SELECT_CORE0 ) & (us_CoreSelect > (us_CPUsRtCyEnabled-1)) then
    retcode := 11;
    HWC_LogError(this, "@0151 (HwControl::AddFirstCallHW) Rt/Cy Tasks are not enabled for the additional cores. Please use <SET MULTICOREOBJS 1> in autoexec.lsl");
    return;

  //Check if the LSL_I_TASK Interface version supports multicore
  elsif ( us_CoreSelect > TASK_SELECT_CORE0 ) & ( Get_ITASK_Version() < LSL_ITASK_VERSION_MULTICORE_SUPPORT ) then
    retcode := -5;
    HWC_LogError(this, "@0152 (HwControl::AddFirstCallHW) Invalid CPU-Core selected for this CPU. Version of LSL_ITASK Interface doesn't support multicore");
    return;
  
  //Check if coreselect is supported by HwControl already     
  elsif ( us_CoreSelect > TASK_SELECT_COREMAX ) then
    retcode := -6;
    HWC_LogValue2(this, "@0153 (HwControl::AddFirstCallHW) Invalid parameter us_CoreSelect 0x{0}. Max. us_CoreSelect by HwControl is 0x{1}",us_CoreSelect,TASK_SELECT_COREMAX);
    return;
  end_if;

  //Check if Rt time is smaller than maintimer
  if ( ud_RtTime_us <> 0 ) & ( ud_RtTime_us < _ClockTicks ) then
    retcode := -7;
    HWC_LogError(this, "@0154 (HwControl::AddFirstCallHW) Parameter ud_RtTime_us is smaller than CPU maintimer !");
    return;
    
  //Check if Rt time is not a multiple of maintimer
  elsif ( ud_RtTime_us <> 0 ) & (ud_RtTime_us MOD _ClockTicks) <> 0 then
    retcode := -8;
    HWC_LogError(this, "@0155 (HwControl::AddFirstCallHW) Parameter ud_RtTime_us not a multiple of CPU maintimer!");
    return;
  end_if;
  
  //Check if Cy time is smaller than maintimer
  if ( ud_CyTime_us <> 0 ) & ud_CyTime_us < _ClockTicks then
    retcode := -9;
    HWC_LogError(this, "@0156 (HwControl::AddFirstCallHW) Parameter ud_CyTime_us is smaller than CPU maintimer !");
    return;
    
  //Check if CY time is not a multiple of maintimer          
  elsif ( ud_CyTime_us <> 0 ) & (ud_CyTime_us MOD _ClockTicks) <> 0 then
    retcode := -10;
    HWC_LogError(this, "@0157 (HwControl::AddFirstCallHW) Parameter ud_CyTime_us not a multiple of CPU maintimer!");
    return;
  end_if;
    
  //set true because a first call object has logged in
  bCallFirstObjects                 := TRUE;  
  
  //set pointer to free place
  sCallFirstObjects[udSelectPlace].pThis          := pThis;
  sCallFirstObjects[udSelectPlace].us_CoreSelect  := us_CoreSelect;
  sCallFirstObjects[udSelectPlace].ud_RtTime_us   := ud_RtTime_us;
  sCallFirstObjects[udSelectPlace].ud_CyTime_us   := ud_CyTime_us;

  //return code ok
  retcode                           := 0;

END_FUNCTION


FUNCTION GLOBAL HwControl::AddHwObject
  VAR_INPUT
    pThis 	        : pVirtualBase;
    Settings 	      : t_HwObjListSettings;
    EscapeSequence 	: USINT;(* := 0 *)
    us_CoreSelect 	: USINT;(* := 0 *)
    ud_RtTime_us 	  : UDINT;(* := 0 *)
    ud_CyTime_us 	  : UDINT;(* := 0 *)
  END_VAR
  VAR_OUTPUT
    retcode 	: DINT;
  END_VAR
  VAR
    pHelp           : ^t_HwObjectListElement;
  END_VAR

  if pThis = nil then
    //Pointer invalid
    retcode := -2;
    HWC_LogError(this,"@015E (HwControl::AddHwObject) Invalid parameter pThis.");    
  end_if;
  
  //If Bit is false we do not take the core-select setting (maybe data is uninitialized)
  if Settings.CoreSelect = FALSE then
    us_CoreSelect := TASK_SELECT_CORE0;
  end_if;
  
  //If Bit is false we do not take the time settings (maybe data is uninitialized)
  if Settings.TimeSet = FALSE then
    ud_RtTime_us := 0;
    ud_CyTime_us := 0;
  end_if;
  
  //Check if the selected core is available on the CPU
  if ( us_CoreSelect > TASK_SELECT_CORE0 ) & (us_CoreSelect > (ud_CPUCoreCount-1)) then
    //CPU does not have the requested core
    HWC_LogValue2(this,"@0150 (HwControl::AddHwObject) Invalid parameter us_CoreSelect 0x{0}. CPU only has 0x{1} core(s)", us_CoreSelect, ud_CPUCoreCount);
    retcode := -4;
    return;
    
  //Check if the use of the additional cores for Realtime and Cyclic is enabled
  elsif ( us_CoreSelect > TASK_SELECT_CORE0 ) & (us_CoreSelect > (us_CPUsRtCyEnabled-1)) then
    retcode := 11;
    HWC_LogError(this, "@0151 (HwControl::AddHwObject) Rt/Cy Tasks are not enabled for the additional cores. Please use <SET MULTICOREOBJS 1> in autoexec.lsl");
    return;
    
  //Check if the LSL_I_TASK Interface version supports multicore
  elsif ( us_CoreSelect > TASK_SELECT_CORE0 ) & ( Get_ITASK_Version() < LSL_ITASK_VERSION_MULTICORE_SUPPORT ) then
    retcode := -5;
    HWC_LogError(this, "@0152 (HwControl::AddHwObject) Invalid CPU-Core selected for this CPU. Version of LSL_ITASK Interface doesn't support multicore");
    return;
  
  //Check if coreselect is supported by HwControl already     
  elsif ( us_CoreSelect > TASK_SELECT_COREMAX ) then
    retcode := -6;
    HWC_LogValue2(this, "@0153 (HwControl::AddHwObject) Invalid parameter us_CoreSelect 0x{0}. Max. us_CoreSelect by HwControl is 0x{1}",us_CoreSelect,TASK_SELECT_COREMAX);
    return;
  end_if;

  //Check if Rt time is smaller than maintimer
  if ( ud_RtTime_us <> 0 ) & ( ud_RtTime_us < _ClockTicks ) then
    retcode := -7;
    HWC_LogError(this, "@0154 (HwControl::AddHwObject) Parameter ud_RtTime_us is smaller than CPU maintimer !");
    return;
    
  //Check if Rt time is not a multiple of maintimer
  elsif ( ud_RtTime_us <> 0 ) & (ud_RtTime_us MOD _ClockTicks) <> 0 then
    retcode := -8;
    HWC_LogError(this, "@0155 (HwControl::AddHwObject) Parameter ud_RtTime_us not a multiple of CPU maintimer!");
    return;
  end_if;
  
  //Check if Cy time is smaller than maintimer
  if ( ud_CyTime_us <> 0 ) & ud_CyTime_us < _ClockTicks then
    retcode := -9;
    HWC_LogError(this, "@0156 (HwControl::AddHwObject) Parameter ud_CyTime_us is smaller than CPU maintimer !");
    return;
    
  //Check if CY time is not a multiple of maintimer          
  elsif ( ud_CyTime_us <> 0 ) & (ud_CyTime_us MOD _ClockTicks) <> 0 then
    retcode := -10;
    HWC_LogError(this, "@0157 (HwControl::AddHwObject) Parameter ud_CyTime_us not a multiple of CPU maintimer!");
    return;
  end_if;
  
  if pHwControlLogins = NIL then
    pHwControlLogins$pVoid := To_StdLib.Malloc(size:=sizeof(t_HwObjectListElement));
    pHelp := pHwControlLogins;
  else
    pHelp := pHwControlLogins;
    while (pHelp^.pThis <> pThis) & (pHelp^.pNext <> NIL) do
      pHelp := pHelp^.pNext;
    end_while;
    if (pHelp^.pThis <> pThis) then
      pHelp^.pNext$pVoid := To_StdLib.Malloc(size:=sizeof(t_HwObjectListElement));
      pHelp := pHelp^.pNext;
//  else
//    already in list and pHelp points to it to update the settings
    end_if;
  end_if;
  
  if pHelp <> NIL then
    pHelp^.pThis          := pThis;
    pHelp^.pRtPostScan    := NIL;
    pHelp^.bdSettings     := Settings;
    pHelp^.usEscSequence  := EscapeSequence;
    pHelp^.us_CoreSelect  := us_CoreSelect;
    pHelp^.ud_RtTime_us   := ud_RtTime_us;
    pHelp^.ud_CyTime_us   := ud_CyTime_us;  
    pHelp^.pNext          := NIL;
    retcode               := 0;
  else
    retcode               := -1;
    HWC_LogError(this,"@015F (HwControl::AddHwObject) Failed to allocate memory for hw object.");
  end_if;

END_FUNCTION


FUNCTION HwControl::PostScanWork
  VAR_INPUT
    us_CoreSelect 	: USINT;
  END_VAR
  VAR
    pHelp : ^t_HwObjectListElement;
#ifdef HWCONTROL_TIME_MEASUREMENT  
  udTimeMeasure1 : UDINT;
  udTimeMeasure2 : UDINT;
#endif    
  END_VAR

#ifdef HWCONTROL_TIME_MEASUREMENT  
  OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_RTPOSTSCAN_START,us_CoreSelect);  
#endif

  if State = _ClassOk then
  
    // objects, which are controlled by HwControl (call before the other hardware classes because the safety manager may start moving the data to another system)
    //**********************************************************************************************************************************************************
#ifdef HWCONTROL_TIME_MEASUREMENT    
    OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_RTPOSTSCAN_START_HW_OBJECTS,us_CoreSelect);
    udTimeMeasure1 := OS_READMICROSEC();  
#endif    

    UpdateRtPostscanLoginObjects(usCoreSelect:= us_CoreSelect);

#ifdef HWCONTROL_TIME_MEASUREMENT    
    udTimeMeasure2 := OS_READMICROSEC();
    aHwControl_Times[us_CoreSelect].sRtPostscan_HwObjects.ActTime := udTimeMeasure2 - udTimeMeasure1;
#endif

    //Call RT Postscan of Varanmanagers
    //**********************************************************************************************************************************************************
#ifdef HWCONTROL_TIME_MEASUREMENT    
    OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_RTPOSTSCAN_START_VARAN_MANAGERS,us_CoreSelect);
    udTimeMeasure1 := OS_READMICROSEC();  
#endif    

    UpdateRtPostScanVaranManager(us_CoreSelect);

#ifdef HWCONTROL_TIME_MEASUREMENT    
    udTimeMeasure2 := OS_READMICROSEC();
    aHwControl_Times[us_CoreSelect].sRtPostscan_Varan.ActTime := udTimeMeasure2 - udTimeMeasure1;
#endif
    
  //-------------------------------------Profiler Start----------------------------------------------
  #ifdef	DiasMasterC_Profiler    
    HWC_Time_RTPostscan.start := OS_ReadMicroSec();
    if ( ( HWC_Time_RTPostscan.start - HWC_Time_RTPostscan.init ) > DM_ProfilerDelay ) then
      HWC_Time_RTPostscan.initfl := 0;
    else
      HWC_Time_RTPostscan.initfl := 1;
    end_if;
  #endif
  //-------------------------------------Profiler End------------------------------------------------

    if us_CoreSelect = TASK_SELECT_CORE0 then

      if s_DiasMaster.p_Functions <> NIL then
        if s_DiasMaster.p_Functions^.p_RtPostScanFunction <> NIL then
          CallPtr	( p_function := s_DiasMaster.p_Functions^.p_RtPostScanFunction
                  , p_this     := s_DiasMaster.p_Functions^.p_This
                  );
        end_if;
      end_if;
    
    //Special objects (objects added via the method AddSpecialHW) only run on core 0
      // special classes, which are controlled by HwControl
      if pSpecialObjects then
        pHelp := pSpecialObjects;
        while pHelp <> NIL do
          pHelp^.pRtPostScan$RtWork((pHelp^.pThis)$UDINT);
          pHelp := pHelp^.pNext;
        end_while;
      end_if;
    end_if;
    
  //-------------------------------------Profiler Stop----------------------------------------------
  #ifdef DiasMasterC_Profiler
    if ( HWC_Time_RTPostscan.initfl = 0 ) then

      HWC_Time_RTPostscan.stop := OS_ReadMicroSec();
      HWC_Time_RTPostscan.diff := HWC_Time_RTPostscan.stop - HWC_Time_RTPostscan.start - DM_CPUconstant;
      HWC_Time_RTPostscan.sum += HWC_Time_RTPostscan.diff;
      HWC_Time_RTPostscan.run += 1;

      if ( HWC_Time_RTPostscan.diff < HWC_Time_RTPostscan._min ) then
        HWC_Time_RTPostscan._min := HWC_Time_RTPostscan.diff;
      end_if;

      if ( HWC_Time_RTPostscan.diff > HWC_Time_RTPostscan._max ) then
        HWC_Time_RTPostscan._max := HWC_Time_RTPostscan.diff;
      end_if;

      HWC_Time_RTPostscan.avg := HWC_Time_RTPostscan.sum * 100 / HWC_Time_RTPostscan.run;

    end_if;
  #endif
  //-------------------------------------Profiler End------------------------------------------------

  end_if;

#ifdef HWCONTROL_TIME_MEASUREMENT  
  OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_RTPOSTSCAN_FINISH,us_CoreSelect);
  CalcTimeMeasurementPostScan(pHwControlTimes:=#aHwControl_Times[us_CoreSelect]);
#endif 
  
END_FUNCTION

#pragma warning(disable: 73)
FUNCTION VIRTUAL GLOBAL HwControl::AddSafetyManager
  VAR_INPUT
    pThis 	  : pVirtualBase;
  END_VAR
  VAR_OUTPUT
    pFirstVM 	: pVirtualBase;
  END_VAR
#pragma warning(default: 73)

// NO LONGER USED SINCE HWCONTROL HAS IT'S OWN CYCLIC TASK
  pFirstVM := NIL;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL HwControl::SafetyState::Read
  VAR_OUTPUT
    output (EAX) 	: DINT;
  END_VAR

  SafetyState := SafetyManager.ClassState.Read();
  output      := SafetyState;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL HwControl::DisableSafetyManager

// NO LONGER USED SINCE HWCONTROL HAS IT'S OWN CYCLIC TASK

END_FUNCTION


FUNCTION VIRTUAL GLOBAL HwControl::Control::NewInst
  VAR_INPUT
    pPara 	            : ^CmdStruct;
    pResult 	          : ^Results;
  END_VAR
  VAR_OUTPUT
    ret_code 	          : IprStates;
  END_VAR
  VAR
    StartTime                 : UDINT;
    pOneManager               : ^t_OneVaranManager;
    i                         : DINT;
    j                         : DINT;
    TempRetCode               : IprStates;
    MyPara                    : CmdStruct;
    MyResult                  : results;
    pHelp                     : ^t_HwObjectListElement;
    pHelpFirst                : ^t_HwObjectListCallFirst;
    TempSettings              : t_HwObjListSettings;
    us_ModuleType             : HSINT;
    us_CoreSelect             : USINT;
    pStr_HWTRequested         : ^CHAR;
    pStr_HWTreeEntry          : ^CHAR;
    usVaranManagerNrTreeEntry : USINT;
    ud_RtTime_us              : UDINT;
    ud_CyTime_Us              : UDINT;
    sd_retval                 : DINT;
    s_objinfo 		            : LSLOBJ_INFO;        
  END_VAR
  
  us_ModuleType     := 0;
  pStr_HWTRequested := NIL;
  pStr_HWTreeEntry  := NIL;

  ret_code := READY;
  
  case pPara^.uiCmd of
//**********************************************************************************************************************************************************
    CMD_POST_INIT_CALL:

      ret_code                := BUSY;
      
      StartTime               := ops.tAbsolute;
      AdditionalPostInitTime  := 0;
      sd_retval               := 0;

//**********************************************************************************************************************************************************
//** CALCULATE, SET AND DISTRIBUTE TASK TIMES                                                                                                             **
//**********************************************************************************************************************************************************
      
      for i:=0 to TASK_SELECT_COREMAX do
      
      //Calculate Tasksettings for each core
        CalculateTaskInfo(us_CoreSelect:=i$USINT, pTaskInfo:=#aTaskInfoCore[i]);
                
        //Special Core 0 has to be running in RtWork method (is needed because if we dont have the new interfaces we cannot move a function to first realtime pos later)
        //Always add Realtime and Cyclic for Core 0: Realtime of Core 0 does watchdog trigger and calls for Diasmaster
        //***********************************************************
        if aTaskInfoCore[i].us_CoreSelect = TASK_SELECT_CORE0 then
                                         
          //Rt Prescan       
          //**********************************************************************************************************************************************                    
          
          //get objectinfo of HwControl object
          //maybe we have a derivation with configured realtime task --> we have to change the task time of the task to the correct setting
          sd_retval := To_TaskObjectControl.GetObjectInfo( thispointer := this, tasktype := OBJ_RT, objinfo := #s_objinfo);
          
          //Check if we have a configured tasktime
          if sd_retval <> 0 | s_objinfo.period = 0 then
          
            //No task configured --> use OS function to add the RT Task
          
            //Note: udPhase must always be TASK_SCAN. At RTK there was an error that using TASK_PRE and TASK_POST occurs an access-exception in the OS.
            //With TASK_SCAN the object/function will be added in the list at the end. (will be moved to first position later if needed)
            if OS_AddRtObject(udMode  := TASK_TIMED
                            , udTime  := aTaskInfoCore[i].ud_MyRtTaskTime_us OR 16#8000_0000
                            , udPhase := TASK_SCAN) = NIL then
              HWC_LogValue1(this,"@0160 (HWControl::Control::NewInst) OS_AddRtObject failed to add Realtime (Prescan) object for core 0x{0}",aTaskInfoCore[i].us_CoreSelect);
            end_if;
          else
          
            // User must have a derivation of the HWControl with a configured Realtime Task --> Change the task time of the existing realtime task
            if To_TaskObjectControl.ChangeObjectState(thispointer :=  this
                                                    , actioncmd   :=  ACTION_NEWTIME
                                                    , tasktype    :=  OBJ_RT
                                                    , debugobj    :=  0
                                                    , newtime     :=  aTaskInfoCore[i].ud_MyRtTaskTime_us OR 16#8000_0000
                                                    ) <> 0 then
              HWC_LogError(this,"@03E3 (HWControl::Control::NewInst) Failed to change the object state to set the correct realtime task settings.");
            end_if;          
          end_if;
        
          //RT Postscan
          //**********************************************************************************************************************************************
          
          //Check for Rt-Debug State. Do not add the Rt func for postscan if RtDebug is activated (because postscan will be called from prescan in this case)
          
          if GetRtDebugState() = TRUE then
            //save thispointer of object in OS-function (leads to that the task is called from the Breakpoint handler from the OS so the user can debug and the Hwcontrol is still running (no watchdog error))
            if p_DebugAPI then
              SaveThisPointer( this, TASK_SELECT_CORE0 );
            else
              HWC_LogError(this,"@0167 (HWControl::Control::NewInst) Pointer p_DebugAPI is invalid. Rt-Debug is not supported");
            end_if;
            
            // Set RtPostScan off if RtDebug is used!
            if To_TaskObjectControl.ChangeObjectState(thispointer :=  #HWRtPostScan.ClassSvr$void
                                                    , actioncmd   :=  ACTION_SUSPEND
                                                    , tasktype    :=  OBJ_RT
                                                    , debugobj    :=  0
                                                    , newtime     :=  0
                                                    ) <> 0 then      
              HWC_LogError(this,"@0161 (HWControl::Control::NewInst) Failed to change object state of HwRtPostscan object");
            end_if;
            
          else
            
            //We have to use the object of HwRtPostscan instead of using the function OS_AddRtObject due to problems with RTK-CPUs (e.g. CP212)
            //The problem is that, with a maintimer of 500µs, and a task time of 1ms it can happen that the realtime (prescan) and the postscan of this class
            //are not "synchronized", which means that they have a time gap of 500µs between each other which leads to problems (TimesliceError).
            //This is not a problem with Salamander CPUs (e.g CP111)
            
            // Synchronize calls of Rt & RtPostScan (same timebase) 
            if To_TaskObjectControl.ChangeObjectState(thispointer :=  #HWRtPostScan.ClassSvr$void
                                                    , actioncmd   :=  ACTION_NEWTIME
                                                    , tasktype    :=  OBJ_RT
                                                    , debugobj    :=  0
                                                    , newtime     :=  aTaskInfoCore[i].ud_MyRtTaskTime_us OR 16#8000_0000
                                                    ) <> 0 then
              HWC_LogError(this,"@0161 (HWControl::Control::NewInst) Failed to change object state of HwRtPostscan object");
            end_if;
                    
            //save NIL-Pointer to OS-function because only HwControl is allowed to use this function
            if p_DebugAPI then
              SaveThisPointer( NIL, TASK_SELECT_CORE0 );
            end_if;
            
            //rt-post scan is added - realtime is added
            sRtTaskControl.usCoresRtActive  += 1;

          end_if;
          
          //Cyclic Task
          //**********************************************************************************************************************************************

          //Note: OS_AddCyFunc can NOT be used!! On RTK-CPUs with emulated SRAM () it leads to a reboot of the CPU if the SRAM is accessed from a function that is added via OS_AddCyFunc (or OS_AddRtFunc).
//          if OS_AddCyFunc (CyWork_CoreX
//                         , pParam  := #aTaskInfoCore[i].us_CoreSelect
//                         , udMode  := TASK_TIMED
//                         , udTime  := aTaskInfoCore[i].ud_MyCyTaskTime_us OR 16#8000_0000  //Time in µs instead of ms
//                         , udPhase := TASK_SCAN
//                          ) = NIL then
//                                               
//            HWC_LogValue1(this,"@0162 (HWControl::Control::NewInst) OS_AddCyFunc failed to add Cyclic function for core 0x{0}",aTaskInfoCore[i].us_CoreSelect);
//          end_if;        
          
          //get objectinfo of HwControl object
          //maybe we have a derivation with configured cyclic task --> we have to change the task time of the task to the correct setting
          sd_retval := To_TaskObjectControl.GetObjectInfo( thispointer := this, tasktype := OBJ_CT, objinfo := #s_objinfo );
          
          //Check if we have a configured tasktime
          if sd_retval <> 0 | s_objinfo.period = 0 then
            //No task configured --> use OS function to add the CY Task
          
            //Note: udPhase must always be TASK_SCAN. At RTK there was an error that using TASK_PRE and TASK_POST occurs an access-exception in the OS.
            //With TASK_SCAN the object/function will be added in the list at the end. (will be moved to first position later if needed)
            if OS_AddCyObject(udMode  := TASK_TIMED
                            , udTime  := aTaskInfoCore[i].ud_MyCyTaskTime_us OR 16#8000_0000
                            , udPhase := TASK_SCAN) = NIL then
              HWC_LogValue1(this,"@0160 (HWControl::Control::NewInst) OS_AddCyObject failed to add Cyclic object for core 0x{0}",aTaskInfoCore[i].us_CoreSelect);
            end_if;
          else
          
            // User must have a derivation of the HWControl with a configured cyclic Task --> Change the task time of the existing cyclic task
            if To_TaskObjectControl.ChangeObjectState(thispointer :=  this
                                                    , actioncmd   :=  ACTION_NEWTIME
                                                    , tasktype    :=  OBJ_CT
                                                    , debugobj    :=  0
                                                    , newtime     :=  aTaskInfoCore[i].ud_MyCyTaskTime_us OR 16#8000_0000
                                                    ) <> 0 then
              HWC_LogError(this,"@03E4 (HWControl::Control::NewInst) Failed to change the object state to set the correct cyclic task settings.");
            end_if;          
          end_if;          
          
        else
        
          //Check if core is needed
          if aTaskInfoCore[i].ud_MyRtTaskTime_us <> 0 
           & aTaskInfoCore[i].ud_MyCyTaskTime_us <> 0 then        
          
            //Check if new interfaces are available                  
            if Get_ITASK_Version() >= LSL_ITASK_VERSION_MULTICORE_SUPPORT then
              //Rt Prescan       
              //**********************************************************************************************************************************************
#ifdef OS_AddRtFuncEx 

              //Check if function pointer is valid. These function will never be valid on a RTK CPU because they don't support multicore features.
              //But maybe the ITASK Version will be extended for an other feature, so we will have an ITASK Version >= LSL_ITASK_VERSION_MULTICORE_SUPPORT at RTK CPUs
              if _LSL_POS^.piTask^.AddRealTimeFunctionEx <> NIL then
              
                if OS_AddRtFuncEx(RtPreScan_CoreX
                                , pParam  := #aTaskInfoCore[i].us_CoreSelect
                                , udMode  := TASK_TIMED
                                , udTime  := aTaskInfoCore[i].ud_MyRtTaskTime_us OR 16#8000_0000  //Time in µs instead of ms
                                , udPhase := TASK_SCAN
                                , core    := aTaskInfoCore[i].us_CoreSelect
                                ) = NIL then
                                                       
                  HWC_LogValue1(this,"@0163 (HWControl::Control::NewInst) OS_AddRtFuncEx Failed to add Realtime (Prescan) function for core 0x{0}",aTaskInfoCore[i].us_CoreSelect);
                end_if;       
                
                //Check if Rt-Debug is used
                if GetRtDebugState() = TRUE then
                  
                  //Check if the new function is supported by the OS
                  if p_DebugAPI & p_DebugAPI^.version >= DEBUG_API_VERSION_MULTICORE_SUPPORT then
#ifdef SaveFunction
                    //Check if pointer is valid
                    if p_DebugAPI^.pSaveFunction <> NIL then
                      SaveFunction(#RtPreScan_CoreX(), this, aTaskInfoCore[i].us_CoreSelect);
                    else
                      HWC_LogError(this,"@0164 (HWControl::Control::NewInst) p_DebugAPI^.SaveFunction is nil. Rt-Debug is not supported.");            
                    end_if;

#else
                    HWC_LogError(this,"@0165 (HWControl::Control::NewInst) Rt-Debug for multicore is not supported. SaveFunction is not defined.");
#endif
                  elsif p_DebugAPI then
                    HWC_LogError(this,"@0166 (HWControl::Control::NewInst) RT-Debug for multicore is not supported with this OS.");            
                  else
                    HWC_LogError(this,"@0167 (HWControl::Control::NewInst) Pointer p_DebugAPI is invalid. Rt-Debug is not supported");          
                  end_if;
                else
                  if p_DebugAPI & p_DebugAPI^.version >= DEBUG_API_VERSION_MULTICORE_SUPPORT then
#ifdef SaveFunction
                    if p_DebugAPI^.pSaveFunction <> NIL then
                      SaveFunction(#RtPreScan_CoreX(), nil, aTaskInfoCore[i].us_CoreSelect);
                    end_if;
#endif
                  elsif p_DebugAPI then
                    HWC_LogError(this,"@0166 (HWControl::Control::NewInst) RT-Debug for multicore is not supported with this OS.");            
                  else
                    HWC_LogError(this,"@0167 (HWControl::Control::NewInst) Pointer p_DebugAPI is invalid. Rt-Debug is not supported");          
                  end_if;
                end_if;                
                
              else
                HWC_LogError(this,"@0168 (HWControl::Control::NewInst) Function pointer of _LSL_POS^.piTask^.AddRealTimeFunctionEx is invalid.");
              end_if;
#else
              //Log that function is not supported by Lasal 
              //Only log here once 
              HWC_LogError(this,"@0169 (HWControl::Control::NewInst) Warning! Unsupported LASAL-Class2 version detected to use OS_AddRtFuncEx function. Version 02.02.172 or higher is required to use this function");
#endif
              
              //RT Postscan
              //**********************************************************************************************************************************************
#ifdef OS_AddRtFuncEx 
              //Check if function pointer is valid. These function will never be valid on a RTK CPU because they don't support multicore features.
              //But maybe the ITASK Version will be extended for an other feature, so we will have an ITASK Version >= LSL_ITASK_VERSION_MULTICORE_SUPPORT at RTK CPUs
              if _LSL_POS^.piTask^.AddRealTimeFunctionEx <> NIL then

                //Don't start Rt Postscan if RT-Debug is used (PostscanWork will be called from Prescan)
                if GetRtDebugState() = FALSE then
                
                  if OS_AddRtFuncEx(RtPostScan_CoreX
                                  , pParam  := #aTaskInfoCore[i].us_CoreSelect
                                  , udMode  := TASK_TIMED
                                  , udTime  := aTaskInfoCore[i].ud_MyRtTaskTime_us OR 16#8000_0000  //Time in µs instead of ms
                                  , udPhase := TASK_SCAN
                                  , core    := aTaskInfoCore[i].us_CoreSelect
                                  ) = NIL then

                    HWC_LogValue1(this,"@016A (HWControl::Control::NewInst) OS_AddRtFuncEx failed to add Realtime (Postscan) function for core 0x{0}",aTaskInfoCore[i].us_CoreSelect);
                  else
                    //rt-post scan is added - realtime is added
                    sRtTaskControl.usCoresRtActive  += 1;
                  end_if;         
                else
                  HWC_LogError(this, "@016B (HWControl::Control::NewInst) RtDebug is used - RtPostScan is not possible together with RtDebug!");
                end_if;               
              else
                HWC_LogError(this,"@0168 (HWControl::Control::NewInst) Function pointer of _LSL_POS^.piTask^.AddRealTimeFunctionEx is invalid.");
              end_if;                
#endif
              
              //Cyclic Task
              //**********************************************************************************************************************************************
#ifdef OS_AddCyFuncEx 

              //Check if function pointer is valid. These function will never be valid on a RTK CPU because they don't support multicore features.
              //But maybe the ITASK Version will be extended for an other feature, so we will have an ITASK Version >= LSL_ITASK_VERSION_MULTICORE_SUPPORT at RTK CPUs
              if _LSL_POS^.piTask^.AddCyclicFunctionEx <> NIL then

                if OS_AddCyFuncEx(CyWork_CoreX
                                , pParam  := #aTaskInfoCore[i].us_CoreSelect
                                , udMode  := TASK_TIMED
                                , udTime  := aTaskInfoCore[i].ud_MyCyTaskTime_us OR 16#8000_0000  //Time in µs instead of ms
                                , udPhase := TASK_SCAN
                                , core    := aTaskInfoCore[i].us_CoreSelect
                                ) = NIL then
                                                       
                  HWC_LogValue1(this,"@016C (HWControl::Control::NewInst) OS_AddCyFuncEx failed to add Cyclic function for core 0x{0}",aTaskInfoCore[i].us_CoreSelect);
                end_if; 
              else
                HWC_LogError(this,"@016D (HWControl::Control::NewInst) Function pointer of _LSL_POS^.piTask^.AddCyclicFunctionEx is invalid.");
              end_if;                
#endif
            end_if;
          end_if;
        end_if;
      end_for;
      
      //read client setting for task synchronization
      RtTaskSync := RtTaskSync.Read() <> 0;
    
      if RtTaskSync = 1 then
        //check if more than one core is active and more than one rt task is available
        if sRtTaskControl.usCoresRtActive > 1 & ud_CPUCoreCount > 1 & us_CPUsRtCyEnabled > 1 then
          //search for different task times
          for i := 1 to sRtTaskControl.usCoresRtActive-1 do
            if aTaskInfoCore[0].ud_MyRtTaskTime_us <> aTaskInfoCore[i].ud_MyRtTaskTime_us then
              //task times are different - synchronizing is not possible
              RtTaskSync := 0;
              HWC_LogError(this, "@06AC (HwControl::Control::NewInst) The Rt task times are different so synchronization is not possible!");
              exit;
            end_if;
          end_for;
        
          if (mt_api = nil) & RtTaskSync = 1 then
            if(OS_CILGet("LSL_MULTITASK", #mt_api$void)) THEN
              mt_api := NIL;
              HWC_LogError(this,"@06AD (HWControl::Control::NewInst) Pointer for event semaphore is invalid. Synchronizing of Rt tasks is not supported!");  
            else
              sRtTaskControl.pvPreRtSyncTaskEvent := OS_MT_CreateSemaphore(MTSEMATYPE_EVENT, 0, 0, "HwControl_PreRtSyncTaskEvent");
              sRtTaskControl.pvPostRtSyncTaskEvent := OS_MT_CreateSemaphore(MTSEMATYPE_EVENT, 0, 0, "HwControl_PostRtSyncTaskEvent");
              if sRtTaskControl.pvPreRtSyncTaskEvent <> NIL & sRtTaskControl.pvPostRtSyncTaskEvent <> NIL then
                //activate rt task synchronizing
                sRtTaskControl.b_RtTaskControlActive := TRUE;
              else
                //adding event semaphore for synchronizing task doesn't work
                HWC_LogError(this,"@06AF (HWControl::Control::NewInst) Pointer for event semaphore is invalid. Synchronizing of Rt tasks is not supported!"); 
              end_if;
            end_if;      
          end_if;
        else
          HWC_LogError(this,"@06B0 (HWControl::Control::NewInst) There is only one Rt task available! Synchronizing of Rt tasks is deactivated.");
        end_if;
      end_if; 
      
      //set client to actual setting
      RtTaskSync := sRtTaskControl.b_RtTaskControlActive;

      
      //Set Varanmanager variables (was done in AddVaranManager before, now we have to set these here because we know the task times just yet)
      //**************************************************************************
      
      //Go through all varanmanagers
      pOneManager := #a_VaranManager[0]; 
      
      for i := 0 to ( MAX_VARAN_MANAGERS - 1 ) do
        for j:= 0 to TASK_SELECT_COREMAX  do
          //Check if manager is available, set for right core and has set a time
          if ( pOneManager^.p_Functions         <> NIL 
             & pOneManager^.p_Functions^.p_This <> NIL 
             & pOneManager^.us_CoreSelect     = j
             ) 
          then
            pOneManager^.ud_SuperiorSync       := (pOneManager^.p_Functions^.ud_SuperiorTime / 1000 ) / (aTaskInfoCore[j].ud_MyRtTaskTime_us);
            pOneManager^.ud_SuperiorSyncActual := pOneManager^.ud_SuperiorSync;
            
      //       if the own tasktime is slower then superior varantime, don't wait for HW-Class Synchronity
            if (aTaskInfoCore[j].ud_MyRtTaskTime_us) > (pOneManager^.p_Functions^.ud_SuperiorTime / 1000) then
              pOneManager^.p_Functions^.b_HWClassSynchron    := TRUE;
              pOneManager^.p_Functions^.b_OverrideFrameCheck := TRUE;
            end_if;
          end_if;
        end_for;
        pOneManager += sizeof(t_OneVaranManager);
      end_for;     
    
            
      //Distribute Task times to all connected classes
      //**************************************************************************      
      MyPara.uiCmd := CMD_POST_INIT_DISTRIBUTE_TASKTIMES;
      
      MyPara.aPara[0]$t_Distribute_TaskTimes_Cmd.udVersion := 1;  //Version of command
      
      for i:=0 to TASK_SELECT_COREMAX do
      
        MyPara.aPara[0]$t_Distribute_TaskTimes_Cmd.udRtTaskTime_us := aTaskInfoCore[i].ud_MyRtTaskTime_us;  //Realtime Task time in µs
        MyPara.aPara[0]$t_Distribute_TaskTimes_Cmd.udCyTaskTime_us := aTaskInfoCore[i].ud_MyCyTaskTime_us;  //Cyclic Task time in µs
        
        //Check if task is active/needed
        if aTaskInfoCore[i].ud_MyRtTaskTime_us <> 0 & aTaskInfoCore[i].ud_MyCyTaskTime_us <> 0 then
       
          //We don't need to distribute the info to the Varanmanagers because the HwControl handles the time sheduling of the managers
          //Neither we distribute the info to the special objects

          // objects, which are controlled by HwControl (BusInterfaceSDIASInternal, Safetymanager,...)
          if pHwControlLogins then
            pHelp := pHwControlLogins;
            while pHelp <> NIL do
              // Check if its the right core
              if pHelp^.us_CoreSelect = i then
                pHelp^.pThis^.NewInst(pPara:=#MyPara, pResult:=#MyResult);
              end_if;
              pHelp := pHelp^.pNext;
            end_while;
          end_if;
          
          //First-Call Objects
          if pCallFirstObjects then
            pHelpFirst := pCallFirstObjects;
            while pHelpFirst <> NIL do
              // Check if its the right core
              if pHelpFirst^.us_CoreSelect = i then
                pHelpFirst^.pThis^.NewInst(pPara:=#MyPara, pResult:=#MyResult);
              end_if;
              pHelpFirst := pHelpFirst^.pNext;
            end_while;
          end_if;
                              
        end_if;        
      end_for;

//**********************************************************************************************************************************************************
//** INITIALIZE EVERYTHING VIA ASYNCHRON ACCESSES                                                                                                         **
//**********************************************************************************************************************************************************

      while (ret_code = BUSY) do
        // check the varanmanagers if they are not ready
        ret_code := READY;

        // only if there is a varan manager
        if VaranManagersAvailable then
          //call the last init of all varan managers
          pOneManager := #a_VaranManager[0];  // RamAnd: using pointers instead of array accesses reduces compiled awl-code by 120 lines!!!
          for i := 0 to ( MAX_VARAN_MANAGERS - 1 ) do

            //look if we have a correct pointer
            if ( pOneManager^.p_Functions & pOneManager^.p_Functions^.p_This ) then
              TempRetCode := pOneManager^.p_Functions^.p_This^.NewInst(pPara, pResult);
              
              // if any manager is still busy, we have to keep calling them
              if TempRetCode = BUSY then
                ret_code := TempRetCode;
              end_if;
            end_if;

            pOneManager += sizeof(t_OneVaranManager);
          end_for;                    
        end_if;

        // objects, which are controlled by HwControl
        if pHwControlLogins then
          pHelp := pHwControlLogins;
          while pHelp <> NIL do
            if pHelp^.bdSettings.PostInit then
              TempRetCode := pHelp^.pThis^.NewInst(pPara, pResult);
              // if any manager is still busy, we have to keep calling them
              if TempRetCode = BUSY then
                ret_code := TempRetCode;
              end_if;
            end_if;

            pHelp := pHelp^.pNext;
          end_while;
        end_if;

        // check timeout
        if ((ops.tAbsolute - StartTime) > (POST_INIT_TIMEOUT + AdditionalPostInitTime)) then
          HWC_LogError(this, "@016E (HwControl::Control::NewInst) Timeout in PostInit (initialize)");

          // only if there is a varan manager
          if VaranManagersAvailable then

            // Force all VM to end the PostInit Phase, Otherwise UpdateCy of HWK will not be called -----------------------------------------
            MyPara.uiCmd := CMD_FORCE_POST_INIT_END;

            //call the last init of all varan managers
            pOneManager := #a_VaranManager[0];
            for i := 0 to ( MAX_VARAN_MANAGERS - 1 ) do

              //look if we have a correct pointer
              if ( pOneManager^.p_Functions & pOneManager^.p_Functions^.p_This ) then
                TempRetCode := pOneManager^.p_Functions^.p_This^.NewInst(#MyPara, #MyResult);
              end_if;

              pOneManager += sizeof(t_OneVaranManager);
            end_for;	// ---------------------------------------------------------------------------------------------------------------------------------------------
          end_if;
          exit;
        end_if;
      end_while;

//**********************************************************************************************************************************************************
//** SORT THE VARAN DOs NEEDED FOR SAFETY                                                                                                                 **
//**********************************************************************************************************************************************************

      MyPara.uiCmd := CMD_POST_INIT_DO_SORT;
      
      // only if there is a varan manager
      if VaranManagersAvailable then
        //send the finish command to all varan managers
        pOneManager := #a_VaranManager[0];
        for i := 0 to ( MAX_VARAN_MANAGERS - 1 ) do

          //look if we have a correct pointer
          if ( pOneManager^.p_Functions & pOneManager^.p_Functions^.p_This ) then
            TempRetCode := pOneManager^.p_Functions^.p_This^.NewInst(pPara:=#MyPara, pResult:=#MyResult);
            
            // if any manager is still busy, we have to keep calling them
            if TempRetCode = BUSY then
              ret_code := TempRetCode;
            end_if;
          end_if;

          pOneManager += sizeof(t_OneVaranManager);
        end_for;                    
      end_if;

//**********************************************************************************************************************************************************
//** START THE REALTIME OF HWCONTROL                                                                                                                      **
//**********************************************************************************************************************************************************

      //bring HwControl to the first realtime task position and start realtime task

      //Check if the new LSL_ITASK functions are supported from the OS
      if Get_ITASK_Version() >= LSL_ITASK_VERSION_MULTICORE_SUPPORT then

        for i:= 0 to TASK_SELECT_COREMAX do
        
          //Special case for Realtime of Core 0 because it has the Standard RTWork Function
          if aTaskInfoCore[i].us_CoreSelect = TASK_SELECT_CORE0 then

            //Use the old (non multicore/extended) functions for Core 0 (Old OS will support this interface)            
            OS_MoveObject(thisPtr   := this
                        , tasktype  := TASK_OBJ_RT
                        , flags     := 1 );
                        
            OS_SetNbrOfLdrPhaseObjects(nbrOfObjs := 1);
            
          // Check if we have time settings for the current core
          elsif aTaskInfoCore[i].ud_MyRtTaskTime_us <> 0 & aTaskInfoCore[i].ud_MyCyTaskTime_us <> 0 then

#ifdef OS_MoveFunctionEx      
            //Check if function pointer is valid. These function will never be valid on a RTK CPU because they don't support multicore features.
            //But maybe the ITASK Version will be extended for an other feature, so we will have an ITASK Version >= LSL_ITASK_VERSION_MULTICORE_SUPPORT at RTK CPUs
            if _LSL_POS^.piTask^.MoveFunctionEx <> NIL then

              //Move RtPreScan function to the first realtime task position of the selected core
              sd_retval := OS_MoveFunctionEx(pFunc     := #RtPreScan_CoreX()
                                           , pParam    := #aTaskInfoCore[i].us_CoreSelect
                                           , taskType  := TASK_OBJ_RT
                                           , flags     := 1
                                           , core      := aTaskInfoCore[i].us_CoreSelect);
                                           
              if sd_retval <> 0 then
                HWC_LogValue1(this,"@016F (HWControl::Control::NewInst) Function OS_MoveFunctionEx failed with retcode 0x{0}.", sd_retval$UDINT);              
              end_if;
            else
              HWC_LogError(this,"@0170 (HWControl::Control::NewInst) Function pointer of _LSL_POS^.piTask^.MoveFunctionEx is invalid.");
            end_if;
#endif         

#ifdef OS_SetNbrOfLdrPhaseObjectsEx      

            //Check if function pointer is valid. These function will never be valid on a RTK CPU because they don't support multicore features.
            //But maybe the ITASK Version will be extended for an other feature, so we will have an ITASK Version >= LSL_ITASK_VERSION_MULTICORE_SUPPORT at RTK CPUs
            if _LSL_POS^.piTask^.SetNbrOfLdrPhaseObjectsEx <> NIL then
            
              sd_retval := OS_SetNbrOfLdrPhaseObjectsEx(nbrOfObjs := 1, core := aTaskInfoCore[i].us_CoreSelect);     

              if sd_retval <> 0 then
                HWC_LogValue1(this,"@0171 (HWControl::Control::NewInst) Function OS_SetNbrOfLdrPhaseObjectsEx failed with retcode 0x{0}.", sd_retval$UDINT);              
              end_if;
              
            else
              HWC_LogError(this,"@0172 (HWControl::Control::NewInst) Function pointer of _LSL_POS^.piTask^.SetNbrOfLdrPhaseObjectsEx is invalid.");
            end_if;
          
#endif                          
          end_if;
        end_for;
        
      else
        //Old version, multicore not supported, just bring realtime of core 0 to first position and start it
        OS_MoveObject(thisPtr   := this
                    , tasktype  := TASK_OBJ_RT
                    , flags     := 1 );
                    
        OS_SetNbrOfLdrPhaseObjects(nbrOfObjs := 1);
      end_if;

//**********************************************************************************************************************************************************
//** WAIT FOR RT TO TAKE OVER THE WATCHDOG TRIGGERING                                                                                                     **
//**********************************************************************************************************************************************************

      MyPara.uiCmd            := CMD_POST_INIT_RT_SYNC;
      ret_code                := BUSY;
      
      StartTime               := ops.tAbsolute;
      AdditionalPostInitTime  := 0;
      
      while (ret_code = BUSY) do
        // check the varanmanagers if they are not ready
        ret_code := READY;

        // only if there is a varan manager
        if VaranManagersAvailable then
          //send the finish command to all varan managers
          pOneManager := #a_VaranManager[0];
          for i := 0 to ( MAX_VARAN_MANAGERS - 1 ) do

            //look if we have a correct pointer
            if ( pOneManager^.p_Functions & pOneManager^.p_Functions^.p_This ) then
              TempRetCode := pOneManager^.p_Functions^.p_This^.NewInst(pPara:=#MyPara, pResult:=#MyResult);
              
              // if any manager is still busy, we have to keep calling them
              if TempRetCode = BUSY then
                ret_code := TempRetCode;
              end_if;
            end_if;

            pOneManager += sizeof(t_OneVaranManager);
          end_for;                    
        end_if;

        // objects, which are controlled by HwControl
        if pHwControlLogins then
          pHelp := pHwControlLogins;
          while pHelp <> NIL do
            if pHelp^.bdSettings.PostInit then
              TempRetCode := pHelp^.pThis^.NewInst(pPara:=#MyPara, pResult:=#MyResult);
              // if any manager is still busy, we have to keep calling them
              if TempRetCode = BUSY then
                ret_code := TempRetCode;
              end_if;
            end_if;

            pHelp := pHelp^.pNext;
          end_while;
        end_if;

        // check timeout
        if ((ops.tAbsolute - StartTime) > (POST_INIT_TIMEOUT + AdditionalPostInitTime)) then
          HWC_LogError(this, "@0173 (HwControl::Control::NewInst) Timeout in PostInit (rt sync)");

          // only if there is a varan manager
          if VaranManagersAvailable then

            // Force all VM to end the PostInit Phase, Otherwise UpdateCy of HWK will not be called -----------------------------------------
            MyPara.uiCmd := CMD_FORCE_POST_INIT_END;

            //call the last init of all varan managers
            pOneManager := #a_VaranManager[0];  // RamAnd: using pointers instead of array accesses reduces compiled awl-code by 120 lines!!!
            for i := 0 to ( MAX_VARAN_MANAGERS - 1 ) do

              //look if we have a correct pointer
              if ( pOneManager^.p_Functions & pOneManager^.p_Functions^.p_This ) then
                TempRetCode := pOneManager^.p_Functions^.p_This^.NewInst(#MyPara, #MyResult);
              end_if;

              pOneManager += sizeof(t_OneVaranManager);
            end_for;	// ---------------------------------------------------------------------------------------------------------------------------------------------
          end_if;
          exit;
        end_if;
      end_while;


//**********************************************************************************************************************************************************
//** LOAD THE SAFETY PROJECT CONFIGURATIONS AT THE SAFETY CPUS                                                                                            **
//**********************************************************************************************************************************************************

      // tell the available safety cpu modules to get their configurations now!
      MyPara.uiCmd := CMD_SM_POST_INIT_FINISHED;
      SafetyManager.ClassState.NewInst(pPara:=#MyPara, pResult:=#MyResult);


//**********************************************************************************************************************************************************
//** FINISH DIAS/CDIAS                                                                                                                                    **
//**********************************************************************************************************************************************************

      //look if DiasMaster is also used ( must be after starting realtime task )
      if ( s_DiasMaster.p_Functions <> NIL ) then
        
        //make final initialization in DiasMaster
        CallPtr	( p_function	:= s_DiasMaster.p_Functions^.p_LastInit
                , p_this		  := s_DiasMaster.p_Functions^.p_This
                );
      end_if;


//**********************************************************************************************************************************************************
//** FINISH VARAN/SDIAS                                                                                                                                   **
//**********************************************************************************************************************************************************

      MyPara.uiCmd            := CMD_POST_INIT_RT_READY;
      ret_code                := BUSY;
      
      StartTime               := ops.tAbsolute;
      AdditionalPostInitTime  := 0;

      while (ret_code = BUSY) do
        // check the varanmanagers if they are not ready
        ret_code := READY;

        // only if there is a varan manager
        if VaranManagersAvailable then
          //send the finish command to all varan managers
          pOneManager := #a_VaranManager[0];
          for i := 0 to ( MAX_VARAN_MANAGERS - 1 ) do

            //look if we have a correct pointer
            if ( pOneManager^.p_Functions & pOneManager^.p_Functions^.p_This ) then
              TempRetCode := pOneManager^.p_Functions^.p_This^.NewInst(pPara:=#MyPara, pResult:=#MyResult);
              
              // if any manager is still busy, we have to keep calling them
              if TempRetCode = BUSY then
                ret_code := TempRetCode;
              end_if;
            end_if;

            pOneManager += sizeof(t_OneVaranManager);
          end_for;                    
        end_if;

        // objects, which are controlled by HwControl
        if pHwControlLogins then
          pHelp := pHwControlLogins;
          while pHelp <> NIL do
            if pHelp^.bdSettings.PostInit then
              TempRetCode := pHelp^.pThis^.NewInst(pPara:=#MyPara, pResult:=#MyResult);
              // if any manager is still busy, we have to keep calling them
              if TempRetCode = BUSY then
                ret_code := TempRetCode;
              end_if;
            end_if;

            pHelp := pHelp^.pNext;
          end_while;
        end_if;

        // check timeout
        if ((ops.tAbsolute - StartTime) > (POST_INIT_TIMEOUT + AdditionalPostInitTime)) then
          HWC_LogError(this, "@0174 (HwControl::Control::NewInst) Timeout in PostInit (finishing)");

          // only if there is a varan manager
          if VaranManagersAvailable then

            // Force all VM to end the PostInit Phase, Otherwise UpdateCy of HWK will not be called -----------------------------------------
            MyPara.uiCmd := CMD_FORCE_POST_INIT_END;

            //call the last init of all varan managers
            pOneManager := #a_VaranManager[0];  // RamAnd: using pointers instead of array accesses reduces compiled awl-code by 120 lines!!!
            for i := 0 to ( MAX_VARAN_MANAGERS - 1 ) do

              //look if we have a correct pointer
              if ( pOneManager^.p_Functions & pOneManager^.p_Functions^.p_This ) then
                TempRetCode := pOneManager^.p_Functions^.p_This^.NewInst(#MyPara, #MyResult);
              end_if;

              pOneManager += sizeof(t_OneVaranManager);
            end_for;	// ---------------------------------------------------------------------------------------------------------------------------------------------
          end_if;
          exit;
        end_if;
      end_while;

//**********************************************************************************************************************************************************
//** Tell everything that the Post-Init is Done                                                                                                           **
//**********************************************************************************************************************************************************

      // Tell DiasMaster that the Post-Init is Done
      // needed for CallRealtime_IM
      MyPara.uiCmd := CMD_SET_POSTINIT_DONE;
      
      if s_DiasMaster.p_Functions then
        ret_code := s_DiasMaster.p_Functions^.p_This$pVirtualBase^.NewInst(#MyPara, pResult:=#MyResult);
      end_if;      

      // only if there is a varan manager
      if VaranManagersAvailable then
        //send the finish command to all varan managers
        pOneManager := #a_VaranManager[0];
        for i := 0 to ( MAX_VARAN_MANAGERS - 1 ) do

          //look if we have a correct pointer
          if ( pOneManager^.p_Functions & pOneManager^.p_Functions^.p_This ) then
            TempRetCode := pOneManager^.p_Functions^.p_This^.NewInst(pPara:=#MyPara, pResult:=#MyResult);
            
            // if any manager is still busy, we have to keep calling them
            if TempRetCode = BUSY then
              ret_code := TempRetCode;
            end_if;
          end_if;

          pOneManager += sizeof(t_OneVaranManager);
        end_for;                    
      end_if;

      // objects, which are controlled by HwControl
      if pHwControlLogins then
        pHelp := pHwControlLogins;
        while pHelp <> NIL do
          if pHelp^.bdSettings.PostInit then
            TempRetCode := pHelp^.pThis^.NewInst(pPara:=#MyPara, pResult:=#MyResult);
            // if any manager is still busy, we have to keep calling them
            if TempRetCode = BUSY then
              ret_code := TempRetCode;
            end_if;
          end_if;
          pHelp := pHelp^.pNext;
        end_while;
      end_if;
      
      bPostInitFinished := TRUE;  //Remember that post init is finished
      
#ifdef HWC_ENABLE_SPAM_PROTECTION
      // stop the override => from now on the spam protection is active
      HwcLogging.OverrideSpamProtection.Write(input:=0);
#endif

//**********************************************************************************************************************************************************
    CMD_GET_SUPPORTED_FEATURES:
      
      //Set length to be flexible for future 
      pResult^.uiLng := 4; 
      pResult^.aData[0]$BDINT := SupportedFeatures; 

//**********************************************************************************************************************************************************
    CMD_HWCONTROL_LOGIN:
      TempSettings  := pPara^.aPara[1]$t_HwObjListSettings;      
      us_ModuleType := pPara^.aPara[2]$USINT;
      us_CoreSelect := pPara^.aPara[3]$USINT;
      ud_RtTime_us  := pPara^.aPara[4]$UDINT;
      ud_CyTime_us  := pPara^.aPara[5]$UDINT;
            
      if (us_ModuleType AND HWT_ESCAPE_SEQU) = 0 then      
        us_ModuleType := 0; // MSB must be set for a valid Escape Sequence
      end_if;
      
      if AddHwObject( pThis           :=  pPara^.aPara[0]$pVirtualBase
                    , Settings        :=  TempSettings
                    , EscapeSequence  :=  us_ModuleType
                    , us_CoreSelect   :=  us_CoreSelect
                    , ud_RtTime_us    :=  ud_RtTime_us
                    , ud_CyTime_us    :=  ud_CyTime_us
                    ) <> 0 then
                    
        ret_code := ERROR;
      end_if;
         
      pResult^.uiLng          := 8;
      //Just return value of maintimer in ns to be compatible
      //Old classes --> do not set a new time --> task will be started with maintimer as time, so they will get the right time
      //New classes don't proove the return values, because the times will be distributed at the beginning of the post init phase
      pResult^.aData[0]$UDINT := _ClockTicks * 1000;      
      pResult^.aData[4]$UDINT := _ClockTicks * 1000;
      
      // post init callback is only possible if the method is supported by loader
      if TempSettings.PostInit & (InstallPostInitCB() <> 0) then
        ret_code := ERROR;
      end_if;

//**********************************************************************************************************************************************************
  CMD_GET_HARDWARE_TREE_ENTRY:
   
    //Reset all Return Values
    pResult^.aData$t_HWCGetHardwareTreeEntryOut.pStr_NextHardewareTreeEntry := nil;
    pResult^.aData$t_HWCGetHardwareTreeEntryOut.retcode                     := _HWC_RETVAL_ERROR; 
    ret_code                                                                := ERROR;
    
    pStr_HWTreeEntry  :=  pPara^.aPara[0]$t_HWCGetHardwareTreeEntryIn.pStr_LastHardewareTreeEntry;
    
    //Standard: Use varan manager number 0
    usVaranManagerNrTreeEntry := 0;

    // if nil, search the first module ==================================================================================================================
    if pPara^.aPara$t_HWCGetHardwareTreeEntryIn.pStr_LastHardewareTreeEntry = nil then
         
      // Call all managers and search the module      
      us_ModuleType := HWT_ESCAPE_VARAN; // 1. entry requested, start with Varan HWKs
      
    //Search the next module =============================================================================================================================
    //Only when there is a valid length we can access the data
    elsif (pStr_HWTreeEntry$^UINT^ <> 0) then // Length is 2 byte
      
      // 3 byte is domain
      // 4 byte is bus type/escape sequence.
      us_ModuleType := (pStr_HWTreeEntry+3)^$USINT;  
      
      
      //Current Index = 4 because first 2 bytes are length, one byte domain number, next byte is escape sequence, 5th byte is port number
      pPara^.aPara[0]$t_HWCGetHardwareTreeEntryIn.us_current_index  := 4;  //points to escape sequence
      
      //Current length is length - 2 (point above domain number and escape sequence)
      pPara^.aPara[0]$t_HWCGetHardwareTreeEntryIn.us_current_length$UINT := pStr_HWTreeEntry^$UINT - 2;
      
      //Multivaran-Manager Support:
      //Check if our module type is the multivaran escape sequence
      if us_ModuleType = HWT_ESCAPE_MULTIVARAN then
        us_ModuleType := (pStr_HWTreeEntry+5)^$USINT;
        
        //Get the varan manager number of the module
        usVaranManagerNrTreeEntry := (pStr_HWTreeEntry+4)^$USINT;
        
        //Increment index + 2 (ESCAPE-SEQUENZ MULTIVARAN + ManagerNumber)
        pPara^.aPara[0]$t_HWCGetHardwareTreeEntryIn.us_current_index  += 2;  //points to escape sequence
        
        //Increment length + 2(ESCAPE-SEQUENZ MULTIVARAN + ManagerNumber)
        pPara^.aPara[0]$t_HWCGetHardwareTreeEntryIn.us_current_length$UINT += 2;
      
      end_if;

    end_if;    
      
    //Go through all managers
    
    //Varan -------------------------------------------------------------------------------------------------------------------
    if us_ModuleType = HWT_ESCAPE_VARAN then
    
      // Loop over all Varanmanger
      //Point to correct manager with the index
      pOneManager := #a_VaranManager[usVaranManagerNrTreeEntry];  // RamAnd: using pointers instead of array accesses reduces compiled awl-code by 120 lines!!!
      
      //look if we have a correct pointer
      if (pOneManager^.p_Functions) & ( pOneManager^.p_Functions^.p_This ) then
        ret_code := pOneManager^.p_Functions^.p_This^.NewInst(pPara, pResult);
        
        if (ret_code = READY) then
          
          if pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode = _HWC_RETVAL_OK_HWTSTR_RETURNED then
            return; // Next HWT string was returned pass it back
          end_if;
          
          if pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode = _HWC_RETVAL_OK_MODULE_FOUND |
             pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode = _HWC_RETVAL_OK_END_OF_LIST then
            // Module was found and was the last module in the Manager 
            // Set the requested HWT string to nil so that the next call is an autohit
            pPara^.aPara$t_HWCGetHardwareTreeEntryIn.pStr_LastHardewareTreeEntry := nil;
            
            ret_code := ERROR;  // Reset ret_code before next call              
            
          end_if;

        end_if;

      end_if;
      
      // Try next Manager
      us_ModuleType := HWT_ESCAPE_CDIAS;
    end_if;  
    
    //CDIAS DIAS -------------------------------------------------------------------------------------------------------------------
    if us_ModuleType = HWT_ESCAPE_CDIAS |
       us_ModuleType = HWT_ESCAPE_DIAS then
      
      if s_DiasMaster.p_Functions then
      
        ret_code := s_DiasMaster.p_Functions^.p_This$pVirtualBase^.NewInst(pPara,pResult);
      
        if pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode = _HWC_RETVAL_OK_HWTSTR_RETURNED then
          return; // Next HWT string was returned pass it back
        end_if;
        
        if pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode = _HWC_RETVAL_OK_MODULE_FOUND |
           pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode = _HWC_RETVAL_OK_END_OF_LIST then
          // Module was found and was the last module in the Manager 
          // Set the requested HWT string to nil so that the next call is an autohit
          pPara^.aPara$t_HWCGetHardwareTreeEntryIn.pStr_LastHardewareTreeEntry := nil;
          
          ret_code := ERROR;  // Reset ret_code before next call              
        end_if;
      
      end_if;

      // Try next Manager
      us_ModuleType := HWT_ESCAPE_SEQU;
    
    end_if;
    
     // Other (Local SDIAS)  -------------------------------------------------------------------------------------------------------------------
    if us_ModuleType AND HWT_ESCAPE_SEQU then
      if pHwControlLogins then
     
        pHelp := pHwControlLogins;
        
        while pHelp <> NIL  do 
          
          if pHelp^.usEscSequence AND HWT_ESCAPE_SEQU then
          
            ret_code := pHelp^.pThis^.NewInst(pPara, pResult);              
            
            if pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode = _HWC_RETVAL_OK_HWTSTR_RETURNED then
              return; // Next HWT string was returned pass it back
            end_if;
            
            if pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode = _HWC_RETVAL_OK_MODULE_FOUND |
               pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode = _HWC_RETVAL_OK_END_OF_LIST then
              // Module was found and was the last module in the Manager 
              // Set the requested HWT string to nil so that the next call is an autohit
              pPara^.aPara$t_HWCGetHardwareTreeEntryIn.pStr_LastHardewareTreeEntry := nil;
              
              ret_code := ERROR;  // Reset ret_code before next call              
            end_if;
          
          end_if;
          
          pHelp := pHelp^.pNext;
          
        end_while;
        
      end_if; 
      
    end_if;
          
    // Check if no further module exits
    if pPara^.aPara$t_HWCGetHardwareTreeEntryIn.pStr_LastHardewareTreeEntry = nil then
      ret_code := READY;
      pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode                      := _HWC_RETVAL_OK_END_OF_LIST;
      pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.pStr_NextHardewareTreeEntry  := NIL;
      
    end_if;

//**********************************************************************************************************************************************************
  CMD_GET_HARDWARE_DIAGNOSIS:
  
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR;
    ret_code := ERROR;
    
    // Reset all return values    
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ClassState      := 16#FFFFFFFF$t_e_VaranErrors;  //invalid value
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pStr_DeviceName := NIL;
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_DeviceID     := HWC_INVALID_DEVICE_ID;
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pStr_VendorName := NIL;
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_VendorID     := 0;
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pStr_SerialNo   := NIL;
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pStr_OrderingNo := NIL;
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_LicenseNo    := 0;
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.hd_HWVersion    := 0;
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_Variante     := 0;
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.hd_FPGAVersion  := 0;
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pStr_FWVersion  := NIL;
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.hd_SafetyNumber := 0;
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_Place        := 16#FFFFFFFF; // Place 0 is valid
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_AxisNo       := 16#FFFFFFFF;
    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;
   
    pStr_HWTRequested  :=  pPara^.aPara[0]$t_HWCGetHardwareDiagnosisIn.pStr_HardewareTreeEntry;

    //Only when there is a valid length we can access the data
    if (pStr_HWTRequested$^UINT^ <> 0) then // Length is 2 byte
      
      // 3 byte is domain
      
      // 4 byte is bus type/escape sequence.
      us_ModuleType := (pStr_HWTRequested+3)^$USINT;  

      //Standard: Use varan manager number 0
      usVaranManagerNrTreeEntry := 0;

      //Current Index = 5 because first 2 bytes are length, one byte domain number, next byte is escape sequence, 5th byte is port number
      pPara^.aPara[0]$t_HWCGetHardwareDiagnosisIn.us_current_index  := 4;  //points to escape sequence
      //Current length is length - 2 (point above domain number and escape sequence)
      pPara^.aPara[0]$t_HWCGetHardwareDiagnosisIn.us_current_length$UINT := pStr_HWTRequested^$UINT - 2;
      
      //Multivaran-Manager Support:
      //Check if our module type is the multivaran escape sequence
      if us_ModuleType = HWT_ESCAPE_MULTIVARAN then
      
        us_ModuleType := (pStr_HWTRequested+5)^$USINT;
        
        //Get the varan manager number of the module
        usVaranManagerNrTreeEntry := (pStr_HWTRequested+4)^$USINT;
        
        //Increment index + 2 (ESCAPE-SEQUENZ MULTIVARAN + ManagerNumber)
        pPara^.aPara[0]$t_HWCGetHardwareTreeEntryIn.us_current_index  += 2;  //points to escape sequence
        
        //Increment length + 2(ESCAPE-SEQUENZ MULTIVARAN + ManagerNumber)
        pPara^.aPara[0]$t_HWCGetHardwareTreeEntryIn.us_current_length$UINT += 2;
      
      end_if;      
      
      case us_ModuleType of
      
        //-------------------------------------------------------------------------------------------
        HWT_ESCAPE_VARAN:
        
          // Loop over all Varanmanger
          pOneManager := #a_VaranManager[usVaranManagerNrTreeEntry];  // RamAnd: using pointers instead of array accesses reduces compiled awl-code by 120 lines!!!

          //look if we have a correct pointer
          if (pOneManager^.p_Functions) & ( pOneManager^.p_Functions^.p_This ) then
            ret_code := pOneManager^.p_Functions^.p_This^.NewInst(pPara, pResult);
          end_if;
        

        //-------------------------------------------------------------------------------------------
        HWT_ESCAPE_CDIAS:
          
          if s_DiasMaster.p_Functions then
            ret_code := s_DiasMaster.p_Functions^.p_This$pVirtualBase^.NewInst(pPara,pResult);
          end_if;
          
        //-------------------------------------------------------------------------------------------
        HWT_ESCAPE_DIAS:
      
          if s_DiasMaster.p_Functions then
            ret_code := s_DiasMaster.p_Functions^.p_This$pVirtualBase^.NewInst(pPara,pResult);
          end_if;
          
        //-------------------------------------------------------------------------------------------        
//        HWT_ESCAPE_SDIAS:
        
        // Other (SDIAS)
        else
          if pHwControlLogins then
            
            pHelp := pHwControlLogins;
            
            while pHelp <> NIL &
              ((ret_code <> READY) & (ret_code <> BUSY)) do // Module was found if retcode is ready or busy
            
              if pHelp^.usEscSequence = us_ModuleType then
                ret_code := pHelp^.pThis^.NewInst(pPara, pResult);                
              end_if;
              
              pHelp := pHelp^.pNext;
              
            end_while;
            
          end_if;
      
      end_case;
    end_if;
    
//**********************************************************************************************************************************************************
  CMD_SET_VARANMANAGER_ERROR:
  
    //Raise manage error at all varan managers
    pOneManager := #a_VaranManager[0]; 
    for i := 0 to ( MAX_VARAN_MANAGERS - 1 ) do

      //look if we have a correct pointer
      if (pOneManager^.p_Functions) & ( pOneManager^.p_Functions^.p_This ) then
        pOneManager^.p_Functions^.p_This^.RaiseManagerError(pPara^.aPara[0]$UDINT);

      end_if;
      pOneManager += sizeof(t_OneVaranManager);
    end_for;          


//**********************************************************************************************************************************************************  
  CMD_EXTEND_POST_INIT_TIME:
      
    AdditionalPostInitTime += pPara^.aPara[0]$UDINT;
  
//**********************************************************************************************************************************************************
  CMD_LOGIN_VARANMANAGER:
    
    ret_code := READY;
    pResult^.aData[0]$DINT := AddVaranManager(ud_manager_number  := pPara^.aPara[0]$UDINT
                                            , p_function_list    := pPara^.aPara[1]$^void 
                                            , us_CoreSelect      := pPara^.aPara[2]$USINT
                                            , ud_RtTime_us       := pPara^.aPara[3]$UDINT
                                            , ud_CyTime_us       := pPara^.aPara[4]$UDINT
                                            );
      
//**********************************************************************************************************************************************************
  CMD_DISABLE_VARANMANAGER:
  
    ret_code := READY;
    pResult^.aData[0]$DINT := DisableVaranManager(ud_manager_number := pPara^.aPara[0]$UDINT
                                                , p_function_list   := pPara^.aPara[1]$^void
                                                );
  
//**********************************************************************************************************************************************************
  CMD_GET_HW_TIMESTAMP:
  
    //NewInst CMD for SmartIO modules to fetch timestamp from HwControl
  
    ret_code := ERROR;
    
    // Version 1 does not support core select
    if pPara^.aPara[0]$t_GetHwTimestampCmd.udVersion = 1 then
      
      ret_code := READY;
      
      pResult^.uiLng      := sizeof(t_GetHwTimestampResult);
      pResult^.aData[0]$t_GetHwTimestampResult.udVersion   := 1;
      pResult^.aData[0]$t_GetHwTimestampResult.uiTimeStamp := aTaskInfoCore[TASK_SELECT_CORE0].uiHwTimeStamp_us;
      
    // Version 2 supports core selection
    elsif pPara^.aPara[0]$t_GetHwTimestampCmd.udVersion = 2 then
    
      ret_code := READY;
      us_CoreSelect := pPara^.aPara[0]$t_GetHwTimestampCmd.udCoreSelect$USINT;

      pResult^.uiLng      := sizeof(t_GetHwTimestampResult);
      pResult^.aData[0]$t_GetHwTimestampResult.udVersion   := 1;
      pResult^.aData[0]$t_GetHwTimestampResult.uiTimeStamp := aTaskInfoCore[us_CoreSelect].uiHwTimeStamp_us;
    
    end_if;
//**********************************************************************************************************************************************************



  CMD_HWC_REQ_PLLNS_REGULATION:
    
    ret_code := ERROR;
    
    //Version
    if pPara^.aPara[0] >= 1 then
   
      pResult^.uiLng := sizeof(DINT) + sizeof(t_HWCRetvalReturnCode);
      pResult^.aData[0]$DINT := 1;                 // Version      
      
      if b_SoftwareSyncActive then
        pResult^.aData[4]   := _HWC_RETVAL_ERROR_SYNCREG_INUSE;//request denied  Software Synchronisation is already in use.
      else
        pResult^.aData[4]$t_HWCRetvalReturnCode := _HWC_RETVAL_OK;//request granted         
        b_SoftwareSyncActive := TRUE;
      end_if;
    
      ret_code := READY;
      
    end_if;
    
    //**********************************************************************************************************************************************************


    //**********************************************************************************************************************************************************
    CMD_HWC_CONVERT_COMPRESSED_HWPATH:
      
      //Forward newinst to safety manager
      ret_code := SafetyManager.ClassState.NewInst(pPara:=pPara, pResult:=pResult);
      
    //**********************************************************************************************************************************************************            
    CMD_HWC_GET_REQUIREDWAITTIME:  //Returns the maximum time, that a required Module should wait in the Init() until the HW is found

      // Command Version 1 ** 

      //aPara[0] = version of command

      //Parameter of Version 1:

      //retcode = error => command not supported
      //retcode = ready => result is filled with data

      // result of version 1
      //result^.aData[0x0]$UDINT  := version of command
      //result^.aData[0x4]$UDINT  := maximum time, that a required Module should wait in the Init() until the HW is found
      
      ret_code := ERROR;
      
      if pPara^.aPara[0] = 1 then // Check Version
      
        ret_code := READY;
        pResult^.uiLng := 8;
        pResult^.aData[0]$UDINT := 1;   //version
        pResult^.aData[4]$UDINT := HWC_DEFAULT_REQUIREDWAITTIME;
      
      end_if;

  end_case;

END_FUNCTION


FUNCTION HwControl::InstallPostInitCB
  VAR_OUTPUT
    sd_retval 	: DINT;
  END_VAR
  VAR
    pFunction   : ^void;
  END_VAR
  
  sd_retval := -1;

  if b_PostInitInstalled = TRUE then
    sd_retval := 0;   // Return OK
  else
  
    // tell the loader that we need a post init phase
    pFunction := _FindFctName("LDR_InstallPostInitCB");
    if ( pFunction <> NIL ) then
      pFunction $ LDR_InstallPostInitCB(pThis:=this, pCmdSvr:=(#this^.Control.pMeth)$^SvrChCmd, newInstCmd:=CMD_POST_INIT_CALL);
      
      b_PostInitInstalled := TRUE;
      sd_retval           := 0;
      
    end_if;
  end_if;
  
END_FUNCTION


FUNCTION GLOBAL HwControl::DisableVaranManager
  VAR_INPUT
    ud_manager_number 	: UDINT;
    p_function_list 	: ^void;
  END_VAR
  VAR_OUTPUT
    sd_retval 	: DINT;
  END_VAR

  // is class ok
  if ( State = _ClassOk ) then
  
    // check pointer of watchdog interface
    if pSCDW = NIL then
    
      //look if it is a correct VaranManager number
      if (( ud_manager_number >= 0 ) &
          ( ud_manager_number <= MAX_VARAN_MANAGERS - 1 )) then
    
        // is this number already in use
        if ( a_VaranManager[ ud_manager_number ].p_Functions <> NIL ) then

          a_VaranManager[ ud_manager_number ].p_Functions	:= NIL;
          VaranManagersAvailable -= 1;
          sd_retval := 0;

        else
          sd_retval := -1;
          HWC_LogError(this, "@0175 (HwControl::DisableVaranManager) Manager is not even used!");
        end_if;
      else
        sd_retval := -2;
        HWC_LogError(this, "@0176 (HwControl::DisableVaranManager) Wrong VaranManagerNumber!");
      end_if;
    else
      sd_retval := -3;
      HWC_LogError(this, "@0177 (HwControl::DisableVaranManager) Called too late, the Watchdog is already active!");
    end_if;
  else 
    sd_retval := -4;
    HWC_LogError(this, "@0178 (HwControl::DisableVaranManager) Class state is not ok!");
  end_if;  

END_FUNCTION


FUNCTION HwControl::UpdateRtVaranManager
  VAR_INPUT
    usActiveCore 	: USINT;
  END_VAR
  VAR
    i			: DINT;
    pOneManager : ^t_OneVaranManager;
  END_VAR
    
  //update realtime functions of all VaranManagers
  //*****************************************************************************
  pOneManager := #a_VaranManager[0];  // RamAnd: using pointers instead of array accesses reduces compiled awl-code by 120 lines!!!
  for i := 0 to ( MAX_VARAN_MANAGERS - 1 ) do
    
    //look if right core, or call all manager if only one core is available
    if ( pOneManager^.us_CoreSelect = usActiveCore) then
          
      //look if we have a correct pointer
      if ( pOneManager^.p_Functions$^INT <> NIL ) then

        // if VMC is used, then check if the framecounter has been increased => right time to call Varan HW-Classes
        if (pOneManager^.p_Functions^.b_IsAlsoClient & (pOneManager^.p_Functions^.b_OverrideFrameCheck = FALSE) & 
            pOneManager^.p_Functions^.p_This^.FrameCounterChanged(#pOneManager^.usOldFrameCnt, #pOneManager^.usActFrameCnt)) then

          // maybe we got some phase shift
          if (pOneManager^.ud_SuperiorSyncActual <> pOneManager^.ud_SuperiorSync) &
             (pOneManager^.ud_SuperiorSyncActual MOD pOneManager^.ud_SuperiorSync) then
             
            pOneManager^.ud_SuperiorSyncActual := pOneManager^.ud_SuperiorSync;
            pOneManager^.ud_CounterRt := pOneManager^.ud_RtTime_us;
             
            pOneManager^.usSyncCheck := 0; // reset synchronity
          end_if;
        end_if;

        //if call time for varan manager is reached
        if ( pOneManager^.ud_CounterRt = pOneManager^.ud_RtTime_us ) then
          
          //reset task time counter
          pOneManager^.ud_CounterRt := 0;

          //call realtime methode of VaranMaster
          pOneManager^.p_Functions^.p_This^.RtWork( 0 ); 
                    
          // if manager is also client and we are in superior task
          if (pOneManager^.p_Functions^.b_IsAlsoClient = 1) & (pOneManager^.p_Functions^.b_OverrideFrameCheck = FALSE) then
            if (pOneManager^.ud_SuperiorSyncActual MOD pOneManager^.ud_SuperiorSync) = 0 then
              pOneManager^.ud_SuperiorSyncActual := 0;

              pOneManager^.usSyncCheck := (pOneManager^.usSyncCheck SHL 1) OR (pOneManager^.usActFrameCnt <> pOneManager^.usOldFrameCnt);

              if (pOneManager^.usSyncCheck = 16#FF) then
                pOneManager^.p_Functions^.b_HWClassSynchron := TRUE;
              else
                pOneManager^.p_Functions^.b_HWClassSynchron := FALSE;
              end_if;
            elsif (pOneManager^.ud_SuperiorSyncActual > pOneManager^.ud_SuperiorSync) then
              pOneManager^.ud_SuperiorSyncActual := 0;
            end_if;
          end_if;
        else
          if (pOneManager^.p_Functions^.b_IsAlsoClient & (pOneManager^.p_Functions^.b_OverrideFrameCheck = FALSE) &
             (((pOneManager^.p_Functions^.ud_SuperiorTime / 1000 ) > pOneManager^.ud_RtTime_us) |
             (pOneManager^.ud_SuperiorSyncActual MOD pOneManager^.ud_SuperiorSync)) &
             pOneManager^.p_Functions^.p_This^.FrameCounterChanged(#pOneManager^.usOldFrameCnt, #pOneManager^.usActFrameCnt)) then
            //set task time counter to HwControl task time
            pOneManager^.ud_CounterRt := 0;
            pOneManager^.ud_SuperiorSyncActual := 0;
            pOneManager^.usSyncCheck := 0;  // reset synchronity
          end_if;
        end_if;

        // add task time to counter
        pOneManager^.ud_CounterRt += aTaskInfoCore[usActiveCore].ud_MyRtTaskTime_us;          

        // increase cycle counter
        pOneManager^.ud_SuperiorSyncActual += 1;
      end_if;
    end_if;

    pOneManager += sizeof(t_OneVaranManager);
  end_for;	

END_FUNCTION


FUNCTION HwControl::UpdateRtPostScanVaranManager
  VAR_INPUT
    usActiveCore 	: USINT;
  END_VAR
  VAR
    i			: DINT;
    pOneManager : ^t_OneVaranManager;
  END_VAR

  //Update Rt PostScan method of all varanmanagers
  //*****************************************************************************
  pOneManager := #a_VaranManager[0];
  for i := 0 TO (MAX_VARAN_MANAGERS - 1) do    
    //Look for right core
    if pOneManager^.us_CoreSelect = usActiveCore then
      if pOneManager^.p_Functions <> NIL & pOneManager^.ud_CounterRt = ( aTaskInfoCore[usActiveCore].ud_MyRtTaskTime_us) then
        pOneManager^.p_Functions^.p_This^.UpdateRtPostscan();
      end_if;
    end_if;
    pOneManager += SIZEOF(t_OneVaranManager);    
  end_for;

END_FUNCTION


#pragma warning(disable:73);
FUNCTION HwControl::CalcTimeMeasurementPreScan
  VAR_INPUT
    pHwControlTimes 	: ^t_HwControl_Times_SINGLE;
  END_VAR
#pragma warning(default:73);

#ifdef HWCONTROL_TIME_MEASUREMENT  
  if ops.tAbsolute > HWCONTROL_TIME_MEASUREMENT_DELAY then

    if pHwControlTimes^.sRtPreScan_Help.bRestart then
      
      pHwControlTimes^.sRtPrescan_Total.ActTime         := 0;
      pHwControlTimes^.sRtPrescan_Total.AvgTime         := 0;
      pHwControlTimes^.sRtPrescan_Total.MinTime         := 16#FFFF;
      pHwControlTimes^.sRtPrescan_Total.MaxTime         := 0;
      
      pHwControlTimes^.sRtPrescan_FirstCallHW.ActTime   := 0;
      pHwControlTimes^.sRtPrescan_FirstCallHW.AvgTime   := 0;
      pHwControlTimes^.sRtPrescan_FirstCallHW.MinTime   := 16#FFFF;
      pHwControlTimes^.sRtPrescan_FirstCallHW.MaxTime   := 0;
      
      pHwControlTimes^.sRtPrescan_Varan.ActTime         := 0;
      pHwControlTimes^.sRtPrescan_Varan.AvgTime         := 0;
      pHwControlTimes^.sRtPrescan_Varan.MinTime         := 16#FFFF;
      pHwControlTimes^.sRtPrescan_Varan.MaxTime         := 0;
      
      pHwControlTimes^.sRtPrescan_Other.ActTime         := 0;
      pHwControlTimes^.sRtPrescan_Other.AvgTime         := 0;
      pHwControlTimes^.sRtPrescan_Other.MinTime         := 16#FFFF;
      pHwControlTimes^.sRtPrescan_Other.MaxTime         := 0;

      pHwControlTimes^.sRtPrescan_HwObjects.ActTime     := 0;
      pHwControlTimes^.sRtPrescan_HwObjects.AvgTime     := 0;
      pHwControlTimes^.sRtPrescan_HwObjects.MinTime     := 16#FFFF;
      pHwControlTimes^.sRtPrescan_HwObjects.MaxTime     := 0;
      
      pHwControlTimes^.sRtPreScan_Help.udCycleCnt       := 0;
      pHwControlTimes^.sRtPreScan_Help.bRestart         := FALSE;
      pHwControlTimes^.sRtPreScan_Help.bFinished        := FALSE;
      
    elsif pHwControlTimes^.sRtPreScan_Help.bFinished = FALSE then
    
      pHwControlTimes^.sRtPreScan_Help.udCycleCnt  += 1;
      
      //First Call Objects Min/Max
      //*****************************************************************************
      if pHwControlTimes^.sRtPrescan_FirstCallHW.ActTime > pHwControlTimes^.sRtPrescan_FirstCallHW.MaxTime then
        pHwControlTimes^.sRtPrescan_FirstCallHW.MaxTime := pHwControlTimes^.sRtPrescan_FirstCallHW.ActTime;
        
      elsif pHwControlTimes^.sRtPrescan_FirstCallHW.ActTime < pHwControlTimes^.sRtPrescan_FirstCallHW.MinTime then
        pHwControlTimes^.sRtPrescan_FirstCallHW.MinTime := pHwControlTimes^.sRtPrescan_FirstCallHW.ActTime;
      end_if;

      //VARAN Objects Min/Max
      //*****************************************************************************
      if pHwControlTimes^.sRtPrescan_Varan.ActTime > pHwControlTimes^.sRtPrescan_Varan.MaxTime then
        pHwControlTimes^.sRtPrescan_Varan.MaxTime := pHwControlTimes^.sRtPrescan_Varan.ActTime;
        
      elsif pHwControlTimes^.sRtPrescan_Varan.ActTime < pHwControlTimes^.sRtPrescan_Varan.MinTime then
        pHwControlTimes^.sRtPrescan_Varan.MinTime := pHwControlTimes^.sRtPrescan_Varan.ActTime;
      end_if;

      //HwControl-Login Objects Min/Max
      //*****************************************************************************
      if pHwControlTimes^.sRtPrescan_HwObjects.ActTime > pHwControlTimes^.sRtPrescan_HwObjects.MaxTime then
        pHwControlTimes^.sRtPrescan_HwObjects.MaxTime := pHwControlTimes^.sRtPrescan_HwObjects.ActTime;
        
      elsif pHwControlTimes^.sRtPrescan_HwObjects.ActTime < pHwControlTimes^.sRtPrescan_HwObjects.MinTime then
        pHwControlTimes^.sRtPrescan_HwObjects.MinTime := pHwControlTimes^.sRtPrescan_HwObjects.ActTime;
      end_if;
      
      //Other Objects Min/Max (DIAS Master and Special HW)
      //*****************************************************************************
      if pHwControlTimes^.sRtPrescan_Other.ActTime > pHwControlTimes^.sRtPrescan_Other.MaxTime then
        pHwControlTimes^.sRtPrescan_Other.MaxTime := pHwControlTimes^.sRtPrescan_Other.ActTime;
        
      elsif pHwControlTimes^.sRtPrescan_Other.ActTime < pHwControlTimes^.sRtPrescan_Other.MinTime then
        pHwControlTimes^.sRtPrescan_Other.MinTime := pHwControlTimes^.sRtPrescan_Other.ActTime;
      end_if;
      
      
      //Calculate Total amount of realtime
      //*****************************************************************************
      pHwControlTimes^.sRtPrescan_Total.ActTime := pHwControlTimes^.sRtPrescan_FirstCallHW.ActTime +
                                                   pHwControlTimes^.sRtPrescan_Varan.ActTime +
                                                   pHwControlTimes^.sRtPrescan_HwObjects.ActTime +
                                                   pHwControlTimes^.sRtPrescan_Other.ActTime;
      //Total Realtime Min/Max                                           
      //*****************************************************************************
      if pHwControlTimes^.sRtPrescan_Total.ActTime > pHwControlTimes^.sRtPrescan_Total.MaxTime then
        pHwControlTimes^.sRtPrescan_Total.MaxTime := pHwControlTimes^.sRtPrescan_Total.ActTime;
        
      elsif pHwControlTimes^.sRtPrescan_Total.ActTime < pHwControlTimes^.sRtPrescan_Total.MinTime then
        pHwControlTimes^.sRtPrescan_Total.MinTime := pHwControlTimes^.sRtPrescan_Total.ActTime;
      end_if;                     
      
      pHwControlTimes^.sRtPrescan_FirstCallHW.AvgTime   += pHwControlTimes^.sRtPrescan_FirstCallHW.ActTime;
      pHwControlTimes^.sRtPrescan_Varan.AvgTime         += pHwControlTimes^.sRtPrescan_Varan.ActTime;
      pHwControlTimes^.sRtPrescan_HwObjects.AvgTime     += pHwControlTimes^.sRtPrescan_HwObjects.ActTime;
      pHwControlTimes^.sRtPrescan_Other.AvgTime         += pHwControlTimes^.sRtPrescan_Other.ActTime;
      pHwControlTimes^.sRtPrescan_Total.AvgTime         += pHwControlTimes^.sRtPrescan_Total.ActTime;
      

      //Finished measurement?
      if pHwControlTimes^.sRtPreScan_Help.udCycleCnt >= HWCONTROL_TIME_MEASUREMENT_CNT then
      
        pHwControlTimes^.sRtPrescan_FirstCallHW.AvgTime   /= HWCONTROL_TIME_MEASUREMENT_CNT;
        pHwControlTimes^.sRtPrescan_Varan.AvgTime         /= HWCONTROL_TIME_MEASUREMENT_CNT;
        pHwControlTimes^.sRtPrescan_HwObjects.AvgTime     /= HWCONTROL_TIME_MEASUREMENT_CNT;
        pHwControlTimes^.sRtPrescan_Other.AvgTime         /= HWCONTROL_TIME_MEASUREMENT_CNT;
        pHwControlTimes^.sRtPrescan_Total.AvgTime         /= HWCONTROL_TIME_MEASUREMENT_CNT;
                
        pHwControlTimes^.sRtPreScan_Help.bFinished         := TRUE;
      end_if;      
    end_if;
  end_if;
#endif 

END_FUNCTION

#pragma warning(disable:73);
FUNCTION HwControl::CalcTimeMeasurementPostScan
  VAR_INPUT
    pHwControlTimes 	: ^t_HwControl_Times_SINGLE;
  END_VAR
#pragma warning(default:73);

#ifdef HWCONTROL_TIME_MEASUREMENT  
  if ops.tAbsolute > HWCONTROL_TIME_MEASUREMENT_DELAY then

    if pHwControlTimes^.sRtPostScan_Help.bRestart then
      
      pHwControlTimes^.sRtPostscan_Total.ActTime      := 0;
      pHwControlTimes^.sRtPostscan_Total.AvgTime      := 0;
      pHwControlTimes^.sRtPostscan_Total.MinTime      := 16#FFFF;
      pHwControlTimes^.sRtPostscan_Total.MaxTime      := 0;
            
      pHwControlTimes^.sRtPostscan_Varan.ActTime      := 0;
      pHwControlTimes^.sRtPostscan_Varan.AvgTime      := 0;
      pHwControlTimes^.sRtPostscan_Varan.MinTime      := 16#FFFF;
      pHwControlTimes^.sRtPostscan_Varan.MaxTime      := 0;
      
      pHwControlTimes^.sRtPostscan_HwObjects.ActTime  := 0;
      pHwControlTimes^.sRtPostscan_HwObjects.AvgTime  := 0;
      pHwControlTimes^.sRtPostscan_HwObjects.MinTime  := 16#FFFF;
      pHwControlTimes^.sRtPostscan_HwObjects.MaxTime  := 0;
      
      pHwControlTimes^.sRtPostScan_Help.udCycleCnt    := 0;
      pHwControlTimes^.sRtPostScan_Help.bRestart      := FALSE;
      pHwControlTimes^.sRtPostScan_Help.bFinished     := FALSE;
      
    elsif pHwControlTimes^.sRtPostScan_Help.bFinished = FALSE then
    
      pHwControlTimes^.sRtPostScan_Help.udCycleCnt  += 1;
      
      //VARAN Objects Min/Max
      if pHwControlTimes^.sRtPostscan_Varan.ActTime > pHwControlTimes^.sRtPostscan_Varan.MaxTime then
        pHwControlTimes^.sRtPostscan_Varan.MaxTime := pHwControlTimes^.sRtPostscan_Varan.ActTime;
        
      elsif pHwControlTimes^.sRtPostscan_Varan.ActTime < pHwControlTimes^.sRtPostscan_Varan.MinTime then
        pHwControlTimes^.sRtPostscan_Varan.MinTime := pHwControlTimes^.sRtPostscan_Varan.ActTime;
      end_if;

      //HwControl-Login Objects Min/Max
      if pHwControlTimes^.sRtPostscan_HwObjects.ActTime > pHwControlTimes^.sRtPostscan_HwObjects.MaxTime then
        pHwControlTimes^.sRtPostscan_HwObjects.MaxTime := pHwControlTimes^.sRtPostscan_HwObjects.ActTime;
        
      elsif pHwControlTimes^.sRtPostscan_HwObjects.ActTime < pHwControlTimes^.sRtPostscan_HwObjects.MinTime then
        pHwControlTimes^.sRtPostscan_HwObjects.MinTime := pHwControlTimes^.sRtPostscan_HwObjects.ActTime;
      end_if;
      
      //Calculate Total amount of realtime
      pHwControlTimes^.sRtPostscan_Total.ActTime := pHwControlTimes^.sRtPostscan_Varan.ActTime +
                                                    pHwControlTimes^.sRtPostscan_HwObjects.ActTime;
      //Total Realtime Min/Max                                           
      if pHwControlTimes^.sRtPostscan_Total.ActTime > pHwControlTimes^.sRtPostscan_Total.MaxTime then
        pHwControlTimes^.sRtPostscan_Total.MaxTime := pHwControlTimes^.sRtPostscan_Total.ActTime;
        
      elsif pHwControlTimes^.sRtPostscan_Total.ActTime < pHwControlTimes^.sRtPostscan_Total.MinTime then
        pHwControlTimes^.sRtPostscan_Total.MinTime := pHwControlTimes^.sRtPostscan_Total.ActTime;
      end_if;                     
      
      pHwControlTimes^.sRtPostscan_Varan.AvgTime         += pHwControlTimes^.sRtPostscan_Varan.ActTime;
      pHwControlTimes^.sRtPostscan_HwObjects.AvgTime     += pHwControlTimes^.sRtPostscan_HwObjects.ActTime;
      pHwControlTimes^.sRtPostscan_Total.AvgTime         += pHwControlTimes^.sRtPostscan_Total.ActTime;
      
      //Finished measurement?
      if pHwControlTimes^.sRtPostScan_Help.udCycleCnt >= HWCONTROL_TIME_MEASUREMENT_CNT then
      
        pHwControlTimes^.sRtPostscan_Varan.AvgTime           /= HWCONTROL_TIME_MEASUREMENT_CNT;
        pHwControlTimes^.sRtPostscan_HwObjects.AvgTime       /= HWCONTROL_TIME_MEASUREMENT_CNT;
        pHwControlTimes^.sRtPostscan_Total.AvgTime           /= HWCONTROL_TIME_MEASUREMENT_CNT;
                
        pHwControlTimes^.sRtPostScan_Help.bFinished   := TRUE;
      end_if;      
    end_if;
  end_if;
#endif 

END_FUNCTION

#pragma warning(disable:73);
FUNCTION HwControl::CalcTimeMeasurementCyclic
  VAR_INPUT
    pHwControlTimes 	: ^t_HwControl_Times_SINGLE;
  END_VAR
#pragma warning(default:73);

#ifdef HWCONTROL_TIME_MEASUREMENT  
  if ops.tAbsolute > HWCONTROL_TIME_MEASUREMENT_DELAY then

    if pHwControlTimes^.sCywork_Help.bRestart then
      
      pHwControlTimes^.sCyWork_Total.ActTime         := 0;
      pHwControlTimes^.sCyWork_Total.AvgTime         := 0;
      pHwControlTimes^.sCyWork_Total.MinTime         := 16#FFFF;
      pHwControlTimes^.sCyWork_Total.MaxTime         := 0;
            
      pHwControlTimes^.sCyWork_Varan.ActTime         := 0;
      pHwControlTimes^.sCyWork_Varan.AvgTime         := 0;
      pHwControlTimes^.sCyWork_Varan.MinTime         := 16#FFFF;
      pHwControlTimes^.sCyWork_Varan.MaxTime         := 0;
      
      pHwControlTimes^.sCyWork_HwObjects.ActTime     := 0;
      pHwControlTimes^.sCyWork_HwObjects.AvgTime     := 0;
      pHwControlTimes^.sCyWork_HwObjects.MinTime     := 16#FFFF;
      pHwControlTimes^.sCyWork_HwObjects.MaxTime     := 0;
      
      pHwControlTimes^.sCywork_Help.udCycleCnt       := 0;
      pHwControlTimes^.sCywork_Help.bRestart         := FALSE;
      pHwControlTimes^.sCywork_Help.bFinished        := FALSE;
      
    elsif pHwControlTimes^.sCywork_Help.bFinished = FALSE then
    
      pHwControlTimes^.sCywork_Help.udCycleCnt  += 1;
      

      //VARAN Objects Min/Max
      if pHwControlTimes^.sCyWork_Varan.ActTime > pHwControlTimes^.sCyWork_Varan.MaxTime then
        pHwControlTimes^.sCyWork_Varan.MaxTime := pHwControlTimes^.sCyWork_Varan.ActTime;
        
      elsif pHwControlTimes^.sCyWork_Varan.ActTime < pHwControlTimes^.sCyWork_Varan.MinTime then
        pHwControlTimes^.sCyWork_Varan.MinTime := pHwControlTimes^.sCyWork_Varan.ActTime;
      end_if;

      //HwControl-Login Objects Min/Max
      if pHwControlTimes^.sCyWork_HwObjects.ActTime > pHwControlTimes^.sCyWork_HwObjects.MaxTime then
        pHwControlTimes^.sCyWork_HwObjects.MaxTime := pHwControlTimes^.sCyWork_HwObjects.ActTime;
        
      elsif pHwControlTimes^.sCyWork_HwObjects.ActTime < pHwControlTimes^.sCyWork_HwObjects.MinTime then
        pHwControlTimes^.sCyWork_HwObjects.MinTime := pHwControlTimes^.sCyWork_HwObjects.ActTime;
      end_if;
      
      //Calculate Total amount of realtime
      pHwControlTimes^.sCyWork_Total.ActTime := pHwControlTimes^.sCyWork_Varan.ActTime +
                                                   pHwControlTimes^.sCyWork_HwObjects.ActTime;
      //Total Realtime Min/Max                                           
      if pHwControlTimes^.sCyWork_Total.ActTime > pHwControlTimes^.sCyWork_Total.MaxTime then
        pHwControlTimes^.sCyWork_Total.MaxTime := pHwControlTimes^.sCyWork_Total.ActTime;
        
      elsif pHwControlTimes^.sCyWork_Total.ActTime < pHwControlTimes^.sCyWork_Total.MinTime then
        pHwControlTimes^.sCyWork_Total.MinTime := pHwControlTimes^.sCyWork_Total.ActTime;
      end_if;                     
      
      pHwControlTimes^.sCyWork_Varan.AvgTime         += pHwControlTimes^.sCyWork_Varan.ActTime;
      pHwControlTimes^.sCyWork_HwObjects.AvgTime     += pHwControlTimes^.sCyWork_HwObjects.ActTime;
      pHwControlTimes^.sCyWork_Total.AvgTime         += pHwControlTimes^.sCyWork_Total.ActTime;
      

      //Finished measurement?
      if pHwControlTimes^.sCywork_Help.udCycleCnt >= HWCONTROL_TIME_MEASUREMENT_CNT then
      
        pHwControlTimes^.sCyWork_Varan.AvgTime           /= HWCONTROL_TIME_MEASUREMENT_CNT;
        pHwControlTimes^.sCyWork_HwObjects.AvgTime       /= HWCONTROL_TIME_MEASUREMENT_CNT;
        pHwControlTimes^.sCyWork_Total.AvgTime           /= HWCONTROL_TIME_MEASUREMENT_CNT;
                
        pHwControlTimes^.sCywork_Help.bFinished   := TRUE;
      end_if;      
    end_if;
  end_if;
#endif 
END_FUNCTION


FUNCTION HwControl::UpdateRtFirstCallObjects
  VAR_INPUT
    usCoreSelect 	: USINT;
  END_VAR
  VAR
    pHelpCallFirst  : ^t_HwObjectListCallFirst;  	
  END_VAR

  // special classes with first call priority, which are controlled by HwControl
  if pCallFirstObjects then
    pHelpCallFirst := pCallFirstObjects;
    while pHelpCallFirst <> NIL do
      if pHelpCallFirst^.us_CoreSelect = usCoreSelect then
      pHelpCallFirst^.pThis^.RtWork(0);   
      end_if;
      pHelpCallFirst := pHelpCallFirst^.pNext;
    end_while;  
    // Record finish of first object call. p4 = "HwCo" as ascii (1.215.775.599 = 0x4857434F = "HwCo")
    OS_MakeTraceEntry(pSystrace, HWCONTROL_SYSTRACE_TYPE, HWCONTROL_SYSTRACE_RTPRESCAN_FINISHED_FIRST_CALL_OBJECTS, usCoreSelect);    
  end_if;
  
END_FUNCTION


FUNCTION HwControl::UpdateRtLoginObjects
  VAR_INPUT
    usCoreSelect 	: USINT;
  END_VAR
  VAR
    pHelp           : ^t_HwObjectListElement;  	
  END_VAR
  
  // objects, which are controlled by HwControl
  if pHwControlLogins then
    pHelp := pHwControlLogins;
    while pHelp <> NIL do
      if pHelp^.bdSettings.RtPreScan & pHelp^.us_CoreSelect = usCoreSelect then
        pHelp^.pThis^.RtWork(CALL_OPTION_RT_PRESCAN);
      end_if;
      pHelp := pHelp^.pNext;
    end_while;
  end_if;

END_FUNCTION


FUNCTION HwControl::UpdateRtPostscanLoginObjects
  VAR_INPUT
    usCoreSelect 	: USINT;
  END_VAR
  VAR
    pHelp           : ^t_HwObjectListElement;  	
  END_VAR
  
  // objects, which are controlled by HwControl
  if pHwControlLogins then
    pHelp := pHwControlLogins;
    while pHelp <> NIL do
      if pHelp^.bdSettings.RtPostScan & pHelp^.us_CoreSelect = usCoreSelect then
        pHelp^.pThis^.RtWork(CALL_OPTION_RT_POSTSCAN);
      end_if;
      pHelp := pHelp^.pNext;
    end_while;
  end_if;
  
END_FUNCTION


FUNCTION HwControl::CalculateTaskInfo
  VAR_INPUT
    us_CoreSelect 	: USINT;
    pTaskInfo 	    : ^t_s_TaskCoreInfo;
  END_VAR
  VAR
    pHelp           : ^t_HwObjectListElement;
    pFirstCall      : ^t_HwObjectListCallFirst;
    pOneManager     : ^t_OneVaranManager;
    CurrGGT         : UDINT;
    i               : USINT;
  END_VAR
    
  //Calculate GGT of all objects (HwObjects, VaranManager, FirstCallHW and DiasMaster)
  
  //Calculate for Realtime
  //**************************************************************************************************************
  CurrGGT := 0;   //Start with 0
  
  //Go through all varanmanagers
  pOneManager := #a_VaranManager[0]; 
  for i := 0 to ( MAX_VARAN_MANAGERS - 1 ) do

    //Check if manager is available, set for right core and has set a time
    if ( pOneManager^.p_Functions         <> NIL 
       & pOneManager^.p_Functions^.p_This <> NIL 
       & pOneManager^.ud_RtTime_us        <> 0
       & pOneManager^.us_CoreSelect        = us_CoreSelect
       ) 
    then
      CurrGGT := CalculateGGT(Var1:=CurrGGT, Var2:=pOneManager^.ud_RtTime_us);
    end_if;    
    pOneManager += sizeof(t_OneVaranManager);
  end_for;                    
  
  pHelp := pHwControlLogins;
  
  //Go through all HwObjects
  while pHelp <> NIL do
    if pHelp^.ud_RtTime_us & pHelp^.us_CoreSelect = us_CoreSelect then
      CurrGGT := CalculateGGT(Var1:=CurrGGT, Var2:=pHelp^.ud_RtTime_us);
    end_if;
    pHelp := pHelp^.pNext;
  end_while;

  pFirstCall := pCallFirstObjects;
  
  //Go through all first call objects
  while pFirstCall <> NIL do
    if pFirstCall^.ud_RtTime_us & pFirstCall^.us_CoreSelect = us_CoreSelect then
      CurrGGT := CalculateGGT(Var1:=CurrGGT, Var2:=pFirstCall^.ud_RtTime_us);
    end_if;
    pFirstCall := pFirstCall^.pNext;
  end_while;
  
  //Also calculate with DIAS Master time (DIAS only runs on core 0)
  if us_CoreSelect = TASK_SELECT_CORE0 then
    if s_DiasMaster.p_Functions <> NIL & s_DiasMaster.p_Functions^.ud_DiasTime then
      CurrGGT := CalculateGGT(Var1:=CurrGGT, Var2:=s_DiasMaster.p_Functions^.ud_DiasTime);
    end_if;
  end_if;

  //Core 0: set to maintimer if no one wants a time
  if ( us_CoreSelect = TASK_SELECT_CORE0 ) & ( CurrGGT = 0 ) then
    CurrGGT := _Clockticks;
  end_if;  
  
  //Check if maintimer is fast enough
  if ( CurrGGT <> 0 ) & ( CurrGGT < _ClockTicks ) then
    HWC_LogValue2(this,"@0179 (HwControl::CalculateTaskInfo) Calc RtTaskTime: Maintimersetting is too slow. Needed maintimer: 0x{0} µs, Actual Maintimer: 0x{1} µs", CurrGGT,_ClockTicks);
    HwControl::State := _InvalidConfguration;
    return;
  end_if;

  //Save realtime task time
  pTaskInfo^.ud_MyRtTaskTime_us := CurrGGT;  
  
  //Calculate for Cyclic
  //**************************************************************************************************************
  CurrGGT := 0; //Start with 0
  
  //Go through all varanmanagers
  pOneManager := #a_VaranManager[0]; 
  for i := 0 to ( MAX_VARAN_MANAGERS - 1 ) do

    //Check if manager is available, set for right core and has set a time
    if ( pOneManager^.p_Functions         <> NIL 
       & pOneManager^.p_Functions^.p_This <> NIL 
       & pOneManager^.ud_CyTime_us        <> 0
       & pOneManager^.us_CoreSelect        = us_CoreSelect
       ) 
    then
      CurrGGT := CalculateGGT(Var1:=CurrGGT, Var2:=pOneManager^.ud_CyTime_us);
    end_if;
    
    pOneManager += sizeof(t_OneVaranManager);
  end_for;                    
  
  pHelp := pHwControlLogins;
  
  //Go through all HwObjects
  while pHelp <> NIL do
    if pHelp^.ud_CyTime_us & pHelp^.us_CoreSelect = us_CoreSelect then
      CurrGGT := CalculateGGT(Var1:=CurrGGT, Var2:=pHelp^.ud_CyTime_us);
    end_if;
    pHelp := pHelp^.pNext;
  end_while;

  pFirstCall := pCallFirstObjects;
  
  //Go through all first call objects
  while pFirstCall <> NIL do
    if pFirstCall^.ud_CyTime_us & pFirstCall^.us_CoreSelect = us_CoreSelect then
      CurrGGT := CalculateGGT(Var1:=CurrGGT, Var2:=pFirstCall^.ud_CyTime_us);
    end_if;
    pFirstCall := pFirstCall^.pNext;
  end_while;
  
  //Core 0: set to maintimer if no one wants a time
  if ( us_CoreSelect = TASK_SELECT_CORE0 ) & ( CurrGGT = 0 ) then
    CurrGGT := _Clockticks;
  end_if;
  
  //Check if maintimer is fast enough
  if ( CurrGGT <> 0 ) & ( CurrGGT < _ClockTicks ) then
    HWC_LogValue2(this,"@017A (HwControl::CalculateTaskInfo) Calc CyTaskTime: Maintimersetting is too slow. Needed maintimer: 0x{0} µs, Actual Maintimer: 0x{1} µs", CurrGGT,_ClockTicks);
    HwControl::State := _InvalidConfguration;
    return;
  end_if;  
  
  //Save realtime task time
  pTaskInfo^.ud_MyCyTaskTime_us := CurrGGT;      

END_FUNCTION


FUNCTION HwControl::CalculateGGT
  VAR_INPUT
    Var1 	: UDINT;
    Var2 	: UDINT;
  END_VAR
  VAR_OUTPUT
    ggT 	: UDINT;
  END_VAR

  if Var2 = 0 then
    ggT := Var1;
  else
    ggT := CalculateGGT(Var1:=Var2, Var2:=Var1 MOD Var2);
  end_if;

END_FUNCTION


FUNCTION HwControl::Get_ITASK_Version
  VAR_OUTPUT
    version 	: UDINT;
  END_VAR
  
  // Anm.: Beim Salamander darf das udVersion Element aus der LSL_ITASK Struktur 
  // (Makro OS_ITASK_VERSION) erst ab 09.03.080 interpretiert werden, weil sonst 
  // keine Versionsnummer dahintersteckt, sondern ein Funktionszeiger auf eine Dummy-Funktion.
  // Die Versionen im Salamander, bei denen udVersion gültig ist:
  //  9.3 er Versionen:   ab 09.03.080
  //  9.2 er Versionen:   ab 09.02.049
  
  IF _RtOSVersion < 16#9000 | _RtOSVersion >= 16#9350 THEN
    version := OS_ITASK_VERSION;
  ELSIF _RtOSVersion < 16#9300 & _RtOSVersion >= 16#9231 THEN
    version := OS_ITASK_VERSION;
  ELSE
    version := 0;
  END_IF;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL HwControl::UpdateRtPostScan
VAR
  us_CoreSelect : USINT;
END_VAR

  us_CoreSelect := TASK_SELECT_CORE0;
  RtPostScan_CoreX(pCoreSelect:=#us_CoreSelect);

END_FUNCTION


FUNCTION VIRTUAL GLOBAL HwControl::CyWork
  VAR_INPUT
    EAX 	: UDINT;
  END_VAR
  VAR_OUTPUT
    state (EAX) 	: UDINT;
  END_VAR
  VAR
    us_CoreSelect : USINT;
  END_VAR

  us_CoreSelect := TASK_SELECT_CORE0;
  CyWork_CoreX(pCoreSelect:=#us_CoreSelect);
  
  state := READY;

END_FUNCTION


FUNCTION GLOBAL __cdecl HWC_ops_cpuequipment_get
VAR_OUTPUT 
  retcode : UDINT;
END_VAR
VAR
  ptr : ^UDINT;
END_VAR
  // we take the offset from _RealMaximumTime because an define for the right address would make troubles
  ptr := #_RealMaximumTime;
  ptr += 16#F44;
  retcode := ptr^;
END_FUNCTION

FUNCTION GLOBAL __cdecl HWC_ops_platform_get
VAR_OUTPUT
  retcode : UDINT;
END_VAR
  retcode := HWC_ops_cpuequipment_get() AND HWCONTROL_OPS_PLATFORMMASK;
END_FUNCTION

FUNCTION GLOBAL __cdecl HWC_ops_is_linux
VAR_OUTPUT
  retcode : UDINT;
END_VAR
  retcode := (HWC_ops_cpuequipment_get() AND (HWCONTROL_OPS_OS_LINUX OR HWCONTROL_OPS_EQUIPMENT_VALID)) = (HWCONTROL_OPS_OS_LINUX OR HWCONTROL_OPS_EQUIPMENT_VALID);
END_FUNCTION

FUNCTION GLOBAL __cdecl HWC_ops_is_salamander
VAR_OUTPUT
  retcode : UDINT;
END_VAR
  // wenn es ein Linux ist und platform = LSL_LASALOS dann ist es auch ein Salamander 
  // bei platform = LSL_SALAMANDER ist es Salamander
  if HWC_ops_is_linux() &
    (HWC_ops_platform_get() = HWCONTROL_OPS_LASALOS |
     HWC_ops_platform_get() = HWCONTROL_OPS_SALAMANDER) then
    retcode := 1;
  else
    retcode := 0;
  end_if;
END_FUNCTION

FUNCTION GLOBAL __cdecl HWC_ops_is_gecko
VAR_OUTPUT
  retcode :UDINT;
END_VAR
  if HWC_ops_is_linux() &
    (HWC_ops_platform_get() = HWCONTROL_OPS_GECKO) then
    retcode := 1;
  else
    retcode := 0;
  end_if;
END_FUNCTION

FUNCTION GLOBAL __cdecl HWC_IsPostInitFinished
VAR_OUTPUT
  retcode : BOOL;
END_VAR

  retcode := bPostInitFinished;

END_FUNCTION

