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

//{{LSL_DEFINES

#define BUSIF_INTERNAL_MAX_NR_DO 100

// Defines for Mutex Generation
#define INTERNAL_STR_MUTEX_NAME_SEPERATOR ".."
#define INTERNAL_MUTEX_NAME_END_LENGTH 5
#define INTERNAL_MUTEX_NAME_MAX_LENGTH 32
//}}LSL_DEFINES

//{{LSL_DECLARATION
#include "..\..\Source\BusInterface.h"
#include "..\..\Source\interfaces\lsl_st_mt.h"
#include "..\..\Class\HwControl\HwControl.h"
#include "..\..\Source\interfaces\lsl_st_hardwaretree.h"

(*!
<Class
	Name               = "BusInterfaceSDIASInternal"
	Revision           = "2.1"
	GUID               = "{0F88252F-E206-4746-9EE2-190EB96646AE}"
	RealtimeTask       = "false"
	CyclicTask         = "false"
	BackgroundTask     = "false"
	Sigmatek           = "true"
	OSInterface        = "false"
	HighPriority       = "false"
	Automatic          = "false"
	UpdateMode         = "Prescan"
	IconPath           = ".\Class\Tool.ico"
	SharedCommandTable = "true"
	Objectsize         = "(484,120)"
	Comment            = "This class provides internal access over an BUS independent interface. &#13;&#10;s. &quot;BusInterface.h&quot; for interface definition. &#13;&#10;The class methods are access via the CallCommand channel.">
	<Channels>
		<Server Name="CallCommand" GUID="{1D4B549F-9FAF-4951-A3A9-982F228F50D2}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Command Channel to access the functionality of this class. All methods are access via the NewInst() method of this Server."/>
		<Server Name="InterfaceState" GUID="{926E79D6-E7D9-476D-A7C4-F7257FDA7396}" Visualized="false" Initialize="false" WriteProtected="true" Retentive="false" Comment="0..OK&#13;&#10;-1..SDIAS Interface not available or too old =&gt; newer OS version needed!"/>
		<Client Name="CoreSelect" Required="false" Internal="false" Comment="The desired CPU core on which the realtime/cyclic task of the manager runs can be selected here.&#13;&#10;0 ... SDIAS manager realtime/cyclic runs on CPU core 0.&#13;&#10;1 ... SDIAS manager realtime/cyclic runs on CPU core 1. (Only if supported by CPU)"/>
		<Client Name="CycleTime" Required="true" Internal="false" Comment="Bus cycle time in µs (max. 32000)"/>
		<Client Name="IsoStartPoint" Required="true" Internal="false" DefValue="50" Comment="% of CycleTime[1..99]&#13;&#10;Defines the offset between start of realtime-task and start of isochronous SDIAS read task (write task starts directly after postscan)&#13;&#10;The value should be set as high as possible to get the most actual values in next realtime"/>
		<Client Name="ToHwControl" Required="true" Internal="false"/>
		<Client Name="ToOSKernel" Required="false" Internal="false"/>
		<Client Name="ToStdLib" Required="false" Internal="false"/>
	</Channels>
	<Dependencies>
		<Files>
			<File Path=".\Source\BusInterface.h" Include="true"/>
			<File Path=".\Source\interfaces\lsl_st_mt.h" Include="true"/>
			<File Path=".\Class\HwControl\HwControl.h" Include="true"/>
			<File Path=".\Source\interfaces\lsl_st_hardwaretree.h" Include="true"/>
		</Files>
	</Dependencies>
	<RevDoku>
		<Owner Company="Sigmatek" Author="RamAnd"/>
		<Dokumentation Revision="2.1" Date="25.11.2020" Author="EisMic" Company="Sigmatek" Description="The newinst commando CMD_HWC_REQ_PLLNS_REGULATION is now be forwared to the HwControl.&#13;&#10;Added comment of client CoreSelect."/>
		<Dokumentation Revision="2.0" Date="26.03.2018" Author="EisMic" Company="Sigmatek" Description="Added support to select the CPU-core on which the realtime and the cyclic task of the class should be executed."/>
		<Dokumentation Revision="1.30" 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="1.29" Date="23.01.2018" Author="RamAnd" Company="Sigmatek" Description="Log messages have been standardized for easier maintenance, easier use in any class and to allow spam filtering. Code for the logging functions is now only located in HwControl."/>
		<Dokumentation Revision="1.28" Date="14.02.2017" Author="ZoePat" Company="Sigmatek" Description="SdiasModules can now request to increase the PostInit timeout."/>
		<Dokumentation Revision="1.27" Date="15.04.2015" Author="RamAnd" Company="Sigmatek" Description="Added another step in initialisation to prevent watchdog error."/>
		<Dokumentation Revision="1.26" Date="30.09.2014" Author="RamAnd" Company="Sigmatek" Description="Removed IsTransparent-Call, since an internal SDIAS cannot be transparent and the call could cause a compiler error."/>
		<Dokumentation Revision="1.25" Date="04.07.2014" Author="EisMic" Company="Sigmatek" Description="Added support for reading hardware diagnosis and hardwaretree entry."/>
		<Dokumentation Revision="1.24" Date="04.06.2014" Author="RamAnd" Company="Sigmatek" Description="The CreateMutex-Command now also returns the pointer to the multitask API. This saves CIL_Get calls (boot time) in other classes."/>
		<Dokumentation Revision="1.23" Date="15.04.2014" Author="RamAnd" Company="Sigmatek" Description="Added new Interface Varan_HwSubBusReady which is called by OS as soon as it has finished enumerating the connected devices on available subbusses."/>
		<Dokumentation Revision="1.22" Date="10.04.2014" Author="RamAnd" Company="Sigmatek" Description="Error trace messages are now also stored in the event log file."/>
		<Dokumentation Revision="1.21" Date="28.02.2014" Author="RamAnd" Company="Sigmatek" Description="Corrected memory initialisation to support SDIAS PC. Changed limits of IsoStartPoint from 10-90% to 1-99%."/>
		<Dokumentation Revision="1.20" Date="12.02.2014" Author="RamAnd" Company="Sigmatek" Description="Added interface to get task info before the payload to detect task errors more accurately."/>
		<Dokumentation Revision="1.10" Date="22.01.2014" Author="RamAnd&#13;&#10;RamAnd" Company="Sigmatek" Description="Added command to get required setting.&#13;&#10;Added support for SDIAS PC."/>
		<Dokumentation Revision="1.0" Date="18.07.2013" Author="RamAnd" Company="Sigmatek" Description="First library version"/>
	</RevDoku>
	<Network Name="BusInterfaceSDIASInternal">
		<!-- List of Components in this network -->
		<Components>
		</Components>
		<Comments>
		</Comments>
		<!-- List of Connections in this network -->
		<Connections>
		</Connections>
		<!-- Headerfiles -->
		<Options>
		</Options>
	</Network>
</Class>
*)
BusInterfaceSDIASInternal : CLASS
	TYPE
#pragma pack(push, 1)
	  t_CALLBACK_POINTERS : STRUCT
	    p_Callback : pVirtualBase;
	    p_UpdateCy : pVirtualBase;
	    p_UpdateRt : pVirtualBase;
	    p_UpDateRtPostScan : pVirtualBase;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_TASK_PRESCALER : STRUCT
	    Cnt : UDINT;
	    MaxCnt : UDINT;
	    RtPreScanTigger : UDINT;
	    RtPostScanTrigger : UDINT;
	  END_STRUCT;
#pragma pack(pop)
	END_TYPE
  //Servers:
	InterfaceState 	: SvrChCmd_DINT;
	CallCommand 	: SvrChCmd_DINT;
  //Clients:
	ToHwControl 	: CltChCmd_HwControl;
	CycleTime 	: CltCh_UDINT;
	IsoStartPoint 	: CltCh_UDINT;
	ToOSKernel 	: CltChCmd__OSKernel;
	ToStdLib 	: CltChCmd__StdLib;
	CoreSelect 	: CltCh_UDINT;
  //Variables:
		us_Firstscan 	: USINT;
		pUserCalls 	: t_CALLBACK_POINTERS;
		sTaskPrescaler 	: t_TASK_PRESCALER;
		mt_api 	: ^LSL_MT_TYPE;
		aObjectPath : ARRAY [0..5] OF USINT;

		pObjectPath 	: ^USINT;
		b_DoPostInit 	: BOOL;
		b_GotNodeHandle 	: BOOL;
		ud_NodeHandle 	: UDINT;
		pSdias 	: ^LSL_SDIAS;
		pSdiasBackup 	: ^LSL_SDIAS;
		pInputImage 	: pVoid;
		pOutputImage 	: pVoid;
		b_CopyRtDataActive 	: BOOL;
		ud_BusTime 	: UDINT;
		ud_IsoStartPoint 	: UDINT;
		sd_SyncOffset 	: DINT;
		ud_HwControlRtTime_us 	: UDINT;
		ud_HwControlCyTime_us 	: UDINT;
		ud_MainTimer 	: UDINT;
		ud_SyncMultiplier 	: UDINT;
		bd_CallbackSettings 	: t_HwObjListSettings;
		b_HwControlTimeChecked 	: DINT;
		ud_LocalRdMemSize 	: UDINT;
		pLocalRdMem 	: ^void;
		ud_LocalWrMemSize 	: UDINT;
		pLocalWrMem 	: ^void;
		b_CopyLocalActive 	: BOOL;
		b_IsRequired 	: BOOL;
		b_Wait4RtSyncReady 	: BOOL;
  //Functions:
				//! <Function Comment="Init for Varan Client" Name="Init"/>
	FUNCTION VIRTUAL GLOBAL Init;
	
	FUNCTION BusInterfaceSDIASInternal
		VAR_OUTPUT
			ret_code 	: ConfStates;
		END_VAR;
	
	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 GLOBAL AddDO
		VAR_INPUT
			pCmd 	: ^CmdStruct;
			presult 	: ^results;
		END_VAR;
	
	FUNCTION GLOBAL AddTask
		VAR_INPUT
			pCmd 	: ^CmdStruct;
			presult 	: ^results;
		END_VAR;
				//! <Function Comment="Sets the pointer to the operator class.&#13;&#10;This pointer must be set in the init phase. &#13;&#10;The passed pointer is used to call functions in the operator class via NewInst.&#13;&#10;Examples: HwConnect, CheckDeviceID ..." Name="SetOperatorClass"/>
	FUNCTION GLOBAL SetOperatorClass
		VAR_INPUT
			pOperator 	: pVirtualBase;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;			//! <Variable Comment="0 .. ok&#13;&#10;1 .. 0 pointer was passed" Name="SetOperatorClass.sd_retval"/>
		END_VAR;
	
	FUNCTION GLOBAL SetSyncData
		VAR_INPUT
			pCmd 	: ^CmdStruct;
			presult 	: ^results;
		END_VAR;
	
	FUNCTION VIRTUAL LogError
		VAR_INPUT
			e_msg 	: ^CHAR;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL CreateMutex
		VAR_INPUT
			MutexName 	: ^CHAR;
			pThis 	: ^VirtualBase := NIL;
		END_VAR
		VAR_OUTPUT
			pv_RetMutex 	: pVoid;
		END_VAR;
	
	FUNCTION GetPointer2ObjectPath
		VAR_OUTPUT
			p_us_ObjectPath 	: ^USINT;
		END_VAR;
	
	FUNCTION GetNodeHandle;
	
	FUNCTION HwControlLogin
		VAR_OUTPUT
			RetVal 	: t_BusIFRetvalErrorcode;
		END_VAR;
	
	FUNCTION GetBusTime;
	
	FUNCTION GetTaskInfo;
	
	FUNCTION VIRTUAL GLOBAL InterfaceState::NewInst
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL CallCommand::NewInst
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
  //Tables:
	FUNCTION @STD
		VAR_OUTPUT
			ret_code	: CONFSTATES;
		END_VAR;
	FUNCTION GLOBAL TAB @CT_;
END_CLASS;

#pragma usingLtd _OSKernel
#pragma usingLtd _StdLib
#pragma usingLtd HwControl


//}}LSL_DECLARATION


FUNCTION GLOBAL TAB BusInterfaceSDIASInternal::@CT_
0$UINT,
2#0100000000000000$UINT, //TY_BUSINTERFACESDIASINTERNAL
2$UINT, 1$UINT, (SIZEOF(::BusInterfaceSDIASInternal))$UINT, 
2$UINT, 6$UINT, 0$UINT, 
TO_UDINT(3882880897), "BusInterfaceSDIASInternal", //Class
TO_UDINT(0), 0, 0$UINT, 0$UINT, //Baseclass
//Servers:
(::BusInterfaceSDIASInternal.InterfaceState.pMeth)$UINT, _CH_CMD$UINT, 2#0000000000000000$UINT, TO_UDINT(2895168853), "InterfaceState", 
(::BusInterfaceSDIASInternal.CallCommand.pMeth)$UINT, _CH_CMD$UINT, 2#0000000000000000$UINT, TO_UDINT(1059212957), "CallCommand", 
//Clients:
(::BusInterfaceSDIASInternal.ToHwControl.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000010$UINT, TO_UDINT(3104445832), "ToHwControl", TO_UDINT(2471641665), "HwControl", 5$UINT, 24$UINT, 
(::BusInterfaceSDIASInternal.CycleTime.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000010$UINT, TO_UDINT(2924485542), "CycleTime", 
(::BusInterfaceSDIASInternal.IsoStartPoint.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000010$UINT, TO_UDINT(102048672), "IsoStartPoint", 
(::BusInterfaceSDIASInternal.ToOSKernel.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000000$UINT, TO_UDINT(2889244023), "ToOSKernel", TO_UDINT(3045737964), "_OSKernel", 0$UINT, 5$UINT, 
(::BusInterfaceSDIASInternal.ToStdLib.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000000$UINT, TO_UDINT(2501598121), "ToStdLib", TO_UDINT(3689364044), "_StdLib", 2$UINT, 0$UINT, 
(::BusInterfaceSDIASInternal.CoreSelect.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(2631154307), "CoreSelect", 
END_FUNCTION


#define USER_CNT_BusInterfaceSDIASInternal 2

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

FUNCTION BusInterfaceSDIASInternal::@STD
	VAR_OUTPUT
		ret_code	: CONFSTATES;
	END_VAR
	VAR
		vmt	: _LSL_STD_VMETH;
	END_VAR

	//Command Methods
	InitCmdTable (nCmd := nSTDCMD + USER_CNT_BusInterfaceSDIASInternal, pCmd := #vmt.CmdTable);
	vmt.CmdTable.NewInstr		:= #NewInst();
	vmt.CmdTable.Init		:= #Init();
	vmt.CmdTable.CyWork		:= #CyWork();
	vmt.CmdTable.RtWork		:= #RtWork();
#pragma warning (disable : 74)
	vmt.UserFcts[0]		:= #LogError();

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

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

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

	IF CallCommand.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	ret_code	:= BusInterfaceSDIASInternal();

END_FUNCTION

//{{LSL_IMPLEMENTATION

FUNCTION VIRTUAL GLOBAL BusInterfaceSDIASInternal::Init
  VAR
  	tempCmd    : CmdStruct;
    _result    : results;
  END_VAR

  us_Firstscan += 1;

  	//in first init phase
	if ( us_Firstscan = 1 ) then  

		//-----------------------------------------------------------------------------------------------
    if b_GotNodeHandle = FALSE then
      GetNodeHandle();
      b_GotNodeHandle := TRUE;
    end_if;
    
    GetBusTime();

  // In 4th init phase
  elsif (us_Firstscan = 4) then    
    // Check for 0 pointer
    if pUserCalls.p_Callback then
      // Call the corresponding function in the operator class
      tempCmd.uiCmd := _BUS_IF_HWCONNECT;  
      pUserCalls.p_Callback^.pSvrChCmd.NewInst(#tempCmd,#_result);
      
      if _result.aData[0] then
        return;
      end_if;
    end_if;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL BusInterfaceSDIASInternal::CallCommand::NewInst
	VAR_INPUT
		pPara 	: ^CmdStruct;
		pResult 	: ^results;
	END_VAR
	VAR_OUTPUT
		ret_code 	: iprStates;
	END_VAR
  VAR    
//  	pRDWRDOCfg        : ^t_RDWRDOCfg;
  	pSETRUNSTATECfg   : ^t_SetRunStateCfg;
    pBusIFAddCallback : ^t_BusIFAddCallback;
    pTemp : ^void;
//    sd_retval : DINT;
  END_VAR

  ret_code := READY;

  if b_GotNodeHandle = FALSE then
    GetNodeHandle();
    b_GotNodeHandle := TRUE;
  end_if;

  CASE pPara^.uiCmd OF
//**********************************************************************************************************************************************************
    _BUS_IF_ADD_CALLBACK :         // Set Callbackpointer
      pResult^.uiLng    := 4;
      pBusIFAddCallback := (pPara^.aPara[0])$^t_BusIFAddCallback;
      
      if (SetOperatorClass(pBusIFAddCallback^.pthis)) then
        pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_ERROR_INVALID_POINTER;
        ret_code := ERROR;
      else
        pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;
      end_if;
          
//**********************************************************************************************************************************************************
    _BUS_IF_ADD_DO :               // Add Data Object
      AddDO(pPara, pResult);
      if presult^.aData$t_AddDORet.retcode <> _BUS_IF_RETVAL_OK then
        ret_code := ERROR;
      end_if;
          
//**********************************************************************************************************************************************************
    _BUS_IF_ADD_TASK :             // Add Varan Task
      AddTask(pPara, pResult); 

//**********************************************************************************************************************************************************
    _BUS_IF_SET_RUN_STATE :       // Set the run State 
      pSETRUNSTATECfg := ((pPara^.aPara[0])$^t_SetRunStateCfg);
      
      if pSETRUNSTATECfg^.NewRunState = _BUS_IF_RUN_STATE_NO_RUN then
        b_CopyRtDataActive := FALSE;
        
      // check pointer here, then we don't need to check it in Rt
      elsif pSdias then
        b_CopyRtDataActive := TRUE;
      end_if;
      pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;

//**********************************************************************************************************************************************************
    _BUS_IF_GET_BUSCYCLE_TIME :   // Get BusCycle time and Iso Startpoint 
      GetBusTime();

      pResult^.aData[0]$t_GetBusCycleTime.retcode         := _BUS_IF_RETVAL_OK;
      pResult^.aData[0]$t_GetBusCycleTime.udBusCycleTime  := ud_BusTime;
      pResult^.aData[0]$t_GetBusCycleTime.udIsoStartPoint := ud_IsoStartPoint;
      pResult^.aData[0]$t_GetBusCycleTime.udMainTimer     := ud_MainTimer;

//**********************************************************************************************************************************************************
    _BUS_IF_SET_DO_PRESCALER :    // Set DO Prescaler 
//      OS_MT_WAIT(pv_Mutex);
//      SetDOPrescaler(pPara, pResult);
//      OS_MT_SIGNAL(pv_Mutex);
          
//**********************************************************************************************************************************************************
    _BUS_IF_SET_TASKS_PRESCALER : // Set Task Prescaler 
//      SetTasksPrescaler(pPara, pResult);
        
//**********************************************************************************************************************************************************
    _BUS_IF_SET_SYNC :            // Set the sync data 
      SetSyncData(pPara, pResult);

//**********************************************************************************************************************************************************
    _BUS_IF_WAIT_4_POST_INIT:
      b_DoPostInit := TRUE;

      b_Wait4RtSyncReady := (pPara^.aPara[0]$USINT SHR 2) AND 1;

      bd_CallbackSettings.PostInit := TRUE;
      pResult^.aData[0]$t_BusIFRetvalErrorcode := HwControlLogin();
        
//**********************************************************************************************************************************************************
    _BUS_IF_POST_INIT_FINISHED:
      b_DoPostInit := FALSE;
      pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;

//**********************************************************************************************************************************************************
    _BUS_IF_RT_SYNC_READY:
      b_Wait4RtSyncReady := FALSE;
      pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;

//**********************************************************************************************************************************************************
    _BUS_IF_GET_HW_PATH:
      pTemp := GetPointer2ObjectPath();
      if pTemp then
        pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;
        pResult^.aData[4]$^void := pTemp;
      else
        pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_ERROR_INVALID_POINTER;
        pResult^.aData[4]$^void := NIL;
      end_if;

//**********************************************************************************************************************************************************
    _BUS_IF_SET_REQUIRED:
      b_IsRequired := TRUE;
    
      // only return that it worked
      pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;
    
//**********************************************************************************************************************************************************
    _BUS_IF_SET_REQUIRED_ERROR:
      pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;

      ToHwControl.SetHardwareOff(e_error:=_RequiredError);

      // restore pointer to raise SDIAS Error
      if pSdias = NIL then
        pSdias := pSdiasBackup;
      end_if;

      // if a required module is not available or doesn't work properly, the system should crash
      SDIAS_iReportEvent(uiEvent:=SDM_EVENT_ERROR_REQUIRED_MODULE, pucEvntMsg:="A required module is not available!");

//**********************************************************************************************************************************************************
    _BUS_IF_SET_ERROR:
      pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;

      ToHwControl.SetHardwareOff(e_error:=pPara^.aPara[0]$t_e_VaranErrors);

      // restore pointer to raise SDIAS Error
      if pSdias = NIL then
        pSdias := pSdiasBackup;
      end_if;

      // if there is a pointer to a string, use it as message to display in CLI
      if pPara^.aPara[1] then
        SDIAS_iReportEvent(uiEvent:=SDM_EVENT_ERROR_REQUIRED_MODULE, pucEvntMsg:=pPara^.aPara[1]$^CHAR);
      else
        SDIAS_iReportEvent(uiEvent:=SDM_EVENT_ERROR_REQUIRED_MODULE, pucEvntMsg:="");
      end_if;

//**********************************************************************************************************************************************************
    _BUS_IF_CREATE_MUTEX:
      pTemp := CreateMutex(pPara^.aPara[0]$^CHAR, pPara^.aPara[1]$pVirtualBase);
      if pTemp then
        pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;
        pResult^.aData[4]$^void := pTemp;
        pResult^.aData[8]$^LSL_MT_TYPE := mt_api;
      else
        pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_ERROR_CREATE_MUTEX_FAILED;
        pResult^.aData[4]$^USINT := NIL;        
        pResult^.aData[8]$^LSL_MT_TYPE := NIL;
      end_if;
    
//**********************************************************************************************************************************************************
    _BUS_IF_GET_DEACTIVATED_STATE:
      pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;
      pResult^.aData[4]$BOOL := pSdias = NIL; // if we have no interface => it's deactivated
      
//**********************************************************************************************************************************************************
    _BUS_IF_GET_INTERFACE_TYPE:
      pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;
      pResult^.aData[4]$t_BusIFType := _BUS_IF_TYPE_LOCAL;
      
//**********************************************************************************************************************************************************          
    _BUS_IF_IS_VARAN_AVAILABLE:
      pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;
      pResult^.aData[4]$BOOL := FALSE;      
      
//**********************************************************************************************************************************************************
    _BUS_IF_GET_NODE_HANDLE:
      if ud_NodeHandle = _BUS_IF_INVALID_DO_HANDLE then
        pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_ERROR_INVALID_HANDLE;
        pResult^.aData[4]$UDINT := ud_NodeHandle;        
      else
        pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;
        pResult^.aData[4]$UDINT := ud_NodeHandle;
      end_if;
      
//**********************************************************************************************************************************************************          
    _BUS_IF_GET_REQUIRED_SETTING:
      pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;
      pResult^.aData[4] := b_IsRequired;

//**********************************************************************************************************************************************************          
    _BUS_IF_TRIGGER_ISO_TASK:
      // copy output data from local memory
      if b_CopyLocalActive then
        _memcpy(ptr1:=pOutputImage, ptr2:=pLocalWrMem, cntr:=ud_LocalWrMemSize);
      else
        SDIAS_iSetOutputImage(ud_NodeHandle, SDIAS_DOL_TYPE_ISO);
      end_if;
      pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;

//**********************************************************************************************************************************************************          
    _BUS_IF_GET_BUS_READY_AVAILABLE:
      pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;
      
      // not available on local SDIAS
      pResult^.aData[4] := FALSE;

//**********************************************************************************************************************************************************
    CMD_EXTEND_POST_INIT_TIME:

      // forward to HwControl
      ret_code := ToHwControl.NewInst(pPara, pResult);
    
//**********************************************************************************************************************************************************
    CMD_GET_HW_TIMESTAMP:
    
      // forward to HwControl
      if pPara^.aPara[0]$t_GetHwTimestampCmd.udVersion = 1 then
        // Insert Coreselect if CmdVersion = 1 and increase CmdVersion to 2
        pPara^.aPara[0]$t_GetHwTimestampCmd.udVersion     := 2;
        pPara^.aPara[0]$t_GetHwTimestampCmd.udCoreSelect  := CoreSelect;
      end_if;
      
      ret_code := ToHwControl.NewInst(pPara, pResult);
      
//**********************************************************************************************************************************************************
    CMD_HWC_REQ_PLLNS_REGULATION:
    
      // forward to HwControl
      ret_code := ToHwControl.NewInst(pPara, pResult);
      
//**********************************************************************************************************************************************************
  ELSE
    // unknown command
    pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_ERROR_NOT_SUPPORTED;
    pResult^.uiLng := 0;
    ret_code := ERROR;
  END_CASE;

END_FUNCTION


FUNCTION GLOBAL BusInterfaceSDIASInternal::SetOperatorClass
	VAR_INPUT
		pOperator 	: pVirtualBase;
	END_VAR
	VAR_OUTPUT
		sd_retval 	: DINT;
	END_VAR
  
  sd_retval := 1;
      
  if pOperator then
    sd_retval := 0;
    pUserCalls.p_Callback := pOperator;    
  end_if;

END_FUNCTION


FUNCTION GLOBAL BusInterfaceSDIASInternal::AddDO
	VAR_INPUT
		pCmd 	: ^CmdStruct;
		presult 	: ^results;
	END_VAR
  VAR
  	pADDDOCfg     : ^t_AddDOCfg;
    _ud_dol_type   : UDINT;
    sd_retval     : DINT;
    RamType       : UDINT;
  END_VAR

  presult^.uiLng    := 20;
  
  if pSdias then            
    
    pADDDOCfg := ((pCmd^.aPara[0])$^t_AddDOCfg);  
    
    // Convert passed t_Priority to VARAN ud_dol_type
    if (pADDDOCfg^.Priority)$t_BusIFPriority  = _BUS_IF_ISO
    |  (pADDDOCfg^.Priority)$t_BusIFPriority  = _BUS_IF_ISO_MOVE then
      _ud_dol_type := SDIAS_DOL_TYPE_ISO;
    else    
      // invalid DOL Type
      pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_ERROR_INVALID_DATA;
      LogError("@017E (BusInterfaceSDIASInternal::AddDO) Invalid value for DOL Type given");
      return;
    end_if;

    // if we don't have both pointers => get them    
    if (pInputImage = NIL) | (pOutputImage = NIL) then
      sd_retval := SDIAS_iGetDataPointers(hNodeHandle   :=ud_NodeHandle
                                        , udDolType     :=_ud_dol_type
                                        , ppvSendData   :=#pOutputImage
                                        , ppvReceiveData:=#pInputImage
                                        );

    else
      // we already have the pointers
      sd_retval := 0;
    end_if;

    b_CopyLocalActive := FALSE;
    if sd_retval = 0 then
      // if it's a new CIL Version (where the RAM Type Property is available)
      if pSdias^.udVersion >= SDIAS_CIL_VERSION_SUPPORTS_RAM_TYPE then

        // check if it's an internal or external memory (we have to copy the data to/from external memory, at the internal the OS does it for us)
        if SDIAS_iGetNodeProperty(hNodeHandle      :=ud_NodeHandle
                                , udPropertyId     :=SDM_PROP_RAM_RAMTYPE
                                , pudPropertyValue :=#RamType
                                ) = SDIAS_OK then

          // if it's internal => OS copies the data and the pointers are meant as local memory
          if RamType = SDIAS_RAMTYPE_INTERN then
            pResult^.aData$t_AddDORet.pDataRead := pInputImage;
            pResult^.aData$t_AddDORet.pDataWrite:= pOutputImage;
          else
            // on external, we have to copy the data and the pointers are meant to external periphery (via PCI, PCIe,...)
            if pADDDOCfg^.ui_length_read then
              ud_LocalRdMemSize := pADDDOCfg^.ui_length_read;
              pLocalRdMem := ToStdLib.Malloc(size:=ud_LocalRdMemSize);
              if pLocalRdMem then
                _memset(dest:=pLocalRdMem, usByte:=0, cntr:=ud_LocalRdMemSize);
                pResult^.aData$t_AddDORet.pDataRead := pLocalRdMem;              
              else
                LogError("@017F (BusInterfaceSDIASInternal::AddDO) Failed to allocate memory for the local input image");
                pResult^.aData$t_AddDORet.retcode := _BUS_IF_RETVAL_ERROR_INVALID_POINTER;                
              end_if;
            end_if;

            if pADDDOCfg^.ui_length_write then
              ud_LocalWrMemSize := pADDDOCfg^.ui_length_write;
              pLocalWrMem := ToStdLib.Malloc(size:=ud_LocalWrMemSize);
              if pLocalWrMem then
                _memset(dest:=pLocalWrMem, usByte:=0, cntr:=ud_LocalWrMemSize);
                pResult^.aData$t_AddDORet.pDataWrite:= pLocalWrMem;                        
              else
                LogError("@0180 (BusInterfaceSDIASInternal::AddDO) Failed to allocate memory for the local output image");
                pResult^.aData$t_AddDORet.retcode := _BUS_IF_RETVAL_ERROR_INVALID_POINTER;
              end_if;
            end_if;

            if pLocalRdMem & pLocalWrMem then
              b_CopyLocalActive := TRUE;
            end_if;            
          end_if;
          
          // Return Values
          presult^.aData$t_AddDORet.retcode   := _BUS_IF_RETVAL_OK;
          pResult^.aData$t_AddDORet.sd_retval := sd_retval;
          pResult^.aData$t_AddDORet.Handle    := 0;
        else
          LogError("@0181 (BusInterfaceSDIASInternal::AddDO) Failed to get the RAM-Type via OS Interface");
          pResult^.aData$t_AddDORet.retcode := _BUS_IF_RETVAL_ERROR_NOT_SUPPORTED;
        end_if;
      else
        // Return Values
        presult^.aData$t_AddDORet.retcode   := _BUS_IF_RETVAL_OK;
        pResult^.aData$t_AddDORet.sd_retval := sd_retval;
        pResult^.aData$t_AddDORet.Handle    := 0;
        pResult^.aData$t_AddDORet.pDataRead := pInputImage;
        pResult^.aData$t_AddDORet.pDataWrite:= pOutputImage;
      end_if;
    else              
      LogError("@0182 (BusInterfaceSDIASInternal::AddDO) Failed to get the pointers to the input and output images");
      pResult^.aData$t_AddDORet.retcode := _BUS_IF_RETVAL_ERROR_CREATE_DO_FAILED;
    end_if;           
  else            
    pResult^.aData$t_AddDORet.retcode := _BUS_IF_RETVAL_ERROR_NOT_SUPPORTED;
  end_if;

END_FUNCTION


FUNCTION GLOBAL BusInterfaceSDIASInternal::AddTask
	VAR_INPUT
		pCmd 	: ^CmdStruct;
		presult 	: ^results;
	END_VAR
  VAR
  	pTASKCfg    : ^t_TaskCfg;
  END_VAR

  presult^.uiLng    := 4;
  
  pTASKCfg := ((pCmd^.aPara[0])$^t_TaskCfg);
  
  // Check for null pointer
  if pTASKCfg^.pthis then   

    // Save the passed callback pointer according to the callOptions
    if pTASKCfg^.callOptions = CALL_OPTION_RT_PRESCAN then
      pUserCalls.p_UpdateRt := (pTASKCfg^.pthis)$pVirtualBase;
      bd_CallbackSettings.RtPreScan := TRUE;
    elsif pTASKCfg^.callOptions = CALL_OPTION_RT_POSTSCAN then
      pUserCalls.p_UpDateRtPostScan := (pTASKCfg^.pthis)$pVirtualBase;    
      bd_CallbackSettings.RtPostScan := TRUE;
    elsif pTASKCfg^.callOptions = (CALL_OPTION_RT_PRESCAN or CALL_OPTION_RT_POSTSCAN) then
      pUserCalls.p_UpdateRt := (pTASKCfg^.pthis)$pVirtualBase;
      bd_CallbackSettings.RtPreScan := TRUE;
      pUserCalls.p_UpDateRtPostScan := (pTASKCfg^.pthis)$pVirtualBase;    
      bd_CallbackSettings.RtPostScan := TRUE;
    else
      pUserCalls.p_UpdateCy := (pTASKCfg^.pthis)$pVirtualBase;
      bd_CallbackSettings.Cyclic := TRUE;
    end_if;
    
    HwControlLogin();

    pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;
  else
    pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_ERROR_INVALID_POINTER;
  end_if;
  
END_FUNCTION

  
FUNCTION GLOBAL BusInterfaceSDIASInternal::SetSyncData
	VAR_INPUT
		pCmd 	: ^CmdStruct;
		presult 	: ^results;
	END_VAR
  VAR  	
    pSYNCDATACfg  :  ^t_SyncData;
    ud_ControlStatus : UDINT;
  END_VAR
  
  if pSdias then
    presult^.uiLng  := 4;
    
    pSYNCDATACfg := ((pCmd^.aPara[0])$^t_SyncData);
    
    // get sync offset
    GetBusTime();
    
    if ud_HwControlRtTime_us = 0 then
      // get rt time of HwControl
      HwControlLogin();
    end_if;
    
    // check timer settings
    if CycleTime MOD ud_MainTimer then
      LogError("@0183 (BusInterfaceSDIASInternal::SetSyncData) CycleTime of SDIAS Manager has to be a multiple of the maintimer setting!");
      pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_ERROR_BUSCYCLE_TIME_NOT_AVAILABLE;
      ToHwControl.SetHardwareOff(e_error:=_PllError);
      return;
    end_if;
    
    if ud_HwControlRtTime_us MOD ud_MainTimer then
      LogError("@0184 (BusInterfaceSDIASInternal::SetSyncData) HwControl realtime setting has to be a multiple of the maintimer setting!");
      pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_ERROR_NOT_SUPPORTED;
      ToHwControl.SetHardwareOff(e_error:=_PllError);
      return;
    end_if;   

    // calculate multiplier for PLL
    ud_SyncMultiplier := CycleTime / ud_MainTimer;
    
    // bit0 = enable sync, bit 1 = enable frame count (will enable the sync automatically when passing the threshold), bit 2 = use system sync (0 = use divided sync)
    pSYNCDATACfg^.us_enable_frame_count := pSYNCDATACfg^.us_enable_frame_count <> 0;
    ud_ControlStatus := 2#101 OR (pSYNCDATACfg^.us_enable_frame_count SHL 1);

    // check if the multiplier is in USINT range (register in FPGA is only 1 Byte)
    if ud_SyncMultiplier <= 16#FF then
      if SDIAS_iConfigurePllSyncOut(hNodeHandle          := ud_NodeHandle, 
                                    udSyncOutId          := pSYNCDATACfg^.us_sync_nr, 
                                    udOffset10ns         := sd_SyncOffset$UDINT,
                                    udPeriodMultiplier   := ud_SyncMultiplier,
                                    udFrameCountThreshold:= pSYNCDATACfg^.us_frame_count_threshold, 
                                    udControlStatus      := ud_ControlStatus
                                    ) = SDIAS_OK then
        
        pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;
      else
        pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_ERROR_INVALID_SYNC;
        LogError("@0185 (BusInterfaceSDIASInternal::SetSyncData) Failed so set sync configuration via OS interface");
      end_if;
    else
      pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_ERROR_NOT_SUPPORTED;
      LogError("@0186 (BusInterfaceSDIASInternal::SetSyncData) Invalid constellation of MainTimer and cycle time of SDIAS! CycleTime/MainTimer has to be smaller than 256!");
    end_if;
  else
    pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_ERROR_NOT_SUPPORTED;
  end_if;
  
END_FUNCTION


FUNCTION BusInterfaceSDIASInternal::BusInterfaceSDIASInternal
	VAR_OUTPUT
		ret_code 	: ConfStates;
	END_VAR

#ifdef HWC_LogInit
  HWC_LogInit();
#endif

  //get pointer for sdias function
	OS_CILGET( INTERFACE_SDIAS, #pSDIAS );

  // if the version doesn't support local SDIAS => we can't use it
  if pSdias & (pSdias^.udVersion < SDIAS_CIL_VERSION_SUPPORTS_LOCAL) then
    pSdias := NIL;
  end_if;
  
  // save the pointer in case we need it to raise an SDIAS Error
  pSdiasBackup := pSdias;
  
  if pSdias = NIL then
    LogError("@0187 (BusInterfaceSDIASInternal::BusInterfaceSDIASInternal) Failed to get SDIAS OS-Interface. A newer OS is necessary to use SDIAS");   
    InterfaceState := -1;
  end_if;

	ret_code := C_OK;

END_FUNCTION

#pragma warning(disable: 73);
FUNCTION VIRTUAL BusInterfaceSDIASInternal::LogError
	VAR_INPUT
		e_msg 	: ^CHAR;
	END_VAR

#ifdef HWC_LogError
  HWC_LogError(this, e_msg);
#endif

END_FUNCTION
#pragma warning(default: 73);

FUNCTION VIRTUAL GLOBAL BusInterfaceSDIASInternal::CreateMutex
	VAR_INPUT
		MutexName 	: ^CHAR;
		pThis 	: ^VirtualBase;
	END_VAR
	VAR_OUTPUT
		pv_RetMutex 	: pVoid;
	END_VAR
  VAR
    str_ObjName : array[0..255] of char;
    str_ObjNamePart1 : array[0..INTERNAL_MUTEX_NAME_MAX_LENGTH-1] of char;
    str_ObjNamePart2 : array[0..INTERNAL_MUTEX_NAME_END_LENGTH] of char; // +1 for 0 Termination
    str_CombinedName : array[0..INTERNAL_MUTEX_NAME_MAX_LENGTH-1] of char; 
    str_this : array[0..11] of char; // 2 byty %m, 8 byte Address, 1 byte for 0 Termination
  	
    ud_LenObjName  : UDINT;    
    ud_LenStr  : UDINT;    
    ud_SepLenStr : UDINT;
    ud_LenCombObjName : UDINT;  
    ud_LenThis : UDINT;

  END_VAR
  
  pv_RetMutex := Nil; // Error OS_CILGetv failed
  
  if pThis = nil then
    pthis := this;
  end_if;  
  
  if (mt_api = nil) then
    if(OS_CILGet("LSL_MULTITASK", #mt_api$void)) THEN
      mt_api := NIL;
    end_if;
  end_if;
  
  if mt_api then
  
    _memset(dest:=#str_ObjName[0], usByte:=0, cntr:=sizeof(str_ObjName) );
    _memset(dest:=#str_ObjNamePart1[0], usByte:=0, cntr:=sizeof(str_ObjNamePart1) );
    _memset(dest:=#str_ObjNamePart2[0], usByte:=0, cntr:=sizeof(str_ObjNamePart2) );
    _memset(dest:=#str_CombinedName[0], usByte:=0, cntr:=sizeof(str_CombinedName) );
    _memset(dest:=#str_this[0], usByte:=0, cntr:=sizeof(str_this) );
    
  
    ud_LenStr := _strlen(MutexName);    

    ud_SepLenStr := _strlen(INTERNAL_STR_MUTEX_NAME_SEPERATOR);
    ud_LenObjName := _GetObjName(pThis:=pthis, pName:=#str_ObjName[0]);
  
    if (ud_LenStr < INTERNAL_MUTEX_NAME_MAX_LENGTH) then
      _strcpy(dest:=#str_CombinedName[0], src:=MutexName);
    else
      _strncpy(dest:=#str_CombinedName[0], src:=MutexName, max:=INTERNAL_MUTEX_NAME_MAX_LENGTH-1);
    end_if;
    
    if (ud_LenObjName + ud_LenStr) < INTERNAL_MUTEX_NAME_MAX_LENGTH then      
      _strcat(dest:=#str_CombinedName[0], src:=#str_ObjName[0]); 
    else
      _strncpy(dest:=#str_ObjNamePart1[0], src:= #str_ObjName[0], max:= INTERNAL_MUTEX_NAME_MAX_LENGTH - ud_LenStr - ud_SepLenStr - INTERNAL_MUTEX_NAME_END_LENGTH - 1);    // Copy Beginning of str_ObjName
      _strncpy(dest:=#str_ObjNamePart2[0], src:= #str_ObjName[ud_LenObjName-INTERNAL_MUTEX_NAME_END_LENGTH-1], max:=INTERNAL_MUTEX_NAME_END_LENGTH);  // Copy Last MUTEX_NAME_END_LENGTH Char of str_ObjName
      
      // Put the Mutex String together
      _strcat(dest:=#str_CombinedName[0], src:= #str_ObjNamePart1[0]);
      _strcat(dest:=#str_CombinedName[0], src:= INTERNAL_STR_MUTEX_NAME_SEPERATOR);
      _strcat(dest:=#str_CombinedName[0], src:= #str_ObjNamePart2[0]);      
    end_if;

    pv_RetMutex := OS_MT_CreateSemaphore(MTSEMATYPE_MUTEX, 1, 0, #str_CombinedName[0]);   
    
    if pv_RetMutex = nil then
    
      // If Create Mutex failed: Insert the this pointer into the string
      ud_LenCombObjName := _strlen(#str_CombinedName[0]);
      
      str_this[0] := '0';
      str_this[1] := 'x';
      _itoa(udNumber:=pthis$UDINT, pString:=#str_this[2]);
      ud_LenThis  := _strlen(src:=#str_this[0]);
      
      _strcpy(dest:=#str_CombinedName[ud_LenCombObjName-ud_LenThis], src:=#str_this[0]);      
      
      pv_RetMutex := OS_MT_CreateSemaphore(MTSEMATYPE_MUTEX, 1, 0, #str_CombinedName[0]); 
    
    end_if;

  end_if;    
  
END_FUNCTION


FUNCTION BusInterfaceSDIASInternal::GetPointer2ObjectPath
	VAR_OUTPUT
		p_us_ObjectPath 	: ^USINT;
	END_VAR

  if pObjectPath = NIL then
    // create object path for the PLC
    aObjectPath[0] := 1;
    aObjectPath[1] := 0;
  
    pObjectPath := #aObjectPath[0];
  end_if;

  p_us_ObjectPath := pObjectPath;

END_FUNCTION


FUNCTION BusInterfaceSDIASInternal::GetNodeHandle

  if pSdias then
    if SDIAS_iGetNodeHandle(udManagerNumber:=0, pszHardwarePath:=GetPointer2ObjectPath(), phNodeHandle:=#ud_NodeHandle) <> SDIAS_OK then
      ud_NodeHandle := _BUS_IF_INVALID_DO_HANDLE;
    end_if;
  else
    ud_NodeHandle := _BUS_IF_INVALID_DO_HANDLE;
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL BusInterfaceSDIASInternal::CyWork
	VAR_INPUT
		EAX 	: UDINT;
	END_VAR
	VAR_OUTPUT
		state (EAX) 	: UDINT;
	END_VAR

  // Call CyWork of operator
  pUserCalls.p_UpdateCy^.CyWork(EAX:=0);

	state := READY;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL BusInterfaceSDIASInternal::RtWork
	VAR_INPUT
		EAX 	: UDINT;
	END_VAR
	VAR_OUTPUT
		state (EAX) 	: UDINT;
	END_VAR

  if EAX = CALL_OPTION_RT_PRESCAN then
    // pre scan

    // Call RtWork of calling class
    
    // No Prescaler
    if sTaskPrescaler.MaxCnt = 0 then
      if b_CopyRtDataActive then
        GetTaskInfo();
        // copy input data to local memory
        if b_CopyLocalActive then
          _memcpy(ptr1:=pLocalRdMem, ptr2:=pInputImage, cntr:=ud_LocalRdMemSize);
        else
          SDIAS_iGetInputImage(ud_NodeHandle, SDIAS_DOL_TYPE_ISO);  
        end_if;
      end_if;
    
      pUserCalls.p_UpdateRt^.RtWork(EAX:=CALL_OPTION_RT_PRESCAN);
    else  
      if sTaskPrescaler.Cnt = sTaskPrescaler.RtPreScanTigger then
        if b_CopyRtDataActive then        
          GetTaskInfo();
          // copy input data to local memory
          if b_CopyLocalActive then
            _memcpy(ptr1:=pLocalRdMem, ptr2:=pInputImage, cntr:=ud_LocalRdMemSize);
          else
            SDIAS_iGetInputImage(ud_NodeHandle, SDIAS_DOL_TYPE_ISO);
          end_if;
        end_if;

        pUserCalls.p_UpdateRt^.RtWork(EAX:=CALL_OPTION_RT_PRESCAN);
      end_if;      
      
      if pUserCalls.p_UpDateRtPostScan = NIL then  // only increment if there is no RtPostScan, otherwise we increment there
        sTaskPrescaler.Cnt += 1;
        if sTaskPrescaler.Cnt > sTaskPrescaler.MaxCnt then
          sTaskPrescaler.Cnt := 0;
        end_if;
      end_if;
    end_if;
  
  else
    // post scan


    // Call RtWork of calling class
    
    if sTaskPrescaler.MaxCnt = 0 then
      pUserCalls.p_UpDateRtPostScan^.RtWork(EAX:=CALL_OPTION_RT_POSTSCAN);

      if b_CopyRtDataActive then      
        // copy output data from local memory
        if b_CopyLocalActive then
          _memcpy(ptr1:=pOutputImage, ptr2:=pLocalWrMem, cntr:=ud_LocalWrMemSize);
        else
          SDIAS_iSetOutputImage(ud_NodeHandle, SDIAS_DOL_TYPE_ISO);
        end_if;
      end_if;
    else
      if sTaskPrescaler.Cnt = sTaskPrescaler.RtPostScanTrigger then
        pUserCalls.p_UpDateRtPostScan^.RtWork(EAX:=CALL_OPTION_RT_POSTSCAN);

        if b_CopyRtDataActive then        
          // copy output data from local memory
          if b_CopyLocalActive then
            _memcpy(ptr1:=pOutputImage, ptr2:=pLocalWrMem, cntr:=ud_LocalWrMemSize);
          else
            SDIAS_iSetOutputImage(ud_NodeHandle, SDIAS_DOL_TYPE_ISO);
          end_if;
        end_if;
      end_if;  
      
      sTaskPrescaler.Cnt += 1;
      if sTaskPrescaler.Cnt > sTaskPrescaler.MaxCnt then
        sTaskPrescaler.Cnt := 0;
      end_if;
    end_if;
  end_if;

	state := READY;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL BusInterfaceSDIASInternal::InterfaceState::NewInst
	VAR_INPUT
		pPara 	: ^CmdStruct;
		pResult 	: ^Results;
	END_VAR
	VAR_OUTPUT
		ret_code 	: IprStates;
	END_VAR
  VAR
  	tempCmd    : CmdStruct;
    _result    : results;
  END_VAR

	ret_code := READY;

  CASE pPara^.uiCmd OF
//**********************************************************************************************************************************************************
    CMD_POST_INIT_CALL:
      // if we're not ready, call the sdias manager and set the state to busy
      if bd_CallbackSettings.Cyclic then
        pUserCalls.p_UpdateCy^.CyWork(EAX:=0);
        if b_DoPostInit then
          ret_code := BUSY;
        end_if;
      end_if;

//**********************************************************************************************************************************************************
    CMD_POST_INIT_RT_READY:
      // check if operator is ready
      tempCmd.uiCmd := _BUS_IF_POST_INIT_RT_READY;  
      ret_code := pUserCalls.p_Callback^.pSvrChCmd.NewInst(#tempCmd, #_result);

//**********************************************************************************************************************************************************
    CMD_POST_INIT_RT_SYNC:
      // check if all modules are ready
      if bd_CallbackSettings.Cyclic then
        if b_Wait4RtSyncReady then
          pUserCalls.p_UpdateCy^.CyWork(EAX:=0);
          ret_code := BUSY;
        end_if;
      end_if;
      
//**********************************************************************************************************************************************************
    CMD_POST_INIT_DISTRIBUTE_TASKTIMES:
        
        if pPara^.aPara[0]$t_Distribute_TaskTimes_Cmd.udVersion = 1 then
          
          ud_HwControlRtTime_us := pPara^.aPara[0]$t_Distribute_TaskTimes_Cmd.udRtTaskTime_us;
          ud_HwControlCyTime_us := pPara^.aPara[0]$t_Distribute_TaskTimes_Cmd.udCyTaskTime_us;
          
          if CycleTime MOD ud_HwControlRtTime_us then
            LogError("@0183 (BusInterfaceSDIASInternal::InterfaceState::NewInst) CycleTime of SDIAS Manager has to be a multiple of the HwControl realtime setting!");
            ret_code := ERROR;
          elsif CycleTime > ud_HwControlRtTime_us then
            // use internal prescaler
            sTaskPrescaler.MaxCnt            := (CycleTime / ud_HwControlRtTime_us) - 1;
            sTaskPrescaler.RtPreScanTigger   := (CycleTime / ud_HwControlRtTime_us) - 1;
            sTaskPrescaler.RtPostScanTrigger := (CycleTime / ud_HwControlRtTime_us) - 1;
            ret_code := READY;
          else
            // hwcontrol time and cycletime are equal

            //No Internal prescaler
            sTaskPrescaler.MaxCnt            := 0;
            sTaskPrescaler.RtPreScanTigger   := 0;
            sTaskPrescaler.RtPostScanTrigger := 0;
            ret_code := READY;
        end_if;
        else
          //Not supported version
          LogError("@0188 (BusInterfaceSDIASInternal::InterfaceState::NewInst) Version of CMD_POST_INIT_DISTRIBUTE_TASKTIMES not supported. Bus is running in HwControl time!");
          ret_code := ERROR;
      end_if;

//**********************************************************************************************************************************************************
    CMD_GET_HARDWARE_DIAGNOSIS:
      // check if operator is ready
      ret_code := pUserCalls.p_Callback^.pSvrChCmd.NewInst(pPara, pResult);
//**********************************************************************************************************************************************************
    CMD_GET_HARDWARE_TREE_ENTRY:
      // check if operator is ready
      ret_code := pUserCalls.p_Callback^.pSvrChCmd.NewInst(pPara, pResult);
//**********************************************************************************************************************************************************
  END_CASE;
  
END_FUNCTION

FUNCTION BusInterfaceSDIASInternal::HwControlLogin
	VAR_OUTPUT
		RetVal 	: t_BusIFRetvalErrorcode;
	END_VAR
  VAR
  	tempCmd    : CmdStruct;
    _result    : results;
    bCheckTaskTimes : BOOL;
  END_VAR

  if pSdias then
  
    if CoreSelect > 0 then
      bd_CallbackSettings.CoreSelect := TRUE;
    end_if;
    
    //Default: We have to check the tasktimes we get from HwControl
    bCheckTaskTimes := TRUE;
    
    tempCmd.uiCmd := CMD_GET_SUPPORTED_FEATURES;
    if ToHwControl.NewInst(#tempCmd, #_result) = READY then
      if _result.aData$t_HWC_SupportedFeatureBits1.CalculateTaskInfo = TRUE then
        //Feature is supported from HwControl.
        bCheckTaskTimes := FALSE;  //At the beginning of the postinit phase we get a newInst Call with the task times, so we don't have to check the times here
        bd_CallbackSettings.TimeSet := TRUE;
      end_if;      
    end_if;
  
    tempCmd.uiCmd := CMD_HWCONTROL_LOGIN;
    tempCmd.aPara[0] := THIS$DINT;
    tempCmd.aPara[1] := bd_CallbackSettings$DINT;    
    tempCmd.aPara[2] := HWT_ESCAPE_SDIAS;  // Escape sequence
    tempCmd.aPara[3] := CoreSelect$DINT;     // Core on which the RT and Cywork should be called from the HwControl
    tempCmd.aPara[4] := (CycleTime)$DINT;    // Rt-Time
    tempCmd.aPara[5] := (CycleTime)$DINT;    // Cy-Time
    
    if ToHwControl.NewInst(#tempCmd, #_result) = READY then
      
      //Only check once and if we have to check the times now
      if b_HwControlTimeChecked = FALSE & bCheckTaskTimes = TRUE then
        b_HwControlTimeChecked := TRUE;
        if _result.uiLng = (sizeof(ud_HwControlCyTime_us) + sizeof(ud_HwControlRtTime_us)) then
          ud_HwControlRtTime_us := _result.aData[0]$UDINT / 1000;
          ud_HwControlCyTime_us := _result.aData[4]$UDINT / 1000;
          
          if CycleTime MOD ud_HwControlRtTime_us then
            LogError("@0183 (BusInterfaceSDIASInternal::HwControlLogin) CycleTime of SDIAS Manager has to be a multiple of the HwControl realtime setting!");
            pSdias := NIL;
            RetVal := _BUS_IF_RETVAL_ERROR_BUSCYCLE_TIME_NOT_AVAILABLE;
          elsif CycleTime > ud_HwControlRtTime_us then
            // use internal prescaler
            sTaskPrescaler.MaxCnt            := 
            sTaskPrescaler.RtPreScanTigger   := 
            sTaskPrescaler.RtPostScanTrigger := (CycleTime / ud_HwControlRtTime_us) - 1;
            
            RetVal := _BUS_IF_RETVAL_OK;
          else
            // hwcontrol time and cycletime are equal
            RetVal := _BUS_IF_RETVAL_OK;
          end_if;
        else      
          LogError("@0189 (BusInterfaceSDIASInternal::HwControlLogin) Response of login at HwControl has an invalid size");
          pSdias := NIL;
          RetVal := _BUS_IF_RETVAL_ERROR_NOT_SUPPORTED;
        end_if;
      else
        RetVal := _BUS_IF_RETVAL_OK;
      end_if;
    else
      LogError("@018A (BusInterfaceSDIASInternal::HwControlLogin) Failed to install callback at HwControl");
      pSdias := NIL;
      RetVal := _BUS_IF_RETVAL_ERROR_NOT_SUPPORTED;
    end_if;
  end_if;

END_FUNCTION


FUNCTION BusInterfaceSDIASInternal::GetBusTime
  
  if ud_BusTime = 0 then
  
    CycleTime := CycleTime.Read();
    IsoStartPoint := IsoStartPoint.Read();

    //--- Calculate SyncOffset and get bus time
    ud_BusTime := CycleTime * 1000;
    
    if (IsoStartPoint < 1) | (IsoStartPoint > 99) then
      IsoStartPoint := 50;
    end_if;
    
    ud_IsoStartPoint := ud_BusTime * IsoStartPoint / 100;
    sd_SyncOffset := ud_IsoStartPoint$DINT / 10;
    
    ud_MainTimer := _ClockTicks;
  end_if;

END_FUNCTION


FUNCTION BusInterfaceSDIASInternal::GetTaskInfo
  VAR
  	tempCmd    : CmdStruct;
    _result    : results;
  END_VAR

  // Call the corresponding function in the operator class
  tempCmd.uiCmd := _BUS_IF_GET_TASK_INFO;  
  pUserCalls.p_Callback^.pSvrChCmd.NewInst(#tempCmd,#_result);

END_FUNCTION
