//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 MDD2000MNG_MAXENTRIES   3        // maximale Anzahl an Achsen
#DEFINE MDD2000MNG_MAXAXISNO    3        // maximale Anzahl an Achsen pro Steckplatz 

// Asy Commands to drive scope
#define MDD2000MNG_DRIVESCOPE_S_CH     246
#define MDD2000MNG_DRIVESCOPE_S_TRIGL  247
#define MDD2000MNG_DRIVESCOPE_S_TRIGB  248
#define MDD2000MNG_DRIVESCOPE_S_INDEX  249
#define MDD2000MNG_DRIVESCOPE_S_WORK   250
#define MDD2000MNG_DRIVESCOPE_S_GET1   251
#define MDD2000MNG_DRIVESCOPE_S_GET2   252
#define MDD2000MNG_DRIVESCOPE_S_GET3   253
#define MDD2000MNG_DRIVESCOPE_S_STAT   254

#define MDD2000MNG_DEFAULT_CPU_LOGFILENAME_PATH           "C:\sysmsg\DriveLog"
#define MDD2000MNG_DEFAULT_CPU_DEBUGLOGFILENAME_PATH      "C:\sysmsg\DriveDebugLog"
#define MDD2000MNG_DEFAULT_CPU_LOGFILENAME_EXTENSION      ".txt"

#define MDD2000MNG_DEFAULT_DRIVE_LOGFILENAME_PATH         "C:\"
#define MDD2000MNG_DEFAULT_DRIVE_LOGFILENAME_NAME         "DriveLog.txt"
#define MDD2000MNG_DEFAULT_DRIVE_DEBUGLOGFILENAME_NAME    "DriveDebugLog.txt"

#define MDD2000MNG_FILE_HANDLING_RETCODE_NOERROR                    0
#define MDD2000MNG_FILE_HANDLING_RETCODE_FILEHANDLING_BUSY         -2   // = DRIVEVVBASE_VANDAL_FILEHANDLING_ERROR_BUSY -2
#define MDD2000MNG_FILE_HANDLING_RETCODE_CMDVERSION_NOTSUPPORTED  -92
#define MDD2000MNG_FILE_HANDLING_RETCODE_WRITEPARA_FAILED         -93
#define MDD2000MNG_FILE_HANDLING_RETCODE_WRITEPARA_TIMEOUT        -94
#define MDD2000MNG_FILE_HANDLING_RETCODE_READBACKPARA_FAILED      -95
#define MDD2000MNG_FILE_HANDLING_RETCODE_READBACKPARA_TIMEOUT     -96
#define MDD2000MNG_FILE_HANDLING_RETCODE_AXIS_ENABLED             -97
#define MDD2000MNG_FILE_HANDLING_RETCODE_NOT_ONLINE               -98
#define MDD2000MNG_FILE_HANDLING_RETCODE_NOT_SUPPORTED            -99

#define MDD2000MNG_FILE_HANDLING_TIMEOUT_LOG_PARAM          10000

#define MDD2000MNG_FILESELECT_LOGFILE       0
#define MDD2000MNG_FILESELECT_DEBUGLOGFILE  1

#define MDD2000MNG_FILE_RESERVE_IDFREE         0
#define MDD2000MNG_FILE_RESERVE_IDDEFAULT     10
#define MDD2000MNG_FILE_RESERVE_IDGETLOGFILE  20

#define MDD2000MNG_DELAYSETSERVICEMODE_TIMEOUT 10000
//}}LSL_DEFINES

//{{LSL_DECLARATION
#include "..\..\class\_drivemngbase\drivemngbase.h"
#include "..\..\Class\MDD2000MngBase\MDD2000ComL2.h"
#include "..\..\Class\HwControl\HwControl.h"
#include "..\..\Source\interfaces\lsl_st_hardwaretree.h"
#include "..\..\Class\MDD2000MngBase\MDD2000MngBase.h"
#include "..\..\Source\DriveSafetyIF.h"

(*!
<Class
	Name               = "MDD2000MngBase"
	Revision           = "1.2"
	GUID               = "{DBEE540D-90A6-4E7A-9666-1FDD5BF8B21D}"
	RealtimeTask       = "false"
	CyclicTask         = "true"
	DefCyclictime      = "10 ms"
	BackgroundTask     = "false"
	Sigmatek           = "true"
	OSInterface        = "false"
	HighPriority       = "false"
	Automatic          = "false"
	UpdateMode         = "Prescan"
	IconPath           = ".\Class\MDD2000_Mng\MDD2000SafetyDrive.ico"
	SharedCommandTable = "true"
	Objectsize         = "(474,120)"
	Comment            = "this class does the connection between the BusIFVVMDD2000 and the _MDD2000Axis">
	<Channels>
		<Server Name="AxisAvailable" GUID="{70FDC0AF-E8A9-4077-9217-7A3C0321C3D5}" Visualized="true" Initialize="false" WriteProtected="false" Retentive="false" Comment="Displays number of axis available on hardware."/>
		<Server Name="ClassState" GUID="{83AFD5A3-D06E-46A4-8BB6-3098FD97DD74}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="This server shows the current status of the hardware class. For more information see: Varan hardware class status."/>
		<Server Name="CmdState" GUID="{CE866518-B9FA-4BAC-99AB-A9B387537211}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Displays the State of the Class"/>
		<Server Name="DeviceAddress" GUID="{CA02851A-B61F-4688-B2C4-9C383A615C19}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="device address of hardware module"/>
		<Server Name="DeviceID" GUID="{C1EE077A-4EC8-44B4-8A7D-83010A412EA7}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Server shows the DeviceID of the Hardware Module."/>
		<Server Name="DriveType" GUID="{634477E1-4A3C-4410-8070-EC53D72A3287}" Visualized="true" Initialize="false" WriteProtected="false" Retentive="false" Comment="Displays which hardware we have connected"/>
		<Server Name="FwVersionDrive" GUID="{2DCA6E6C-C693-42A1-8487-244870B9187E}" Class="String" Visualized="true" Initialize="true" WriteProtected="false" Retentive="false" Comment="Shows the firmware version of the drive as string."/>
		<Server Name="FwVersionSafety" GUID="{255A6622-0A22-4739-B954-09DE497EE003}" Class="String" Visualized="true" Initialize="true" WriteProtected="false" Retentive="false" Comment="Shows the firmware version of the safety controllers."/>
		<Server Name="HWVersion" GUID="{F12A7970-1E95-478C-8546-BC5F5F08D7F6}" Class="String" Visualized="true" Initialize="true" WriteProtected="false" Retentive="false" Comment="Display Hardware Version (Parameter I-HW from Drive)."/>
		<Server Name="Online" GUID="{86D65796-C6CE-46B7-B5F4-1EFD21DA6B87}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="This server is set as soon as the hardware class is processed properly (when the data are valid, drives synchronized,..) &#13;&#10;The server is reset when an error occurs or when disconnected."/>
		<Server Name="Release" GUID="{42066945-5B18-4B4C-B273-0B4125E63FE0}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="FPGA - Version"/>
		<Server Name="RetryCounter" GUID="{E07A2894-8269-4403-871B-15D44CC95966}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="retry counter of the varan module"/>
		<Server Name="SafetyNumber" GUID="{C1461C9C-FF86-4229-8855-4B398798FD37}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Shows the unique safety number of the drive."/>
		<Server Name="SafetyRunState" GUID="{7792DB38-C7A5-443B-9A4B-1D8FCFB793B0}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Shows the current safety runstate. &#13;&#10;More Information to the different states can be found in the class documentation."/>
		<Server Name="SerialNo" GUID="{5B8EEBF5-8D72-4D5F-A5A6-7538DBD63338}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Displays Drive Serial number"/>
		<Server Name="StrDriveType" GUID="{30D46C6D-5A84-4070-8C6A-134D123CBF89}" Class="String" Visualized="true" Initialize="true" WriteProtected="false" Retentive="false" Comment="Shows the drive type as string"/>
		<Server Name="VendorID" GUID="{84976718-3B81-4228-998C-7E1E549820B4}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="This server contains the vendor ID of the hardware modul."/>
		<Client Name="cOnline" Required="true" Internal="false" Comment="Reads if the initialisation was done correctly and if we can start the communication with the drive"/>
		<Client Name="coStdLib" Required="false" Internal="false" Comment="Object channel to _StdLib.&#13;&#10;Is automatically connected."/>
		<Client Name="DriveTypeStr" Required="true" Internal="true"/>
		<Client Name="FwNumString" Required="true" Internal="true"/>
		<Client Name="FwSafeNumString" Required="true" Internal="true"/>
		<Client Name="HWNumString" Required="true" Internal="true"/>
		<Client Name="To_TaskObjectControl" Required="false" Internal="false" Comment="Object channel to _TaskObjectControl.&#13;&#10;Is automatically connected."/>
		<Client Name="ToBusIF" Required="false" Internal="false" Comment="Command channel to businterface class."/>
		<Client Name="toSafetyRunState" Required="false" Internal="false"/>
	</Channels>
	<Separators>
		<Servers>
			<SepChn Position="14"/>
		</Servers>
	</Separators>
	<Dependencies>
		<Files>
			<File Path=".\class\_drivemngbase\drivemngbase.h" Include="true"/>
			<File Path=".\Class\MDD2000MngBase\MDD2000ComL2.h" Include="true"/>
			<File Path=".\Class\HwControl\HwControl.h" Include="true"/>
			<File Path=".\Source\interfaces\lsl_st_hardwaretree.h" Include="true"/>
			<File Path=".\Class\MDD2000MngBase\MDD2000MngBase.h" Include="true"/>
			<File Path=".\Source\DriveSafetyIF.h" Include="true"/>
		</Files>
	</Dependencies>
	<RevDoku>
		<Owner Company="Sigmatek" Author="LanSte"/>
		<Dokumentation Revision="1.2" Date="16.12.2024" Author="LanSte" Company="Sigmatek" Description="Fixed function of commands _ MDD2000INIT and _ MDD2000URINIT"/>
		<Dokumentation Revision="1.1" Date="13.06.2024" Author="ZoePat" Company="Sigmatek" Description="Increased the array &quot;G_SDD_HW_DATA&quot; for the DriveIntegration to 255. Same as the limit in the DriveIntegration itself. Ensure all classes with this array are updated, to avoid different definitions for the same array."/>
		<Dokumentation Revision="1.0" Date="28.08.2023" Author="LanSte" Company="Sigmatek" Description="First library version."/>
	</RevDoku>
	<Network Name="MDD2000MngBase">
		<!-- List of Components in this network -->
		<Components>
			<Object
				Name       = "DriveTypeStr"
				GUID       = "{D26E4708-9025-458D-8F61-9DCA9FD8D56C}"
				Class      = "String"
				Position   = "(180,600)"
				Visualized = "true"
				Remotely   = "true">
				<Channels>
					<Server Name="Data"/>
					<Client Name="SingleRealloc" Value="1"/>
				</Channels>
			</Object>
			<Object
				Name       = "FwNumString"
				GUID       = "{547A7780-0C86-40B7-AD15-E24BE457BE61}"
				Class      = "String"
				Position   = "(180,960)"
				Visualized = "true"
				Remotely   = "true">
				<Channels>
					<Server Name="Data"/>
					<Client Name="SingleRealloc" Value="1"/>
				</Channels>
			</Object>
			<Object
				Name       = "FwSafeNumString"
				GUID       = "{F4E2D924-2685-4B44-8D9F-6233FDB44506}"
				Class      = "String"
				Position   = "(180,1140)"
				Visualized = "true"
				Remotely   = "true">
				<Channels>
					<Server Name="Data"/>
					<Client Name="SingleRealloc" Value="1"/>
				</Channels>
			</Object>
			<Object
				Name       = "HWNumString"
				GUID       = "{B25C0F01-CB4E-420B-8DBE-15D6726C142D}"
				Class      = "String"
				Position   = "(180,780)"
				Visualized = "true"
				Remotely   = "true">
				<Channels>
					<Server Name="Data"/>
					<Client Name="SingleRealloc" Value="1"/>
				</Channels>
			</Object>
		</Components>
		<Comments>
		</Comments>
		<!-- List of Connections in this network -->
		<Connections>
			<Connection Source="this.DriveTypeStr" Destination="DriveTypeStr.Data"/>
			<Connection Source="this.StrDriveType" Destination="DriveTypeStr.Data" Vertices="(668,750),(496,690),"/>
			<Connection Source="this.FwNumString" Destination="FwNumString.Data"/>
			<Connection Source="this.FwVersionDrive" Destination="FwNumString.Data" Vertices="(668,990),(496,1050),"/>
			<Connection Source="this.FwSafeNumString" Destination="FwSafeNumString.Data"/>
			<Connection Source="this.FwVersionSafety" Destination="FwSafeNumString.Data" Vertices="(668,1050),(496,1230),"/>
			<Connection Source="this.HWNumString" Destination="HWNumString.Data"/>
			<Connection Source="this.HWVersion" Destination="HWNumString.Data" Vertices="(668,930),(496,870),"/>
		</Connections>
		<!-- Headerfiles -->
		<Options>
		</Options>
	</Network>
</Class>
*)
MDD2000MngBase : CLASS
	TYPE
#pragma pack(push, 1)
	  _AXDEF : STRUCT
	    pThis : ^void;
	    AxisNo : DINT;
	    AxisOk : DINT;
	    AxisIndex : USINT;
	    pAsyPipeHandle : ^void;
	    sCurrentAsyncParaEntry : t_MDD2000Mng_AsyncPara_Entry;
	    bdStates : BDINT
	    [
	      1 InitFinished,
	      3 SafeVerifyDone,
	      4 SafeZeroPosDone,
	      6 ResetSafeZeroPos,
	      8 Wait4ResetSafeZeroPos,
	      9 Bit9,
	      10 Bit10,
	      11 Bit11,
	      12 Bit12,
	      13 Bit13,
	      14 Bit14,
	      15 Bit15,
	      16 Bit16,
	      17 Bit17,
	      18 Bit18,
	      19 Bit19,
	      20 Bit20,
	      21 Bit21,
	      22 Bit22,
	      23 Bit23,
	      24 Bit24,
	      25 Bit25,
	      26 Bit26,
	      27 Bit27,
	      28 Bit28,
	      29 Bit29,
	      30 Bit30,
	      31 Bit31,
	      32 Bit32,
	    ];
	    udActEntries : UDINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  _ParaRefreshBufEntry : STRUCT
	    AxisNo : USINT;
	    Reserved : USINT;
	    ParaNo : UINT;
	    NewValue : DINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  _ParaRefreshRingBufferType : STRUCT
	    pStart : ^_ParaRefreshBufEntry;
	    pEnd : ^_ParaRefreshBufEntry;
	    pRead : ^_ParaRefreshBufEntry;
	    pWrite : ^_ParaRefreshBufEntry;
	    ActEntries : DINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  _SDDL2BUFFER : STRUCT
	    AxisNo : USINT;
	    ParRW : USINT;
	    ParNo : USINT;
	    ParValue : DINT;
	    ParState : USINT;
	    ParError : SINT;
	    bActive : BOOL;
	  END_STRUCT;
#pragma pack(pop)
	  RequiredReferenceToHWCLogging : ^HwcLogging;
	  RequiredReferenceToSigClib : ^SigCLib;
	  t_e_GetLogFileSSW :
	  (
	    IdleGetLogFile,
	    StartGetLogFileSSW,
	    WriteLOGFileParam,
	    Wait4WrLOGFileResponse,
	    ReadLOGFileParam,
	    Wait4RdLOGFileResponse,
	    StartGetLogFile,
	    wait4GetLogFile,
	    ErrorGetLogFile
	  )$UDINT;
#pragma pack(push, 1)
	  s_LogFileVar : STRUCT
	    eGetLogFileSSW : t_e_GetLogFileSSW;
	    ErrorCodeLogFile : DINT;
	    dParaLogVal : DINT;
	    dParaLogValRd : DINT;
	    udParaLogTimeout : UDINT;
	    udTimeStampLogPara : UDINT;
	    bWait4LogFilePara : BOOL;
	    udFileSelectId : UDINT;
	    hParaLogIndex : HINT;
	    hsParaLogSubIndex : HSINT;
	    aDestinationLogFile : ARRAY [0..199] OF CHAR;
	  END_STRUCT;
#pragma pack(pop)
	  SDDParam :
	  (
	    SSW_SDD_I_HW,
	    SSW_SDD_I_SER,
	    SSW_SDD_I_FW,
	    SSW_SDD_I_BUILD
	  )$UDINT;
	  t_e_InitSSW :
	  (
	    _StartInit,
	    _Wait4AxisConfig,
	    _ReadDriveParaMeter,
	    _Wait4DriveParameter,
	    _ReadSafetyDriveParameter,
	    _Wait4ReadSafetyDriveParameter,
	    _EndInit,
	    _ErrorInit
	  )$UDINT;
	  t_e_MD2000Type :  //! <Type Public="true" Name="t_e_MD2000Type"/>
	  (
	    _NotFound:=0,
	    MDP210X_X_00:=18,
	    MDD210X_X_00:=19,
	    MDP220X_X_00:=20,
	    MDD220X_X_00:=21,
	    MDP212X_X_00:=26,
	    MDD212X_X_00:=27,
	    MDP222X_X_00:=28,
	    MDD222X_X_00:=29,
	    MDP210X_XX_00:=34,
	    MDD210X_XX_00:=35,
	    MDP220X_XX_00:=36,
	    MDD220X_XX_00:=37,
	    MDP230X_XX_00:=38,
	    MDD230X_XX_00:=39,
	    MDP212X_XX_00:=42,
	    MDD212X_XX_00:=43,
	    MDP222X_XX_00:=44,
	    MDD222X_XX_00:=45,
	    MDP232X_XX_00:=46,
	    MDD232X_XX_00:=47,
	    MDP210X_XXX_00:=50,
	    MDD210X_XXX_00:=51,
	    MDP220X_XXX_00:=52,
	    MDD220X_XXX_00:=53,
	    MDP212X_XXX_00:=58,
	    MDD212X_XXX_00:=59,
	    MDP222X_XXX_00:=60,
	    MDD222X_XXX_00:=61,
	    MDP210X_X_03:=82,
	    MDD210X_X_03:=83,
	    MDP220X_X_03:=84,
	    MDD220X_X_03:=85,
	    MDP212X_X_03:=90,
	    MDD212X_X_03:=91,
	    MDP222X_X_03:=92,
	    MDD222X_X_03:=93,
	    MDP210X_XX_03:=98,
	    MDD210X_XX_03:=99,
	    MDP220X_XX_03:=100,
	    MDD220X_XX_03:=101,
	    MDP220X_XX_02:=102,
	    MDD220X_XX_01:=103,
	    MDP212X_XX_03:=106,
	    MDD212X_XX_03:=107,
	    MDP222X_XX_03:=108,
	    MDD222X_XX_03:=109,
	    MDP222X_XX_02:=110,
	    MDD222X_XX_01:=111,
	    MDP210X_XXX_03:=114,
	    MDD210X_XXX_03:=115,
	    MDP220X_XXX_03:=116,
	    MDD220X_XXX_03:=117,
	    MDP212X_XXX_03:=122,
	    MDD212X_XXX_03:=123,
	    MDP222X_XXX_03:=124,
	    MDD222X_XXX_03:=125
	  )$UDINT;
	  t_e_MDD2000SafetyConfigState :  //! <Type Public="true" Name="t_e_MDD2000SafetyConfigState"/>
	  (
	    CFG_UNKNOWN:=0,  //! <Type Comment="unknown state (not initialized)" Name="t_e_MDD2000SafetyConfigState.CFG_UNKNOWN"/>
	    CFG_INVALID:=1,  //! <Type Comment="invalid configuration" Name="t_e_MDD2000SafetyConfigState.CFG_INVALID"/>
	    CFG_DELETED:=2,  //! <Type Comment="custom config was deleted by SCP, waiting for new config" Name="t_e_MDD2000SafetyConfigState.CFG_DELETED"/>
	    CFG_CUSTOM:=4,  //! <Type Comment="custom config from SCP" Name="t_e_MDD2000SafetyConfigState.CFG_CUSTOM"/>
	    CFG_DEFAULT:=128  //! <Type Comment="default configuration (used initially and after factory reset)" Name="t_e_MDD2000SafetyConfigState.CFG_DEFAULT"/>
	  )$UDINT;
	  t_e_MDD2000SafetyRunState :  //! <Type Public="true" Name="t_e_MDD2000SafetyRunState"/>
	  (
	    _POST:=0,
	    _CHK_CFG:=1,
	    _PREOP:=2,
	    _TEMP_OP:=3,
	    _OP:=4,
	    _SERVICE:=5,
	    _ERROR:=6,
	    _INACTIVE:=255,
	    _FSOE_COMSETUPFAILED:=1073741824  //! <Type Comment="Could not increase size of FSoE DOs. Reset of SPS is required" Name="t_e_MDD2000SafetyRunState._FSOE_COMSETUPFAILED"/>
	  )$UDINT;
	  t_e_MDD2000SafetySubRunState :  //! <Type Public="true" Name="t_e_MDD2000SafetySubRunState"/>
	  (
	    No_SubRunState:=0,  //! <Type Comment="RunState has no SubRunState" Name="t_e_MDD2000SafetySubRunState.No_SubRunState"/>
	    CHK_CFG_IDLE:=100,  //! <Type Comment="initial state" Name="t_e_MDD2000SafetySubRunState.CHK_CFG_IDLE"/>
	    CHK_CFG_CFG_DELETED:=101,  //! <Type Comment="custom config deleted" Name="t_e_MDD2000SafetySubRunState.CHK_CFG_CFG_DELETED"/>
	    CHK_CFG_PARSE_CFG:=102,  //! <Type Comment="parse selected safety configuration" Name="t_e_MDD2000SafetySubRunState.CHK_CFG_PARSE_CFG"/>
	    CHK_CFG_CHECK_PARSED_CFG:=103,  //! <Type Comment="check parsed safety configuration" Name="t_e_MDD2000SafetySubRunState.CHK_CFG_CHECK_PARSED_CFG"/>
	    CHK_CFG_SETUP_MODULES:=104,  //! <Type Comment="setup modules that require config" Name="t_e_MDD2000SafetySubRunState.CHK_CFG_SETUP_MODULES"/>
	    CHK_CFG_CHECK_HDSL:=105,  //! <Type Comment="check HDSL encoder" Name="t_e_MDD2000SafetySubRunState.CHK_CFG_CHECK_HDSL"/>
	    CHK_CFG_CHECK_ENC:=106,  //! <Type Comment="perform general encoder checks" Name="t_e_MDD2000SafetySubRunState.CHK_CFG_CHECK_ENC"/>
	    CHK_CFG_OK:=107,  //! <Type Comment="check is done successfully" Name="t_e_MDD2000SafetySubRunState.CHK_CFG_OK"/>
	    PRE_OP_IDLE:=200,  //! <Type Comment="initial state" Name="t_e_MDD2000SafetySubRunState.PRE_OP_IDLE"/>
	    PRE_OP_HWTEST:=201,  //! <Type Comment="execution of HW tests" Name="t_e_MDD2000SafetySubRunState.PRE_OP_HWTEST"/>
	    PRE_OP_DI_FILTER_SETTLING:=202,  //! <Type Comment="wait for digital input filters to be settled" Name="t_e_MDD2000SafetySubRunState.PRE_OP_DI_FILTER_SETTLING"/>
	    PRE_OP_SF_FILTER_SETTLING:=203,  //! <Type Comment="wait for safety function framework filters (velocity, steady time) to be settled" Name="t_e_MDD2000SafetySubRunState.PRE_OP_SF_FILTER_SETTLING"/>
	    PRE_OP_FSOE_SETUP:=204,  //! <Type Comment="wait for FSoE connection state DATA" Name="t_e_MDD2000SafetySubRunState.PRE_OP_FSOE_SETUP"/>
	    PRE_OP_DONE:=205,  //! <Type Comment="check is done successfully" Name="t_e_MDD2000SafetySubRunState.PRE_OP_DONE"/>
	    Invalid:=4294967295
	  )$UDINT;
	  t_e_SSWSafetyCfgChg :
	  (
	    _Idle,
	    Wait4ValidConfig,
	    ReadNewConfig,
	    Wait4ReadNewConfig,
	    CfgChgFinished,
	    CfgChgError
	  )$UDINT;
	  t_e_SSWSafetyChangeServiceMode :
	  (
	    _Idle,
	    _SetServiceMode,
	    _Wait4SetServiceMode,
	    _LeaveServiceMode,
	    _Wait4LeaveServiceMode,
	    _UpdateSafetyState,
	    _Wait4UpdateSafetyState,
	    _Error
	  )$UDINT;
	  t_e_SSWSafetyCy :
	  (
	    _Start,
	    _UpdateSafetyState,
	    _Wait4UpdateSafetyState,
	    _CheckVerifiedDone,
	    _DelayedSetServiceMode,
	    _Wait4SetServiceMode,
	    _SetServiceMode,
	    _FinishVerify,
	    _Wait4FinishVerify,
	    _LeaveServiceMode,
	    _ResetSafetyAxes,
	    _Wait4ResetSafetyAxes,
	    _QuitSafetyError,
	    _Done,
	    _Error
	  )$UDINT;
#pragma pack(push, 1)
	  t_s_ChangesBuffer : STRUCT
	    ActEntries : UDINT;
	    pChangesPipeHandle : ^void;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_s_SafetyConfigChanged : STRUCT
	    SSWSafetyCfgChg : t_e_SSWSafetyCfgChg;
	    SafetyCFGCRC : HDINT;
	    SafetySubRunState : t_e_MDD2000SafetySubRunState;
	    SafetyLenOutFSoEFrame : DINT;
	    SafetyLenInFSoEFrame : DINT;
	    bdFaultInfo : BDINT
	    [
	      1 Bit1,
	      2 Bit2,
	      3 Bit3,
	      4 Bit4,
	      5 Bit5,
	      6 Bit6,
	      7 Bit7,
	      8 Bit8,
	      9 Bit9,
	      10 Bit10,
	      11 Bit11,
	      12 Bit12,
	      13 Bit13,
	      14 Bit14,
	      15 Bit15,
	      16 Bit16,
	      17 Bit17,
	      18 Bit18,
	      19 Bit19,
	      20 Bit20,
	      21 Bit21,
	      22 Bit22,
	      23 Bit23,
	      24 Bit24,
	      25 Bit25,
	      26 Bit26,
	      27 Bit27,
	      28 Bit28,
	      29 Bit29,
	      30 Bit30,
	      31 Bit31,
	      32 Bit32,
	    ];
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_s_SafetyErrInfo : STRUCT
	    SafetyErrorCode_SC1 : DINT;
	    SafetyErrorInformation1_SC1 : DINT;
	    SafetyErrorInformation2_SC1 : DINT;
	    SafetyErrorInformation3_SC1 : DINT;
	    SafetyErrorCode_SC2 : DINT;
	    SafetyErrorInformation1_SC2 : DINT;
	    SafetyErrorInformation2_SC2 : DINT;
	    SafetyErrorInformation3_SC2 : DINT;
	    bdAsyFlags : BDINT
	    [
	      1 w4SafetyErrorCode_SC1,
	      2 w4SafetyErrorInformation1_SC1,
	      3 w4SafetyErrorInformation2_SC1,
	      4 w4SafetyErrorInformation3_SC1,
	      5 w4SafetyErrorCode_SC2,
	      6 w4SafetyErrorInformation1_SC2,
	      7 w4SafetyErrorInformation2_SC2,
	      8 w4SafetyErrorInformation3_SC2,
	      9 errSafetyErrorCode_SC1,
	      10 errSafetyErrorInformation1_SC1,
	      11 errSafetyErrorInformation2_SC1,
	      12 errSafetyErrorInformation3_SC1,
	      13 errSafetyErrorCode_SC2,
	      14 errSafetyErrorInformation1_SC2,
	      15 errSafetyErrorInformation2_SC2,
	      16 errSafetyErrorInformation3_SC2,
	      17 Bit17,
	      18 Bit18,
	      19 Bit19,
	      20 Bit20,
	      21 Bit21,
	      22 Bit22,
	      23 Bit23,
	      24 Bit24,
	      25 Bit25,
	      26 Bit26,
	      27 Bit27,
	      28 Bit28,
	      29 Bit29,
	      30 Bit30,
	      31 Bit31,
	      32 Bit32,
	    ];
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_TimeVars : STRUCT
	    tSysTime : SYSTIME;
	    tSysDate : SYSDATE;
	    hdKDATEP241 : HDINT;
	    bTimeIsSet : BOOL;
	    udLastWrite : UDINT;
	  END_STRUCT;
#pragma pack(pop)
	END_TYPE
  //Servers:
	CmdState 	: SvrChCmd_iprStates;
	ClassState 	: SvrCh_t_e_VaranErrors;
	Online 	: SvrCh_DINT;
	Release 	: SvrCh_HDINT;
	DeviceAddress 	: SvrCh_HDINT;
	VendorID 	: SvrCh_UDINT;
	DeviceID 	: SvrCh_UDINT;
	RetryCounter 	: SvrCh_UDINT;
	DriveType 	: SvrCh_t_e_MD2000Type_PTofCls_MDD2000MngBase;
	StrDriveType 	: SvrChCmd_UDINT;
	AxisAvailable 	: SvrCh_BDINT;
	SerialNo 	: SvrCh_DINT;
	HWVersion 	: SvrChCmd_UDINT;
	FwVersionDrive 	: SvrChCmd_UDINT;
	FwVersionSafety 	: SvrChCmd_UDINT;
	SafetyNumber 	: SvrCh_HDINT;
	SafetyRunState 	: SvrCh_t_e_MDD2000SafetyRunState_PTofCls_MDD2000MngBase;
  //Clients:
	cOnline 	: CltCh_DINT;
	coStdLib 	: CltChCmd__StdLib;
	To_TaskObjectControl 	: CltChCmd__TaskObjectControl;
	ToBusIF 	: CltChCmd_DINT;
	toSafetyRunState 	: CltCh_t_e_MDD2000SafetyRunState_PTofCls_MDD2000MngBase;
	DriveTypeStr 	: CltChCmd_String;
	FwNumString 	: CltChCmd_String;
	FwSafeNumString 	: CltChCmd_String;
	HWNumString 	: CltChCmd_String;
  //Variables:
		InitCounter 	: DINT;			//! <Variable Comment="Initialisierungszähler" Name="InitCounter"/>
		eInitSSW 	: t_e_InitSSW;
		AxCount 	: DINT;			//! <Variable Comment="Count of available axis" Name="AxCount"/>
		AxBuffer : ARRAY [0..MDD2000MNG_MAXENTRIES-1] OF _AXDEF;

		AxisActive : BDINT
		[
		];

		bdSettings : BDINT
		[
		  1 HwConnect,
		  3 DriveIsInitialized,
		  4 AxisInit,
		  5 bRingBufferRead,
		  6 bRingBufferWrite,
		  8 InitModuleDone,
		  9 ResetSafetyAxis,
		  10 ResetSafeVerify,
		  11 QuitSafetyError,
		  12 SetServiceMode,
		  13 LeaveServiceMode,
		  14 SafetyConfigChanged,
		  15 RtSafetyRunState,
		];

		L2Buffer : ARRAY [0..29] OF _SDDL2BUFFER;

		L2WrIndex 	: DINT;
		L2NewEntry 	: DINT;
		AxIndizesL2 : BDINT
		[
		];

		FwVersionInt 	: DINT;
		sChangesData 	: t_s_ChangesBuffer;
		LastRetcode 	: results;
		ud_TimeoutCycles 	: UDINT;
		ud_CycleCounter 	: UDINT;
		aDriveScopeData : ARRAY [0..2] OF DINT;

		bLasalErrorBufferRequest 	: BOOL;
		sTimeVars 	: t_TimeVars;
		bdWait4HwInfoResponse : BDINT
		[
		  1 I_SER,
		  2 I_FW,
		  4 I_HW,
		  5 I_Type,
		];

		bdWait4SafetyInfoResponse : BDINT
		[
		  1 FwVersion,
		  2 SafetyNo,
		  3 RunState,
		  4 SetServiceMode,
		  5 LeaveServiceMode,
		  6 FinishVerify,
		  7 ResetSafeVerify,
		  8 CFG_CRC,
		  9 SubRunState,
		  10 LenOutFSoEFrame,
		  11 LenInFSoEFrame,
		];

		Parameter_I_Type 	: DINT;
		Parameter_I_HW 	: DINT;
		udCycleTimems 	: UDINT;
		ud_FileHandlingReserved 	: UDINT;
		s_LogFileV 	: s_LogFileVar;
		bSafetyActive 	: BOOL;
		SSWUpdateSafety 	: t_e_SSWSafetyCy;
		SSWUpdateSafetySetServicemodeNext 	: t_e_SSWSafetyCy;
		SSWSafetyChangeServiceMode 	: t_e_SSWSafetyChangeServiceMode;
		LastSafetyRunState 	: t_e_MDD2000SafetyRunState;
		udTimeStampDelaySetServiceMode 	: UDINT;
		sParaObjectList : ARRAY [0..MDD2000MNG_MAX_PARAIDX_CNT-1] OF t_MDD2000Mng_ParaObjectListEntry;

		sSafetyErrInfo 	: t_s_SafetyErrInfo;
		sSafetyCfgChg 	: t_s_SafetyConfigChanged;
		SafetyRunStateInternal 	: t_e_MDD2000SafetyRunState;
  //Functions:
	
	FUNCTION MDD2000MngBase
		VAR_OUTPUT
			ret_code 	: ConfStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL Init;
	
	FUNCTION VIRTUAL GLOBAL CyWork
		VAR_INPUT
			EAX 	: UDINT;
		END_VAR
		VAR_OUTPUT
			state (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION AddAxObj
		VAR_INPUT
			pThis 	: ^void;
			AxisNo 	: DINT;
			pAsyPipeHandle 	: ^void;
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;
		END_VAR;
	
	FUNCTION InitAxisState;
	
	FUNCTION SetParaList
		VAR_INPUT
			usAxis 	: USINT;
			adress 	: ^void;
			ui_counter 	: UINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION CreateDefParaBase
		VAR_INPUT
			CmdPara 	: ^CmdStruct;
			Results 	: ^results;
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GetParameterState
		VAR_INPUT
			usAxis 	: USINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL SetParameter
		VAR_INPUT
			usAxis 	: USINT;
			paranr 	: USINT;
			rdwr 	: USINT;
			paravalue 	: DINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GetParameter
		VAR_INPUT
			usAxis 	: USINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL UpdateSvr;
	
	FUNCTION VIRTUAL UpdateASync;
	
	FUNCTION DriveInitState
		VAR_OUTPUT
			retcode 	: BOOL;
		END_VAR;
	
	FUNCTION AxisInitFinished
		VAR_INPUT
			AxisIdx 	: USINT;
			IdFinished 	: DINT;
		END_VAR;
	
	FUNCTION ResetAxisInit;
	
	FUNCTION CommunicationState
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION GetAxisWrPtr
		VAR_INPUT
			usAxis 	: USINT;
			pWrLen 	: ^UDINT := nil;
		END_VAR
		VAR_OUTPUT
			ptr 	: ^void;
		END_VAR;
	
	FUNCTION GetAxisRdPtr
		VAR_INPUT
			usAxis 	: USINT;
			pRdLen 	: ^UDINT := nil;
		END_VAR
		VAR_OUTPUT
			ptr 	: ^void;
		END_VAR;
	
	FUNCTION InitDrive
		VAR_INPUT
			Mode 	: USINT;
		END_VAR;
	
	FUNCTION L2CmdFinished
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION GetAxIndex
		VAR_INPUT
			AxisNo 	: USINT;
		END_VAR
		VAR_OUTPUT
			AxIndex 	: USINT;
		END_VAR;
	
	FUNCTION GetFirstAxIndex
		VAR_OUTPUT
			AxIndex 	: USINT;
		END_VAR;
	
	FUNCTION SetFwVersion
		VAR_INPUT
			FwVersionInt 	: DINT;
			StringSelect 	: DINT;
		END_VAR;
	
	FUNCTION Bin2Ascii
		VAR_INPUT
			pt 	: ^CHAR;
			value 	: DINT;
			format 	: BINT;
		END_VAR;
	
	FUNCTION SetSyncEntry
		VAR_INPUT
			usAxis 	: USINT;
			usValue 	: USINT;
			usPData 	: DINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION GetSyncEntry
		VAR_INPUT
			usAxis 	: USINT;
			usValue 	: USINT;
			usPData 	: ^DINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION GetVaranDriveState
		VAR_OUTPUT
			retcode 	: DINT;			//! <Variable Comment="0 .. _InitAxis&#13;&#10;1 .. _GetSendParaList (Write Axis Tables to drive)&#13;&#10;2 .. _WaitForSynchrony&#13;&#10;3 .. _Operational" Name="GetVaranDriveState.retcode"/>
		END_VAR;
				//! <Function Comment="If no cyclic time is set on the object, because the cyclic is being called from another class, this method should be used to tell the class in which time base it will be called.&#13;&#10;The time base is used to check for a timeout on asynchron methods." Name="SetTimeBase"/>
	FUNCTION VIRTUAL GLOBAL SetTimeBase
		VAR_INPUT
			ud_timebase_ms 	: UDINT;			//! <Variable Comment="Timebase in ms" Name="SetTimeBase.ud_timebase_ms"/>
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;			//! <Variable Comment=" 0..OK&#13;&#10;-1..Function has been called too early (must be after the 2nd init run)&#13;&#10;-2..Timebase must be bigger than 0" Name="SetTimeBase.sd_retval"/>
		END_VAR;
	
	FUNCTION VIRTUAL GetDefaultLogFileDestinationDPNE
		VAR_INPUT
			pDPNE 	: ^CHAR;
			FileSelect 	: UDINT := 0;
		END_VAR;
	
	FUNCTION VIRTUAL GetDefaultLogFileNameDrive
		VAR_INPUT
			pFileName 	: ^CHAR;
			FileSelect 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GetDefaultLogFilePathDrive
		VAR_INPUT
			pFilePath 	: ^CHAR;
			FileSelect 	: UDINT;
		END_VAR;
				//! <Function Comment="Function to disable device." Name="DisableDevice"/>
	FUNCTION VIRTUAL GLOBAL DisableDevice
		VAR_OUTPUT
			RetCode 	: DINT;			//! <Variable Comment="return value&#13;&#10;0  .. ok&#13;&#10;-1 .. function not available" Name="DisableDevice.RetCode"/>
		END_VAR;
				//! <Function Comment="Function to enable device." Name="EnableDevice"/>
	FUNCTION VIRTUAL GLOBAL EnableDevice
		VAR_OUTPUT
			RetCode 	: DINT;			//! <Variable Comment="return value&#13;&#10;0  .. ok&#13;&#10;-1 .. function not available" Name="EnableDevice.RetCode"/>
		END_VAR;
				//! <Function Comment="Adds an asynchron parameter access to the buffer.&#13;&#10;If the access is succesfful the NewInst Command MDD2000MNG_IF_ASYNC_READY is sent to the object that was set via pThisObj.&#13;&#10;If the access fails the NewInst Command MDD2000MNG_IF_ASYNC_ERROR is sent to the object that was set via pThisObj." Name="AddASyncEntryDS402"/>
	FUNCTION VIRTUAL AddASyncEntryDS402
		VAR_INPUT
			AxisIdx 	: USINT;			//! <Variable Comment="Axis Index" Name="AddASyncEntryDS402.AxisIdx"/>
			uiParaID 	: UINT;			//! <Variable Comment="Parameter Index, which should be accessed (2 Byte)." Name="AddASyncEntryDS402.uiParaID"/>
			usParaSubID 	: USINT;			//! <Variable Comment="Parameter SubIndex, which should be accessed (1 Byte)" Name="AddASyncEntryDS402.usParaSubID"/>
			usRdWr 	: USINT;			//! <Variable Comment="0 .. read the value of the parameter number&#13;&#10;1 .. write a new value to the parameter number" Name="AddASyncEntryDS402.usRdWr"/>
			pValue 	: ^void;			//! <Variable Comment="Read Command = Not Used&#13;&#10;Write Command = Pointer to the new value which has to written to the parameter" Name="AddASyncEntryDS402.pValue"/>
			bsDataInfo 	: BSINT;			//! <Variable Comment="Size of the Parameter:&#13;&#10;0...4  Byte&#13;&#10;1...8  Byte&#13;&#10;2...12 Byte&#13;&#10;" Name="AddASyncEntryDS402.bsDataInfo"/>
			pThisObj 	: ^void;			//! <Variable Comment="This pointer of the object that should recive the callback with the parameter has been read/written." Name="AddASyncEntryDS402.pThisObj"/>
			usEntry 	: USINT := 0;			//! <Variable Comment="For internal use only" Name="AddASyncEntryDS402.usEntry"/>
			udTimeout 	: UDINT := 0;			//! <Variable Comment="Timeout of the Asy Access in ms. (0 = use default timeout)" Name="AddASyncEntryDS402.udTimeout"/>
			dCallID 	: DINT := 0;			//! <Variable Comment="For internal use only" Name="AddASyncEntryDS402.dCallID"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;			//! <Variable Comment="0 .. Ok&#13;&#10;-1 .. Asy Buffer is full." Name="AddASyncEntryDS402.retcode"/>
		END_VAR;
	
	FUNCTION SetParameterDS402
		VAR_INPUT
			usAxis 	: USINT;
			uiParaID 	: UINT;
			usParaSubID 	: USINT;
			usRdWr 	: USINT;
			pparavalue 	: ^USINT;
			bsDataInfo 	: BSINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION GetParameterDS402
		VAR_INPUT
			usAxis 	: USINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: ^DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GetBusDeviceID
		VAR_OUTPUT
			output 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GetDrvDeviceID
		VAR_OUTPUT
			output 	: UDINT;
		END_VAR;
	
	FUNCTION IsAnyAxisEnabled
		VAR_OUTPUT
			AnyAxisEnabled 	: BOOL;
		END_VAR;
	
	FUNCTION VIRTUAL GetDriveTypeStr
		VAR_INPUT
			pDriveTypeStr 	: ^CHAR;
			DriveTypeStrSize 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GetSystemTime;
				//! <Function Comment="Method has to be called by derivation if needed." Name="SetSystemTimeAtDrive"/>
	FUNCTION VIRTUAL SetSystemTimeAtDrive
		VAR_INPUT
			AxisIdx 	: USINT;
		END_VAR;
				//! <Function Comment="Method to start the upload a specific file from the drive and save it on the PLC.&#13;&#10;If retcode is READY the filetransfer is started and running. Use GetFileState() for the state of the file upload." Name="GetFile"/>
	FUNCTION VIRTUAL GLOBAL GetFile
		VAR_INPUT
			pDestinationDPNE 	: ^CHAR;			//! <Variable Comment="Pointer to destination path + name + extension where the logfile should be saved on the SPS" Name="GetFile.pDestinationDPNE"/>
			pFileNameDrive 	: ^CHAR;			//! <Variable Comment="Pointer to filename of the drive" Name="GetFile.pFileNameDrive"/>
			pFilePathDrive 	: ^CHAR;			//! <Variable Comment="Pointer to the file path/directory of the drive " Name="GetFile.pFilePathDrive"/>
			pdError 	: ^DINT := nil;			//! <Variable Comment="Pointer to a 4 Byte Error variable where errorcodes will be written when there is an error (optional, can be NIL)&#13;&#10;Errorcodes: &#13;&#10;0 ... No Error&#13;&#10;-1 ... Mailbox for File Transfer not available&#13;&#10;-2 ... Filetransfer busy (other Upload/Download is still running)&#13;&#10;-3 ... Invalid pointer given&#13;&#10;-4 ... String &quot;Filename of the drive&quot; is too long&#13;&#10;-5 ... String &quot;Filepath of the drive&quot; is too long&#13;&#10;-6 ... String &quot;Destination path + name + extension&quot; is too long&#13;&#10;-7 ... Vandal Communication Error&#13;&#10;-8 ... Vandal Communication Timeout&#13;&#10;-9 ... File was not found on drive&#13;&#10;-10 ... Failed to create local file&#13;&#10;-11 ... Failed to write data to local file&#13;&#10;-12 ... Invalid length&#13;&#10;-13 ... Buffer is to small&#13;&#10;-14 ... An attempt was made to read out more bytes of data than are available in the file.&#13;&#10;-15 ... Failed to create thread for filehandling&#13;&#10;-93 ... The writing of the asynchron parameter for reading out the log file failed.&#13;&#10;-94 ... Timeout when writing the asynchron parameter for reading out the log file.&#13;&#10;-95 ... The read-back of the asynchron parameter for reading out the log file failed.&#13;&#10;-96 ... Timeout when reading back the asynchron parameter for reading out the log file.&#13;&#10;-97 ... Axis must not be enabled.&#13;&#10;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="GetFile.pdError"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="READY ... File Upload was started succesfully (Current progress of upload can be fetched with method GetFileState)&#13;&#10;ERROR ... File Upload Error (see parameter pdError for more information)" Name="GetFile.retcode"/>
		END_VAR;
				//! <Function Comment="Method to start the upload of the logfile from the drive and save it on the PLC. &#13;&#10;If retcode is READY the filetransfer is started and running. Use GetFileState() for the state of the file upload." Name="GetLogFile"/>
	FUNCTION VIRTUAL GLOBAL GetLogFile
		VAR_INPUT
			pDestinationDPNE 	: ^CHAR := NIL;			//! <Variable Comment="Pointer to destination path + name + extension where the logfile should be saved on the SPS&#13;&#10;&#13;&#10;If this parameter is not used, one of the following files, depending on &quot;udFileSelectID&quot;, will be used:&#13;&#10;&quot;C:\sysmsg\DriveLog&lt;Serial No&gt;.txt&quot; or &quot;C:\sysmsg\DriveDebugLog&lt;Serial No&gt;.txt&quot;. " Name="GetLogFile.pDestinationDPNE"/>
			pdError 	: ^DINT := nil;			//! <Variable Comment="Pointer to a 4 Byte Error variable where errorcodes will be written when there is an error (optional, can be NIL)&#13;&#10;Errorcodes: &#13;&#10;0 ... No Error&#13;&#10;-1 ... Mailbox for File Transfer not available&#13;&#10;-2 ... Filetransfer busy (other Upload/Download is still running)&#13;&#10;-3 ... Invalid pointer given&#13;&#10;-4 ... String &quot;Filename of the drive&quot; is too long&#13;&#10;-5 ... String &quot;Filepath of the drive&quot; is too long&#13;&#10;-6 ... String &quot;Destination path + name + extension&quot; is too long&#13;&#10;-7 ... Vandal Communication Error&#13;&#10;-8 ... Vandal Communication Timeout&#13;&#10;-9 ... File was not found on drive&#13;&#10;-10 ... Failed to create local file&#13;&#10;-11 ... Failed to write data to local file&#13;&#10;-12 ... Invalid length&#13;&#10;-13 ... Buffer is to small&#13;&#10;-14 ... An attempt was made to read out more bytes of data than are available in the file.&#13;&#10;-15 ... Failed to create thread for filehandling&#13;&#10;-93 ... The writing of the asynchron parameter for reading out the log file failed.&#13;&#10;-94 ... Timeout when writing the asynchron parameter for reading out the log file.&#13;&#10;-95 ... The read-back of the asynchron parameter for reading out the log file failed.&#13;&#10;-96 ... Timeout when reading back the asynchron parameter for reading out the log file.&#13;&#10;-97 ... Axis must not be enabled.&#13;&#10;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="GetLogFile.pdError"/>
			udFileSelectID 	: UDINT := MDD2000MNG_FILESELECT_LOGFILE;			//! <Variable Comment="Optional: Select which log file is fetched from the drive:&#13;&#10;0 .. Default logfile (Default selection if this parameter is not set.)&#13;&#10;1 .. Debug log file." Name="GetLogFile.udFileSelectID"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="READY ... File Upload was started succesfully (Current progress of upload can be fetched with method GetFileState)&#13;&#10;ERROR ... File Upload Error - see parameter pdError" Name="GetLogFile.retcode"/>
		END_VAR;
				//! <Function Comment="Method to check the current progress of the filetransfer started with e.g. GetFile, GetLogFile or SetFile methods." Name="GetFileState"/>
	FUNCTION VIRTUAL GLOBAL GetFileState
		VAR_INPUT
			pdError 	: ^DINT := nil;			//! <Variable Comment="Pointer to a 4 Byte Error variable where errorcodes will be written when there is an error (optional, can be NIL)&#13;&#10;Errorcodes: &#13;&#10;0 ... No Error&#13;&#10;-1 ... Mailbox for File Transfer not available&#13;&#10;-2 ... Filetransfer busy (other Upload/Download is still running)&#13;&#10;-3 ... Invalid pointer given&#13;&#10;-4 ... String &quot;Filename of the drive&quot; is too long&#13;&#10;-5 ... String &quot;Filepath of the drive&quot; is too long&#13;&#10;-6 ... String &quot;Destination path + name + extension&quot; is too long&#13;&#10;-7 ... Vandal Communication Error&#13;&#10;-8 ... Vandal Communication Timeout&#13;&#10;-9 ... File was not found on drive&#13;&#10;-10 ... Failed to create local file&#13;&#10;-11 ... Failed to write data to local file&#13;&#10;-12 ... Invalid length&#13;&#10;-13 ... Buffer is to small&#13;&#10;-14 ... An attempt was made to read out more bytes of data than are available in the file.&#13;&#10;-15 ... Failed to create thread for filehandling&#13;&#10;-93 ... The writing of the asynchron parameter for reading out the log file failed.&#13;&#10;-94 ... Timeout when writing the asynchron parameter for reading out the log file.&#13;&#10;-95 ... The read-back of the asynchron parameter for reading out the log file failed.&#13;&#10;-96 ... Timeout when reading back the asynchron parameter for reading out the log file.&#13;&#10;-97 ... Axis must not be enabled.&#13;&#10;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="GetFileState.pdError"/>
			pdProgress 	: ^DINT := nil;			//! <Variable Comment="Pointer to a 4 Byte variable where the progress of the fileupload will be written in percentage (0-1000) (optional, can be nil)" Name="GetFileState.pdProgress"/>
			pudBytesRead 	: ^UDINT := nil;			//! <Variable Comment="Pointer to where the amount of read bytes will be copied (optional, can be NIL)" Name="GetFileState.pudBytesRead"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="BUSY  ... File transfer is not finished yet&#13;&#10;READY ... File transfer was not started yet / File transfer is finished&#13;&#10;ERROR ... File transfer Error - see parameter pdError" Name="GetFileState.retcode"/>
		END_VAR;
				//! <Function Comment="Method to write a specific file on the drive.&#13;&#10;If retcode is READY the filetransfer is started and running. Use GetFileState() for the state of the file upload." Name="SetFile"/>
	FUNCTION VIRTUAL GLOBAL SetFile
		VAR_INPUT
			pWriteData 	: ^void;			//! <Variable Comment="Pointer to data which will be written into the selected file." Name="SetFile.pWriteData"/>
			udWriteDataLen 	: UDINT;			//! <Variable Comment="Length of data which will be written to the selected file on the drive." Name="SetFile.udWriteDataLen"/>
			pFilePathDrive 	: ^CHAR;			//! <Variable Comment="Pointer to the file path/directory of the drive " Name="SetFile.pFilePathDrive"/>
			pFileNameDrive 	: ^CHAR;			//! <Variable Comment="Pointer to filename of the drive which should be written" Name="SetFile.pFileNameDrive"/>
			pdError 	: ^DINT := nil;			//! <Variable Comment="Pointer to a 4 Byte Error variable where errorcodes will be written when there is an error (optional, can be NIL)&#13;&#10;Errorcodes: &#13;&#10;0 ... No Error&#13;&#10;-1 ... Mailbox for File Transfer not available&#13;&#10;-2 ... Filetransfer busy (other Upload/Download is still running)&#13;&#10;-3 ... Invalid pointer given&#13;&#10;-4 ... String &quot;Filename of the drive&quot; is too long&#13;&#10;-5 ... String &quot;Filepath of the drive&quot; is too long&#13;&#10;-6 ... String &quot;Destination path + name + extension&quot; is too long&#13;&#10;-7 ... Vandal Communication Error&#13;&#10;-8 ... Vandal Communication Timeout&#13;&#10;-9 ... File was not found on drive&#13;&#10;-10 ... Failed to create local file&#13;&#10;-11 ... Failed to write data to local file&#13;&#10;-12 ... Invalid length&#13;&#10;-13 ... Buffer is to small&#13;&#10;-14 ... An attempt was made to read out more bytes of data than are available in the file.&#13;&#10;-15 ... Failed to create thread for filehandling&#13;&#10;-93 ... The writing of the asynchron parameter for reading out the log file failed.&#13;&#10;-94 ... Timeout when writing the asynchron parameter for reading out the log file.&#13;&#10;-95 ... The read-back of the asynchron parameter for reading out the log file failed.&#13;&#10;-96 ... Timeout when reading back the asynchron parameter for reading out the log file.&#13;&#10;-97 ... Axis must not be enabled.&#13;&#10;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="SetFile.pdError"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="READY ... File Write was started succesfully (Current progress can be fetched with method GetFileState)&#13;&#10;ERROR ... File Write Error (see parameter pdError for more information)" Name="SetFile.retcode"/>
		END_VAR;
				//! <Function Comment="Method to get the size of a specific file from the drive.&#13;&#10;If retcode is READY the filetransfer is started and running. Use GetFileState() for the state of the file upload." Name="GetFileSize"/>
	FUNCTION VIRTUAL GLOBAL GetFileSize
		VAR_INPUT
			pFileNameDrive 	: ^CHAR;			//! <Variable Comment="Pointer to filename of the drive" Name="GetFileSize.pFileNameDrive"/>
			pFilePathDrive 	: ^CHAR;			//! <Variable Comment="Pointer to the file path/directory of the drive " Name="GetFileSize.pFilePathDrive"/>
			pudSize 	: ^UDINT;			//! <Variable Comment="Pointer to where the filesize will be written. The value is valid after &quot;GetFileState&quot; returns READY." Name="GetFileSize.pudSize"/>
			pdError 	: ^DINT := nil;			//! <Variable Comment="Pointer to a 4 Byte Error variable where errorcodes will be written when there is an error (optional, can be NIL)&#13;&#10;Errorcodes: &#13;&#10;0 ... No Error&#13;&#10;-1 ... Mailbox for File Transfer not available&#13;&#10;-2 ... Filetransfer busy (other Upload/Download is still running)&#13;&#10;-3 ... Invalid pointer given&#13;&#10;-4 ... String &quot;Filename of the drive&quot; is too long&#13;&#10;-5 ... String &quot;Filepath of the drive&quot; is too long&#13;&#10;-6 ... String &quot;Destination path + name + extension&quot; is too long&#13;&#10;-7 ... Vandal Communication Error&#13;&#10;-8 ... Vandal Communication Timeout&#13;&#10;-9 ... File was not found on drive&#13;&#10;-10 ... Failed to create local file&#13;&#10;-11 ... Failed to write data to local file&#13;&#10;-12 ... Invalid length&#13;&#10;-13 ... Buffer is to small&#13;&#10;-14 ... An attempt was made to read out more bytes of data than are available in the file.&#13;&#10;-15 ... Failed to create thread for filehandling&#13;&#10;-93 ... The writing of the asynchron parameter for reading out the log file failed.&#13;&#10;-94 ... Timeout when writing the asynchron parameter for reading out the log file.&#13;&#10;-95 ... The read-back of the asynchron parameter for reading out the log file failed.&#13;&#10;-96 ... Timeout when reading back the asynchron parameter for reading out the log file.&#13;&#10;-97 ... Axis must not be enabled.&#13;&#10;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="GetFileSize.pdError"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="READY ... Fetching the filesize  was started succesfully (Current progress can be fetched with method GetFileState)&#13;&#10;ERROR ... get filesize failed (see parameter pdError for more information)&#13;&#10;" Name="GetFileSize.retcode"/>
		END_VAR;
				//! <Function Comment="Method to read data from a specific file from the drive and write data into an user buffer.&#13;&#10;If retcode is READY the filetransfer is started and running. Use GetFileState() for the state of the file upload." Name="GetFileBuffer"/>
	FUNCTION VIRTUAL GLOBAL GetFileBuffer
		VAR_INPUT
			pFileNameDrive 	: ^CHAR;			//! <Variable Comment="Pointer to filename of the drive" Name="GetFileBuffer.pFileNameDrive"/>
			pFilePathDrive 	: ^CHAR;			//! <Variable Comment="Pointer to the file path/directory of the drive " Name="GetFileBuffer.pFilePathDrive"/>
			udBufferSize 	: UDINT;			//! <Variable Comment="Size of buffer (pDataBuffer) in bytes." Name="GetFileBuffer.udBufferSize"/>
			pDataBuffer 	: ^void := nil;			//! <Variable Comment="Pointer to buffer where read data will be copied.&#13;&#10;The data is valid after &quot;GetFileState&quot; returns READY." Name="GetFileBuffer.pDataBuffer"/>
			udDataLenToRead 	: UDINT := 0;			//! <Variable Comment="Optional parameter. Can be used if only x-bytes from the file should be read. Otherwise all data from the file will be read out.&#13;&#10;0 ... Read all bytes from file.&#13;&#10;x ... Read x bytes from file." Name="GetFileBuffer.udDataLenToRead"/>
			pdError 	: ^DINT := nil;			//! <Variable Comment="Pointer to a 4 Byte Error variable where errorcodes will be written when there is an error (optional, can be NIL)&#13;&#10;Errorcodes: &#13;&#10;0 ... No Error&#13;&#10;-1 ... Mailbox for File Transfer not available&#13;&#10;-2 ... Filetransfer busy (other Upload/Download is still running)&#13;&#10;-3 ... Invalid pointer given&#13;&#10;-4 ... String &quot;Filename of the drive&quot; is too long&#13;&#10;-5 ... String &quot;Filepath of the drive&quot; is too long&#13;&#10;-6 ... String &quot;Destination path + name + extension&quot; is too long&#13;&#10;-7 ... Vandal Communication Error&#13;&#10;-8 ... Vandal Communication Timeout&#13;&#10;-9 ... File was not found on drive&#13;&#10;-10 ... Failed to create local file&#13;&#10;-11 ... Failed to write data to local file&#13;&#10;-12 ... Invalid length&#13;&#10;-13 ... Buffer is to small&#13;&#10;-14 ... An attempt was made to read out more bytes of data than are available in the file.&#13;&#10;-15 ... Failed to create thread for filehandling&#13;&#10;-93 ... The writing of the asynchron parameter for reading out the log file failed.&#13;&#10;-94 ... Timeout when writing the asynchron parameter for reading out the log file.&#13;&#10;-95 ... The read-back of the asynchron parameter for reading out the log file failed.&#13;&#10;-96 ... Timeout when reading back the asynchron parameter for reading out the log file.&#13;&#10;-97 ... Axis must not be enabled.&#13;&#10;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="GetFileBuffer.pdError"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="READY ... File read was started succesfully (Current progress of read can be fetched with method GetFileState)&#13;&#10;ERROR ... File read Error (see parameter pdError for more information)" Name="GetFileBuffer.retcode"/>
		END_VAR;
	
	FUNCTION VIRTUAL GetLogFileCyclic;
	
	FUNCTION VIRTUAL GetLogFileWrParam
		VAR_INPUT
			pParaIndex 	: ^HINT;
			pParaSubIndex 	: ^HSINT;
			pParaVal 	: ^DINT;
			pParaTimeout 	: ^UDINT;
			FileSelect 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GetLogFileRdParam
		VAR_INPUT
			pParaIndex 	: ^HINT;
			pParaSubIndex 	: ^HSINT;
			pParaVal 	: ^DINT;
			pParaTimeout 	: ^UDINT;
			FileSelect 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL ReserveFileHandling
		VAR_INPUT
			ReserveID 	: UDINT := DRIVEMNG_FILE_RESERVE_IDDEFAULT;
		END_VAR
		VAR_OUTPUT
			bReserverdOK 	: BOOL;
		END_VAR;
	
	FUNCTION VIRTUAL ReleaseFileHandling;
	
	FUNCTION VIRTUAL CheckFileHandlingAvailable
		VAR_INPUT
			pdError 	: ^DINT := nil;
			ReserveID 	: UDINT := MDD2000MNG_FILE_RESERVE_IDDEFAULT;
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;
		END_VAR;
	
	FUNCTION SetDriveType
		VAR_INPUT
			ITYPE 	: DINT;
		END_VAR;
	
	FUNCTION ConvertLC2ParaFormatToDS402Format
		VAR_INPUT
			ParaNo 	: DINT;
			phParaIndex 	: ^HINT;
			phsParaSubIndex 	: ^HSINT;
		END_VAR;
	
	FUNCTION ConvertDS402ParaFormatToLC2Format
		VAR_INPUT
			hParaIndex 	: HINT;
			hsParaSubIndex 	: HSINT;
			ParaNo 	: ^DINT;
		END_VAR;
	
	FUNCTION VIRTUAL InitModule;
	
	FUNCTION VIRTUAL UpdateSafetyCy;
	
	FUNCTION VIRTUAL AddParaObjects
		VAR_INPUT
			Index 	: USINT;
			pThis 	: ^void;
		END_VAR
		VAR_OUTPUT
			retcode 	: BOOL;
		END_VAR;
	
	FUNCTION SetParaState
		VAR_INPUT
			ActState 	: UINT;
			StateInfo 	: DINT := 0;
		END_VAR;
	
	FUNCTION SafetyChangeServiceMode
		VAR_INPUT
			SetLeaveServiceMode 	: BOOL;			//! <Variable Comment="0 .. Leave&#13;&#10;1 .. Enter" Name="SafetyChangeServiceMode.SetLeaveServiceMode"/>
		END_VAR
		VAR_OUTPUT
			retstate 	: iprStates;
		END_VAR;
	
	FUNCTION ResetSafeVerifyZeropos
		VAR_INPUT
			AxisIdx 	: USINT;
			IdReset 	: DINT;
		END_VAR;
	
	FUNCTION ResetAxisSafeVerifyZeroPos;
	
	FUNCTION VIRTUAL SendSafteyConfigChanged;
	
	FUNCTION VIRTUAL SafetyConfigChanged
		VAR_OUTPUT
			retstate 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL CmdState::GetState
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL CmdState::NewInst
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL CmdState::Read
		VAR_OUTPUT
			output (EAX) 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL ClassState::Read
		VAR_OUTPUT
			output (EAX) 	: t_e_VaranErrors;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL Online::Read
		VAR_OUTPUT
			output (EAX) 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL Release::Read
		VAR_OUTPUT
			output (EAX) 	: HDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL DeviceAddress::Read
		VAR_OUTPUT
			output (EAX) 	: HDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL VendorID::Read
		VAR_OUTPUT
			output (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL DeviceID::Read
		VAR_OUTPUT
			output (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL RetryCounter::Read
		VAR_OUTPUT
			output (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL StrDriveType::Read
		VAR_OUTPUT
			output (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL StrDriveType::Write
		VAR_INPUT
			input (EAX) 	: UDINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL AxisAvailable::Write
		VAR_INPUT
			input (EAX) 	: BDINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: BDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL HWVersion::Read
		VAR_OUTPUT
			output (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL HWVersion::Write
		VAR_INPUT
			input (EAX) 	: UDINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL FwVersionDrive::Read
		VAR_OUTPUT
			output (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL FwVersionDrive::Write
		VAR_INPUT
			input (EAX) 	: UDINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL FwVersionSafety::Read
		VAR_OUTPUT
			output (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL FwVersionSafety::Write
		VAR_INPUT
			input (EAX) 	: UDINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: UDINT;
		END_VAR;
  //Tables:
	FUNCTION @STD
		VAR_OUTPUT
			ret_code	: CONFSTATES;
		END_VAR;
	FUNCTION GLOBAL TAB @CT_;
END_CLASS;

#pragma using String
#pragma usingLtd _StdLib
#pragma usingLtd _TaskObjectControl


//}}LSL_DECLARATION


FUNCTION GLOBAL TAB MDD2000MngBase::@CT_
0$UINT,
2#0100000000000000$UINT, //TY_MDD2000MNGBASE
1$UINT, 2$UINT, (SIZEOF(::MDD2000MngBase))$UINT, 
17$UINT, 9$UINT, 0$UINT, 
TO_UDINT(4153957792), "MDD2000MngBase", //Class
TO_UDINT(0), 0, 0$UINT, 0$UINT, //Baseclass
//Servers:
(::MDD2000MngBase.CmdState.pMeth)$UINT, _CH_CMD$UINT, 2#0000000000000000$UINT, TO_UDINT(3787497970), "CmdState", 
(::MDD2000MngBase.ClassState.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1096059024), "ClassState", 
(::MDD2000MngBase.Online.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1858763116), "Online", 
(::MDD2000MngBase.Release.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2701327623), "Release", 
(::MDD2000MngBase.DeviceAddress.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(19004412), "DeviceAddress", 
(::MDD2000MngBase.VendorID.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2218535187), "VendorID", 
(::MDD2000MngBase.DeviceID.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(4261957967), "DeviceID", 
(::MDD2000MngBase.RetryCounter.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(3383993698), "RetryCounter", 
(::MDD2000MngBase.DriveType.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1915542502), "DriveType", 
(::MDD2000MngBase.StrDriveType.pMeth)$UINT, _CH_SVR_OBJ$UINT, 2#0000000001000000$UINT, TO_UDINT(3516102920), "StrDriveType", 
(::MDD2000MngBase.AxisAvailable.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2910492347), "AxisAvailable", 
(::MDD2000MngBase.SerialNo.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1856804640), "SerialNo", 
(::MDD2000MngBase.HWVersion.pMeth)$UINT, _CH_SVR_OBJ$UINT, 2#0000000001000000$UINT, TO_UDINT(3247816137), "HWVersion", 
(::MDD2000MngBase.FwVersionDrive.pMeth)$UINT, _CH_SVR_OBJ$UINT, 2#0000000001000000$UINT, TO_UDINT(1995891270), "FwVersionDrive", 
(::MDD2000MngBase.FwVersionSafety.pMeth)$UINT, _CH_SVR_OBJ$UINT, 2#0000000001000000$UINT, TO_UDINT(1932912004), "FwVersionSafety", 
(::MDD2000MngBase.SafetyNumber.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2430374202), "SafetyNumber", 
(::MDD2000MngBase.SafetyRunState.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1037834220), "SafetyRunState", 
//Clients:
(::MDD2000MngBase.cOnline.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000010$UINT, TO_UDINT(931620949), "cOnline", 
(::MDD2000MngBase.coStdLib.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000000$UINT, TO_UDINT(3815072667), "coStdLib", TO_UDINT(3689364044), "_StdLib", 2$UINT, 0$UINT, 
(::MDD2000MngBase.To_TaskObjectControl.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000000$UINT, TO_UDINT(2751224004), "To_TaskObjectControl", TO_UDINT(1584830088), "_TaskObjectControl", 1$UINT, 1$UINT, 
(::MDD2000MngBase.ToBusIF.pCh)$UINT, _CH_CLT_CMD$UINT, 2#0000000000000000$UINT, TO_UDINT(3135692506), "ToBusIF", 
(::MDD2000MngBase.toSafetyRunState.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(2194086269), "toSafetyRunState", 
(::MDD2000MngBase.DriveTypeStr.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000010$UINT, TO_UDINT(930233636), "DriveTypeStr", TO_UDINT(1850111279), "String", 1$UINT, 11$UINT, 
(::MDD2000MngBase.FwNumString.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000010$UINT, TO_UDINT(4286323315), "FwNumString", TO_UDINT(1850111279), "String", 1$UINT, 11$UINT, 
(::MDD2000MngBase.FwSafeNumString.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000010$UINT, TO_UDINT(3576862559), "FwSafeNumString", TO_UDINT(1850111279), "String", 1$UINT, 11$UINT, 
(::MDD2000MngBase.HWNumString.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000010$UINT, TO_UDINT(2903126389), "HWNumString", TO_UDINT(1850111279), "String", 1$UINT, 11$UINT, 
END_FUNCTION


#define USER_CNT_MDD2000MngBase 34

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	IF CmdState.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	ClassState.pMeth			:= StoreMethod( #ClassState::Read(), #M_NO_F() );
	IF ClassState.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	Online.pMeth			:= StoreMethod( #Online::Read(), #M_NO_F() );
	IF Online.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	Release.pMeth			:= StoreMethod( #Release::Read(), #M_NO_F() );
	IF Release.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	DeviceAddress.pMeth			:= StoreMethod( #DeviceAddress::Read(), #M_NO_F() );
	IF DeviceAddress.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	VendorID.pMeth			:= StoreMethod( #VendorID::Read(), #M_NO_F() );
	IF VendorID.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	DeviceID.pMeth			:= StoreMethod( #DeviceID::Read(), #M_NO_F() );
	IF DeviceID.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	RetryCounter.pMeth			:= StoreMethod( #RetryCounter::Read(), #M_NO_F() );
	IF RetryCounter.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	DriveType.pMeth			:= StoreMethod( #M_RD_DIRECT(), #M_WR_DIRECT() );
	IF DriveType.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	_memcpy((#vmt.CmdTable)$^USINT, StrDriveType.pMeth, SIZEOF(CMDMETH));
	vmt.CmdTable.nCmds		:= nSTDCMD;
	vmt.CmdTable.Read		:= #StrDriveType::Read();
	vmt.CmdTable.Write		:= #StrDriveType::Write();
	StrDriveType.pMeth		:= StoreCmd (pCmd := #vmt.CmdTable, SHARED);

	IF StrDriveType.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	AxisAvailable.pMeth			:= StoreMethod( #M_RD_DIRECT(), #AxisAvailable::Write() );
	IF AxisAvailable.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	_memcpy((#vmt.CmdTable)$^USINT, HWVersion.pMeth, SIZEOF(CMDMETH));
	vmt.CmdTable.nCmds		:= nSTDCMD;
	vmt.CmdTable.Read		:= #HWVersion::Read();
	vmt.CmdTable.Write		:= #HWVersion::Write();
	HWVersion.pMeth		:= StoreCmd (pCmd := #vmt.CmdTable, SHARED);

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

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

	IF FwVersionSafety.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	ret_code	:= MDD2000MngBase();

END_FUNCTION

#pragma usingLtd HwcLogging
#pragma usingLtd SigCLib

//{{LSL_IMPLEMENTATION
#ifdef MDD2000CommL2
  VAR_GLOBAL
    G_SDD_HW_Count  : UDINT;
    G_SDD_HW_DATA   : ARRAY[0..254] of UDINT;
  END_VAR
#else
  VAR_EXTERNAL
    G_SDD_HW_Count  : UDINT;
    G_SDD_HW_DATA   : ARRAY[0..254] of UDINT;
  END_VAR
#endif

  #if MDD2000MNG_ASY_TIMEOUT < 20000
    #pragma message("Timeout for asynchronous communication is too small - will be set to default (3000000 microseconds) - please set SDD_ASY_TIMEOUT in file SDDDefinitions.h")
    #undef MDD2000MNG_ASY_TIMEOUT
    #define MDD2000MNG_ASY_TIMEOUT 3000000
  #endif

VAR_PRIVATE
  //Private Variables for CMD_GET_HARDWARE_DIAGNOSIS AND CMD_GET_HARDWARE_TREE_ENTRY  
  a_HWTEntryStr   : ARRAY[0.. VARAN_MAX_DEPTH+1] OF CHAR;  // VaranMaxDepth +1 because length is 2 byte long
  a_SerialNo      : ARRAY[0..31] OF CHAR;
  a_FWVersion     : ARRAY[0..31] OF CHAR;
END_VAR
  
FUNCTION VIRTUAL GLOBAL MDD2000MngBase::Init
VAR
	objinfo : LSLOBJ_INFO;
  MyPara   : CmdStruct;
  MyResult : results;   
END_VAR

  // erst im 2.ten Init, da im 1.Init sich die Achsbausteine anmelden
  if InitCounter = 1 then
  
    //Initialize logging
    #ifdef HWC_LogInit
      HWC_LogInit();
    #endif
    
    //*****************************************************************************
    //** compute timeout for asynchronous parameters                             **
    //*****************************************************************************
    objinfo.period := 0;
    IF  To_TaskObjectControl.GetObjectInfo(this,  OBJ_CT, #objinfo) = 0 THEN
      IF objinfo.period AND 16#8000_0000 THEN
        objinfo.period := objinfo.period AND 16#7FFF_FFFF;
      ELSE
        objinfo.period := objinfo.period * 1000;
      END_IF;
      IF objinfo.period <> 0 THEN
        udCycleTimems := objinfo.period;
        ud_TimeoutCycles := ( MDD2000MNG_ASY_TIMEOUT / objinfo.period ) + 5;
      ELSE
        udCycleTimems := 10000;
        ud_TimeoutCycles := 300 + 5;  //Rev. 1.16: Timeout calculated with default Cyclic of 10ms
      END_IF;
    ELSE
      udCycleTimems := 10000;
      ud_TimeoutCycles := 300 + 5;    //Rev. 1.16: Timeout calculated with default Cyclic of 10ms
    END_IF;
        
    // Set the extended axis info    
    MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_STARTCOMMUNICATION;
    MyPara.aPara[0] := 0; // to_dint(AxisExtendAll); AxisExtendAll is not used anymore
    MyPara.aPara[1] := 0; //to_dint(AxisFastAll); AxisFast is not used anymore
    MyPara.aPara[2] := (#AxisAvailable)$DINT;
    MyPara.aPara[3] := (AxisActive)$DINT; 
    ToBusIF.NewInst(#MyPara, #MyResult);
       
    // Set the callback pointer for diagnosis call
    MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_SET_OBJECT_CALLBACK;
    MyPara.aPara[0] := this$DINT; 
    ToBusIF.NewInst(#MyPara, #MyResult); 
    
    // initialize the global variables for the Lasal2 communication
    G_SDD_HW_Count := 0;
    _memset(#G_SDD_HW_DATA[0], 16#00, sizeof(G_SDD_HW_DATA));
    
    // initialize SafetyRunState (enum <> 0)
    SafetyRunState := SafetyRunStateInternal := t_e_MDD2000SafetyRunState::_INACTIVE;
  end_if;
  
  // necessary for Lasal2 to communicate with the SDDIntfc objects
  if (_firstscan = TRUE) then
    if G_SDD_HW_Count >= (sizeof(G_SDD_HW_DATA) / sizeof(G_SDD_HW_DATA[0])) then
      // maximum count of _DriveMng Objects reached
      HWC_LogError(this,"@094E (MDD2000MngBase::Init) Maximum count of drive objects reached for DiasDrive-Tool");
      G_SDD_HW_Count := 0;
    end_if;
    G_SDD_HW_DATA[G_SDD_HW_Count] := this$UDINT;
    G_SDD_HW_Count += 1;
  end_if;
    
  InitCounter += 1;
  
END_FUNCTION

FUNCTION VIRTUAL MDD2000MngBase::InitModule
  VAR
  	AxisIdx      : USINT;
    x       : USINT;
    MyPara   : CmdStruct;
    MyResult : results;  
  END_VAR

  case eInitSSW of

//*********************************************************************************************************  
  	t_e_InitSSW::_StartInit:
    
      if (cOnline) & (AxisAvailable) & 
         (GetVaranDriveState() > 0) then // 0 .. _InitAxis, 1 .. _GetSendParaList (Write Axis Tables to drive, 2 .. _WaitForSynchrony , 3 .. _Operational)
        
        eInitSSW := t_e_InitSSW::_Wait4AxisConfig;
        
      end_if;
      
//*********************************************************************************************************
    t_e_InitSSW::_Wait4AxisConfig:

      for x := 0 to MDD2000MNG_MAXENTRIES -1 do
        if (AxBuffer[x].pThis <> NIL) then
          if(AxBuffer[x].bdStates.InitFinished = FALSE) & (AxBuffer[x].AxisOk = 1) then
            return;
          end_if;
        else
          exit;
        end_if;
      end_for;
  
      bdSettings.AxisInit := TRUE;
  
      MyPara.uiCmd := BUSIF_DRIVEMNGBASE_EXTERN_INIT_FINISH;
      ToBusIF.NewInst(#MyPara, #MyResult);
      
      eInitSSW := t_e_InitSSW::_ReadDriveParaMeter;
  	
//*********************************************************************************************************
    t_e_InitSSW::_ReadDriveParaMeter:
    
      if (GetVaranDriveState() >= 2) then
      
        // re-read the device-id to get the drive-type. it may have changed
        DeviceID.Read();
    
        // get the standard information of the drive
        AxisIdx := GetFirstAxIndex();
        
        bdWait4HwInfoResponse := 0;
        if AxisIdx <> 16#FF then
          //Get I-Type parameter (is needed to determine the correct drive type)
          //I-Type only available at newer drives (MDD100 and SDD1xx-SDD3xx does not have I-Type Paramete, there is I-FBB Parameter with this para number)
          if AddASyncEntryDS402(AxisIdx     :=  AxisIdx
                              , uiParaID    :=  MDD2000_PID_SIGMATEKPARA_INDEX_INFO
                              , usParaSubID :=  MDD2000_SPID_I_TYPE
                              , usRdWr      :=  0
                              , pValue      :=  NIL
                              , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                              , pThisObj    :=  this
                              , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                              , udTimeout   :=  0) = 0 then
            bdWait4HwInfoResponse.I_Type := TRUE;
          else
            HWC_LogPrintf(this,"@081D (MDD2000MngBase::InitModule) Failed to read Parameter I-TYPE.");
          end_if;
                        
          if AddASyncEntryDS402(AxisIdx     :=  AxisIdx
                              , uiParaID    :=  MDD2000_PID_SIGMATEKPARA_INDEX_INFO
                              , usParaSubID :=  MDD2000_SPID_I_HW
                              , usRdWr      :=  0
                              , pValue      :=  NIL
                              , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                              , pThisObj    :=  this
                              , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                              , udTimeout   :=  0) = 0 then
            bdWait4HwInfoResponse.I_HW := TRUE;
          else
            HWC_LogPrintf(this,"@081E (MDD2000MngBase::InitModule) Failed to read Parameter I-HW.");
          end_if;
          
          // at the other drives we show the serial number of the first axis
          if AddASyncEntryDS402(AxisIdx     :=  AxisIdx
                              , uiParaID    :=  MDD2000_PID_SIGMATEKPARA_INDEX_INFO
                              , usParaSubID :=  MDD2000_SPID_I_SER
                              , usRdWr      :=  0
                              , pValue      :=  NIL
                              , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                              , pThisObj    :=  this
                              , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                              , udTimeout   :=  0) = 0 then
            bdWait4HwInfoResponse.I_SER := TRUE;
          else
            HWC_LogPrintf(this,"@081F (MDD2000MngBase::InitModule) Failed to read Parameter I-SER.");
          end_if;

          if AddASyncEntryDS402(AxisIdx     :=  AxisIdx
                              , uiParaID    :=  MDD2000_PID_SIGMATEKPARA_INDEX_INFO
                              , usParaSubID :=  MDD2000_SPID_I_FW
                              , usRdWr      :=  0
                              , pValue      :=  NIL
                              , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                              , pThisObj    :=  this
                              , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                              , udTimeout   :=  0) = 0 then
            bdWait4HwInfoResponse.I_FW := TRUE;
          else
            HWC_LogPrintf(this,"@0820 (MDD2000MngBase::InitModule) Failed to read Parameter I-FW.");
          end_if;
          
          eInitSSW := t_e_InitSSW::_Wait4DriveParameter;
          
        end_if;
      end_if;
      
//*********************************************************************************************************
    t_e_InitSSW::_Wait4DriveParameter:
      
      //Check if we already got the resonse of all needed infos (is used to wait before we have all infos before the online server will be set)
      if bdWait4HwInfoResponse = 0 then        
        
        eInitSSW := t_e_InitSSW::_ReadSafetyDriveParameter;
        //*****************************************************************************   
        
        if abs(FwVersionInt) < MDD2000MNGBASE_FKTFWVERSION_SAFETYSUPPORT then
          eInitSSW := t_e_InitSSW::_EndInit; // Safety not supported by FW, Skip step.
        end_if;

        
      end_if;
  	
//*********************************************************************************************************
    t_e_InitSSW::_ReadSafetyDriveParameter:
      
      AxisIdx := GetFirstAxIndex();
      
      bSafetyActive := FALSE;
      bdWait4SafetyInfoResponse := 0;
      if AddASyncEntryDS402(AxisIdx     :=  AxisIdx
                          , uiParaID    :=  MDD2000_PID_SAFETY_IMG_INFO
                          , usParaSubID :=  MDD2000_SPID_SAFETY_IMG_FWVERSION
                          , usRdWr      :=  0
                          , pValue      :=  NIL
                          , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                          , pThisObj    :=  this
                          , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                          , udTimeout   :=  0) = 0 then
        bdWait4SafetyInfoResponse.FwVersion := TRUE;
      else
        HWC_LogPrintf(this,"@08B4 (MDD2000MngBase::InitModule) Failed to read Parameter FwVersionSafety.");
      end_if;
      
      if AddASyncEntryDS402(AxisIdx     :=  AxisIdx
                          , uiParaID    :=  MDD2000_PID_SAFETY_CFG_INFO
                          , usParaSubID :=  MDD2000_SPID_SAFETY_NO
                          , usRdWr      :=  0
                          , pValue      :=  NIL
                          , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                          , pThisObj    :=  this
                          , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                          , udTimeout   :=  0) = 0 then
        bdWait4SafetyInfoResponse.SafetyNo := TRUE;
      else
        HWC_LogPrintf(this,"@08B5 (MDD2000MngBase::InitModule) Failed to read Parameter SafetyNumber.");
      end_if;
      
      // Check if RT SafetyRunState is suported
      if (IsClientConnected(input:=#toSafetyRunState)) & 
         (toSafetyRunState.Read() <> t_e_MDD2000SafetyRunState::_INACTIVE) then 
      
        bdSettings.RtSafetyRunState := TRUE;
        SafetyRunStateInternal := toSafetyRunState.Read();
        if sSafetyCfgChg.bdFaultInfo = 0 then
          SafetyRunState := SafetyRunStateInternal;
        else
          SafetyRunState := _FSOE_COMSETUPFAILED;
        end_if;        
        
      else // Read SafetyRunState Asynchrone
      
        bdSettings.RtSafetyRunState := FALSE; 
        
        if AddASyncEntryDS402(AxisIdx     :=  AxisIdx
                            , uiParaID    :=  MDD2000_PID_SAFETY_RUN_INFO
                            , usParaSubID :=  MDD2000_SPID_SAFETY_RUN_STATE
                            , usRdWr      :=  0
                            , pValue      :=  NIL
                            , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                            , pThisObj    :=  this
                            , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                            , udTimeout   :=  0) = 0 then
          bdWait4SafetyInfoResponse.RunState := TRUE;
        else
          HWC_LogPrintf(this,"@08B6 (MDD2000MngBase::InitModule) Failed to read Parameter SafetyRunState.");
        end_if;
      end_if;
      
      if AddASyncEntryDS402(AxisIdx     := AxisIdx
                          , uiParaID    := MDD2000_PID_SAFETY_CFG_INFO
                          , usParaSubID := MDD2000_SPID_SAFETY_CFG_CRC
                          , usRdWr      := 0
                          , pValue      := NIL
                          , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                          , pThisObj    := this) = 0 then
            
              
        bdWait4SafetyInfoResponse.CFG_CRC := TRUE;
      else
        HWC_LogPrintf(this,"@08E8 (MDD2000MngBase::InitModule) Failed to read Parameter SafetyCFGCRC.");
      end_if;
    
      eInitSSW := t_e_InitSSW::_Wait4ReadSafetyDriveParameter;
      
//*********************************************************************************************************
    t_e_InitSSW::_Wait4ReadSafetyDriveParameter:
    
      if bdWait4SafetyInfoResponse = 0 then 
        bSafetyActive := TRUE;
        eInitSSW := t_e_InitSSW::_EndInit;
  	  end_if;
      
//*********************************************************************************************************
    t_e_InitSSW::_EndInit:
    
      bdSettings.InitModuleDone := TRUE;
      SetParaState(MDD2000MNG_IF_UPDATEPARACLASS_STATE_GENERAL_READY); // Now we tell all the connected classes, that our initialization is done and okay
      if bSafetyActive then
        LastSafetyRunState := SafetyRunStateInternal;
        SetParaState(ActState:=MDD2000MNG_IF_UPDATEPARACLASS_STATE_SAFETY_READY);  // Now we tell all the connected safety classes, that our initialization is done and okay        
        if SafetyRunStateInternal = t_e_MDD2000SafetyRunState::_ERROR then
          SetParaState(ActState:=MDD2000MNG_IF_UPDATEPARACLASS_STATE_SAFETY_ERROR);
        else
          SetParaState(ActState:=MDD2000MNG_IF_UPDATEPARACLASS_STATE_SAFETY_CHANGED, StateInfo:=SafetyRunState$DINT);
        end_if;

      end_if;
  	
//*********************************************************************************************************
    t_e_InitSSW::_ErrorInit:
    
  end_case;


END_FUNCTION

FUNCTION VIRTUAL GLOBAL MDD2000MngBase::CyWork
	VAR_INPUT
		EAX 	: UDINT;
	END_VAR
	VAR_OUTPUT
		state (EAX) 	: UDINT;
	END_VAR
  VAR
  	x           : DINT;
    pThisCyWork : ^void;
    pAxBuff     : ^_AXDEF;
  END_VAR
  
  ud_CycleCounter += 1;

  // *********************************************************************************************************
  // ** update all server parameters
  // *********************************************************************************************************
  UpdateSvr();
  
  bdSettings.DriveIsInitialized := DriveInitState();
  
  // ***************************************************************************************************************
  // ** Hardware ist verbunden und Varan Kommunikation ist initialisiert.                                         **
  // ** nun können wir schauen welche Achsen nicht nur softwaremässig sondern auch hardwaremässig vorhanden sind  **
  // ***************************************************************************************************************
  if bdSettings.HwConnect = TRUE then
    // set the Axis-objects to the correct state
    InitAxisState();
    bdSettings.HwConnect := FALSE;
  end_if;
  
// *********************************************************************************************************
// ** call the cywork method of all available axis objects                                                **
// *********************************************************************************************************
  for x := 0 to (MDD2000MNG_MAXENTRIES - 1) do
    pAxBuff := #AxBuffer[x];
    if pAxBuff^.pThis <> NIL then
      if pAxBuff^.AxisOk = 1 then
        pThisCyWork := pAxBuff^.pThis;
        pThisCyWork$^VirtualBase^.CyWork(EAX);       
      end_if;
    else
      exit;
    end_if;
  end_for;


  // only if hardware is online 
  if cOnline = 1 then
    
// *********************************************************************************************************
// ** check if asyncronous information is needed	                                                        **
// *********************************************************************************************************
    UpdateASync();    
    
    if (bdSettings.InitModuleDone = FALSE) then
      
      InitModule();
      
    end_if;
                      
    if Online.read() then
    
      if AxisAvailable then
        //Set sysdate/systime to drive
        //--------------------------------------------------------------------------------------------  
        SetSystemTimeAtDrive(AxisIdx:=0);
      end_if;
      
      if (s_LogFileV.eGetLogFileSSW <> t_e_GetLogFileSSW::IdleGetLogFile) then
        GetLogFileCyclic();
      end_if;
      
      if bSafetyActive then
        UpdateSafetyCy();
      end_if;
      
      // Update Parameter Classes
      SetParaState(ActState:=MDD2000MNG_IF_UPDATEPARACLASS_STATE_UPDATE_CY, SafetyRunStateInternal$DINT);

    end_if;

  else
  
    Online := 0;
    
    s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::IdleGetLogFile;
    ReleaseFileHandling();

    if bdSettings.AxisInit = TRUE then
      // Reset the info AxisInit 
      ResetAxisInit();
    end_if;
    eInitSSW := t_e_InitSSW::_StartInit;
    
    bdSettings.DriveIsInitialized := FALSE;
    bdSettings.AxisInit           := FALSE;
    
    bdSettings.InitModuleDone     := FALSE;
    bdSettings.ResetSafetyAxis    := FALSE;
    bdSettings.ResetSafeVerify    := FALSE;
    bdSettings.QuitSafetyError    := FALSE;
    bdSettings.SetServiceMode     := FALSE;
    bdSettings.LeaveServiceMode   := FALSE;
    bdSettings.SafetyConfigChanged:= FALSE;
    
    SSWUpdateSafety               := t_e_SSWSafetyCy::_Start;
    SSWSafetyChangeServiceMode    := t_e_SSWSafetyChangeServiceMode::_Idle;
    sSafetyCfgChg.SSWSafetyCfgChg := t_e_SSWSafetyCfgChg::_Idle;
    sSafetyCfgChg.bdFaultInfo     := 0;
        
    DriveType := _NotFound;
    DriveTypeStr.Clear();
    
    SerialNo  := 0;
    
    HWNumString.Clear();
    FwNumString.Clear();
    
    FwSafeNumString.Clear();
    
    SafetyNumber    := 0;
    SafetyRunState  := SafetyRunStateInternal := t_e_MDD2000SafetyRunState::_INACTIVE;

  end_if;
    
  state := READY;

END_FUNCTION

FUNCTION VIRTUAL MDD2000MngBase::UpdateSafetyCy
VAR
	idx : DINT;
  bVerifyOk : BOOL;
  bResetVerify : BOOL;
  dvalue : DINT;
  myretcode : iprStates;
END_VAR

  case SSWUpdateSafety of
  
// *********************************************************************************************************  
  	t_e_SSWSafetyCy::_Start:
    
      if bdWait4SafetyInfoResponse = 0 then
        SSWUpdateSafety := t_e_SSWSafetyCy::_UpdateSafetyState;
      end_if;

// *********************************************************************************************************
  	t_e_SSWSafetyCy::_UpdateSafetyState:
    
      if bdSettings.RtSafetyRunState = TRUE then
         
        SafetyRunStateInternal := toSafetyRunState.Read();        
        if sSafetyCfgChg.bdFaultInfo = 0 then
          SafetyRunState := SafetyRunStateInternal;
        else
          SafetyRunState := _FSOE_COMSETUPFAILED;
        end_if;  
        SSWUpdateSafety := t_e_SSWSafetyCy::_Wait4UpdateSafetyState;
      
      else
      
        if AddASyncEntryDS402(AxisIdx     :=  GetFirstAxIndex()
                            , uiParaID    :=  MDD2000_PID_SAFETY_RUN_INFO
                            , usParaSubID :=  MDD2000_SPID_SAFETY_RUN_STATE
                            , usRdWr      :=  0
                            , pValue      :=  NIL
                            , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                            , pThisObj    :=  this
                            , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                            , udTimeout   :=  0) = 0 then
          SSWUpdateSafety := t_e_SSWSafetyCy::_Wait4UpdateSafetyState;
          bdWait4SafetyInfoResponse.RunState := TRUE;
        else
          SSWUpdateSafety := t_e_SSWSafetyCy::_Error;                  
          HWC_LogPrintf(this,"@08B7 (MDD2000MngBase::UpdateSafetyCy) Failed to read Parameter SafetyRunState.");
        end_if;
      
      end_if;

// *********************************************************************************************************
  	t_e_SSWSafetyCy::_Wait4UpdateSafetyState:
    
      if bdWait4SafetyInfoResponse.RunState = FALSE then
        
        if LastSafetyRunState <> SafetyRunStateInternal then
        
          if SafetyRunStateInternal = t_e_MDD2000SafetyRunState::_ERROR then
            SetParaState(ActState:=MDD2000MNG_IF_UPDATEPARACLASS_STATE_SAFETY_ERROR, SafetyRunStateInternal$DINT);  // Now we tell all the connected safety classes, to update their safetystate
          else
            SetParaState(ActState:=MDD2000MNG_IF_UPDATEPARACLASS_STATE_SAFETY_CHANGED, SafetyRunStateInternal$DINT);  // Now we tell all the connected safety classes, to update their safetystate
            
            if (SafetyRunStateInternal = t_e_MDD2000SafetyRunState::_TEMP_OP) then
              // Reset all Verify and Zeropos bits. New safe Config may have been downloaded
              ResetAxisSafeVerifyZeroPos();
            end_if;

          end_if;
          
          // Check for change in Config state
          if (LastSafetyRunState = t_e_MDD2000SafetyRunState::_SERVICE) & // Config can only change in Service Mode
             (bdWait4SafetyInfoResponse.CFG_CRC = FALSE)  then  
          
            if AddASyncEntryDS402(AxisIdx     := GetFirstAxIndex()
                                , uiParaID    := MDD2000_PID_SAFETY_CFG_INFO
                                , usParaSubID := MDD2000_SPID_SAFETY_CFG_CRC
                                , usRdWr      := 0
                                , pValue      := NIL
                                , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                                , pThisObj    := this) = 0 then
            
              
              bdWait4SafetyInfoResponse.CFG_CRC := TRUE;
            end_if;
            
          elsif (LastSafetyRunState = t_e_MDD2000SafetyRunState::_ERROR) then 
            
            bdSettings.SafetyConfigChanged := TRUE; // Always Recheck the configuration after _ERROR, no valid config can be read during _ERROR even if a valid crc is returned.
            
          end_if;
          
          // Reset SafetySubRunState
          sSafetyCfgChg.SafetySubRunState := t_e_MDD2000SafetySubRunState::Invalid;
          
        end_if;
        
        LastSafetyRunState := SafetyRunStateInternal;
        
        // Decide which step to handle next
        if bdSettings.QuitSafetyError then
        
          bdSettings.QuitSafetyError:= FALSE;
          
          SSWUpdateSafety := t_e_SSWSafetyCy::_QuitSafetyError;
          
        elsif (bdSettings.SetServiceMode) then 
         
          bdSettings.SetServiceMode := FALSE;
          if (SafetyRunStateInternal <> t_e_MDD2000SafetyRunState::_SERVICE) then
            SSWUpdateSafety     := t_e_SSWSafetyCy::_SetServiceMode;
            SSWUpdateSafetySetServicemodeNext := t_e_SSWSafetyCy::_Done;  // State that is called after _SetServiceMode finished
          else
            // Nothing to do
            SSWUpdateSafety := t_e_SSWSafetyCy::_Done;
          end_if;
        
        elsif (bdSettings.LeaveServiceMode) then
        
          bdSettings.LeaveServiceMode := FALSE;
          if (SafetyRunStateInternal = t_e_MDD2000SafetyRunState::_SERVICE) then
            SSWUpdateSafety     := t_e_SSWSafetyCy::_LeaveServiceMode;
          else
            // Nothing to do
            SSWUpdateSafety := t_e_SSWSafetyCy::_Done;
          end_if;
          
        elsif bdSettings.ResetSafetyAxis then
          
          bdSettings.ResetSafetyAxis := FALSE;
          
          if (SafetyRunStateInternal = t_e_MDD2000SafetyRunState::_ERROR) | (SafetyRunStateInternal = t_e_MDD2000SafetyRunState::_SERVICE) then 
            SSWUpdateSafety := t_e_SSWSafetyCy::_ResetSafetyAxes; // Reset can be done directly in ERROR or SERVICE mode
          elsif (SafetyRunStateInternal = t_e_MDD2000SafetyRunState::_TEMP_OP) | (SafetyRunStateInternal = t_e_MDD2000SafetyRunState::_OP) then
            SSWUpdateSafetySetServicemodeNext := t_e_SSWSafetyCy::_ResetSafetyAxes; // State that is called after _SetServiceMode finished
            SSWUpdateSafety := t_e_SSWSafetyCy::_DelayedSetServiceMode;  // Reset cannot be done, switch to service mode 1st
          end_if;
        
        elsif SafetyRunStateInternal = t_e_MDD2000SafetyRunState::_TEMP_OP then
          SSWUpdateSafety := t_e_SSWSafetyCy::_CheckVerifiedDone;
        else
          // Nothing to do
          SSWUpdateSafety := t_e_SSWSafetyCy::_Done;
        end_if;
        
      end_if;

// *********************************************************************************************************
    t_e_SSWSafetyCy::_CheckVerifiedDone:
    
      bVerifyOk := TRUE;  // Do Countercheck, if 1 axis is not verified cancel 
      
      for idx := 0 to MDD2000MNG_MAXENTRIES -1 do
        if (AxBuffer[idx].pThis <> NIL) then
          if(AxBuffer[idx].bdStates.SafeVerifyDone  = FALSE) | 
            (AxBuffer[idx].bdStates.SafeZeroPosDone = FALSE) then
            // Not all Axis have been Verified
            bVerifyOk := FALSE;
            exit;
          end_if;
        else
          exit;
        end_if;
      end_for; 
      
      SSWUpdateSafety := _Done;
      
      if bVerifyOk then
        SSWUpdateSafetySetServicemodeNext := t_e_SSWSafetyCy::_FinishVerify;  // State that is called after _SetServiceMode finished
        SSWUpdateSafety := t_e_SSWSafetyCy::_DelayedSetServiceMode;
      end_if;

// *********************************************************************************************************      
    t_e_SSWSafetyCy::_DelayedSetServiceMode:
    
      udTimeStampDelaySetServiceMode := ops.tAbsolute;
      SetParaState(ActState:=MDD2000MNG_IF_UPDATEPARACLASS_STATE_SAFETY_SETSERVICEMODE_PENDING, SafetyRunStateInternal$DINT); // Inform connected object that a change to service mode wil be performed
      SSWUpdateSafety := t_e_SSWSafetyCy::_Wait4SetServiceMode;
      
// *********************************************************************************************************
    t_e_SSWSafetyCy::_Wait4SetServiceMode:
      // Wait for all axis to be disabled before switching to service Mode
      if (IsAnyAxisEnabled() = FALSE) | 
         ( (ops.tAbsolute - udTimeStampDelaySetServiceMode) > MDD2000MNG_DELAYSETSERVICEMODE_TIMEOUT) then
        SSWUpdateSafety := t_e_SSWSafetyCy::_SetServiceMode;
      end_if;

// *********************************************************************************************************
    t_e_SSWSafetyCy::_SetServiceMode:
    
      myretcode := SafetyChangeServiceMode(SetLeaveServiceMode:=TRUE);
      
      if myretcode = READY then
        SSWUpdateSafety := SSWUpdateSafetySetServicemodeNext;
      elsif myretcode = ERROR then
        SSWUpdateSafety := t_e_SSWSafetyCy::_Error;
      end_if;

// *********************************************************************************************************
    t_e_SSWSafetyCy::_FinishVerify:
    
      dvalue := 1;
      if AddASyncEntryDS402(AxisIdx     := GetFirstAxIndex()
                          , uiParaID    := MDD2000_PID_SAFETY_COMMANDS
                          , usParaSubID := MDD2000_SPID_SAFETY_FINISH_VERIFY
                          , usRdWr      := 1
                          , pValue      := #dvalue
                          , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                          , pThisObj    := this) = 0 then
        bdWait4SafetyInfoResponse.FinishVerify := TRUE;
        SSWUpdateSafety := t_e_SSWSafetyCy::_Wait4FinishVerify;
      else
        SSWUpdateSafety := t_e_SSWSafetyCy::_Error;                  
        HWC_LogPrintf(this,"@08B8 (MDD2000MngBase::UpdateSafetyCy) Failed to write Parameter finish verify.");
      end_if;

// *********************************************************************************************************
    t_e_SSWSafetyCy::_Wait4FinishVerify:
    
      if bdWait4SafetyInfoResponse.FinishVerify = FALSE then
        SSWUpdateSafety := t_e_SSWSafetyCy::_LeaveServiceMode;
      end_if;

// *********************************************************************************************************
    t_e_SSWSafetyCy::_LeaveServiceMode:
    
      myretcode := SafetyChangeServiceMode(SetLeaveServiceMode:=FALSE);
      if myretcode = READY then
        SSWUpdateSafety := t_e_SSWSafetyCy::_Done;
      elsif myretcode = ERROR then
        SSWUpdateSafety := t_e_SSWSafetyCy::_Error;
      end_if;

// *********************************************************************************************************
    t_e_SSWSafetyCy::_ResetSafetyAxes:
     
      SSWUpdateSafety := t_e_SSWSafetyCy::_Wait4ResetSafetyAxes;
      
      if bdSettings.ResetSafeVerify then
        bdSettings.ResetSafeVerify := FALSE;
        dvalue := 1;
        if AddASyncEntryDS402(AxisIdx     :=  GetFirstAxIndex()
                            , uiParaID    :=  MDD2000_PID_SAFETY_COMMANDS
                            , usParaSubID :=  MDD2000_SPID_SAFETY_RESET_VERIFY
                            , usRdWr      :=  1
                            , pValue      :=  #dValue
                            , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                            , pThisObj    :=  this
                            , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                            , udTimeout   :=  0) = 0 then
                            
          bdWait4SafetyInfoResponse.ResetSafeVerify := TRUE;
        else
          HWC_LogPrintf(this,"@08B9 (MDD2000MngBase::UpdateSafetyCy) Failed to write Parameter reset verify.");
        end_if;
      end_if;
      
      for idx := 0 to MDD2000MNG_MAXENTRIES -1 do
        if (AxBuffer[idx].pThis <> NIL) then
        
          AxBuffer[idx].bdStates.SafeVerifyDone := FALSE; // Reset any active requests to Verify the axis
          
          if (AxBuffer[idx].bdStates.ResetSafeZeroPos = TRUE) then
            
            dvalue := DRIVESAFETYIF_REFCMD_RESET;
            if AddASyncEntryDS402(AxisIdx     :=  idx$USINT
                                , uiParaID    :=  MDD2000_PID_SAFETY_AXIS_INFO
                                , usParaSubID :=  MDD2000_SPID_SAFETY_AXIS_SETZEROPOS
                                , usRdWr      :=  1
                                , pValue      :=  #dValue
                                , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                                , pThisObj    :=  this
                                , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                                , udTimeout   :=  0) = 0 then
              
              AxBuffer[idx].bdStates.ResetSafeZeroPos       := FALSE;
              AxBuffer[idx].bdStates.Wait4ResetSafeZeroPos  := TRUE;
              AxBuffer[idx].bdStates.SafeZeroPosDone        := FALSE; // Reset any active requests to set the zeropos
            else
              HWC_LogPrintf(this,"@08BA (MDD2000MngBase::UpdateSafetyCy) Failed to write Parameter SETZEROPOS.");
            end_if;
            
          end_if;

        end_if;
        
      end_for; 

// *********************************************************************************************************      
    t_e_SSWSafetyCy::_Wait4ResetSafetyAxes:
      
      bResetVerify := TRUE;  // Do Countercheck, if 1 axis SDO is not done => cancel 
      if bdWait4SafetyInfoResponse.ResetSafeVerify = TRUE then  // Check if ResetSafeVerify Response has been recieved
        bResetVerify := FALSE;
      else

        // Check if Wait4ResetSafeZeroPos Response has been received for all axes
        for idx := 0 to MDD2000MNG_MAXENTRIES -1 do
          if (AxBuffer[idx].pThis <> NIL) then
            
            if AxBuffer[idx].bdStates.Wait4ResetSafeZeroPos  = TRUE then
              bResetVerify := FALSE;
              exit;
            end_if;

          end_if;
        end_for;
      end_if;
      
      // All responses received
      if bResetVerify = TRUE then
        
        if (SafetyRunStateInternal = t_e_MDD2000SafetyRunState::_SERVICE) then
          SSWUpdateSafety := t_e_SSWSafetyCy::_LeaveServiceMode;
        elsif (SafetyRunStateInternal = t_e_MDD2000SafetyRunState::_ERROR) then
        
          // Do not need to tell connected objects, will be done in _UpdateSafetyState
          // SetParaState(ActState:=MDD2000MNG_IF_UPDATEPARACLASS_STATE_SAFETY_ERROR);  // Now we tell all the connected safety classes, to update their verify and reference state
          
          SSWUpdateSafety := t_e_SSWSafetyCy::_Done;
        else
          SSWUpdateSafety := t_e_SSWSafetyCy::_Done;  // Case should be impossible, either we were in _ERROR or we used the step t_e_SSWSafetyCy::_SetServiceMode
        end_if;

      end_if;

// *********************************************************************************************************      
    t_e_SSWSafetyCy::_QuitSafetyError:
      
      dValue := 1; //Quit safety error
      
      if AddASyncEntryDS402(AxisIdx     :=  GetFirstAxIndex()
                          , uiParaID    :=  MDD2000_PID_SAFETY_COMMANDS
                          , usParaSubID :=  MDD2000_SPID_SAFETY_ERROR_QUIT
                          , usRdWr      :=  1
                          , pValue      :=  #dValue
                          , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                          , pThisObj    :=  this
                          , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                          , udTimeout   :=  0) <> 0 then
                        
        HWC_LogPrintf(this,"@08BB (MDD2000MngBase::UpdateSafetyCy) Failed to write Parameter Error Quit.");
      end_if;

      SSWUpdateSafety := t_e_SSWSafetyCy::_Done;
      
// *********************************************************************************************************
  	t_e_SSWSafetyCy::_Done:
      SSWUpdateSafety := t_e_SSWSafetyCy::_Start;

// *********************************************************************************************************
    t_e_SSWSafetyCy::_Error:
      SSWUpdateSafety := t_e_SSWSafetyCy::_Start;

// *********************************************************************************************************
  end_case;
  
  if bdSettings.SafetyConfigChanged then
  
    if SafetyConfigChanged() <> BUSY then
      bdSettings.SafetyConfigChanged := FALSE;
    end_if;
  
  end_if; 
 
END_FUNCTION

FUNCTION MDD2000MngBase::SafetyChangeServiceMode
	VAR_INPUT
		SetLeaveServiceMode 	: BOOL;
	END_VAR
	VAR_OUTPUT
		retstate 	: iprStates;
	END_VAR
  VAR
  	dValue : DINT;
  END_VAR

  
  retstate := BUSY;

  case SSWSafetyChangeServiceMode of
// *********************************************************************************************************
  	t_e_SSWSafetyChangeServiceMode::_Idle:
    
      LastSafetyRunState := SafetyRunStateInternal;
      if (SetLeaveServiceMode = TRUE) &
         (SafetyRunStateInternal <> t_e_MDD2000SafetyRunState::_SERVICE) then
        SSWSafetyChangeServiceMode := t_e_SSWSafetyChangeServiceMode::_SetServiceMode;
      elsif (SetLeaveServiceMode = FALSE) &
         (SafetyRunStateInternal = t_e_MDD2000SafetyRunState::_SERVICE) then
        SSWSafetyChangeServiceMode := t_e_SSWSafetyChangeServiceMode::_LeaveServiceMode;
      else
        // Nothing todo
        retstate := READY;
      end_if;

// *********************************************************************************************************
  	t_e_SSWSafetyChangeServiceMode::_SetServiceMode:
      
      dValue := 1;  //Start servicemode
      
      if AddASyncEntryDS402(AxisIdx     :=  GetFirstAxIndex()
                          , uiParaID    :=  MDD2000_PID_SAFETY_COMMANDS
                          , usParaSubID :=  MDD2000_SPID_SAFETY_SETSERVICEMODE
                          , usRdWr      :=  1
                          , pValue      :=  #dValue
                          , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                          , pThisObj    :=  this
                          , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                          , udTimeout   :=  0) = 0 then
        SSWSafetyChangeServiceMode := t_e_SSWSafetyChangeServiceMode::_Wait4SetServiceMode;
        bdWait4SafetyInfoResponse.SetServiceMode := TRUE;
      else
        SSWSafetyChangeServiceMode := t_e_SSWSafetyChangeServiceMode::_Error;                  
        HWC_LogPrintf(this,"@08BC (MDD2000MngBase::SafetyChangeServiceMode) Failed to set servicemode.");
      end_if;

// *********************************************************************************************************
  	t_e_SSWSafetyChangeServiceMode::_Wait4SetServiceMode:
    
      if bdWait4SafetyInfoResponse.SetServiceMode = FALSE then
        SSWSafetyChangeServiceMode := t_e_SSWSafetyChangeServiceMode::_UpdateSafetyState;
      end_if;

// *********************************************************************************************************
  	t_e_SSWSafetyChangeServiceMode::_LeaveServiceMode:
    
      dValue := 1;  //Leave servicemode

      if AddASyncEntryDS402(AxisIdx     :=  GetFirstAxIndex()
                          , uiParaID    :=  MDD2000_PID_SAFETY_COMMANDS
                          , usParaSubID :=  MDD2000_SPID_SAFETY_LEAVESERVICEMODE
                          , usRdWr      :=  1
                          , pValue      :=  #dValue
                          , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                          , pThisObj    :=  this
                          , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                          , udTimeout   :=  0) = 0 then
        SSWSafetyChangeServiceMode := t_e_SSWSafetyChangeServiceMode::_Wait4LeaveServiceMode;
        bdWait4SafetyInfoResponse.LeaveServiceMode := TRUE;
      else
        SSWSafetyChangeServiceMode := t_e_SSWSafetyChangeServiceMode::_Error;                  
        HWC_LogPrintf(this,"@08BD (MDD2000MngBase::SafetyChangeServiceMode) Failed to leave servicemode.");
      end_if;

// *********************************************************************************************************  
  	t_e_SSWSafetyChangeServiceMode::_Wait4LeaveServiceMode:
    
     if bdWait4SafetyInfoResponse.LeaveServiceMode = FALSE then
        SSWSafetyChangeServiceMode := t_e_SSWSafetyChangeServiceMode::_UpdateSafetyState;
      end_if;

// *********************************************************************************************************
  	t_e_SSWSafetyChangeServiceMode::_UpdateSafetyState:
    
      if AddASyncEntryDS402(AxisIdx     :=  GetFirstAxIndex()
                          , uiParaID    :=  MDD2000_PID_SAFETY_RUN_INFO
                          , usParaSubID :=  MDD2000_SPID_SAFETY_RUN_STATE
                          , usRdWr      :=  0
                          , pValue      :=  NIL
                          , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                          , pThisObj    :=  this
                          , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                          , udTimeout   :=  0) = 0 then
        SSWSafetyChangeServiceMode := t_e_SSWSafetyChangeServiceMode::_Wait4UpdateSafetyState;
        bdWait4SafetyInfoResponse.RunState := TRUE;
      else
        SSWSafetyChangeServiceMode := t_e_SSWSafetyChangeServiceMode::_Error;                  
        HWC_LogPrintf(this,"@08DE (MDD2000MngBase::SafetyChangeServiceMode) Failed to read Parameter SafetyRunState.");
      end_if;

// *********************************************************************************************************
  	t_e_SSWSafetyChangeServiceMode::_Wait4UpdateSafetyState:
    
      if bdWait4SafetyInfoResponse.RunState = FALSE then
        if LastSafetyRunState <> SafetyRunStateInternal then
          // Check if state change was successful
          if (SetLeaveServiceMode = TRUE) &
             (SafetyRunStateInternal = t_e_MDD2000SafetyRunState::_SERVICE) then
            SSWSafetyChangeServiceMode := t_e_SSWSafetyChangeServiceMode::_Idle;
            retstate := READY;
          elsif (SetLeaveServiceMode = FALSE) &
             (SafetyRunStateInternal <> t_e_MDD2000SafetyRunState::_SERVICE) then
            SSWSafetyChangeServiceMode := t_e_SSWSafetyChangeServiceMode::_Idle;
            retstate := READY;
          else
            // Unexpected State
            HWC_LogPrintf(this,"@08BF (MDD2000MngBase::SafetyChangeServiceMode) Unexpected SafetyRunState: %d.", #SafetyRunState.dData);
            SSWSafetyChangeServiceMode := t_e_SSWSafetyChangeServiceMode::_Error;
          end_if;
      
        else
          // State has not changed, read again
          SSWSafetyChangeServiceMode := t_e_SSWSafetyChangeServiceMode::_UpdateSafetyState;
        end_if;
      end_if;

// *********************************************************************************************************
    t_e_SSWSafetyChangeServiceMode::_Error:
    
       retstate := ERROR;
       SSWSafetyChangeServiceMode := t_e_SSWSafetyChangeServiceMode::_Idle;
       
  end_case;


END_FUNCTION

FUNCTION VIRTUAL MDD2000MngBase::SafetyConfigChanged
	VAR_OUTPUT
		retstate 	: iprStates;
	END_VAR
  
  retstate := BUSY;

    case sSafetyCfgChg.SSWSafetyCfgChg of
      
// *********************************************************************************************************
    t_e_SSWSafetyCfgChg::_Idle:
      sSafetyCfgChg.SSWSafetyCfgChg := t_e_SSWSafetyCfgChg::Wait4ValidConfig;

// *********************************************************************************************************
    t_e_SSWSafetyCfgChg::Wait4ValidConfig:
    
      if (SafetyRunStateInternal <> t_e_MDD2000SafetyRunState::_CHK_CFG) then
        // Already completed _CHK_CFG => Safety Config is valid
        sSafetyCfgChg.SSWSafetyCfgChg := t_e_SSWSafetyCfgChg::ReadNewConfig;
        
      elsif bdWait4SafetyInfoResponse.SubRunState = FALSE then    
        
        if (sSafetyCfgChg.SafetySubRunState = t_e_MDD2000SafetySubRunState::Invalid) | 
           (sSafetyCfgChg.SafetySubRunState <= t_e_MDD2000SafetySubRunState::CHK_CFG_PARSE_CFG) then 
          // SafetySubRunState is still parsing config, read again. 
          
          // Read Subrunstate
          if AddASyncEntryDS402(AxisIdx     := GetFirstAxIndex()
                              , uiParaID    := MDD2000_PID_SAFETY_RUN_INFO
                              , usParaSubID := MDD2000_SPID_SAFETY_RUN_SUBSTATE
                              , usRdWr      := 0
                              , pValue      := NIL
                              , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                              , pThisObj    := this) = 0 then
        
            bdWait4SafetyInfoResponse.SubRunState := TRUE;
          else
            HWC_LogPrintf(this,"@08E9 (MDD2000MngBase::SafetyConfigChanged) Failed to read Parameter SafetySubRunState.");
            sSafetyCfgChg.SSWSafetyCfgChg :=  t_e_SSWSafetyCfgChg::CfgChgError;
          end_if;
        else
        
          // SafetySubRunState finished parsing config => Safety Config is valid
          sSafetyCfgChg.SSWSafetyCfgChg := t_e_SSWSafetyCfgChg::ReadNewConfig;
          
        end_if;
      end_if;

// *********************************************************************************************************
    t_e_SSWSafetyCfgChg::ReadNewConfig:
    
      if AddASyncEntryDS402(AxisIdx     := GetFirstAxIndex()
                          , uiParaID    := MDD2000_PID_SAFETY_CFG_INFO
                          , usParaSubID := MDD2000_SPID_SAFETY_CFG_OUT_FSOEFRAME
                          , usRdWr      := 0
                          , pValue      := NIL
                          , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                          , pThisObj    := this) = 0 then
        
        bdWait4SafetyInfoResponse.LenOutFSoEFrame := TRUE;
      else
        HWC_LogPrintf(this,"@08EA (MDD2000MngBase::SafetyConfigChanged) Failed to read Parameter SafetyLenOutFSoEFrame.");
      end_if;
      
      if AddASyncEntryDS402(AxisIdx     := GetFirstAxIndex()
                          , uiParaID    := MDD2000_PID_SAFETY_CFG_INFO
                          , usParaSubID := MDD2000_SPID_SAFETY_CFG_IN_FSOEFRAME
                          , usRdWr      := 0
                          , pValue      := NIL
                          , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                          , pThisObj    := this) = 0 then
    
        bdWait4SafetyInfoResponse.LenInFSoEFrame := TRUE;
      else
        HWC_LogPrintf(this,"@08EB (MDD2000MngBase::SafetyConfigChanged) Failed to read Parameter SafetyLenInFSoEFrame.");
      end_if;
      
      if (bdWait4SafetyInfoResponse.LenOutFSoEFrame) & 
         (bdWait4SafetyInfoResponse.LenInFSoEFrame) then
        sSafetyCfgChg.SSWSafetyCfgChg := t_e_SSWSafetyCfgChg::Wait4ReadNewConfig;
      else
        sSafetyCfgChg.SSWSafetyCfgChg :=  t_e_SSWSafetyCfgChg::CfgChgError;
      end_if;

// *********************************************************************************************************
    t_e_SSWSafetyCfgChg::Wait4ReadNewConfig:
      if (bdWait4SafetyInfoResponse.LenOutFSoEFrame = FALSE) & 
         (bdWait4SafetyInfoResponse.LenInFSoEFrame  = FALSE) then
        SendSafteyConfigChanged();
        sSafetyCfgChg.SSWSafetyCfgChg := t_e_SSWSafetyCfgChg::CfgChgFinished;
      end_if;
    
// *********************************************************************************************************
    t_e_SSWSafetyCfgChg::CfgChgFinished:
      sSafetyCfgChg.SSWSafetyCfgChg := t_e_SSWSafetyCfgChg::_Idle;
      retstate := READY;

// *********************************************************************************************************
    t_e_SSWSafetyCfgChg::CfgChgError:
      sSafetyCfgChg.SSWSafetyCfgChg := t_e_SSWSafetyCfgChg::_Idle;
      retstate := ERROR;

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

FUNCTION MDD2000MngBase::AddAxObj
	VAR_INPUT
		pThis 	: ^void;
		AxisNo 	: DINT;
		pAsyPipeHandle 	: ^void;
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR
  VAR
    idx : DINT;
  	AxisBit   : BDINT;
  END_VAR
  
  retcode := ERROR;
  
  // check parameters
  if (pThis = NIL) then
    HWC_LogPrintf(pThis:=this, format:="@08C0 (MDD2000MngBase::AddAxObj): Invalid this pointer!");
    return;
  end_if;
  
  // check if the axis number is correct
  if (AxisNo < 1) | (AxisNo > MDD2000MNG_MAXAXISNO) then
    HWC_LogPrintf(pThis:=this, format:="@08C1 (MDD2000MngBase::AddAxObj): AxisNo %d is not allowed!", #AxisNo);
    return;
  end_if;
  
  //Check for too many logins
  if AxCount = MDD2000MNG_MAXENTRIES then
    HWC_LogPrintf(pThis:=this, format:="@08C2 (MDD2000MngBase::AddAxObj): Error while initialising axis objects. -> too many objects available");
    return;
  end_if;
  
  if pAsyPipeHandle = NIL then
    HWC_LogPrintf(pThis:=this, format:="@08C3 (MDD2000MngBase::AddAxObj): Invalid pointer pAsyPipeHandle!");
    return;
  end_if;
  
  idx := AxisNo - 1;
  if AxBuffer[idx].pThis = NIL then
  
    // set the necessary bit for comparison with the real hardware
    AxisBit := 1;
    AxisBit := AxisBit SHL (AxisNo - 1);
    
    AxisActive := AxisActive OR AxisBit;
  
    AxBuffer[idx].pThis   := pThis;
    AxBuffer[idx].AxisNo  := AxisNo;
    AxBuffer[idx].pAsyPipeHandle := pAsyPipeHandle;
        
    AxCount += 1;
    retcode := READY;
  
  end_if;
  
END_FUNCTION


FUNCTION MDD2000MngBase::InitAxisState
VAR
	x                : UDINT;
  pThisNewInst     : ^void;
  ret_code         : iprStates;
  UserPara         : CmdStruct;
  UserResult       : Results;
  retcode          : BOOL;
  TempAxisAvailHW  : BDINT;
  TempAxisAvailSW  : BDINT;
END_VAR
  
  retcode := FALSE;
  
  AxIndizesL2 := 0; //hashan
  
  for x:= 0 to (MDD2000MNG_MAXENTRIES - 1) do
    TempAxisAvailSW := (AxisActive SHR x) AND 16#01;
    TempAxisAvailHW := (AxisAvailable SHR x) AND 16#01;
    
    if (TempAxisAvailHW = 1) then
      if TempAxisAvailHW = TempAxisAvailSW then
        // Achse ist physikalisch und softwaremässig vorhanden
        if AxBuffer[x].pThis <> NIL then
          AxBuffer[x].AxisOk    := 1;
          AxBuffer[x].AxisIndex := x$USINT;
          AxIndizesL2  += 2#1 SHL x;
        end_if;
      end_if;
    end_if;
  end_for;
    
  // check all axis objects
  for x := 0 to (MDD2000MNG_MAXENTRIES - 1) do
    
    // axis object available
    if AxBuffer[x].pThis <> NIL then
        
      pThisNewInst := AxBuffer[x].pThis;
      
      // set the actual state of the axis object
      UserPara.uiCmd    := MDD2000MNG_IF_SET_AXIS_STATE;
      UserPara.aPara[0] := MDD2000MNG_IF_SET_AXIS_STATE_VER_1;
      UserPara.aPara[1] := to_dint(x);  // laufende Achsnummer vom internen Buffer
                                        // nicht zu verwechseln mit der laufenden Achsnummer im DPRAM
                                        // diese kann unterschiedlich sein (ist in der Struktur _AXDEF.AXISINDEX zu finden
      UserPara.aPara[2] := AxBuffer[x].AxisOk;
      
      ret_code := pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);

    else
      exit;
    end_if;
    
  end_for;
  
END_FUNCTION


FUNCTION MDD2000MngBase::SetParaList
	VAR_INPUT
		usAxis 	: USINT;
		adress 	: ^void;
		ui_counter 	: UINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;   
  END_VAR

  //Sends the adress from Parameter list to the Varan Hardware Class
  
  if adress <> NIL then
    
    MyPara.uiCmd  := BUSIF_DRIVEMNGBASE_SET_PARALIST;
    MyPara.aPara[0] := to_dint(AxBuffer[usAxis].AxisIndex);
    MyPara.aPara[1] := (adress)$DINT;
    MyPara.aPara[2] := to_dint(ui_counter);
    ToBusIF.NewInst(#MyPara, #MyResult);
    retcode := MyResult.aData[0]$DINT;
  
  else
    retcode := -1;
  end_if;
  
END_FUNCTION


FUNCTION MDD2000MngBase::CreateDefParaBase
	VAR_INPUT
		CmdPara 	: ^CmdStruct;
		Results 	: ^results;
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
  END_VAR
  
  CmdPara^.aPara[2] := AxBuffer[CmdPara^.aPara[2]].AxisIndex;
  
  if CmdPara^.uiCmd = 1 then
    CmdPara^.uiCmd  := BUSIF_DRIVEMNGBASE_CREATE_DEF_PARALIST;
    MyPara          := CmdPara^;
    ToBusIF.NewInst(#MyPara, Results);
    retcode := Results^.aData[0]$iprStates;
  end_if;
  
END_FUNCTION

FUNCTION VIRTUAL MDD2000MngBase::GetParameterState
	VAR_INPUT
		usAxis 	: USINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;   
  END_VAR
  
  MyPara.uiCmd  := BUSIF_DRIVEMNGBASE_GET_PARA_STATE;
  MyPara.aPara[0] := to_dint(AxBuffer[usAxis].AxisIndex);
  ToBusIF.NewInst(#MyPara, #MyResult);
  retcode := MyResult.aData[0]$DINT;
  
END_FUNCTION

FUNCTION VIRTUAL MDD2000MngBase::SetParameter
	VAR_INPUT
		usAxis 	: USINT;
		paranr 	: USINT;
		rdwr 	: USINT;
		paravalue 	: DINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;   
  END_VAR
  
  MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_SET_PARAMETER;
  MyPara.aPara[0] := to_dint(usAxis);
  MyPara.aPara[1] := to_dint(DS402_ASYNCPARA_DEFAULT_LASALPARA_INDEX);
  MyPara.aPara[2] := to_dint(paranr);
  MyPara.aPara[3] := to_dint(rdwr); 
  MyPara.aPara[4] := (#paravalue)$DINT;  
  //byte for datalength and offset, not used for standard parameters
  MyPara.aPara[5] := 0;
  ToBusIF.NewInst(#MyPara, #MyResult);
  retcode := MyResult.aData[0]$DINT;
  
END_FUNCTION

FUNCTION MDD2000MngBase::SetParameterDS402
	VAR_INPUT
		usAxis 	: USINT;
		uiParaID 	: UINT;
		usParaSubID 	: USINT;
		usRdWr 	: USINT;
		pparavalue 	: ^USINT;
		bsDataInfo 	: BSINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;
  END_VAR 

  MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_SET_PARAMETER;
  MyPara.aPara[0] := to_dint(usAxis);
  MyPara.aPara[1] := to_dint(uiParaID);
  MyPara.aPara[2] := to_dint(usParaSubID);
  MyPara.aPara[3] := to_dint(usRdWr);
  MyPara.aPara[4] := (pparavalue)$DINT;
  MyPara.aPara[5] := to_dint(bsDataInfo);
  ToBusIF.NewInst(#MyPara, #MyResult);
  retcode := MyResult.aData[0]$DINT;
  
END_FUNCTION



FUNCTION VIRTUAL GLOBAL MDD2000MngBase::AxisAvailable::Write
	VAR_INPUT
		input (EAX) 	: BDINT;
	END_VAR
	VAR_OUTPUT
		result (EAX) 	: BDINT;
	END_VAR

	AxisAvailable := input;
 	result := AxisAvailable;
  bdSettings.HwConnect := TRUE;

END_FUNCTION


FUNCTION VIRTUAL MDD2000MngBase::GetParameter
	VAR_INPUT
		usAxis 	: USINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;
    pTempData: ^USINT;
  END_VAR
  
  MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_PARAMETER;
  MyPara.aPara[0] := to_dint(usAxis);
  ToBusIF.NewInst(#MyPara, #MyResult);
  pTempData := (MyResult.aData[0])$^USINT;
  retcode   := (pTempData)^$DINT;
  
END_FUNCTION


FUNCTION MDD2000MngBase::GetParameterDS402
	VAR_INPUT
		usAxis 	: USINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: ^DINT;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;
    pTempData: ^USINT;
  END_VAR  
  
  MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_PARAMETER;
  MyPara.aPara[0] := to_dint(usAxis);
  ToBusIF.NewInst(#MyPara, #MyResult);
  pTempData := (MyResult.aData[0])$^USINT;
  retcode   := pTempData$^DINT;  
  
END_FUNCTION



FUNCTION VIRTUAL GLOBAL MDD2000MngBase::CmdState::Read
	VAR_OUTPUT
		output (EAX) 	: iprStates;
	END_VAR
  
  output := CmdState;

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MDD2000MngBase::ClassState::Read
	VAR_OUTPUT
		output (EAX) 	: t_e_VaranErrors;
	END_VAR

	VAR
  	oldCmdState   : t_e_VaranErrors;
    x             : UDINT;
    pThisNewInst  : ^void;
    UserPara      : CmdStruct;
    UserResult    : Results;
    MyPara   : CmdStruct;
    MyResult : results;  
  END_VAR

  oldCmdState := ClassState;  

  MyPara.uiCmd   := BUSIF_DRIVEMNGBASE_GET_CMD_STATE;
  ToBusIF.NewInst(#MyPara, #MyResult);
  ClassState := MyResult.aData[0]$t_e_VaranErrors;   
  
  if oldCmdState <> ClassState then
    
    for x := 0 to (MDD2000MNG_MAXENTRIES - 1) do
      if AxBuffer[x].pThis <> NIL then
          
        UserPara.uiCmd    := MDD2000MNG_IF_SET_STATE;  
        UserPara.aPara[0] := MDD2000MNG_IF_SET_STATE_VER_1;
        
        //Set state 0 .. OK, <> 0 ... error or not ready
        UserPara.aPara[1] := CmdState$DINT;
        
        pThisNewInst := AxBuffer[x].pThis;
        pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
      else
        exit;
      end_if;
    end_for;
  end_if;
  
  output := ClassState;

END_FUNCTION


FUNCTION VIRTUAL MDD2000MngBase::UpdateSvr

  CmdState.Read();
  ClassState.Read();
  Online.Read();
  Release.Read();
  VendorID.Read();
  DeviceAddress.Read();
  DeviceID.Read();
  RetryCounter.read();
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::Release::Read
	VAR_OUTPUT
		output (EAX) 	: HDINT;
	END_VAR 
  VAR
    MyPara   : CmdStruct;
    MyResult : results;
  END_VAR

  MyPara.uiCmd  := BUSIF_DRIVEMNGBASE_READ_FPGA_VERSION;
  ToBusIF.NewInst(#MyPara, #MyResult);
  Release := MyResult.aData[0]$HDINT; 

  output := Release;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::DeviceAddress::Read
	VAR_OUTPUT
		output (EAX) 	: HDINT;
	END_VAR
  VAR
    MyPara   : CmdStruct;
    MyResult : results;
  END_VAR

  MyPara.uiCmd  := BUSIF_DRIVEMNGBASE_READ_PARAMETER;
  Mypara.aPara[0] := _BUS_IF_DRVMNG_DEVICEADDRESS;
  if (ToBusIF.NewInst(#MyPara, #MyResult)) = READY then
    DeviceAddress := MyResult.aData[0]$HDINT; 
  else
    DeviceAddress := 0;
  end_if;
  
  output := DeviceAddress;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::VendorID::Read
	VAR_OUTPUT
		output (EAX) 	: UDINT;
	END_VAR
  VAR
    MyPara   : CmdStruct;
    MyResult : results;
  END_VAR

  MyPara.uiCmd  := BUSIF_DRIVEMNGBASE_READ_PARAMETER;
  Mypara.aPara[0] := _BUS_IF_DRVMNG_VENDORID;
  if (ToBusIF.NewInst(#MyPara, #MyResult)) = READY then
    VendorID := MyResult.aData[0]$UDINT; 
  else
    // this server is not used over sdias
    VendorID := 0;
  end_if; 

  output := VendorID;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::DeviceID::Read
	VAR_OUTPUT
		output (EAX) 	: UDINT;
	END_VAR
  VAR
    MyPara   : CmdStruct;
    MyResult : results;  
  END_VAR

  MyPara.uiCmd  := BUSIF_DRIVEMNGBASE_READ_DEVICEID;
  ToBusIF.NewInst(#MyPara, #MyResult);    
  DeviceID := MyResult.aData[0]$UDINT; 
    
  output := DeviceID;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::Online::Read
	VAR_OUTPUT
		output (EAX) 	: DINT;
	END_VAR

  cOnline := cOnline.read();
  if (cOnline = 1) & (bdSettings.DriveIsInitialized = TRUE) & (bdSettings.InitModuleDone = TRUE) then
    Online := 1;
  else
    Online := 0;
  end_if;

  output := Online;

END_FUNCTION

FUNCTION VIRTUAL MDD2000MngBase::AddASyncEntryDS402
	VAR_INPUT
		AxisIdx 	: USINT;
		uiParaID 	: UINT;
		usParaSubID 	: USINT;
		usRdWr 	: USINT;
		pValue 	: ^void;
		bsDataInfo 	: BSINT;
		pThisObj 	: ^void;
		usEntry 	: USINT;(* := 0 *)
		udTimeout 	: UDINT;(* := 0 *)
		dCallID 	: DINT;(* := 0 *)
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR
    TmpBufEntry : t_MDD2000Mng_AsyncPara_Entry;
    tmpActEntries : UDINT;
  END_VAR
  
  retcode := -1;
  
  // check the Axisnumber
  if AxisIdx >= 0 & AxisIdx < MDD2000MNG_MAXENTRIES then //HasHan
  
    tmpActEntries := cPipe_GetUsed(p:=AxBuffer[AxisIdx].pAsyPipeHandle);
    
    if (AxBuffer[AxisIdx].pThis <> NIL) & (tmpActEntries < MDD2000MNG_ASY_BUFFERENTRY) then

      _memset(dest:=#TmpBufEntry, usByte:=0, cntr:=sizeof(TmpBufEntry));
      
      TmpBufEntry.pThisObj        := pThisObj;
      TmpBufEntry.uiParaIndex     := uiParaID;
      TmpBufEntry.usParaSubIndex  := usParaSubID;
      TmpBufEntry.usRDWR          := usRdWr;
      TmpBufEntry.bsDataInfo      := bsDataInfo;
      TmpBufEntry.usEntry         := usEntry;
      TmpBufEntry.udTimeStamp     := ud_CycleCounter;
      TmpBufEntry.dCallID         := dCallID;
      TmpBufEntry.bSent           := FALSE;
      TmpBufEntry.bFinished       := FALSE;
      
      if udTimeout = 0 then
        TmpBufEntry.udTimeoutCycles := ud_TimeoutCycles;
      else
        TmpBufEntry.udTimeoutCycles := udTimeout * 1000 /  udCycleTimems;  
      end_if;
      
      if usRdWr then
        _memcpy(ptr1:=#TmpBufEntry.dValue, ptr2:=pValue, cntr:=4*((bsDataInfo and 0x0F) + 1));
      end_if;      

      cPipe_Add(p:=AxBuffer[AxisIdx].pAsyPipeHandle, pdata:=#TmpBufEntry, datasize:=sizeof(TmpBufEntry));
      retcode := 0;
          
    end_if;
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL MDD2000MngBase::UpdateASync
VAR
  pThisNewInst	: ^void;
	ret_code		: IPRSTATES;
	UserPara		: CmdStruct;
	UserResult  : Results;
	ActState    : DINT;
  pRead         : ^t_MDD2000Mng_AsyncPara_Entry;
  x             : USINT;
  bNothingToDo  : BOOL;
  retcode       : DINT;
  pAxBuff       : ^_AXDEF;
  TmpChangeEntry : _ParaRefreshBufEntry;
#ifdef MDD2000MNG_DBG_LOGGING_SDO  
  LogVal1, LogVal2, LogVal3, LogVal4, LogVal5, LogVal6  :  HDINT;
#endif
END_VAR

  bdSettings.bRingBufferRead := TRUE;

  // check all axis objects
  for x := 0 to (MDD2000MNG_MAXENTRIES - 1) do 
    
    pAxBuff := #AxBuffer[x];
    
    // axis object available
    if pAxBuff^.pThis <> NIL then
      bNothingToDo := FALSE;
      
      pAxBuff^.udActEntries := cPipe_GetUsed(p:=pAxBuff^.pAsyPipeHandle);
      
      //Check if we have a entry in our buffer or the last command is not finished yet
      if pAxBuff^.udActEntries > 0 | pAxBuff^.sCurrentAsyncParaEntry.bFinished = FALSE then
        
        pRead := #pAxBuff^.sCurrentAsyncParaEntry;
        
        ActState := GetParameterState(usAxis:=x);
        
        //If act state is ok, or we had an error but this is a new SDO (bSent = false)
        if ActState = 0 | ((pRead^.bSent = FALSE) & (ActState <> -1) & (ActState <> -3))   then
        
          if pRead^.bSent = FALSE then
          
            //Get new entry from pipe
            cPipe_Get(pd:=pRead, p:=pAxBuff^.pAsyPipeHandle);
          
            if pRead^.uiParaIndex = DS402_ASYNCPARA_DEFAULT_LASALPARA_INDEX then
              // set the next command to the drive
              retcode := SetParameter( usAxis         := pAxBuff^.AxisIndex,
                                       paranr         := pRead^.usParaSubIndex, 
                                       rdwr           := pRead^.usRDWR,
                                       paravalue      := pRead^.dValue[0]$DINT);
                                       
            else                    
              retcode := SetParameterDS402(usAxis     := pAxBuff^.AxisIndex
                                        , uiParaID    := pRead^.uiParaIndex
                                        , usParaSubID := pRead^.usParaSubIndex
                                        , usRdWr      := pRead^.usRdWR
                                        , pparavalue  := #pRead^.dValue[0]
                                        , bsDataInfo  := pRead^.bsDataInfo
                                        );
            end_if; 
            
            if retcode = 0 then
              pRead^.udTimestamp := ud_CycleCounter;
              pRead^.bFinished := FALSE;
              pRead^.bSent := TRUE;
              bNothingToDo := TRUE;
            end_if;
            
          // now finish the command
          elsif pRead^.bFinished = FALSE then
          
            pRead^.bFinished := TRUE;
            pRead^.bSent := FALSE;
            pThisNewInst := pRead^.pThisObj;  //call class which added the async command
            if pThisNewInst <> NIL then
              if pRead^.usRDWR = 0 then
                // it was a reading parameter command
                if pRead^.uiParaIndex = DS402_ASYNCPARA_DEFAULT_LASALPARA_INDEX then
                  pRead^.dValue[0]$DINT := GetParameter(usAxis:= pAxBuff^.AxisIndex);
                else
                  _memcpy(ptr1:=#pRead^.dValue[0], ptr2:=GetParameterDS402(usAxis:=pAxBuff^.AxisIndex), cntr:=12);
                end_if;
              end_if;
              
              // Asynchronous access is finished
              UserPara.uiCmd    := MDD2000MNG_IF_ASYNC_READY;
              UserPara.aPara[0] := MDD2000MNG_IF_ASYNC_READY_VER_1;
              UserPara.aPara[1] := pRead^.uiParaIndex;
              UserPara.aPara[2] := pRead^.usParaSubIndex;
              UserPara.aPara[3] := pRead^.usRDWR;
              UserPara.aPara[4] := to_dint(pAxBuff^.AxisIndex); // Achsennummer;
              UserPara.aPara[5] := pRead^.bsDataInfo;
              UserPara.aPara[6] := (#pRead^.dValue[0])$DINT;  //Pointer to data
              UserPara.aPara[7] := pRead^.dCallID;

#ifdef MDD2000MNG_DBG_LOGGING_SDO
              LogVal1 := pRead^.uiParaIndex; LogVal2 := pRead^.usParaSubIndex; LogVal3 := pRead^.bsDataInfo;
              LogVal4 := to_udint(pRead^.usRDWR); LogVal5 := to_udint(pRead^.dValue$DINT);
              HWC_LogPrintf(pThis:=this, format:="@DEBUG (MDD2000_MngBase::UpdateASync) SDO ok: idx: 0x%04x, subidx: %V1, size: %V1,RW:%V1, data: %V4,", p0:=#LogVal1, p1:=#LogVal2, p2:=#LogVal3, p3:=#LogVal4, p4:=#LogVal5);
#endif

// Bedeutung usEntry ..
// 0... default
// 1... Refresh der Driveparameter wenn Parameterklassen vorhanden sind
// 2... Ist der erste Part vom Refresh der Parameterklassen abgeschlossen (wird als letztes gesendet)
// 3... Eintrag kommt von Lasal2 Tool zum Lesen/Schreiben asynchroner Parameter

              // internal command of Lasal2
              if (pRead^.usEntry = MDD2000MNG_ENTRY_TYPE_FROM_LASAL) then  

                UserPara.aPara[4] := to_dint(pAxBuff^.AxisIndex); // Achsennummer für Lasal2
                ret_code := L2CmdFinished(#UserPara, #UserResult);
                
                // when lasal2 reads a parameter, we use the value also for eventually placed parameter-objects
                UserPara.uiCmd    := MDD2000MNG_IF_REFRESH_PARA_OBJECTS;
                UserPara.aPara[0] := MDD2000MNG_IF_REFRESH_PARA_OBJECTS_VER_1;
                
                pThisNewInst := pAxBuff^.pThis;
                pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);

              else
                ret_code := pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
              end_if;
             
              // check if parameter has to be saved
              if (pRead^.usRDWR = 1) & ((pRead^.usEntry = MDD2000MNG_ENTRY_TYPE_DEFAULT) | (pRead^.usEntry = MDD2000MNG_ENTRY_TYPE_FROM_LASAL)) then
              
                UserPara.uiCmd    := MDD2000MNG_IF_SAVE_PARAMETER;
                UserPara.aPara[0] := MDD2000MNG_IF_SAVE_PARAMETER_VER_1;
                UserPara.aPara[1] := pRead^.uiParaIndex;
                UserPara.aPara[2] := pRead^.usParaSubIndex;
                UserPara.aPara[3] := pRead^.usRDWR;
                UserPara.aPara[4] := to_dint(pAxBuff^.AxisIndex); // Achsennummer;
                UserPara.aPara[5] := pRead^.bsDataInfo;
                UserPara.aPara[6] := (#pRead^.dValue[0])$DINT;  //Pointer to data
                UserPara.aPara[7] := pRead^.dCallID;
                UserPara.aPara[8] := 1; //Save parameter
              
                pThisNewInst := pAxBuff^.pThis;
                ret_code := pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
                
                // if it's a change from the classes, refresh the values in lasal
                if (pRead^.usEntry = MDD2000MNG_ENTRY_TYPE_DEFAULT) then
                  
                  //Create the pipe if not created yet
                  if sChangesData.pChangesPipeHandle = NIL then
                    sChangesData.pChangesPipeHandle := cPipe_CTor(record_size:=sizeof(_ParaRefreshBufEntry), record_no:=MDD2000MNG_ASY_BUFFERENTRY);
                    sChangesData.ActEntries := 0;
                  end_if;
                  
                  // save the new changes into the pipe
                  if sChangesData.pChangesPipeHandle then
                    TmpChangeEntry.AxisNo   := pAxBuff^.AxisIndex;
                    TmpChangeEntry.Reserved := 0;
                    TmpChangeEntry.ParaNo   := pRead^.usParaSubIndex;
                    TmpChangeEntry.NewValue := pRead^.dValue[0]$DINT;
                    
                    cPipe_Add(p:=sChangesData.pChangesPipeHandle, pdata:=#TmpChangeEntry, datasize:=sizeof(TmpChangeEntry));
                    sChangesData.ActEntries := cPipe_GetUsed(p:=sChangesData.pChangesPipeHandle);
                  end_if;

                end_if;
              end_if;

              // Überprüfung ob der Parameter abgespeichert werden muss
              if (pRead^.usEntry = MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA) then
                
                UserPara.uiCmd    := MDD2000MNG_IF_SAVE_PARAMETER;
                UserPara.aPara[0] := MDD2000MNG_IF_SAVE_PARAMETER_VER_1;
                UserPara.aPara[1] := pRead^.uiParaIndex;
                UserPara.aPara[2] := pRead^.usParaSubIndex;
                UserPara.aPara[3] := pRead^.usRDWR;
                UserPara.aPara[4] := to_dint(pAxBuff^.AxisIndex); // Achsennummer;
                UserPara.aPara[5] := pRead^.bsDataInfo;
                UserPara.aPara[6] := (#pRead^.dValue[0])$DINT;  //Pointer to data
                UserPara.aPara[7] := pRead^.dCallID;
                UserPara.aPara[8] := 0; //Don't save parameter
                                
                pThisNewInst := pAxBuff^.pThis;
                ret_code := pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
              end_if;

            end_if;
            
            // Ist der Parameter refresh abgeschlossen ?
            if pRead^.usEntry = MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA_LAST then
              // Refresh all parameter is now successfully finished
              UserPara.uiCmd    := MDD2000MNG_IF_REFRESH_PARAMETER_FINISHED;
              UserPara.aPara[0] := MDD2000MNG_IF_REFRESH_PARAMETER_FINISHED_VER_1;
              
              pThisNewInst := pAxBuff^.pThis;
              ret_code := pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
            end_if;
          end_if;
          
          if bNothingToDo = FALSE then

            pAxBuff^.udActEntries := cPipe_GetUsed(p:=pAxBuff^.pAsyPipeHandle);
            
            // check if we have a next command
            if pAxBuff^.udActEntries > 0 then
            
              //Get new entry from pipe
              cPipe_Get(pd:=pRead, p:=pAxBuff^.pAsyPipeHandle);
              
              if pRead^.uiParaIndex = DS402_ASYNCPARA_DEFAULT_LASALPARA_INDEX then
                // set the next command to the drive
                retcode := SetParameter( usAxis         := pAxBuff^.AxisIndex,
                                         paranr         := pRead^.usParaSubIndex, 
                                         rdwr           := pRead^.usRDWR,
                                         paravalue      := pRead^.dValue[0]$DINT); 
                                         
              else                    
                retcode := SetParameterDS402(usAxis     := pAxBuff^.AxisIndex
                                          , uiParaID    := pRead^.uiParaIndex
                                          , usParaSubID := pRead^.usParaSubIndex
                                          , usRdWr      := pRead^.usRdWR
                                          , pparavalue  := #pRead^.dValue[0]
                                          , bsDataInfo  := pRead^.bsDataInfo
                                          );
              end_if; 
                
              IF retcode = 0 THEN
                pRead^.udTimestamp := ud_CycleCounter;
                pRead^.bFinished := FALSE;
                pRead^.bSent := TRUE;
              END_IF;
            
            end_if;
          end_if;
        
        // class not ready or maximum time for asynchronous access exceeded
        elsif (ActState <> -1) | ((ud_CycleCounter - pRead^.udTimeStamp) > pRead^.udTimeoutCycles) then                
          pRead^.bFinished := TRUE;
          pRead^.bSent := FALSE;
          pThisNewInst := pRead^.pThisObj;
          if pThisNewInst <> NIL then
            
            if ((ud_CycleCounter - pRead^.udTimeStamp) > pRead^.udTimeoutCycles) then
              ActState := MDD2000MNG_ERR_OBJ_HANDLING_TIMEOUT;
            end_if;
            
            // now we have an error
            UserPara.uiCmd    := MDD2000MNG_IF_ASYNC_ERROR;
            UserPara.aPara[0] := MDD2000MNG_IF_ASYNC_ERROR_VER_1;
            UserPara.aPara[1] := pRead^.uiParaIndex;
            UserPara.aPara[2] := pRead^.usParaSubIndex;
            UserPara.aPara[3] := pRead^.usRDWR;
            UserPara.aPara[4] := to_dint(pAxBuff^.AxisIndex); // Achsennummer;
            UserPara.aPara[5] := pRead^.bsDataInfo;
            UserPara.aPara[6] := (#pRead^.dValue[0])$DINT;  //Pointer to data
            UserPara.aPara[7] := pRead^.dCallID;
            UserPara.aPara[8] := ActState;                  //Errorcode
            
#ifdef MDD2000MNG_DBG_LOGGING_SDO
            LogVal1 := pRead^.uiParaIndex; LogVal2 := pRead^.usParaSubIndex; LogVal3 := pRead^.bsDataInfo;
            LogVal4 := to_udint(pRead^.usRDWR); LogVal5 := to_udint(pRead^.dValue$DINT); LogVal6 := to_udint(ActState);
            HWC_LogPrintf(pThis:=this, format:="@DEBUG (MDD2000_MngBase::UpdateASync) SDO err: idx: 0x%04x, subidx: %V1, size: %V1,RW:%V1, data: %V4, Errcode: %V4", p0:=#LogVal1, p1:=#LogVal2, p2:=#LogVal3, p3:=#LogVal4, p4:=#LogVal5, p5:=#LogVal6);
#endif
            
            //Check if the command was from Lasal2 or from the application
            if (pRead^.usEntry = MDD2000MNG_ENTRY_TYPE_FROM_LASAL) then
            
              // internal command of Lasal2
              UserPara.aPara[4] := to_dint(pAxBuff^.AxisIndex); // Achsennummer für Lasal2
              ret_code := L2CmdFinished(#UserPara, #UserResult);
              
            else
              // asynchronous command from applikation
              ret_code := pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
              
            end_if; 

            pAxBuff^.udActEntries := cPipe_GetUsed(p:=pAxBuff^.pAsyPipeHandle);
            
            // check if we have a next command
            if pAxBuff^.udActEntries > 0 then
            
              //Get new entry from pipe
              cPipe_Get(pd:=pRead, p:=pAxBuff^.pAsyPipeHandle);

              if pRead^.uiParaIndex = DS402_ASYNCPARA_DEFAULT_LASALPARA_INDEX then
                // set the next command to the drive
                retcode := SetParameter( usAxis         := pAxBuff^.AxisIndex,
                                         paranr         := pRead^.usParaSubIndex, 
                                         rdwr           := pRead^.usRDWR,
                                         paravalue      := pRead^.dValue[0]$DINT); 
                                         
              else                    
                retcode := SetParameterDS402(usAxis     := pAxBuff^.AxisIndex
                                          , uiParaID    := pRead^.uiParaIndex
                                          , usParaSubID := pRead^.usParaSubIndex
                                          , usRdWr      := pRead^.usRdWR
                                          , pparavalue  := #pRead^.dValue[0]
                                          , bsDataInfo  := pRead^.bsDataInfo
                                          );
              end_if; 

              IF retcode = 0 THEN
                pRead^.udTimestamp := ud_CycleCounter;
                pRead^.bFinished := FALSE;
                pRead^.bSent := TRUE;
              END_IF;
            end_if;
          end_if;
          // Ist der erste Part vom Refresh abgeschlossen ?
          if pRead^.usEntry = MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA_LAST then
            // Refresh all parameter is now successfully finished
            pThisNewInst := pAxBuff^.pThis;
            
            UserPara.uiCmd    := MDD2000MNG_IF_REFRESH_PARAMETER_FINISHED;
            UserPara.aPara[0] := MDD2000MNG_IF_REFRESH_PARAMETER_FINISHED_VER_1;
            ret_code := pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
          end_if;
        end_if;
      end_if;
    else
      exit;
    end_if;
  end_for;
	
  bdSettings.bRingBufferRead := FALSE;

END_FUNCTION


FUNCTION MDD2000MngBase::DriveInitState
	VAR_OUTPUT
		retcode 	: BOOL;
	END_VAR

  retcode := FALSE;
  
  if (bdSettings.AxisInit = TRUE) & (cOnline = 1) & (GetVaranDriveState() = 3) then // 3 is operational state
    retcode := TRUE;
  end_if;     
  
END_FUNCTION


FUNCTION MDD2000MngBase::AxisInitFinished
	VAR_INPUT
		AxisIdx 	: USINT;
		IdFinished 	: DINT;
	END_VAR

  if AxisIdx >= 0 & AxisIdx < MDD2000MNG_MAXENTRIES then
    
    case IdFinished of
      MDD2000MNG_IF_AXISINITFINISHED_FUNCT:
        AxBuffer[AxisIdx].bdStates.InitFinished     := TRUE;
      MDD2000MNG_IF_AXISINITFINISHED_SAFEVERIFIY:
        AxBuffer[AxisIdx].bdStates.SafeVerifyDone   := TRUE;
      MDD2000MNG_IF_AXISINITFINISHED_SAFEZEROPOS:
        AxBuffer[AxisIdx].bdStates.SafeZeroPosDone  := TRUE;
    end_case; 
    
  end_if;
  
END_FUNCTION


FUNCTION MDD2000MngBase::ResetAxisInit
  VAR
  	x       : USINT;
  END_VAR

    for x := 0 to MDD2000MNG_MAXENTRIES -1 do
      if (AxBuffer[x].pThis <> NIL) then
        if (AxBuffer[x].AxisOk = 1) then
          AxBuffer[x].bdStates.InitFinished           := FALSE;
          AxBuffer[x].bdStates.SafeVerifyDone         := FALSE;
          AxBuffer[x].bdStates.SafeZeroPosDone        := FALSE;
          AxBuffer[x].bdStates.ResetSafeZeroPos       := FALSE;
          AxBuffer[x].bdStates.Wait4ResetSafeZeroPos  := FALSE;
        end_if;
      end_if;
    end_for;

END_FUNCTION

FUNCTION MDD2000MngBase::ResetAxisSafeVerifyZeroPos
  VAR
  	x       : USINT;
  END_VAR

    for x := 0 to MDD2000MNG_MAXENTRIES -1 do
      if (AxBuffer[x].pThis <> NIL) then
        if (AxBuffer[x].AxisOk = 1) then          
          AxBuffer[x].bdStates.SafeVerifyDone         := FALSE;
          AxBuffer[x].bdStates.SafeZeroPosDone        := FALSE;
        end_if;
      end_if;
    end_for;

END_FUNCTION

FUNCTION MDD2000MngBase::ResetSafeVerifyZeropos
	VAR_INPUT
		AxisIdx 	: USINT;
		IdReset 	: DINT;
	END_VAR

  if AxisIdx >= 0 & AxisIdx < MDD2000MNG_MAXENTRIES then
    
    case IdReset of
      MDD2000MNG_IF_AXISINITFINISHED_SAFEVERIFIY:
        bdSettings.ResetSafetyAxis  := TRUE;
        bdSettings.ResetSafeVerify  := TRUE;
      MDD2000MNG_IF_AXISINITFINISHED_SAFEZEROPOS:
        bdSettings.ResetSafetyAxis := TRUE;
        AxBuffer[AxisIdx].bdStates.ResetSafeZeroPos := TRUE;
      MDD2000MNG_IF_RESET_SAFE_VERIFY_ZEROPOS_SAFEVERIFIYZEROPOS:
        bdSettings.ResetSafetyAxis  := TRUE;
        bdSettings.ResetSafeVerify  := TRUE;
        AxBuffer[AxisIdx].bdStates.ResetSafeZeroPos := TRUE;
    end_case; 
    
  end_if;
END_FUNCTION


FUNCTION MDD2000MngBase::CommunicationState
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  
  retcode := cOnline;
  
END_FUNCTION

FUNCTION MDD2000MngBase::L2CmdFinished
	VAR_INPUT
		pPara 	: ^CmdStruct;
		pResult 	: ^results;
	END_VAR
	VAR_OUTPUT
		ret_code 	: iprStates;
	END_VAR
  VAR
  	ParNo : DINT;
  END_VAR

  ret_code := READY;
    
  ConvertDS402ParaFormatToLC2Format(hParaIndex:=pPara^.aPara[1]$HINT, hsParaSubIndex:=pPara^.aPara[2]$HSINT, ParaNo:=#ParNo);
  
  L2Buffer[L2WrIndex].AxisNo := to_usint(pPara^.aPara[4]);
  L2Buffer[L2WrIndex].ParRW := to_usint(pPara^.aPara[3]);
  L2Buffer[L2WrIndex].ParNo := ParNo$USINT;
  L2Buffer[L2WrIndex].ParValue := to_dint(pPara^.aPara[6]$^DINT^);
  L2Buffer[L2WrIndex].bActive := TRUE;
  
  case pPara^.uiCmd of
//*****************************************************************************
    MDD2000MNG_IF_ASYNC_READY:
    
      L2Buffer[L2WrIndex].ParState := 0;  //No error
    
//*****************************************************************************
    MDD2000MNG_IF_ASYNC_ERROR:
    
      L2Buffer[L2WrIndex].ParState := 1;  //Error
      L2Buffer[L2WrIndex].ParError := to_sint(pPara^.aPara[8]); //Errorcode
  end_case;
  
  L2WrIndex += 1;
  L2NewEntry += 1;
  if L2WrIndex > (MDD2000MNG_L2MAXINDEX - 1) then
    L2WrIndex := 0;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::CmdState::NewInst
	VAR_INPUT
		pPara 	: ^CmdStruct;
		pResult 	: ^results;
	END_VAR
	VAR_OUTPUT
		ret_code 	: iprStates;
	END_VAR
  VAR
    AxisNo          : USINT;
    ParRW           : USINT;
    ParNo           : USINT;
    AxIndex         : USINT;
    RetcodeSizeLeft : UDINT;
    pActRetEntry    : ^_ParaRefreshBufEntry;
    i               : USINT;
    pThisRes        : ^UDINT;
    FoundAxis       : USINT;
    
    // Variables for CMD_GET_HARDWARE_DIAGNOSIS and CMD_GET_HARDWARE_TREE_ENTRY
    pStr_HWTRequested         : ^CHAR;
    us_HWTRequestedCurrIndex  : USINT;
    us_RequestedPlace         : USINT;
    us_RequestedAxis          : USINT;
    us_NextAxis               : USINT;
    us_NextPlace              : USINT;
    ud_StrSize                : UDINT;
    ud_TempSerNo              : UDINT;
    
    MyPara   : CmdStruct;
    MyResult : results;  
    tmpRetCode                : DINT;
    hIndex        : HINT;
    hsSubIndex    : HSINT;
    bRW           : BOOL;
    dValue        : DINT;
    dErrorCode    : DINT;
    
    var1 : HDINT;
    var2 : HDINT;
    szValue     : ARRAY[0..19] of CHAR;
  END_VAR

  pStr_HWTRequested         := NIL;
  us_HWTRequestedCurrIndex  := 0;
  us_RequestedPlace         := 16#FF;
  us_RequestedAxis          := 16#FF;
  us_NextAxis               := 16#FF;
  us_NextPlace              := 16#FF;
  ud_StrSize                := 0;
  ud_TempSerNo              := 0;

  ret_code := READY;

  CASE pPara^.uiCmd Of
  
//*******************************************************************************************************************
  MDD2000MNG_IF_ASYNC_READY :
  
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_ASYNC_READY_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_ASYNC_READY_VER_1 then
          
      ret_code := READY;   

      hIndex      := pPara^.aPara[1]$HINT;
      hsSubIndex  := pPara^.aPara[2]$HSINT;
      bRW         := pPara^.aPara[3]$BOOL;
      AxIndex     := pPara^.aPara[4]$USINT;
      dValue      := pPara^.aPara[6]$^DINT^;
      
      // Parameter for log file are dependent on the drive, usParaLogIdx is set in GetLogFileCyclic
      if (hIndex = s_LogFileV.hParaLogIndex) & (hsSubIndex = s_LogFileV.hsParaLogSubIndex) then
        s_LogFileV.dParaLogValRd     := dValue;
        s_LogFileV.bWait4LogFilePara := FALSE;
      else
        case hIndex of 
          
          //*****************************************************************************
          MDD2000_PID_SIGMATEKPARA_INDEX_INFO:
        
            // check the parameter number
            case hsSubIndex of
            
              MDD2000_SPID_I_HW :
              
                Parameter_I_HW := dValue;
              
                var1 := (dValue$HDINT AND 16#FF000000) shr  24;
                var2 := (dValue$HDINT AND 16#00FF0000) shr  16;
                sigclib_sprintfST(pd:=#szValue[0], "%2u.%02u", #var1, #var2);
                HWNumString.TxtSet(dstchrsize:=1, psrc:=#szValue[0], srcchrsize:=1);
                
                bdWait4HwInfoResponse.I_HW := FALSE;

              MDD2000_SPID_I_TYPE :
                
                Parameter_I_Type := dValue;
                SetDriveType(ITYPE:=Parameter_I_Type);
                bdWait4HwInfoResponse.I_Type := FALSE;
              
              MDD2000_SPID_I_SER :
                
                SerialNo := dValue; 
                bdWait4HwInfoResponse.I_SER := FALSE;
              
              MDD2000_SPID_I_FW :
              
                FwVersionInt :=  dValue;
                bdWait4HwInfoResponse.I_FW := FALSE;
                SetFWVersion(FwVersionInt, 0);
                
          end_case;
          
          //*****************************************************************************
          MDD2000_PID_SAFETY_IMG_INFO:
          
            // check the parameter number
            case hsSubIndex of
              
              MDD2000_SPID_SAFETY_IMG_FWVERSION:
                
                SetFWVersion(dValue, 1);
                bdWait4SafetyInfoResponse.FwVersion := FALSE;
                
            end_case;
          
          //*****************************************************************************
          MDD2000_PID_SAFETY_CFG_INFO:
          
            // check the parameter number
            case hsSubIndex of
            
              MDD2000_SPID_SAFETY_NO:

                SafetyNumber := dValue$HDINT;
                bdWait4SafetyInfoResponse.SafetyNo := FALSE;
                  
              MDD2000_SPID_SAFETY_CFG_CRC:
                
                if (sSafetyCfgChg.SafetyCFGCRC <> 0) &  // Ignore Config change if it has not been read yet
                   (sSafetyCfgChg.SafetyCFGCRC <> dValue$HDINT) then
                  bdSettings.SafetyConfigChanged := TRUE;
                end_if;

                sSafetyCfgChg.SafetyCFGCRC := dValue$HDINT;
                bdWait4SafetyInfoResponse.CFG_CRC := FALSE;
                
              MDD2000_SPID_SAFETY_CFG_OUT_FSOEFRAME:
              
                sSafetyCfgChg.SafetyLenOutFSoEFrame := dValue;
                bdWait4SafetyInfoResponse.LenOutFSoEFrame := FALSE;
              
              MDD2000_SPID_SAFETY_CFG_IN_FSOEFRAME:
              
                sSafetyCfgChg.SafetyLenInFSoEFrame :=  dValue;
                bdWait4SafetyInfoResponse.LenInFSoEFrame := FALSE;
            
            end_case;
            
          //*****************************************************************************
          MDD2000_PID_SAFETY_RUN_INFO:
          
            // check the parameter number
            case hsSubIndex of
            
              MDD2000_SPID_SAFETY_RUN_STATE:
                    
                SafetyRunStateInternal := dValue$t_e_MDD2000SafetyRunState;
                if sSafetyCfgChg.bdFaultInfo = 0 then
                  SafetyRunState := SafetyRunStateInternal;
                else
                  SafetyRunState := _FSOE_COMSETUPFAILED;
                end_if;
                bdWait4SafetyInfoResponse.RunState := FALSE;
              
              MDD2000_SPID_SAFETY_RUN_SUBSTATE: 
              
                if ((SafetyRunStateInternal = t_e_MDD2000SafetyRunState::_CHK_CFG) | (SafetyRunStateInternal = t_e_MDD2000SafetyRunState::_PREOP)) then
                  sSafetyCfgChg.SafetySubRunState$UDINT := (SafetyRunStateInternal$UDINT * 100) + dValue$UDINT;  // SafetyRunState is factored in with a multipler of 100 in t_e_MDD2000SafetySubRunState
                else
                  sSafetyCfgChg.SafetySubRunState$UDINT := dValue$UDINT;
                end_if;
                bdWait4SafetyInfoResponse.SubRunState := FALSE;
                
            end_case;
            
          //*****************************************************************************
          MDD2000_PID_SAFETY_ERROR:
          
            // check the parameter number
            case hsSubIndex of
            
              MDD2000_SPID_SAFETY_ERROR_SC1_CODE:
                sSafetyErrInfo.SafetyErrorCode_SC1 := dValue;
                sSafetyErrInfo.bdAsyFlags.w4SafetyErrorCode_SC1 := FALSE;
              MDD2000_SPID_SAFETY_ERROR_SC1_INFO1:
                sSafetyErrInfo.SafetyErrorInformation1_SC1 := dValue;
                sSafetyErrInfo.bdAsyFlags.w4SafetyErrorInformation1_SC1 := FALSE;
              MDD2000_SPID_SAFETY_ERROR_SC1_INFO2:
                sSafetyErrInfo.SafetyErrorInformation2_SC1 := dValue;
                sSafetyErrInfo.bdAsyFlags.w4SafetyErrorInformation2_SC1 := FALSE;
              MDD2000_SPID_SAFETY_ERROR_SC1_INFO3:
                sSafetyErrInfo.SafetyErrorInformation3_SC1 := dValue;
                sSafetyErrInfo.bdAsyFlags.w4SafetyErrorInformation3_SC1 := FALSE;
              MDD2000_SPID_SAFETY_ERROR_SC2_CODE:
                sSafetyErrInfo.SafetyErrorCode_SC2 := dValue;
                sSafetyErrInfo.bdAsyFlags.w4SafetyErrorCode_SC2 := FALSE;
              MDD2000_SPID_SAFETY_ERROR_SC2_INFO1:
                sSafetyErrInfo.SafetyErrorInformation1_SC2 := dValue;
                sSafetyErrInfo.bdAsyFlags.w4SafetyErrorInformation1_SC2 := FALSE;
              MDD2000_SPID_SAFETY_ERROR_SC2_INFO2:
                sSafetyErrInfo.SafetyErrorInformation2_SC2 := dValue;
                sSafetyErrInfo.bdAsyFlags.w4SafetyErrorInformation2_SC2 := FALSE;
              MDD2000_SPID_SAFETY_ERROR_SC2_INFO3:
                sSafetyErrInfo.SafetyErrorInformation3_SC2 := dValue;
                sSafetyErrInfo.bdAsyFlags.w4SafetyErrorInformation3_SC2 := FALSE;
            
            end_case;
            
          //*****************************************************************************
          MDD2000_PID_SAFETY_COMMANDS:
            
            // check the parameter number
            case hsSubIndex of
            
              MDD2000_SPID_SAFETY_FINISH_VERIFY:
              
                bdWait4SafetyInfoResponse.FinishVerify := FALSE;
                
              MDD2000_SPID_SAFETY_RESET_VERIFY:
              
                bdWait4SafetyInfoResponse.ResetSafeVerify := FALSE;
                
              MDD2000_SPID_SAFETY_SETSERVICEMODE:
              
                bdWait4SafetyInfoResponse.SetServiceMode  := FALSE;
                
              MDD2000_SPID_SAFETY_LEAVESERVICEMODE:
              
                bdWait4SafetyInfoResponse.LeaveServiceMode := FALSE;
                          
            end_case;
          
          //*****************************************************************************
          MDD2000_PID_SAFETY_AXIS_INFO:
          
            // check the parameter number
            case hsSubIndex of
            
              MDD2000_SPID_SAFETY_AXIS_SETZEROPOS:
              
                for i := 0 to MDD2000MNG_MAXENTRIES -1 do
                  if (AxBuffer[i].pThis <> NIL) then 
                    if (AxBuffer[i].AxisIndex = AxIndex) then
                      AxBuffer[i].bdStates.Wait4ResetSafeZeroPos := FALSE;
                      exit;
                    end_if;
                  end_if;
                end_for;
                
            end_case;
            
        end_case;
        
      end_if;
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_ASYNC_READY detected", #pPara^.aPara[0]);      
    end_if;

//*******************************************************************************************************************
  MDD2000MNG_IF_ASYNC_ERROR :
  
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_ASYNC_ERROR_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_ASYNC_ERROR_VER_1 then
          
      ret_code := READY;   
      
      hIndex      := pPara^.aPara[1]$HINT;
      hsSubIndex  := pPara^.aPara[2]$HSINT;
      bRW         := pPara^.aPara[3]$BOOL;
      AxIndex     := pPara^.aPara[4]$USINT;
      dValue      := pPara^.aPara[6]$^DINT^;
      dErrorCode  := pPara^.aPara[8]$DINT;
      
      // Parameter for log file are dependent on the drive, usParaLogIdx is set in GetLogFileCyclic
      if (hIndex = s_LogFileV.hParaLogIndex) & (hsSubIndex = s_LogFileV.hsParaLogSubIndex) then
        s_LogFileV.dParaLogValRd     := 16#7FFFFFFF;
        s_LogFileV.bWait4LogFilePara := FALSE;
      
      else
      
        case hIndex of 
        
          //*****************************************************************************
          MDD2000_PID_SIGMATEKPARA_INDEX_INFO:
          
            //Check subindex
            case hsSubIndex of
            
              MDD2000_SPID_I_HW :
                
                bdWait4HwInfoResponse.I_HW := FALSE;
                
              MDD2000_SPID_I_TYPE :
                
                Parameter_I_Type := 16#7FFFFFFF;
                DriveType := _NotFound;
                bdWait4HwInfoResponse.I_Type := FALSE;
              
              MDD2000_SPID_I_SER :
                
                SerialNo := 16#7FFFFFFF; 
                bdWait4HwInfoResponse.I_SER := FALSE;

              MDD2000_SPID_I_FW :
              
                FwVersionInt :=  16#7FFFFFFF;
                bdWait4HwInfoResponse.I_FW := FALSE;

            end_case;
            
          //*****************************************************************************
          MDD2000_PID_SAFETY_IMG_INFO:
          
            // check the parameter number
            case hsSubIndex of
              
              MDD2000_SPID_SAFETY_IMG_FWVERSION:
              
                FwVersionSafety := 16#7FFFFFFF;
                bdWait4SafetyInfoResponse.FwVersion := FALSE;
                
            end_case;
          
          //*****************************************************************************
          MDD2000_PID_SAFETY_CFG_INFO:
          
            // check the parameter number
            case hsSubIndex of
            
              MDD2000_SPID_SAFETY_NO:
                  
                SafetyNumber := 16#7FFFFFFF;
                bdWait4SafetyInfoResponse.SafetyNo := FALSE;
                  
              MDD2000_SPID_SAFETY_CFG_CRC:
                
                bdWait4SafetyInfoResponse.CFG_CRC := FALSE;
              
              MDD2000_SPID_SAFETY_CFG_OUT_FSOEFRAME:
                
                // Set Invalid
                sSafetyCfgChg.SafetyLenOutFSoEFrame := -1;
                bdWait4SafetyInfoResponse.LenOutFSoEFrame := FALSE;
              
              MDD2000_SPID_SAFETY_CFG_IN_FSOEFRAME:
              
                // Set Invalid
                sSafetyCfgChg.SafetyLenInFSoEFrame :=  -1;
                bdWait4SafetyInfoResponse.LenInFSoEFrame := FALSE;
                
            end_case;
            
          //*****************************************************************************
          MDD2000_PID_SAFETY_RUN_INFO:
          
            // check the parameter number
            case hsSubIndex of
            
              MDD2000_SPID_SAFETY_RUN_STATE:
                    
                SafetyRunStateInternal := SafetyRunState := t_e_MDD2000SafetyRunState::_INACTIVE;
                bdWait4SafetyInfoResponse.RunState := FALSE;
              
              MDD2000_SPID_SAFETY_RUN_SUBSTATE: 
              
                sSafetyCfgChg.SafetySubRunState := t_e_MDD2000SafetySubRunState::Invalid;
                bdWait4SafetyInfoResponse.SubRunState := FALSE;
                
                 
            end_case;
          
          //*****************************************************************************
          MDD2000_PID_SAFETY_ERROR:
          
            // check the parameter number
            case hsSubIndex of
            
              MDD2000_SPID_SAFETY_ERROR_SC1_CODE:
                sSafetyErrInfo.bdAsyFlags.errSafetyErrorCode_SC1 := TRUE;
              MDD2000_SPID_SAFETY_ERROR_SC1_INFO1:
                sSafetyErrInfo.bdAsyFlags.errSafetyErrorInformation1_SC1 := TRUE;
              MDD2000_SPID_SAFETY_ERROR_SC1_INFO2:
                sSafetyErrInfo.bdAsyFlags.errSafetyErrorInformation2_SC1 := TRUE;
              MDD2000_SPID_SAFETY_ERROR_SC1_INFO3:
                sSafetyErrInfo.bdAsyFlags.errSafetyErrorInformation3_SC1 := TRUE;
              MDD2000_SPID_SAFETY_ERROR_SC2_CODE:
                sSafetyErrInfo.bdAsyFlags.errSafetyErrorCode_SC2 := TRUE;
              MDD2000_SPID_SAFETY_ERROR_SC2_INFO1:
                sSafetyErrInfo.bdAsyFlags.errSafetyErrorInformation1_SC2 := TRUE;
              MDD2000_SPID_SAFETY_ERROR_SC2_INFO2:
                sSafetyErrInfo.bdAsyFlags.errSafetyErrorInformation2_SC2 := TRUE;
              MDD2000_SPID_SAFETY_ERROR_SC2_INFO3:
                sSafetyErrInfo.bdAsyFlags.errSafetyErrorInformation3_SC2 := TRUE;
            
            end_case;
          
          //*****************************************************************************
          MDD2000_PID_SAFETY_COMMANDS:
            
            // check the parameter number
            case hsSubIndex of
            
              MDD2000_SPID_SAFETY_FINISH_VERIFY:
              
                bdWait4SafetyInfoResponse.FinishVerify := FALSE;
                
              MDD2000_SPID_SAFETY_RESET_VERIFY:
              
                bdWait4SafetyInfoResponse.ResetSafeVerify := FALSE;
                
              MDD2000_SPID_SAFETY_SETSERVICEMODE:
              
                bdWait4SafetyInfoResponse.SetServiceMode  := FALSE;
                
              MDD2000_SPID_SAFETY_LEAVESERVICEMODE:
              
                bdWait4SafetyInfoResponse.LeaveServiceMode := FALSE;
                
            end_case;
            
          //*****************************************************************************
          MDD2000_PID_SAFETY_AXIS_INFO:
          
            // check the parameter number
            case hsSubIndex of
            
              MDD2000_SPID_SAFETY_AXIS_SETZEROPOS:
              
                for i := 0 to MDD2000MNG_MAXENTRIES -1 do
                  if (AxBuffer[i].pThis <> NIL) then 
                    if (AxBuffer[i].AxisIndex = AxIndex) then
                      AxBuffer[i].bdStates.Wait4ResetSafeZeroPos := FALSE;
                      exit;
                    end_if;
                  end_if;
                end_for;
                
            end_case;
            
        end_case;
        
      end_if;
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_ASYNC_ERROR detected", #pPara^.aPara[0]);      
    end_if;
    
//*******************************************************************************************************************
  MDD2000MNG_LC2_NEWINST_GETVERSION :
    ret_code := READY;
    pResult^.uiLng := sizeof(UINT);
    pResult^.aData[0] := MDD2000MNG_LC2_NEWINST_L2VERSION;
    pResult^.aData[1] := 0;
  
//*******************************************************************************************************************
  MDD2000MNG_LC2_NEWINST_ONLINEOK :
    
    ret_code := READY;
    pResult^.uiLng := sizeof(USINT);
    pResult^.aData[0] := to_usint(Online.read());
    
    //Reset old data from pipe
    if sChangesData.pChangesPipeHandle then
    
      //Read out entries of pipe until no entry is left in the pipe
      while sChangesData.ActEntries do
        sChangesData.ActEntries := cPipe_GetUsed(p:=sChangesData.pChangesPipeHandle);
        cPipe_Get(pd:=NIL, p:=sChangesData.pChangesPipeHandle);
      end_while;
    end_if;
  
//*******************************************************************************************************************
  MDD2000MNG_LC2_NEWINST_RWPARLASAL2 :
    
    if Online.read() = 1 then
      ret_code := BUSY;
      
      // get Axisnumber
      AxisNo := to_usint(pPara^.aPara[0] AND 16#FF);
      
      AxIndex := GetAxIndex(AxisNo-1);
      
      if AxIndex = 16#FF then
        ret_code := ERROR;
        return;
      end_if;
      
      // read or write
      ParRw   := to_usint((pPara^.aPara[0] AND 16#FF00) SHR 8);
      // parameter number 
      ParNo   := to_usint((pPara^.aPara[0] AND 16#FF0000) SHR 16);
      
      //Convert Parameter number to DS402 parameter format
      ConvertLC2ParaFormatToDS402Format(ParaNo:=ParNo, phParaIndex:=#hIndex, phsParaSubIndex:=#hsSubIndex);
      
      case ParRw of
      0 : // Read the parameter

        tmpRetCode := AddASyncEntryDS402( AxisIdx     :=  AxIndex
                                        , uiParaID    :=  hIndex
                                        , usParaSubID :=  hsSubIndex
                                        , usRdWr      :=  ParRw
                                        , pValue      :=  NIL
                                        , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                                        , pThisObj    :=  this
                                        , usEntry     :=  MDD2000MNG_ENTRY_TYPE_FROM_LASAL
                                        , udTimeout   :=  0);
        
      1 : // Write the parameter
        
        tmpRetCode := AddASyncEntryDS402( AxisIdx     :=  AxIndex
                                        , uiParaID    :=  hIndex
                                        , usParaSubID :=  hsSubIndex
                                        , usRdWr      :=  ParRw
                                        , pValue      :=  #pPara^.aPara[1]
                                        , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                                        , pThisObj    :=  this
                                        , usEntry     :=  MDD2000MNG_ENTRY_TYPE_FROM_LASAL
                                        , udTimeout   :=  0);
      else
        ret_code := ERROR;
      end_case;
      
      if tmpRetCode < 0 then
        // internal failure
        Ret_code := ERROR;
      end_if;
    else
      ret_code := ERROR;
    end_if;
  
//*******************************************************************************************************************
  MDD2000MNG_LC2_NEWINST_GETAXISINUSE :
    ret_code := READY;
    pResult^.uiLng := sizeof(BDINT);
    pResult^.aData[0]$BDINT :=  AxIndizesL2;
  
//*******************************************************************************************************************
  MDD2000MNG_LC2_NEWINST_GETSERIE :
    ret_code := READY;
    pResult^.uiLng := sizeof(USINT);
    
    //sdias drive connected
    MyPara.uiCmd  := BUSIF_DRIVEMNGBASE_SDD_GETSERIES;
    ToBusIF.NewInst(#MyPara, #MyResult);    
    pResult^.aData[0] := MyResult.aData[0];

  // new commands in lasal communication version 4 (MDD2000MNG_LC2_NEWINST_GET_CHANGE_CNT, MDD2000MNG_LC2_NEWINST_GET_PARAMS)
//*******************************************************************************************************************
  MDD2000MNG_LC2_NEWINST_GET_CHANGE_CNT :
    ret_code := READY;
    pResult^.uiLng := sizeof(UDINT);
    pResult^.aData[0]$^UDINT := #sChangesData.ActEntries;
  
//*******************************************************************************************************************
  MDD2000MNG_LC2_NEWINST_GET_PARAMS :
    ret_code := READY;
    
    sChangesData.ActEntries := cPipe_GetUsed(p:=sChangesData.pChangesPipeHandle);
    
    if sChangesData.ActEntries then

      RetcodeSizeLeft := sizeof(pResult^.aData) - SIZEOF(UINT);
      pResult^.uiLng := 0;

      pActRetEntry := (#pResult^.aData[2])$^_ParaRefreshBufEntry;

      // as long as there are entries in change buffer and we still have some place in the return value array
      while sChangesData.ActEntries & (RetcodeSizeLeft > sizeof(_ParaRefreshBufEntry)) do
        
        // store actual buffer entry in returncode
        cPipe_Get(pd:=pActRetEntry, p:=sChangesData.pChangesPipeHandle);
              
        // increase size of returncode in it's header
        pResult^.uiLng += sizeof(_ParaRefreshBufEntry);
        
        // decrease available size of returncode
        RetcodeSizeLeft -= sizeof(_ParaRefreshBufEntry);

        // increase pointer in retcode
        pActRetEntry += sizeof(_ParaRefreshBufEntry);
        
        // decrease available changes
        sChangesData.ActEntries := cPipe_GetUsed(p:=sChangesData.pChangesPipeHandle);
      end_while;
      
      // save number of entries in the first 2 byte of the array
      pResult^.aData[0]$UINT := pResult^.uiLng / sizeof(_ParaRefreshBufEntry);
      
      LastRetcode := pResult^;
    else
      // no changes to fetch
      pResult^.uiLng := 0;
    end_if;

//*******************************************************************************************************************
  MDD2000MNG_NEWINST_GET_AXIS_PTR_LIST:
  
    ret_code := READY;
    
    //                    NoAxis    +  Thisptr per axis
    pResult^.uiLng := (sizeof(DINT) + AxCount * sizeof(UDINT))$UINT;
    
    // get no of axis
    pResult^.aData[0]$DINT := AxCount;
    
    // get this pointer of axis to resultbuffer (with increasing AxNumber)
    pThisRes := #pResult^.aData[4]$UDINT;
    FoundAxis := 0;
    for i := 0 to MDD2000MNG_MAXENTRIES-1 do
      
      if AxBuffer[i].pThis then
        FoundAxis += 1;
        pThisRes^ := AxBuffer[i].pThis$UDINT;
        pThisRes += sizeof(UDINT);
      end_if;

      if FoundAxis = AxCount then
        // all avaliable found, exit loop
        exit;
      end_if;
    end_for;
    // fill space with NIL if a axis is not found
    while FoundAxis < AxCount do
      pThisRes^ := NIL;
      pThisRes += sizeof(UDINT);
      FoundAxis += 1;
    end_while;

//*******************************************************************************************************************
  CMD_GET_HARDWARE_DIAGNOSIS : 

    pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR;
    ret_code := ERROR;
    
    pStr_HWTRequested := pPara^.aPara[0]$t_HWCGetHardwareDiagnosisIn.pStr_HardewareTreeEntry;
    
    // Check HWT String
    if pStr_HWTRequested then      
      
      us_HWTRequestedCurrIndex := to_usint(pStr_HWTRequested$^UINT^ + 1); // +1 for 2byte length, points to end of HWT String
      
      if ( (pStr_HWTRequested + us_HWTRequestedCurrIndex - 1)^ = HWT_ESCAPE_DRIVE ) then // second to last byte is Drive escape sequence

        us_RequestedPlace := (pStr_HWTRequested + us_HWTRequestedCurrIndex)^; // Get passed place
      
        // Return State and Device ID and set retcode ----------------------------------------------------------
        pResult^.aData$t_HWCGetHardwareDiagnosisOut.ClassState := ClassState;
        
        pResult^.aData$t_HWCGetHardwareDiagnosisOut.ud_DeviceID := GetDrvDeviceID();
        
        if ClassState = _NoHardware then
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_NO_HARDWARE;
        elsif ClassState = _WrongHardware then
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_WRONG_HARDWARE;
        elsif ClassState = _NoCalibDataFound then
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_NO_CALIB_DATA_FOUND;
        elsif ClassState <> _ClassOk then
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_NO_HARDWARE;
        end_if;
        //------------------------------------------------------------------------------------------------------
        
        if ClassState= _ClassOk then 
        
          // Search for Axis with the passed place
          for i := 0 to MDD2000MNG_MAXENTRIES - 1 do
            if AxBuffer[i].pThis then
              
              if ( 0 = us_RequestedPlace ) then
                
                // Diagnosis info is stored with the axis class
                ret_code := AxBuffer[i].pThis$pVirtualBase^.NewInst(pPara, pResult);
                
                // FW Version ----------------------------------------------------------------------------------------------------------
                pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pStr_FWVersion := #a_FWVersion[0];  // Will be overwritten if this pointer is not equal 

                ud_StrSize := FwNumString.GetLength();
                pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pStr_FWVersion     := NIL;
                
                if ud_StrSize then
                  // Copy String
                  FwNumString.TxtGet(pdst:=#a_FWVersion[0], dstsize:=sizeof(a_FWVersion) );
                  pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pStr_FWVersion := #a_FWVersion[0];
                end_if;
                
                // HW Version 
                pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.hd_HWVersion := Parameter_I_HW$UDINT;
                
                return;
              end_if;
            
            end_if;
          
          end_for;
          
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_AXIS_MODULE_NOT_FOUND;
          ret_code := ERROR;
        
        end_if;
        
      elsif ( (pStr_HWTRequested + us_HWTRequestedCurrIndex - 1)^ = HWT_ESCAPE_AXIS ) &      // second to last byte is Axis escape sequence
            ( (pStr_HWTRequested + us_HWTRequestedCurrIndex - 3)^ = HWT_ESCAPE_DRIVE ) then  
      
        
        us_RequestedPlace := (pStr_HWTRequested + us_HWTRequestedCurrIndex - 2)^; // Get passed place
        us_RequestedAxis  := (pStr_HWTRequested + us_HWTRequestedCurrIndex)^ + 1; // Get passed axisno (+1 AxisNo in HWT String run from 0 to 2)
        
        // Return State and Device ID and set retcode ----------------------------------------------------------
        pResult^.aData$t_HWCGetHardwareDiagnosisOut.ClassState := ClassState;
        
        pResult^.aData$t_HWCGetHardwareDiagnosisOut.ud_DeviceID := GetDrvDeviceID();
        
        if ClassState = _NoHardware then
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_NO_HARDWARE;
        elsif ClassState = _WrongHardware then
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_WRONG_HARDWARE;
        elsif ClassState = _NoCalibDataFound then
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_NO_CALIB_DATA_FOUND;
        elsif ClassState <> _ClassOk then
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_NO_HARDWARE;
        end_if;
        //------------------------------------------------------------------------------------------------------
        
        if ClassState= _ClassOk then 
        
          // Search for Axis with the passed place and axisno
          for i := 0 to MDD2000MNG_MAXENTRIES - 1 do
            if AxBuffer[i].pThis then
              
              if ( AxBuffer[i].AxisNo = us_RequestedAxis  ) then
                
                ret_code := AxBuffer[i].pThis$pVirtualBase^.NewInst(pPara, pResult);
                return;
              end_if;
            
            end_if;
          
          end_for;
            
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_AXIS_MODULE_NOT_FOUND;
          ret_code := ERROR;
        
        end_if;
      else
      
        // Return diagnosis for the DriveMng
        
        // Return State and Device ID and set retcode ----------------------------------------------------------
        pResult^.aData$t_HWCGetHardwareDiagnosisOut.ClassState := ClassState;
        
        pResult^.aData$t_HWCGetHardwareDiagnosisOut.ud_DeviceID := GetBusDeviceID();
        
        if ClassState = _NoHardware then
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_NO_HARDWARE;
        elsif ClassState = _WrongHardware then
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_WRONG_HARDWARE;
        elsif ClassState = _NoCalibDataFound then
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_NO_CALIB_DATA_FOUND;
        elsif ClassState <> _ClassOk then
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_NO_HARDWARE;
        end_if;
        //------------------------------------------------------------------------------------------------------
        
        if ClassState= _ClassOk then      
          
          //StrDriveType which is already in HWK available
          pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_DeviceID := DeviceID;
          pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_VendorID := VendorID;
          
          pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_OK;
          ret_code := READY;
          
        end_if;
      end_if;

    end_if;
    
//*******************************************************************************************************************
  CMD_GET_HARDWARE_TREE_ENTRY:

    ret_code := ERROR;
    pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_ERROR;
    
    pStr_HWTRequested := pPara^.aPara[0]$t_HWCGetHardwareTreeEntryIn.pStr_LastHardewareTreeEntry;
    
    if pStr_HWTRequested then
    
      us_HWTRequestedCurrIndex := to_usint(pStr_HWTRequested$^UINT^ + 1); // +1 for 2byte length, points to end of HWT String
      
      // -----------------------------------------------------------------------------------------------------------------------------
      // Return 1st axis at place, if no axis at place return next place
      if ( (pStr_HWTRequested + us_HWTRequestedCurrIndex - 1)^ = HWT_ESCAPE_DRIVE ) then
      
        us_RequestedPlace := (pStr_HWTRequested + us_HWTRequestedCurrIndex)^; // Get last place
        
        // Find 1.st axis at place
        us_NextAxis := 16#FF;
        
        for i := 0 to MDD2000MNG_MAXENTRIES - 1 do
        
          if (AxBuffer[i].pThis) & 
             (0 = us_RequestedPlace) &
             (AxBuffer[i].AxisNo < us_NextAxis) then

            us_NextAxis := to_usint(AxBuffer[i].AxisNo);
          end_if;
          
        end_for;
        
        if (us_NextAxis < 16#FF) then
          // Copy string and add axis no 
          // Copy passed string 
          _memcpy(ptr1 := #a_HWTEntryStr[0]
                , ptr2 := pStr_HWTRequested
                , cntr := pStr_HWTRequested^$UINT+2); // +2 for 2 byte length
                
          // Add Escape Sequence axis
          a_HWTEntryStr[0]$UINT += 1;   
          a_HWTEntryStr[a_HWTEntryStr[0]$UINT+1] := HWT_ESCAPE_AXIS;
          
          // Add axis no
          a_HWTEntryStr[0]$UINT += 1;   
          a_HWTEntryStr[a_HWTEntryStr[0]$UINT+1] := us_NextAxis - 1; // -1 AxisNo in HWT String run from 0 to 2
          
          // Set return pointer
          pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.pStr_NextHardewareTreeEntry := #a_HWTEntryStr[0];
          
          ret_code := READY;
          pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_OK_HWTSTR_RETURNED;
          
          return;
        else          
          
          ret_code := READY;
          pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_OK_END_OF_LIST;
          return;

        end_if;
      
      // -----------------------------------------------------------------------------------------------------------------------------
      // return next axis, if last axis at passed place return next place
      elsif ( (pStr_HWTRequested + us_HWTRequestedCurrIndex - 1)^ = HWT_ESCAPE_AXIS )  & 
            ( (pStr_HWTRequested + us_HWTRequestedCurrIndex - 3)^ = HWT_ESCAPE_DRIVE ) then  // Must be 1st entry second to last byte is next Axis escape sequence
         
        us_RequestedPlace := (pStr_HWTRequested + us_HWTRequestedCurrIndex - 2)^; // Get last place
        us_RequestedAxis  := (pStr_HWTRequested + us_HWTRequestedCurrIndex)^ + 1; // Get last axisno (+1 AxisNo in HWT String run from 0 to 2)
        
        // Find min next axis
        us_NextAxis := 16#FF;
        
        for i := 0 to MDD2000MNG_MAXENTRIES - 1 do
        
          if (AxBuffer[i].pThis) &
             (0 = us_RequestedPlace) & 
             (AxBuffer[i].AxisNo > us_RequestedAxis) & 
             (AxBuffer[i].AxisNo < us_NextAxis) then
            
            us_NextAxis := to_usint(AxBuffer[i].AxisNo);
          end_if;
          
        end_for;
        
        if (us_NextAxis < 16#FF) then
        
          // Copy string and replace AxisNo
          // Copy passed string 
          _memcpy(ptr1 := #a_HWTEntryStr[0]
                , ptr2 := pStr_HWTRequested
                , cntr := pStr_HWTRequested^$UINT+2); // +2 for 2 byte length   
                
          // replace AxisNo
          a_HWTEntryStr[a_HWTEntryStr[0]$UINT+1] := us_NextAxis - 1;  // -1 AxisNo in HWT String run from 0 to 2
          
          // Set return pointer
          pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.pStr_NextHardewareTreeEntry := #a_HWTEntryStr[0];
          
          ret_code := READY;
          pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_OK_HWTSTR_RETURNED;
          return;
        
        else
        
          ret_code := READY;
          pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_OK_END_OF_LIST;
          return;
        
        end_if;
        
      // -----------------------------------------------------------------------------------------------------------------------------
      else  // 1st call after manager, find and return min valid place
      
        // Find min next place
        us_NextPlace := 16#FF;
      
        // Search for next Place
        for i := 0 to MDD2000MNG_MAXENTRIES - 1 do
          
          if (AxBuffer[i].pThis) then
             
            us_NextPlace := 0;
          end_if;
        end_for;
        
        if (us_NextPlace < 16#FF) then
          // Copy 1st part of HWT
          _memcpy(ptr1 := #a_HWTEntryStr[0]
                , ptr2 := pStr_HWTRequested
                , cntr := pStr_HWTRequested^$UINT+2); // +2 for 2 byte length
                
          // Add Escape Sequence drive
          a_HWTEntryStr[0]$UINT += 1;      
          a_HWTEntryStr[a_HWTEntryStr[0]$UINT+1] := HWT_ESCAPE_DRIVE;
          
          // Add Place
          a_HWTEntryStr[0]$UINT += 1;
          a_HWTEntryStr[a_HWTEntryStr[0]$UINT+1] := us_NextPlace; 
          
          // Set return pointer
          pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.pStr_NextHardewareTreeEntry := #a_HWTEntryStr[0];
            
          ret_code := READY;
          pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_OK_HWTSTR_RETURNED;
          return;
        else
        
          ret_code := READY;
          pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_OK_END_OF_LIST;
          return;
        
        end_if;
      
      end_if;
      
//    else
//     
//      // Error, Need valid HWT String from Manager
//      return;
    end_if;    

 
  //*******************************************************************************************************************
  MDD2000MNG_LC2_NEWINST_GET_DEVICESERIALNO:
  
    //is not called at 2000er drive from lasal
    pResult^.uiLng := 0;
    ret_code := READY;

  //*******************************************************************************************************************
  MDD2000MNG_LC2_NEWINST_GET_MNG_TRANSPARENT:  //Called from Lasal2
    
    // Get transparent information from VaranCommunication object. used to not show transparent objects in DiasDriveOnline Window
    MyPara.uiCmd  := BUSIF_DRIVEMNGBASE_GET_TRANSPARENT_STATE;
    
    if ToBusIF.NewInst(#MyPara, #MyResult) = ERROR then
      //Transparent info not available
      MyResult.aData[4] := 0;
    end_if;
    
    ret_code := READY;
    pResult^.uiLng := sizeof(DINT);        
    pResult^.aData[0] := MyResult.aData[4]; 
    
  //*******************************************************************************************************************
  MDD2000MNG_NEWINST_GETFILE: //command will be called from application

    ret_code := ERROR;    
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_NEWINST_GETFILE_VER_1 then
      //Call method
      ret_code := GetFile(pDestinationDPNE := pPara^.aPara[1]$^CHAR
                        , pFileNameDrive   := pPara^.aPara[2]$^CHAR 
                        , pFilePathDrive   := pPara^.aPara[3]$^CHAR
                        , pdError          := pPara^.aPara[4]$^DINT
                        );
    elsif pPara^.aPara[4] then 
      (pPara^.aPara[4]$^DINT)^ := MDD2000MNG_FILE_HANDLING_RETCODE_CMDVERSION_NOTSUPPORTED;
    end_if;
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_NEWINST_GETFILE_VER_MAX;  //max supported version
    
  //*******************************************************************************************************************
  MDD2000MNG_NEWINST_GETLOGFILE: //command will be called from application
  
    ret_code := ERROR; //unsupported version

    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_NEWINST_GETLOGFILE_VER_1 then
      //Call method
      ret_code := GetLogFile(pDestinationDPNE  := pPara^.aPara[1]$^CHAR
                           , pdError           := pPara^.aPara[2]$^DINT
                           );
    //Check version 2
    elsif pPara^.aPara[0] = MDD2000MNG_NEWINST_GETLOGFILE_VER_2 then
      //Call method
      ret_code := GetLogFile(pDestinationDPNE  := pPara^.aPara[1]$^CHAR
                           , pdError           := pPara^.aPara[2]$^DINT
                           , udFileSelectID    := pPara^.aPara[3]$UDINT
                           );
    elsif pPara^.aPara[2] then 
      (pPara^.aPara[2]$^DINT)^ := MDD2000MNG_FILE_HANDLING_RETCODE_CMDVERSION_NOTSUPPORTED;
    end_if;

    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_NEWINST_GETLOGFILE_VER_MAX;  //max supported version

  //*******************************************************************************************************************
  MDD2000MNG_NEWINST_GETFILESTATE:  //command will be called from application

    ret_code := ERROR; //unsupported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_NEWINST_GETFILESTATE_VER_1 then
      //Call method
      ret_code := GetFileState(pdError      :=  pPara^.aPara[1]$^DINT
                             , pdProgress   :=  pPara^.aPara[2]$^DINT
                             , pudBytesRead :=  pPara^.aPara[3]$^UDINT
                              );
    elsif pPara^.aPara[1] then 
      (pPara^.aPara[1]$^DINT)^ := MDD2000MNG_FILE_HANDLING_RETCODE_CMDVERSION_NOTSUPPORTED;
    end_if;

    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_NEWINST_GETFILESTATE_VER_MAX;  //max supported version

  //*******************************************************************************************************************
  MDD2000MNG_NEWINST_SETFILE: //command will be called from application

    ret_code := ERROR;    
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_NEWINST_SETFILE_VER_1 then
      //Call method
      ret_code := SetFile(pWriteData      :=  pPara^.aPara[1]$^void
                        , udWriteDataLen  :=  pPara^.aPara[2]$UDINT
                        , pFilePathDrive  :=  pPara^.aPara[3]$^cHAR
                        , pFileNameDrive  :=  pPara^.aPara[4]$^cHAR
                        , pdError         :=  pPara^.aPara[5]$^DINT
                        );      
    elsif pPara^.aPara[5] then 
      (pPara^.aPara[5]$^DINT)^ := MDD2000MNG_FILE_HANDLING_RETCODE_CMDVERSION_NOTSUPPORTED;
    end_if;
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_NEWINST_SETFILE_VER_MAX;  //max supported version


//*******************************************************************************************************************
  MDD2000MNG_NEWINST_GETFILESIZE:  //command will be called from application

    ret_code := ERROR; //unsupported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_NEWINST_GETFILESIZE_VER_1 then
      //Call method
      ret_code := GetFileSize(pFileNameDrive  :=  pPara^.aPara[1]$^CHAR
                            , pFilePathDrive  :=  pPara^.aPara[2]$^CHAR
                            , pudSize         :=  pPara^.aPara[3]$^UDINT
                            , pdError         :=  pPara^.aPara[4]$^DINT
                            );
    elsif pPara^.aPara[4] then 
      (pPara^.aPara[4]$^DINT)^ := MDD2000MNG_FILE_HANDLING_RETCODE_CMDVERSION_NOTSUPPORTED;
    end_if;

    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_NEWINST_GETFILESIZE_VER_MAX;  //max supported version

//*******************************************************************************************************************
  MDD2000MNG_NEWINST_GETFILEBUFFER:  //command will be called from application

    ret_code := ERROR; //unsupported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_NEWINST_GETFILEBUFFER_VER_1 then
      //Call method
      
      ret_code := GetFileBuffer(pFileNameDrive  :=  pPara^.aPara[1]$^CHAR
                              , pFilePathDrive  :=  pPara^.aPara[2]$^CHAR
                              , udBufferSize    :=  pPara^.aPara[3]$UDINT
                              , pDataBuffer     :=  pPara^.aPara[4]$^void
                              , udDataLenToRead :=  pPara^.aPara[5]$UDINT
                              , pdError         :=  pPara^.aPara[6]$^DINT
                              );
    elsif pPara^.aPara[6] then 
      (pPara^.aPara[6]$^DINT)^ := MDD2000MNG_FILE_HANDLING_RETCODE_CMDVERSION_NOTSUPPORTED;
    end_if;

    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_NEWINST_GETFILEBUFFER_VER_MAX;  //max supported version

//*******************************************************************************************************************
  MDD2000MNG_IF_LOGINAXISOBJECT:  //command will be called from axis hardware class

    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_LOGINAXISOBJECT_VER_MAX;  //max supported version
    
    //Check version
    if pPara^.aPara[0] = MDD2000MNG_IF_LOGINAXISOBJECT_VER_1 then
      
      //Call method
      ret_code := AddAxObj(pThis          :=  pPara^.aPara[1]$^void
                         , AxisNo         :=  pPara^.aPara[2]$DINT
                         , pAsyPipeHandle :=  pPara^.aPara[3]$^void
                         );
    
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_LOGINAXISOBJECT detected", #pPara^.aPara[0]);      
    end_if;

//*******************************************************************************************************************
  MDD2000MNG_IF_GET_SYNC_ENTRY:

    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_GET_SYNC_ENTRY_VER_MAX;  //max supported version  
    
    //Check version
    if pPara^.aPara[0] = MDD2000MNG_IF_GET_SYNC_ENTRY_VER_1 then
      
      pResult^.uiLng := 8;
      pResult^.aData[4]$DINT := GetSyncEntry(usAxis:=pPara^.aPara[1]$USINT, usValue:=pPara^.aPara[2]$USINT, usPData:=pPara^.aPara[3]$^DINT);
      
      ret_code := READY;
    
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_GET_SYNC_ENTRY detected", #pPara^.aPara[0]);      
    end_if;
  
//*******************************************************************************************************************
  MDD2000MNG_IF_SET_SYNC_ENTRY:
  
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_SET_SYNC_ENTRY_VER_MAX;  //max supported version
    
    //Check version
    if pPara^.aPara[0] = MDD2000MNG_IF_SET_SYNC_ENTRY_VER_1 then
    
      pResult^.uiLng := 8;
      pResult^.aData[4]$DINT := SetSyncEntry(usAxis:=pPara^.aPara[1]$USINT, usValue:=pPara^.aPara[2]$USINT, usPData:=pPara^.aPara[3]);
      
      ret_code := READY;
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_SET_SYNC_ENTRY detected", #pPara^.aPara[0]);      
    end_if;
  
//*******************************************************************************************************************
  MDD2000MNG_IF_GET_COMM_STATE:

    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_GET_COMM_STATE_VER_MAX;  //max supported version
    
    //Check version
    if pPara^.aPara[0] = MDD2000MNG_IF_GET_COMM_STATE_VER_1 then
    
      pResult^.uiLng := 8;
      pResult^.aData[4]$DINT := CommunicationState();
      
      ret_code := READY;
    
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_GET_COMM_STATE detected", #pPara^.aPara[0]);      
    end_if;

//*******************************************************************************************************************
  MDD2000MNG_IF_AXISINITFINISHED:
  
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_AXISINITFINISHED_VER_MAX;  //max supported version
    
    //Check version
    if pPara^.aPara[0] = MDD2000MNG_IF_AXISINITFINISHED_VER_1 then
    
      AxisInitFinished(AxisIdx:=pPara^.aPara[1]$USINT, IdFinished:=pPara^.aPara[2]);
      ret_code := READY;
    
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_AXISINITFINISHED detected", #pPara^.aPara[0]);      
    end_if;

//*******************************************************************************************************************
  MDD2000MNG_IF_SET_PARALIST:
  
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_SET_PARALIST_VER_MAX;  //max supported version
    
    //Check version
    if pPara^.aPara[0] = MDD2000MNG_IF_SET_PARALIST_VER_1 then
      
      SetParaList(usAxis      :=  pPara^.aPara[1]$USINT  
                , adress      :=  pPara^.aPara[2]$^void
                , ui_counter  :=  pPara^.aPara[3]$UINT);
                
      ret_code := READY;
    
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_SET_PARALIST detected", #pPara^.aPara[0]);      
    end_if;

//*******************************************************************************************************************
  MDD2000MNG_IF_GET_PARA_STATE:
  
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_GET_PARA_STATE_VER_MAX;  //max supported version
    
    //Check version
    if pPara^.aPara[0] = MDD2000MNG_IF_GET_PARA_STATE_VER_1 then
    
      pResult^.uiLng := 8;    
      pResult^.aData[4]$DINT := GetParameterState(usAxis:=pPara^.aPara[1]$USINT);
      
      ret_code := READY;
    
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_GET_PARA_STATE detected", #pPara^.aPara[0]);      
    end_if;

//*******************************************************************************************************************
  MDD2000MNG_IF_GET_AXIS_RD_WR_PTR:
  
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_GET_AXIS_RD_WR_PTR_VER_MAX;  //max supported version
    
    //Check version
    if pPara^.aPara[0] = MDD2000MNG_IF_GET_AXIS_RD_WR_PTR_VER_1 then
    
      pResult^.uiLng := 12;    
      
      //Read
      if pPara^.aPara[1] = 0 then
        pResult^.aData[4]$^void := GetAxisRdPtr(usAxis:=pPara^.aPara[2]$USINT, pRdLen := (#pResult^.aData[8])$^UDINT)$^void;
        ret_code := READY;
      
      //Write
      elsif pPara^.aPara[1] = 1 then
        pResult^.aData[4]$^void := GetAxisWrPtr(usAxis:=pPara^.aPara[2]$USINT, pWrLen := (#pResult^.aData[8])$^UDINT)$^void;
        ret_code := READY;
      
      else  //Invalid parameter
        pResult^.aData[4]$^void := NIL;
        pResult^.aData[8]$UDINT := 0;
      end_if;      
    
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_GET_AXIS_RD_WR_PTR detected", #pPara^.aPara[0]);      
    end_if;

//*******************************************************************************************************************
  MDD2000MNG_IF_INIT_DRIVE:

    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_INIT_DRIVE_VER_MAX;  //max supported version
    
    //Check version
    if pPara^.aPara[0] = MDD2000MNG_IF_INIT_DRIVE_VER_1 then
    
      InitDrive(Mode:=pPara^.aPara[1]$USINT);
      
      ret_code := READY;
    
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_INIT_DRIVE detected", #pPara^.aPara[0]);      
    end_if;

//*******************************************************************************************************************
  MDD2000MNG_IF_IS_ANY_AXIS_ENABLED:
  
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_IS_ANY_AXIS_ENABLED_VER_MAX;  //max supported version
    
    //Check version
    if pPara^.aPara[0] = MDD2000MNG_IF_IS_ANY_AXIS_ENABLED_VER_1 then
    
      pResult^.uiLng := 8;    
      pResult^.aData[4]$BOOL := IsAnyAxisEnabled();
      
      ret_code := READY;
    
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_IS_ANY_AXIS_ENABLED detected", #pPara^.aPara[0]);      
    end_if;
    
//*******************************************************************************************************************
  MDD2000MNG_IF_ADD_ASYNC_ENTRY_DS402:  //command will be called from axis hardware class
        
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_ADD_ASYNC_ENTRY_DS402_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_ADD_ASYNC_ENTRY_DS402_VER_1 then
      
      //Call method
      tmpRetCode := AddASyncEntryDS402(AxisIdx      :=  pPara^.aPara[1]$USINT
                                     , uiParaID     :=  pPara^.aPara[2]$UINT
                                     , usParaSubID  :=  pPara^.aPara[3]$USINT
                                     , usRdWr       :=  pPara^.aPara[4]$USINT
                                     , pValue       :=  pPara^.aPara[5]$^void
                                     , bsDataInfo   :=  pPara^.aPara[6]$BSINT
                                     , pThisObj     :=  pPara^.aPara[7]$^void
                                     , usEntry      :=  pPara^.aPara[8]$USINT
                                     , udTimeout    :=  pPara^.aPara[9]$UDINT
                                     , dCallID      :=  pPara^.aPara[10]$DINT
                                     );
                                     
      pResult^.uiLng := 8;
      pResult^.aData[4]$DINT := tmpRetCode; //Give back return code
      
      ret_code := READY;
      
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_ADD_ASYNC_ENTRY_DS402 detected", #pPara^.aPara[0]);      
    end_if;

//*******************************************************************************************************************
  MDD2000MNG_IF_IS_ONLINE:  //command will be called from axis hardware class

    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_IS_ONLINE_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_IS_ONLINE_VER_1 then
      
      pResult^.uiLng := 8;
      pResult^.aData[4]$DINT := Online.Read();
      
      ret_code := READY;
      
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_IS_ONLINE detected", #pPara^.aPara[0]);      
    end_if;

//*******************************************************************************************************************
  MDD2000MNG_IF_CREATE_DEF_PARA_BASE:  //command will be called from axis hardware class

    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_CREATE_DEF_PARA_BASE_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_CREATE_DEF_PARA_BASE_VER_1 then
      
      pResult^.uiLng := 8;
      pResult^.aData[4]$DINT := Online.Read();
      
      MyPara.uiCmd    := pPara^.aPara[1]$UINT;
      MyPara.aPara[0] := pPara^.aPara[2];
      MyPara.aPara[1] := pPara^.aPara[3];
      MyPara.aPara[2] := pPara^.aPara[4];
      
      CreateDefParaBase(CmdPara:=#MyPara, Results:=#MyResult);
      
      ret_code := READY;
      
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_CREATE_DEF_PARA_BASE detected", #pPara^.aPara[0]);      
    end_if;

//*******************************************************************************************************************    
  MDD2000MNG_IF_GET_DRIVE_TYP_STR:
    
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_CREATE_DEF_PARA_BASE_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_CREATE_DEF_PARA_BASE_VER_1 then
    
      GetDriveTypeStr(pDriveTypeStr   := pPara^.aPara[1]$^Char
                    , DriveTypeStrSize:= pPara^.aPara[2]$UDINT);
      
      ret_code := READY;
      
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_GET_DRIVE_TYP_STR detected", #pPara^.aPara[0]);      
    end_if;

//*******************************************************************************************************************    
  MDD2000MNG_IF_GET_MNGRDY_4_AXISCONFIG:
    
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_GET_MNGRDY_4_AXISCONFIG_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_GET_MNGRDY_4_AXISCONFIG_VER_1 then
      
      pResult^.uiLng := 8;
      pResult^.aData[4]$DINT := 0;
      if eInitSSW = t_e_InitSSW::_Wait4AxisConfig then
        pResult^.aData[4]$DINT := 1;
      end_if;

      ret_code := READY;
      
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_GET_MNGRDY_4_AXISCONFIG detected", #pPara^.aPara[0]);      
    end_if;
    
//*******************************************************************************************************************
  MDD2000MNG_IF_ADD_PARA_OBJECT:
  
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_ADD_PARA_OBJECT_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_ADD_PARA_OBJECT_VER_1 then
      
      pResult^.uiLng := 8;
      pResult^.aData[4]$DINT := AddParaObjects(Index:=pPara^.aPara[1]$USINT, pThis:=pPara^.aPara[2]$^void);
      
      ret_code := READY;
      
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_ADD_PARA_OBJECT detected", #pPara^.aPara[0]);      
    end_if;
    
//*****************************************************************************
  MDD2000MNG_IF_IS_AXIS_READY_4_ASYPARA:
  
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_IS_AXIS_READY_4_ASYPARA_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_IS_AXIS_READY_4_ASYPARA_VER_1 then
      
      pResult^.uiLng := 8;
      
      if Online.Read() then
        pResult^.aData[4]$DINT := TRUE;
      else
        pResult^.aData[4]$BOOL := FALSE;
      end_if;
      
      ret_code := READY;
      
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_IS_AXIS_READY_4_ASYPARA detected", #pPara^.aPara[0]);      
    end_if;
    
//*****************************************************************************
  MDD2000MNG_IF_RESET_SAFE_VERIFY_ZEROPOS:

    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_RESET_SAFE_VERIFY_ZEROPOS_VER_MAX;  //max supported version
    
    //Check version
    if pPara^.aPara[0] = MDD2000MNG_IF_RESET_SAFE_VERIFY_ZEROPOS_VER_1 then
    
      ResetSafeVerifyZeropos(AxisIdx:=pPara^.aPara[1]$USINT, IdReset:=pPara^.aPara[2]);
      ret_code := READY;
    
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_RESET_SAFE_VERIFY_ZEROPOS detected", #pPara^.aPara[0]);      
    end_if;
    
//*****************************************************************************    
    MDD2000MNG_IF_SAFETYCONFIG_CHANGEDRESULT:
    
      ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_SAFETYCONFIG_CHANGEDRESULT_VER_MAX;  //max supported version
    
    //Check version
    if pPara^.aPara[0] = MDD2000MNG_IF_SAFETYCONFIG_CHANGEDRESULT_VER_1 then
      sSafetyCfgChg.bdFaultInfo := pPara^.aPara[1]$BDINT;
      if sSafetyCfgChg.bdFaultInfo = 0 then
        SafetyRunState := SafetyRunStateInternal;
      else
        SafetyRunState := _FSOE_COMSETUPFAILED;
      end_if;

      ret_code := READY;
    
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_SAFETYCONFIG_CHANGEDRESULT detected", #pPara^.aPara[0]);      
    end_if;
    
//*****************************************************************************
  DRIVESAFETYIF_DOSAFETYAXERRORQUIT:
    
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := DRIVESAFETYIF_DOSAFETYAXERRORQUIT_VER_MAX;  //max supported version
    
    //Check version
    if pPara^.aPara[0] = DRIVESAFETYIF_DOSAFETYAXERRORQUIT_VER_1 then
    
      if (pPara^.aPara[1] = DRIVESAFETYIF_ERROR_QUIT) then
        
        bdSettings.QuitSafetyError := TRUE;
        ret_code := READY;
        
      elsif (pPara^.aPara[1] = DRIVESAFETYIF_RESTART_ACK) | 
            (pPara^.aPara[1] = DRIVESAFETYIF_ERROR_ACK) then
        
        // Axis specific, pass on to axis
        // Search for AxIndex
        for AxIndex := 0 to MDD2000MNG_MAXENTRIES -1 do
          if (AxBuffer[AxIndex].pThis <> NIL) then
            
            if (AxBuffer[AxIndex].AxisIndex = to_usint(pPara^.aPara[2]) ) then
              // pass on to axis
              ret_code :=  AxBuffer[AxIndex].pThis$^VirtualBase^.NewInst(pPara, pResult);
              exit;
            end_if;

          end_if;
        end_for;
      end_if;
    
    else
      HWC_LogPrintf(pThis:=this, format:="@08B3 (MDD2000MngBase::CmdState::NewInst) Unsupported version %d of commando DRIVESAFETYIF_DOSAFETYAXERRORQUIT detected", #pPara^.aPara[0]);      
    end_if;
    
//*****************************************************************************
  DRIVESAFETYIF_GETSAFETYERRORINFOS:
    
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := DRIVESAFETYIF_GETSAFETYERRORINFOS_VER_MAX;  //max supported version
    
    //Check version
    if pPara^.aPara[0] = DRIVESAFETYIF_GETSAFETYERRORINFOS_VER_1 then
    
      AxIndex := GetFirstAxIndex();
      
      if pPara^.aPara[1] <> 0 then  // ReRead Error Info:
      
        ret_code := READY;
        sSafetyErrInfo.bdAsyFlags := 0;  // Reset Flags
        
        if (AddAsyncEntryDS402(AxisIdx := AxIndex, uiParaID:=MDD2000_PID_SAFETY_ERROR, usParaSubID:=MDD2000_SPID_SAFETY_ERROR_SC1_CODE,  usRdWr:=0, pValue:=NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
          sSafetyErrInfo.bdAsyFlags.w4SafetyErrorCode_SC1 := TRUE;
        else
          sSafetyErrInfo.bdAsyFlags.errSafetyErrorCode_SC1 := TRUE;
          ret_code := ERROR;
        end_if;
        if (AddAsyncEntryDS402(AxisIdx := AxIndex, uiParaID:=MDD2000_PID_SAFETY_ERROR, usParaSubID:=MDD2000_SPID_SAFETY_ERROR_SC1_INFO1, usRdWr:=0, pValue:=NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
          sSafetyErrInfo.bdAsyFlags.w4SafetyErrorInformation1_SC1 := TRUE;
        else
          sSafetyErrInfo.bdAsyFlags.errSafetyErrorInformation1_SC1 := TRUE;
          ret_code := ERROR;
        end_if;
        if (AddAsyncEntryDS402(AxisIdx := AxIndex, uiParaID:=MDD2000_PID_SAFETY_ERROR, usParaSubID:=MDD2000_SPID_SAFETY_ERROR_SC1_INFO2, usRdWr:=0, pValue:=NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
          sSafetyErrInfo.bdAsyFlags.w4SafetyErrorInformation2_SC1 := TRUE;
        else
          sSafetyErrInfo.bdAsyFlags.errSafetyErrorInformation2_SC1 := TRUE;
          ret_code := ERROR;
        end_if;
        if (AddAsyncEntryDS402(AxisIdx := AxIndex, uiParaID:=MDD2000_PID_SAFETY_ERROR, usParaSubID:=MDD2000_SPID_SAFETY_ERROR_SC1_INFO3, usRdWr:=0, pValue:=NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
          sSafetyErrInfo.bdAsyFlags.w4SafetyErrorInformation3_SC1 := TRUE;
        else
          sSafetyErrInfo.bdAsyFlags.errSafetyErrorInformation3_SC1 := TRUE;
          ret_code := ERROR;
        end_if;
        if (AddAsyncEntryDS402(AxisIdx := AxIndex, uiParaID:=MDD2000_PID_SAFETY_ERROR, usParaSubID:=MDD2000_SPID_SAFETY_ERROR_SC2_CODE,  usRdWr:=0, pValue:=NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
          sSafetyErrInfo.bdAsyFlags.w4SafetyErrorCode_SC2 := TRUE;
        else
          sSafetyErrInfo.bdAsyFlags.errSafetyErrorCode_SC2 := TRUE;
          ret_code := ERROR;
        end_if;
        if (AddAsyncEntryDS402(AxisIdx := AxIndex, uiParaID:=MDD2000_PID_SAFETY_ERROR, usParaSubID:=MDD2000_SPID_SAFETY_ERROR_SC2_INFO1, usRdWr:=0, pValue:=NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
          sSafetyErrInfo.bdAsyFlags.w4SafetyErrorInformation1_SC2 := TRUE;
        else
          sSafetyErrInfo.bdAsyFlags.errSafetyErrorInformation1_SC2 := TRUE;
          ret_code := ERROR;
        end_if;
        if (AddAsyncEntryDS402(AxisIdx := AxIndex, uiParaID:=MDD2000_PID_SAFETY_ERROR, usParaSubID:=MDD2000_SPID_SAFETY_ERROR_SC2_INFO2, usRdWr:=0, pValue:=NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
          sSafetyErrInfo.bdAsyFlags.w4SafetyErrorInformation2_SC2 := TRUE;
        else
          sSafetyErrInfo.bdAsyFlags.errSafetyErrorInformation2_SC2 := TRUE;
          ret_code := ERROR;
        end_if;
        if (AddAsyncEntryDS402(AxisIdx := AxIndex, uiParaID:=MDD2000_PID_SAFETY_ERROR, usParaSubID:=MDD2000_SPID_SAFETY_ERROR_SC2_INFO3, usRdWr:=0, pValue:=NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
          sSafetyErrInfo.bdAsyFlags.w4SafetyErrorInformation3_SC2 := TRUE;
        else
          sSafetyErrInfo.bdAsyFlags.errSafetyErrorInformation3_SC2 := TRUE;
          ret_code := ERROR;
        end_if;
      
      else  // Return read Error info
      
        if sSafetyErrInfo.bdAsyFlags = 0 then // All flags 0, data valid
        
          pResult^.uiLng := 36;
          pResult^.aData[4]$DINT  := sSafetyErrInfo.SafetyErrorCode_SC1;
          pResult^.aData[8]$DINT  := sSafetyErrInfo.SafetyErrorInformation1_SC1;
          pResult^.aData[12]$DINT := sSafetyErrInfo.SafetyErrorInformation2_SC1;
          pResult^.aData[16]$DINT := sSafetyErrInfo.SafetyErrorInformation3_SC1;
          pResult^.aData[20]$DINT := sSafetyErrInfo.SafetyErrorCode_SC2;
          pResult^.aData[24]$DINT := sSafetyErrInfo.SafetyErrorInformation1_SC2;
          pResult^.aData[28]$DINT := sSafetyErrInfo.SafetyErrorInformation2_SC2;
          pResult^.aData[32]$DINT := sSafetyErrInfo.SafetyErrorInformation3_SC2;
          
          ret_code := READY;
          
        else
        
          if ((sSafetyErrInfo.bdAsyFlags AND 16#FF00) <> 0) then // One of the bits errSafetyErrorCode_SC1 to errSafetyErrorInformation3_SC2 is set
            ret_code := ERROR;
          else  // One of the bits w4SafetyErrorCode_SC1 to w4SafetyErrorInformation3_SC2 is set
            ret_code := BUSY;
          end_if;
          
        end_if;
        
      end_if;
    
    end_if;
    
//*****************************************************************************
  DRIVESAFETYIF_CHANGESAFESERVICEMODE:
    
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := DRIVESAFETYIF_CHANGESAFESERVICEMODE_VER_MAX;  //max supported version
    
    //Check version
    if pPara^.aPara[0] = DRIVESAFETYIF_CHANGESAFESERVICEMODE_VER_1 then
      
      pResult^.uiLng := 8;
      pResult^.aData[4]$t_e_MDD2000SafetyRunState := SafetyRunState;
      
      if pPara^.aPara[1] = 0 then
        ret_code := READY;        
      elsif pPara^.aPara[1] = 1 then
        bdSettings.SetServiceMode := TRUE;
        ret_code := READY;
      elsif pPara^.aPara[1] = 2 then
        bdSettings.LeaveServiceMode := TRUE;
        ret_code := READY;
      // else 
      //  // Error Only aPara[1] = 0,1,2 are defined
      end_if;
      
    end_if;
    
  end_case;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::CmdState::GetState
	VAR_INPUT
		pPara 	: ^CmdStruct;
		pResult 	: ^results;
	END_VAR
	VAR_OUTPUT
		ret_code 	: iprStates;
	END_VAR
  VAR
  	x         : BOOL;
    IntRdIndex  : DINT;
    AxisNo      : USINT;
    ParRW       : USINT;
    ParNo       : USINT;
  END_VAR

  ret_code := READY;
  
  case pPara^.uiCmd of
  
//*****************************************************************************
  MDD2000MNG_LC2_NEWINST_RWPARLASAL2 :
    
    ret_code := BUSY;
    
    // get Axisnumber
    AxisNo := to_usint(pPara^.aPara[0] AND 16#FF) - 1;
    
    // read or write
    ParRw   := to_usint((pPara^.aPara[0] AND 16#FF00) SHR 8);
    // parameter number 
    ParNo   := to_usint((pPara^.aPara[0] AND 16#FF0000) SHR 16);
    
    x := FALSE;
    if L2NewEntry <> 0 then
      for IntRdIndex := 0 to (MDD2000MNG_L2MAXINDEX - 1) do
        // now check if the right command is available
        if ((AxisNo =  L2Buffer[IntRdIndex].AxisNo) | (AxisNo = 0xFF)) & //0xFF for drive scope parameter and SDD1X00 drives
           ParRw = L2Buffer[IntRdIndex].ParRW & 
           ParNo = L2Buffer[IntRdIndex].ParNo  & 
           L2Buffer[IntRdIndex].bActive = TRUE then
           // we found the correct info
           pResult^.uiLng := 8; // Result info hat 8 Byte
           pResult^.aData[0] := AxisNo;
           pResult^.aData[1] := L2Buffer[IntRdIndex].ParState ;// hier steht ob ein Error vorhanden ist oder Nicht
           if L2Buffer[IntRdIndex].ParState = 0 then
            pResult^.aData[2] := ParRw;
           else
            pResult^.aData[2] := to_usint(L2Buffer[IntRdIndex].ParError);
           end_if;
           pResult^.aData[3] := ParNo;
           pResult^.aData[4]$DINT := L2Buffer[IntRdIndex].ParValue;
           
           ret_code := READY;
           
           // Daten werden gelöscht :
           L2Buffer[IntRdIndex].AxisNo := 0;
           L2Buffer[IntRdIndex].bActive := FALSE;
           L2NewEntry -= 1;
           if L2NewEntry < 0 then
             L2NewEntry := 0;
           end_if;
           exit;
        end_if;
      end_for;
    
    end_if;

  else
    ret_code := NewInst(pPara, pResult);
  end_case;


END_FUNCTION


FUNCTION MDD2000MngBase::GetAxisWrPtr
	VAR_INPUT
		usAxis 	: USINT;
		pWrLen 	: ^UDINT;(* := nil *)
	END_VAR
	VAR_OUTPUT
		ptr 	: ^void;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;   
  END_VAR
  
  ptr := NIL;
  if pWrLen then
    pWrLen^ := 0;
  end_if;
    
  if usAxis >= 0 & usAxis < MDD2000MNG_MAXENTRIES then
  
    MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_AXIS_WR_PTR_AND_LEN;
    MyPara.aPara[0] := BUSIF_DRIVEMNGBASE_GET_AXIS_WR_PTR_AND_LEN_VER_1;
    MyPara.aPara[1] := to_dint(AxBuffer[usAxis].AxisIndex);
    if ToBusIF.NewInst(#MyPara, #MyResult) = READY then
      ptr := MyResult.aData[4]$^void;
      if pWrLen then
        pWrLen^ := MyResult.aData[8]$UDINT;
      end_if;

    end_if;
  end_if;
    
END_FUNCTION


FUNCTION MDD2000MngBase::GetAxisRdPtr
	VAR_INPUT
		usAxis 	: USINT;
		pRdLen 	: ^UDINT;(* := nil *)
	END_VAR
	VAR_OUTPUT
		ptr 	: ^void;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;
  END_VAR
  
  ptr := NIL;
  if pRdLen then
    pRdLen^ := 0;
  end_if;
  
  if usAxis >= 0 & usAxis < MDD2000MNG_MAXENTRIES then
  
    MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_AXIS_RD_PTR_AND_LEN;
    MyPara.aPara[0] := BUSIF_DRIVEMNGBASE_GET_AXIS_RD_PTR_AND_LEN_VER_1;
    MyPara.aPara[1] := to_dint(AxBuffer[usAxis].AxisIndex);
    if ToBusIF.NewInst(#MyPara, #MyResult) = READY then
      ptr := MyResult.aData[4]$^void;
      if pRdLen then
        pRdLen^ := MyResult.aData[8]$UDINT;
      end_if;

    end_if;
  end_if;
  
END_FUNCTION


FUNCTION MDD2000MngBase::InitDrive
	VAR_INPUT
		Mode 	: USINT;
	END_VAR
  VAR
    UserPara     : CmdStruct;
    UserResult   : Results;
    x            : USINT;
    pThisNewInst : ^void;
  END_VAR

  UserPara.uiCmd := BUSIF_DRIVEMNGBASE_INIT_DRIVE;
  ToBusIF.NewInst(#UserPara, #UserResult);
  
  bdSettings.InitModuleDone := FALSE;
  eInitSSW := _StartInit;  
  
  for x := 0 to (MDD2000MNG_MAXENTRIES - 1) do
    if (AxBuffer[x].pThis <> NIL) then
      if (AxBuffer[x].AxisOk = 1) then
        if Mode = 0 then
          UserPara.uiCmd := MDD2000MNG_NEWINST_INITAXLE;
        else
          UserPara.uiCmd := MDD2000MNG_NEWINST_URINITAXLE;
        end_if;
        
        AxBuffer[x].bdStates.InitFinished := FALSE;
        
        pThisNewInst := AxBuffer[x].pThis;
        pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
      end_if;
    end_if;
  end_for;
  
END_FUNCTION


FUNCTION MDD2000MngBase::GetAxIndex
	VAR_INPUT
		AxisNo 	: USINT;
	END_VAR
	VAR_OUTPUT
		AxIndex 	: USINT;
	END_VAR
  VAR
  	x     : USINT;
  END_VAR
  
  AxIndex := 16#FF;
  
  for x := 0 to (MDD2000MNG_MAXENTRIES - 1) do
    if (AxBuffer[x].pThis <> NIL) then
      if (AxBuffer[x].AxisOk = 1) & (AxBuffer[x].AxisIndex = AxisNo) then
        AxIndex := x;
        exit;
      end_if;
    else
      exit;
    end_if;
  end_for;

END_FUNCTION

FUNCTION MDD2000MngBase::GetFirstAxIndex
	VAR_OUTPUT
		AxIndex 	: USINT;
	END_VAR
  VAR
  	x     : USINT;
  END_VAR
  
  AxIndex := 16#FF;
  
  for x := 0 to (MDD2000MNG_MAXENTRIES - 1) do
    if (AxBuffer[x].pThis <> NIL) then
      if (AxBuffer[x].AxisOk = 1) then
        AxIndex := x;
        exit;
      end_if;
    else
      exit;
    end_if;
  end_for;

END_FUNCTION

FUNCTION MDD2000MngBase::SetFwVersion
	VAR_INPUT
		FwVersionInt 	: DINT;
		StringSelect 	: DINT;
	END_VAR
  VAR
    szValue     : ARRAY[0..19] of CHAR;
    var1 : HDINT;
    var2 : HDINT;
    var3 : HDINT;
  END_VAR
  
  if StringSelect = 0 then
    Bin2Ascii(pt:=#szValue[0], value:=FwVersionInt, format:=16#820);
    FwNumString.TxtSet(dstchrsize:=1, psrc:=#szValue[0], srcchrsize:=1);
  else
    var1 := (FwVersionInt$HDINT AND 16#000000FF);
    var2 := (FwVersionInt$HDINT AND 16#0000FF00) shr  8;
    var3 := (FwVersionInt$HDINT AND 16#00FF0000) shr 16;
    sigclib_sprintfST(pd:=#szValue[0], "%2x.%02x.%02x", #var1, #var2, #var3);
    FwSafeNumString.TxtSet(dstchrsize:=1, psrc:=#szValue[0], srcchrsize:=1);
  end_if;
  
END_FUNCTION

(*
Der String kann folgendermaßen formatiert werden.
xxxx 0000 0000 0000     xxxx = keine Funktion.
     .... .... ****     Anzahl der Dezimalstellen.
     .... **** ....     Position des Dezimalpunkts.
     ...* .... ....     Vornullen (Anzahl der Dezimalstellen).
     ..*. .... ....     Nachkomma Nullen.
     .*.. .... ....     Vorzeichen unmittelbar vor wert (-3 ansonsten - 3).
     *... .... ....     Anzahl der Stellen automatisch ermitteln.

*)


FUNCTION MDD2000MngBase::Bin2Ascii
	VAR_INPUT
		pt 	: ^CHAR;
		value 	: DINT;
		format 	: BINT;
	END_VAR
  VAR
    tmp    : DINT;
    nk     : UINT;
    dig    : UINT;
    hp     : ^CHAR; 
    pd     : UINT; 
    h      : UINT;
  END_VAR

  if((format AND 16#000F) = 0) then
    format := format OR 16#0800;
  end_if;

  if(format AND 16#0800) then
    tmp  := value;
    if tmp = 0 then
      dig := 1;
    else
      dig := 0;
    end_if;

    while(tmp) do
      
      tmp := tmp / 10;
      dig += 1;
    end_while;

    nk := ((format SHR 4) AND 16#0F);
      
    if(nk >= dig) then
      dig := nk + 1;
    end_if;
      
    format := (format AND 16#FFF0) OR (dig AND 16#000F);
  end_if;


  dig := (format and 16#0F);        // Anzahl der Stellen
  hp  := pt + dig;                  // pointer auf String-Ende
  tmp := value;                     // Zahl
  pd  := (format shr 4) and 16#0F;  // position des Komma

  
  if(value < 0) then    // kontrolle ob Zahl negativ
    hp    += 1;    
    value := -value;    // Zahl * (-1)
    pt^   := '-';       // Erstes Zeichen auf '-' setzen
  end_if; 	 

  if(format and 16#0200) then // Nachnullen löschen
    h := pd; 
    while(h) do               // Nur Nullen hinter Komma
      h -= 1; 
      if((value mod 10) = 0) then // Ist Ziffer Null?
        value := value / 10;      // wenn ja, Null löschen
        pd -= 1; 
      else
        h := 0; 
      end_if; 

    end_while; 
  end_if; 
  
  if(pd <> 0) then       // Komma noch zu setzen?
    hp += 1;
  end_if; 

  hp^ := 0;               // String mit Ascii-0 abschließen
  hp  -= 1;   

  repeat
    hp^   := '0' + TO_USINT(value mod 10);  //akt. Ziffer
    hp    -= 1; 
    pd    -= 1; 
    dig   -= 1; 
    if(pd = 0)then    // Komma setzen?
      hp^ := '.';
      hp -= 1; 
    end_if; 

    value := value / 10;   // nächste Ziffer
    
    if((dig = 0) & (value <> 0)) then // Zahl zu groß 
      pt^   := '?';   // Formatfehler
      value := 0; 
    end_if; 
  until(value = 0) end_repeat; 
 
 
  if(dig > 0) then  // mit Vornullen auffüllen
    repeat          // so lange bis Digits auf Null
      if((format and 16#0100)|(pd$INT >= 0)) then   // Vornullen im 
        hp^ := '0';   // Format angegeben?
      else            // formatfehler (digit zu groß und keine Vornullen) 
        pt^   := '?'; // Formatfehler
        value := 0;
      end_if; 
      pd -= 1;
      hp -= 1;
      if(pd = 0) then // Komma setzen
        hp^ := '.';
        hp -= 1; 
      end_if; 
      dig -= 1;
    until(dig = 0) end_repeat;  // letzte Ziffer?
  end_if;

END_FUNCTION



FUNCTION VIRTUAL GLOBAL MDD2000MngBase::RetryCounter::Read
	VAR_OUTPUT
		output (EAX) 	: UDINT;
	END_VAR
  VAR
    MyPara   : CmdStruct;
    MyResult : results;  
  END_VAR

  MyPara.uiCmd  := BUSIF_DRIVEMNGBASE_READ_RETRY_COUNTER;
  ToBusIF.NewInst(#MyPara, #MyResult);    
  RetryCounter := MyResult.aData[0]$UDINT; 

  output := RetryCounter;	

END_FUNCTION


FUNCTION MDD2000MngBase::SetSyncEntry
	VAR_INPUT
		usAxis 	: USINT;
		usValue 	: USINT;
		usPData 	: DINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR
    MyPara   : CmdStruct;
    MyResult : results;  
  END_VAR
  
  if usAxis >= 0 & usAxis < MDD2000MNG_MAXENTRIES then //HasHan
    MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_SET_SYNC_PARA;
    MyPara.aPara[0] := to_dint(AxBuffer[usAxis].AxisIndex);
    MyPara.aPara[1] := to_dint(usValue);
    MyPara.aPara[2] := to_dint(usPData);
    
    ToBusIF.NewInst(#MyPara, #MyResult);
    retcode := MyResult.aData[0]$DINT;
  else 
    retcode := -1;
  end_if;  
  	
END_FUNCTION


FUNCTION MDD2000MngBase::GetSyncEntry
	VAR_INPUT
		usAxis 	: USINT;
		usValue 	: USINT;
		usPData 	: ^DINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR
    MyPara   : CmdStruct;
    MyResult : results;  
  END_VAR  
  
  if usAxis >= 0 & usAxis < MDD2000MNG_MAXENTRIES then //HasHan    
    MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_SYNC_PARA;
    MyPara.aPara[0] := to_dint(AxBuffer[usAxis].AxisIndex);
    MyPara.aPara[1] := to_dint(usValue);
    MyPara.aPara[2] := (usPData)$DINT;
    
    ToBusIF.NewInst(#MyPara, #MyResult);
    retcode := MyResult.aData[0]$DINT;
  else
    retcode := -1;
  end_if;  
  
END_FUNCTION

FUNCTION MDD2000MngBase::SetDriveType
	VAR_INPUT
		ITYPE 	: DINT;
	END_VAR
  VAR
  	ResStr : array [0..31] of char;
    Drivesize : DINT;
    noAxis : DINT;
  END_VAR
  
  // Generate Drive Type String from ITYPE
  
  // 0 Bit MDD/MDP Module type
  if (ITYPE AND 1) then
    sigclib_strcpy(dst0:=#ResStr[0], src0:="MDD2");
  else
    sigclib_strcpy(dst0:=#ResStr[0], src0:="MDP2");
  end_if;
  
  // Bit 1-2 Size (1, 2 or 3)
  Drivesize := (ITYPE shr 1) AND 2#11;
  sigclib_sprintfST(pd:=#ResStr[0], format:="%s%d", p0:=#ResStr[0], p1:=#Drivesize);
  
  //Bit 3 Cooling type
  if (ITYPE shr 3) AND 1 then
    sigclib_strcat(ps1:=#ResStr[0], ps2:="2");  // Coldplate
  else
    sigclib_strcat(ps1:=#ResStr[0], ps2:="0");  // Fan
  end_if;
  
  //Bit 4-5 no axis
  noAxis := (ITYPE shr 4) AND 2#11;
  
  // Voltage, Axis Current, Varan Min IO
  if noAxis = 3 then
    sigclib_strcat(ps1:=#ResStr[0], "X-XXX-0");
  elsif noAxis = 2 then
    sigclib_strcat(ps1:=#ResStr[0], "X-XX-0");
  else
    sigclib_strcat(ps1:=#ResStr[0], "X-X-0");
  end_if;  
  
  //Bit 6 Encoder module
  if (ITYPE shr 6) AND 1 then
    sigclib_strcat(ps1:=#ResStr[0], ps2:="3");  // encoder
  else
    sigclib_strcat(ps1:=#ResStr[0], ps2:="0");  // hyperface
  end_if;
  
  DriveTypeStr.TxtSet(dstchrsize:=1, psrc:=#ResStr[0], srcchrsize:=1);
  
  // Check if drivetype is valid / defined in enum
  DriveType := ITYPE$t_e_MD2000Type;
  
  case DriveType of
  	MDD2000MngBase::t_e_MD2000Type::_NotFound,
  	MDD2000MngBase::t_e_MD2000Type::MDP210X_X_00,
  	MDD2000MngBase::t_e_MD2000Type::MDD210X_X_00,
  	MDD2000MngBase::t_e_MD2000Type::MDP220X_X_00,
  	MDD2000MngBase::t_e_MD2000Type::MDD220X_X_00,
  	MDD2000MngBase::t_e_MD2000Type::MDP212X_X_00,
  	MDD2000MngBase::t_e_MD2000Type::MDD212X_X_00,
  	MDD2000MngBase::t_e_MD2000Type::MDP222X_X_00,
  	MDD2000MngBase::t_e_MD2000Type::MDD222X_X_00,
  	MDD2000MngBase::t_e_MD2000Type::MDP210X_XX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDD210X_XX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDP220X_XX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDD220X_XX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDP230X_XX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDD230X_XX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDP212X_XX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDD212X_XX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDP222X_XX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDD222X_XX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDP232X_XX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDD232X_XX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDP210X_XXX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDD210X_XXX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDP220X_XXX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDD220X_XXX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDP212X_XXX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDD212X_XXX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDP222X_XXX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDD222X_XXX_00,
  	MDD2000MngBase::t_e_MD2000Type::MDP210X_X_03,
  	MDD2000MngBase::t_e_MD2000Type::MDD210X_X_03,
  	MDD2000MngBase::t_e_MD2000Type::MDP220X_X_03,
  	MDD2000MngBase::t_e_MD2000Type::MDD220X_X_03,
  	MDD2000MngBase::t_e_MD2000Type::MDP212X_X_03,
  	MDD2000MngBase::t_e_MD2000Type::MDD212X_X_03,
  	MDD2000MngBase::t_e_MD2000Type::MDP222X_X_03,
  	MDD2000MngBase::t_e_MD2000Type::MDD222X_X_03,
  	MDD2000MngBase::t_e_MD2000Type::MDP210X_XX_03,
  	MDD2000MngBase::t_e_MD2000Type::MDD210X_XX_03,
  	MDD2000MngBase::t_e_MD2000Type::MDP220X_XX_03,
  	MDD2000MngBase::t_e_MD2000Type::MDD220X_XX_03,
  	MDD2000MngBase::t_e_MD2000Type::MDP220X_XX_02,
  	MDD2000MngBase::t_e_MD2000Type::MDD220X_XX_01,
  	MDD2000MngBase::t_e_MD2000Type::MDP212X_XX_03,
  	MDD2000MngBase::t_e_MD2000Type::MDD212X_XX_03,
  	MDD2000MngBase::t_e_MD2000Type::MDP222X_XX_03,
  	MDD2000MngBase::t_e_MD2000Type::MDD222X_XX_03,
  	MDD2000MngBase::t_e_MD2000Type::MDP222X_XX_02,
  	MDD2000MngBase::t_e_MD2000Type::MDD222X_XX_01,
  	MDD2000MngBase::t_e_MD2000Type::MDP210X_XXX_03,
  	MDD2000MngBase::t_e_MD2000Type::MDD210X_XXX_03,
  	MDD2000MngBase::t_e_MD2000Type::MDP220X_XXX_03,
  	MDD2000MngBase::t_e_MD2000Type::MDD220X_XXX_03,
  	MDD2000MngBase::t_e_MD2000Type::MDP212X_XXX_03,
  	MDD2000MngBase::t_e_MD2000Type::MDD212X_XXX_03,
  	MDD2000MngBase::t_e_MD2000Type::MDP222X_XXX_03,
  	MDD2000MngBase::t_e_MD2000Type::MDD222X_XXX_03: // DriveType Ok, Nothing to do
  else
    DriveType := _NotFound;
  end_case;

  
END_FUNCTION


FUNCTION MDD2000MngBase::GetVaranDriveState
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;
  END_VAR

  MyPara.uiCmd := BUSIF_DRIVEMNGBASE_GET_DRIVE_INT_STATE;
  ToBusIF.NewInst(#MyPara, #MyResult);
  retcode := MyResult.aData[0]$DINT;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::SetTimeBase
	VAR_INPUT
		ud_timebase_ms 	: UDINT;
	END_VAR
	VAR_OUTPUT
		sd_retval 	: DINT;
	END_VAR

  //When the DriveMng is called manuelly instead of setting the CyWork Time, 
  //the Customer has to tell the Class, witch TimeBase is set, because this Time is use somewhere in the Class.

  IF InitCounter <= 1 THEN  //The Init use the ud_TimeoutCycles and set any value, to prevent 
                            //the override from this Value after the Customer has set the TimeBase manuelly, this Methode only works after the first Init run.   
    sd_retval := -1;
  else
    IF ud_timebase_ms <> 0 THEN
      ud_timebase_ms *= 1000; // Rev. 1.16: us is the unit for the calculation
      udCycleTimems := ud_timebase_ms;  //save for timeout calculation
      ud_TimeoutCycles := ( MDD2000MNG_ASY_TIMEOUT / ud_timebase_ms ) + 5;
      sd_retval := 0;
    ELSE
      sd_retval := -2;
    END_IF;
  END_IF;

END_FUNCTION


FUNCTION MDD2000MngBase::MDD2000MngBase
	VAR_OUTPUT
		ret_code 	: ConfStates;
	END_VAR

  //Rev. 1.16: to avoid wrong information on server if drive is used as a transparent client
  ClassState := _NotInitialized;
  
  ret_code := C_OK;

END_FUNCTION


FUNCTION VIRTUAL MDD2000MngBase::GetBusDeviceID
	VAR_OUTPUT
		output 	: UDINT;
	END_VAR
  
  //Overwrite this method in derived class
  output := HWC_INVALID_DEVICE_ID;

END_FUNCTION


FUNCTION VIRTUAL MDD2000MngBase::GetDrvDeviceID
	VAR_OUTPUT
		output 	: UDINT;
	END_VAR

  //Overwrite this method in derived class
  output := HWC_INVALID_DEVICE_ID;
  
END_FUNCTION


FUNCTION MDD2000MngBase::IsAnyAxisEnabled
	VAR_OUTPUT
		AnyAxisEnabled 	: BOOL;
	END_VAR
  VAR
    UserPara     : CmdStruct;
    UserResult   : Results;
    x            : USINT;
    pThisNewInst : ^void;
  END_VAR

  // search for any enabled axis (all axis must be disabled to set absolut position, because drive needs to switch communication)
  AnyAxisEnabled := FALSE;
  UserPara.uiCmd    := MDD2000MNG_IF_IS_AXIS_ENABLED;
  UserPara.aPara[0] := MDD2000MNG_IF_IS_AXIS_ENABLED_VER_1;

  for x := 0 to (MDD2000MNG_MAXENTRIES - 1) do
    if (AxBuffer[x].pThis <> NIL) then
      if (AxBuffer[x].AxisOk = 1) then
        UserResult.uiLng := 0;
        
        pThisNewInst := AxBuffer[x].pThis;
        pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
        
        // if there is an enabled axis
        if (UserResult.uiLng = 8) & UserResult.aData[4] then
          // leave method
          AnyAxisEnabled := TRUE;
          return;
        end_if;
      end_if;
    end_if;
  end_for; 

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::DisableDevice
	VAR_OUTPUT
		RetCode 	: DINT;
	END_VAR
  VAR
    MyPara   : CmdStruct;
    MyResult : results;  
  END_VAR

  MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_WRITE_PARAMETER;
  Mypara.aPara[0] := _BUS_IF_DRVMNG_DISABLE_DEVICE;
  RetCode$UDINT   := ToBusIF.NewInst(#MyPara, #MyResult);
  if RetCode$IprStates = ERROR then
    RetCode := -1;
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::EnableDevice
	VAR_OUTPUT
		RetCode 	: DINT;
	END_VAR
  VAR
    MyPara   : CmdStruct;
    MyResult : results;  
  END_VAR

  MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_WRITE_PARAMETER;
  Mypara.aPara[0] := _BUS_IF_DRVMNG_ENABLE_DEVICE;
  RetCode$UDINT   := ToBusIF.NewInst(#MyPara, #MyResult);
  if RetCode$IprStates = ERROR then
    RetCode := -1;
  end_if;
  
END_FUNCTION

FUNCTION VIRTUAL MDD2000MngBase::GetDriveTypeStr
	VAR_INPUT
		pDriveTypeStr 	: ^CHAR;
		DriveTypeStrSize 	: UDINT;
	END_VAR
  
  if pDriveTypeStr then
  
    DriveTypeStr.TxtGet(pdst:=pDriveTypeStr, dstsize:=DriveTypeStrSize);
    
  end_if;
  
END_FUNCTION  


FUNCTION VIRTUAL MDD2000MngBase::GetSystemTime

  sigclib_getsysdate(pdate:=#sTimeVars.tSysDate);
  sigclib_getsystime(ptime:=#sTimeVars.tSysTime);
  
  //check for not set time stamp
  if sTimeVars.tSysDate.wYear < 2000 then
    sTimeVars.tSysDate.wYear := 2000;
  end_if;
  
  //YEAR     MONTH      DAY      HOUR    MINUTE     SEC
  //31 26    25 22     21 17    16 12    11   6    5  0
  //  3F       0F        1F       1F       3F       3F
  
  //set time and date with structure from drive firmware
  sTimeVars.hdKDATEP241 := sTimeVars.tSysTime.wSecond 
                           OR (sTimeVars.tSysTime.wMinute shl 6)
                           OR (sTimeVars.tSysTime.wHour shl 12)
                           OR (sTimeVars.tSysDate.wDay shl 17)
                           OR (sTimeVars.tSysDate.wMonth shl 22)
                           OR ((sTimeVars.tSysDate.wYear-2000) shl 26);

END_FUNCTION


FUNCTION VIRTUAL MDD2000MngBase::SetSystemTimeAtDrive
	VAR_INPUT
		AxisIdx 	: USINT;
	END_VAR

  if sTimeVars.bTimeIsSet = FALSE  
  & ((ops.tAbsolute-sTimeVars.udLastWrite) >= DRIVEMNG_WRITE_PLCTIME) | (sTimeVars.udLastWrite = 0) then      //check if time is 0 to write time at startup once
  
    //get System Time
    GetSystemTime();
    
    //set system time and date at drive
    if AddASyncEntryDS402( AxisIdx      :=  AxisIdx
                         , uiParaID     :=  MDD2000_PID_SIGMATEKPARA_INDEX_INFO
                         , usParaSubID  :=  MDD2000_SPID_K_DATE
                         , usRdWr       :=  TRUE
                         , pValue       :=  (#sTimeVars.hdKDATEP241)$^USINT
                         , bsDataInfo   :=  MDD2000MNG_DATASIZE_4BYTE
                         , pThisObj     :=  this
                         , usEntry      :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                         ) = 0 then
                  
      // time is set at drive, store timestamp for next time update       
      sTimeVars.udLastWrite := ops.tAbsolute - sigclib_random(DRIVEMNG_SDO_TIMOUT);
    end_if;           
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::GetFile
	VAR_INPUT
		pDestinationDPNE 	: ^CHAR;
		pFileNameDrive 	: ^CHAR;
		pFilePathDrive 	: ^CHAR;
		pdError 	: ^DINT;(* := nil *)
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR
  VAR
    MyPara   : CmdStruct;
    MyResult : results;
  END_VAR
  
  retcode := CheckFileHandlingAvailable(pdError);
  
  if retcode = READY then
  
    MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_FILE;
    MyPara.aPara[0] := BUSIF_DRIVEMNGBASE_GET_FILE_CB_VER1$DINT;  //Version
    MyPara.aPara[1] := pDestinationDPNE$DINT;
    MyPara.aPara[2] := pFileNameDrive$DINT;
    MyPara.aPara[3] := pFilePathDrive$DINT;
    MyPara.aPara[4] := pdError$DINT;

    retcode := ToBusIF.NewInst(#MyPara, #MyResult);
  
    if retcode <> READY then
      // Failed to start filehandling, release lock
      ReleaseFileHandling();
      
      // Set ErrorCode if not already set in NewInst
      if pdError & (pdError^ = MDD2000MNG_FILE_HANDLING_RETCODE_NOERROR) then
        pdError^ := MDD2000MNG_FILE_HANDLING_RETCODE_NOT_SUPPORTED;
      end_if;
    
#ifdef DEBUG_DRIVEMNGBASE
      if retcode <> ERROR then
        // Unreachable Code
        ((0)$^USINT)^ := 0;
      end_if;
#endif
    end_if;
    
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::GetLogFile
	VAR_INPUT
		pDestinationDPNE 	: ^CHAR;(* := NIL *)
		pdError 	: ^DINT;(* := nil *)
		udFileSelectID 	: UDINT;(* := MDD2000MNG_FILESELECT_LOGFILE *)
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR

  retcode := CheckFileHandlingAvailable(pdError, MDD2000MNG_FILE_RESERVE_IDGETLOGFILE);
  
  if retcode = READY then
  
    if pDestinationDPNE then
      // Safe Destination File
      _strcpy(dest:=#s_LogFileV.aDestinationLogFile[0], src:=pDestinationDPNE);
    else
      // Clear Destination File
      s_LogFileV.aDestinationLogFile[0] := 0;  // 0 Termination
    end_if;
    
    s_LogFileV.udFileSelectId := udFileSelectID;
    
    s_LogFileV.eGetLogFileSSW := StartGetLogFileSSW;

  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::GetFileState
	VAR_INPUT
		pdError 	: ^DINT;(* := nil *)
		pdProgress 	: ^DINT;(* := nil *)
		pudBytesRead 	: ^UDINT;(* := nil *)
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR
  VAR
    MyPara   : CmdStruct;
    MyResult : results;
  END_VAR  
  
  if Online.read() = 0 then
    retcode := ERROR; //Drive is not online
    if pdError then
      pdError^ := MDD2000MNG_FILE_HANDLING_RETCODE_NOT_ONLINE;
    end_if;
    return;
  end_if;
  
  // Check if filehandling is active only in busif 
  if (sigclib_atomic_getU32(pValue:=#ud_FileHandlingReserved) = MDD2000MNG_FILE_RESERVE_IDDEFAULT) then
  
    // Pass on command to Busif
    MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_FILE_STATE;
    MyPara.aPara[0] := BUSIF_DRIVEMNGBASE_GET_FILE_STATE_CB_VER1$DINT;  //Version
    MyPara.aPara[1] := pdError$DINT;  
    MyPara.aPara[2] := pdProgress$DINT;
    MyPara.aPara[3] := pudBytesRead$DINT;
    
    retcode := ToBusIF.NewInst(#MyPara, #MyResult);
    
    if (retcode = READY) | (retcode = ERROR) then
      // File handling has completed => unlock
      ReleaseFileHandling();
    end_if;

  // Check if filehandling is active get log file
  elsif (sigclib_atomic_getU32(pValue:=#ud_FileHandlingReserved) = MDD2000MNG_FILE_RESERVE_IDGETLOGFILE) then
    
    if s_LogFileV.eGetLogFileSSW = wait4GetLogFile then 
      
      // Pass on command to Busif
      MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_FILE_STATE;
      MyPara.aPara[0] := BUSIF_DRIVEMNGBASE_GET_FILE_STATE_CB_VER1$DINT;  //Version
      MyPara.aPara[1] := pdError$DINT;  
      MyPara.aPara[2] := pdProgress$DINT;
      MyPara.aPara[3] := pudBytesRead$DINT;
      
      retcode := ToBusIF.NewInst(#MyPara, #MyResult);
      
      if (retcode = READY) | (retcode = ERROR) then
        // Reset SSW
        s_LogFileV.eGetLogFileSSW := IdleGetLogFile;
        // File handling has completed => unlock
        ReleaseFileHandling();
      end_if;
    
    elsif s_LogFileV.eGetLogFileSSW = ErrorGetLogFile then
      
      retcode := ERROR;
      
      if pdError then
        pdError^ := s_LogFileV.ErrorCodeLogFile;
      end_if;
      
      s_LogFileV.eGetLogFileSSW := IdleGetLogFile;
      
      // File handling has completed => unlock
      ReleaseFileHandling();
      
    elsif s_LogFileV.eGetLogFileSSW = IdleGetLogFile then

#ifdef DEBUG_DRIVEMNGBASE
      // Unreachable Code
      #pragma message("LanSte 02.06.2022 12:43 \ TODO Remove for release Version")
      ((0)$^USINT)^ := 0;
#endif
      
      retcode := READY;
      ReleaseFileHandling();
      
    else
      
      // Busy in SSW
      retcode := BUSY;
      
      if pdError then
        pdError^ := MDD2000MNG_FILE_HANDLING_RETCODE_NOERROR;
      end_if;
    
    end_if;
    
  else
    
    // No File handling active, ready for new.
    retcode := READY;
    if pdError then
      pdError^ := MDD2000MNG_FILE_HANDLING_RETCODE_NOERROR;
    end_if;
    
  end_if;

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MDD2000MngBase::SetFile
	VAR_INPUT
		pWriteData 	: ^void;
		udWriteDataLen 	: UDINT;
		pFilePathDrive 	: ^CHAR;
		pFileNameDrive 	: ^CHAR;
		pdError 	: ^DINT;(* := nil *)
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR  
  VAR
    MyPara   : CmdStruct;
    MyResult : results;
  END_VAR  

  retcode := CheckFileHandlingAvailable(pdError);
  
  if retcode = READY then
  
    //we are connected via businterface
    MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_SET_FILE;
    MyPara.aPara[0] := BUSIF_DRIVEMNGBASE_SET_FILE_CB_VER1$DINT;  //Version
    MyPara.aPara[1] := pWriteData$DINT;
    MyPara.aPara[2] := udWriteDataLen$DINT;
    MyPara.aPara[3] := pFilePathDrive$DINT;
    MyPara.aPara[4] := pFileNameDrive$DINT;
    MyPara.aPara[5] := pdError$DINT;

    retcode := ToBusIF.NewInst(#MyPara, #MyResult);
    
    if retcode <> READY then
      // Failed to start filehandling, release lock
      ReleaseFileHandling();
      
      // Set ErrorCode if not already set in NewInst
      if pdError & (pdError^ = MDD2000MNG_FILE_HANDLING_RETCODE_NOERROR) then
        pdError^ := MDD2000MNG_FILE_HANDLING_RETCODE_NOT_SUPPORTED;
      end_if;
      
#ifdef DEBUG_DRIVEMNGBASE
      if retcode <> ERROR then
        // Unreachable Code
        ((0)$^USINT)^ := 0;
      end_if;
#endif
    end_if;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::GetFileSize
	VAR_INPUT
		pFileNameDrive 	: ^CHAR;
		pFilePathDrive 	: ^CHAR;
		pudSize 	: ^UDINT;
		pdError 	: ^DINT;(* := nil *)
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR  
  VAR
    MyPara   : CmdStruct;
    MyResult : results;  
  END_VAR  

  retcode := CheckFileHandlingAvailable(pdError);
  
  if retcode = READY then
    
    //we are connected via businterface
    MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_FILE_SIZE;
    MyPara.aPara[0] := BUSIF_DRIVEMNGBASE_GET_FILE_SIZE_CB_VER1$DINT;  //Version
    MyPara.aPara[1] := pFileNameDrive$DINT;
    MyPara.aPara[2] := pFilePathDrive$DINT;
    MyPara.aPara[3] := pudSize$DINT;
    MyPara.aPara[4] := pdError$DINT;

    retcode := ToBusIF.NewInst(#MyPara, #MyResult);
    
    if retcode <> READY then
      // Failed to start filehandling, release lock
      ReleaseFileHandling();
      
      // Set ErrorCode if not already set in NewInst
      if pdError & (pdError^ = MDD2000MNG_FILE_HANDLING_RETCODE_NOERROR) then
        pdError^ := MDD2000MNG_FILE_HANDLING_RETCODE_NOT_SUPPORTED;
      end_if;
      
#ifdef DEBUG_DRIVEMNGBASE
      if retcode <> ERROR then
        // Unreachable Code
        ((0)$^USINT)^ := 0;
      end_if;
#endif
    end_if;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::GetFileBuffer
	VAR_INPUT
		pFileNameDrive 	: ^CHAR;
		pFilePathDrive 	: ^CHAR;
		udBufferSize 	: UDINT;
		pDataBuffer 	: ^void;(* := nil *)
		udDataLenToRead 	: UDINT;(* := 0 *)
		pdError 	: ^DINT;(* := nil *)
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR  
  VAR
    MyPara   : CmdStruct;
    MyResult : results;  
  END_VAR  

  retcode := CheckFileHandlingAvailable(pdError);
  
  if retcode = READY then
    
    //we are connected via businterface
    MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_FILE_BUFFER;
    MyPara.aPara[0] := BUSIF_DRIVEMNGBASE_GET_FILE_BUFFER_CB_VER1$DINT;  //Version
    MyPara.aPara[1] := pFileNameDrive$DINT;
    MyPara.aPara[2] := pFilePathDrive$DINT;
    MyPara.aPara[3] := udBufferSize$DINT;
    MyPara.aPara[4] := pDataBuffer$DINT;
    MyPara.aPara[5] := udDataLenToRead$DINT;
    MyPara.aPara[6] := pdError$DINT;

    retcode := ToBusIF.NewInst(#MyPara, #MyResult);
    
    if retcode <> READY then
      // Failed to start filehandling, release lock
      ReleaseFileHandling();
      
      // Set ErrorCode if not already set in NewInst
      if pdError & (pdError^ = MDD2000MNG_FILE_HANDLING_RETCODE_NOERROR) then
        pdError^ := MDD2000MNG_FILE_HANDLING_RETCODE_NOT_SUPPORTED;
      end_if;
#ifdef DEBUG_DRIVEMNGBASE
      if retcode <> ERROR then
        // Unreachable Code
        ((0)$^USINT)^ := 0;
      end_if;
#endif
    end_if;
  end_if;

END_FUNCTION

FUNCTION VIRTUAL MDD2000MngBase::GetLogFileCyclic
  VAR
    retcode  : iprStates;
    MyPara   : CmdStruct;
    MyResult : results;  
    aFileNameDrive    : ARRAY [0..199] OF CHAR;
    aFilePathDrive    : ARRAY [0..199] OF CHAR;
    AxisIdx : USINT;
  END_VAR
  
  case s_LogFileV.eGetLogFileSSW of

//*****************************************************************************    
    t_e_GetLogFileSSW::IdleGetLogFile: 
      // Do Nothing
      
//*****************************************************************************
    t_e_GetLogFileSSW::StartGetLogFileSSW,
    t_e_GetLogFileSSW::WriteLOGFileParam:
    
      s_LogFileV.ErrorCodeLogFile := MDD2000MNG_FILE_HANDLING_RETCODE_NOERROR;  // Fehlercode zurücksetzen
      
      //Only allow to get logfile if no axis is enabled
      if IsAnyAxisEnabled() = FALSE then
      
        // get the standard information of the drive
        AxisIdx := GetFirstAxIndex();
                
        if AxisIdx <> 16#FF then
          //We have to tell the firmware that the logfile should be written
          
          //Writing to K-LOG leads to that the firmware is going to write their logbuffer into the logfile on the drive 
          //This will block the other asynchronous communication and can take some seconds
          //Give this access a high timeout so we won't get an error with the default timeout
          
          // Get usParaLogIdx and dParaLogVal from derived class
          GetLogFileWrParam(pParaIndex:=#s_LogFileV.hParaLogIndex, pParaSubIndex:=#s_LogFileV.hsParaLogSubIndex, pParaVal:=#s_LogFileV.dParaLogVal, pParaTimeout:=#s_LogFileV.udParaLogTimeout,s_LogFileV.udFileSelectId);
          
          if s_LogFileV.hParaLogIndex then
          
            if AddASyncEntryDS402( AxisIdx      :=  AxisIdx
                                 , uiParaID     :=  s_LogFileV.hParaLogIndex
                                 , usParaSubID  :=  s_LogFileV.hsParaLogSubIndex
                                 , usRdWr       :=  1
                                 , pValue       :=  (#s_LogFileV.dParaLogVal)$^USINT  //Start to write logfile
                                 , bsDataInfo   :=  MDD2000MNG_DATASIZE_4BYTE
                                 , pThisObj     :=  this
                                 , usEntry      :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                                 , udTimeout    :=  s_LogFileV.udParaLogTimeout) = 0 then

              s_LogFileV.bWait4LogFilePara := TRUE;
              s_LogFileV.udTimeStampLogPara := ops.tAbsolute;
              s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::Wait4WrLOGFileResponse;
            end_if;
          else
            // usParaLogIdx not used to write parameter, skip step.
            s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::ReadLOGFileParam;
          end_if;

        else
        
          s_LogFileV.ErrorCodeLogFile := MDD2000MNG_FILE_HANDLING_RETCODE_NOT_ONLINE;  //Drive is not online
          s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::ErrorGetLogFile;
          
        end_if;
      else
      
        s_LogFileV.ErrorCodeLogFile := MDD2000MNG_FILE_HANDLING_RETCODE_AXIS_ENABLED;  //Axis must be not enabled to start get logfile
        s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::ErrorGetLogFile;          
        
      end_if;
      
//*****************************************************************************
    t_e_GetLogFileSSW::Wait4WrLOGFileResponse:
      //Wait until we get response from K_LOG
      if s_LogFileV.bWait4LogFilePara = FALSE then
        
        // Check Return Value
        if s_LogFileV.dParaLogValRd <> 16#7FFFFFFF then
          s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::ReadLOGFileParam;
        else
          s_LogFileV.ErrorCodeLogFile := MDD2000MNG_FILE_HANDLING_RETCODE_WRITEPARA_FAILED;  // Unexpected Para Val was returned
          s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::ErrorGetLogFile;
        end_if;
      
      elsif ops.tAbsolute - s_LogFileV.udTimeStampLogPara > s_LogFileV.udParaLogTimeout then  //Timeout while waiting for response of K-LOG
        s_LogFileV.ErrorCodeLogFile := MDD2000MNG_FILE_HANDLING_RETCODE_WRITEPARA_TIMEOUT;  // Unexpected Para Val was returned
        s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::ErrorGetLogFile;
      end_if;

//*****************************************************************************
    t_e_GetLogFileSSW::ReadLOGFileParam:
      
      //Only allow to get logfile if no axis is enabled
      if IsAnyAxisEnabled() = FALSE then
      
        // get the standard information of the drive
        AxisIdx := GetFirstAxIndex();
                
        if AxisIdx <> 16#FF then
          
          // Read back parameters to see if file was successfully copied to drive
          
          // Get usParaLogIdx and dParaLogVal from derived class
          GetLogFileRdParam(pParaIndex:=#s_LogFileV.hParaLogIndex, pParaSubIndex:=#s_LogFileV.hsParaLogSubIndex, pParaVal:=#s_LogFileV.dParaLogVal, pParaTimeout:=#s_LogFileV.udParaLogTimeout,s_LogFileV.udFileSelectId);
          
          if s_LogFileV.hParaLogIndex then
          
            if AddASyncEntryDS402( AxisIdx      :=  AxisIdx
                                 , uiParaID     :=  s_LogFileV.hParaLogIndex
                                 , usParaSubID  :=  s_LogFileV.hsParaLogSubIndex
                                 , usRdWr       :=  0
                                 , pValue       :=  (#s_LogFileV.dParaLogVal)$^USINT  //Start to write logfile
                                 , bsDataInfo   :=  MDD2000MNG_DATASIZE_4BYTE
                                 , pThisObj     :=  this
                                 , usEntry      :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                                 , udTimeout    :=  s_LogFileV.udParaLogTimeout) = 0 then
                             
              s_LogFileV.bWait4LogFilePara := TRUE;
              s_LogFileV.udTimeStampLogPara := ops.tAbsolute;
              s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::Wait4RdLOGFileResponse;
            end_if;
            
          else
            // usParaLogIdx not used to write parameter, skip step.
            s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::StartGetLogFile;
          end_if;
          
        else
          
          s_LogFileV.ErrorCodeLogFile := MDD2000MNG_FILE_HANDLING_RETCODE_NOT_ONLINE;  //Drive is not online
          s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::ErrorGetLogFile;
          
        end_if;
      else
        
        s_LogFileV.ErrorCodeLogFile := MDD2000MNG_FILE_HANDLING_RETCODE_AXIS_ENABLED;  //Axis must be not enabled to start get logfile
        s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::ErrorGetLogFile;
        
      end_if;
      
//*****************************************************************************
    t_e_GetLogFileSSW::Wait4RdLOGFileResponse:
      //Wait until we get response from K_LOG
      if s_LogFileV.bWait4LogFilePara = FALSE then
        
        // Check Return Value
        if s_LogFileV.dParaLogVal = s_LogFileV.dParaLogValRd then
          s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::StartGetLogFile;
        else
          s_LogFileV.ErrorCodeLogFile := MDD2000MNG_FILE_HANDLING_RETCODE_READBACKPARA_FAILED;  // Unexpected Para Val was returned
          s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::ErrorGetLogFile;
        end_if;
       
      
      elsif ops.tAbsolute - s_LogFileV.udTimeStampLogPara > s_LogFileV.udParaLogTimeout then  //Timeout while waiting for response of K-LOG        
        s_LogFileV.ErrorCodeLogFile := MDD2000MNG_FILE_HANDLING_RETCODE_READBACKPARA_TIMEOUT;  // Unexpected Para Val was returned
        s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::ErrorGetLogFile;
      end_if;
      
//*****************************************************************************
    t_e_GetLogFileSSW::StartGetLogFile:
      //Check if user wants to set a specific name or if we should use the default name
      if _strlen(src:=#s_LogFileV.aDestinationLogFile[0]) = 0 then
        GetDefaultLogFileDestinationDPNE(#s_LogFileV.aDestinationLogFile[0], s_LogFileV.udFileSelectId);  //Use default DPNE
      // else
        //Use given DPNE
      end_if;
      
      GetDefaultLogFileNameDrive(#aFileNameDrive[0],s_LogFileV.udFileSelectId);
      GetDefaultLogFilePathDrive(#aFilePathDrive[0],s_LogFileV.udFileSelectId);
      
      MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_FILE;
      MyPara.aPara[0] := BUSIF_DRIVEMNGBASE_GET_FILE_CB_VER1$DINT;  //Version
      MyPara.aPara[1] := (#s_LogFileV.aDestinationLogFile[0])$DINT; 
      MyPara.aPara[2] := (#aFileNameDrive[0])$DINT;
      MyPara.aPara[3] := (#aFilePathDrive[0])$DINT;
      MyPara.aPara[4] := (#s_LogFileV.ErrorCodeLogFile)$DINT;
      
      retcode := ToBusIF.NewInst(#MyPara, #MyResult);
      
      if retcode = READY then
        s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::wait4GetLogFile;
      elsif retcode = ERROR then
        
        // Check if Error code was set
        if s_LogFileV.ErrorCodeLogFile = MDD2000MNG_FILE_HANDLING_RETCODE_NOERROR then
          s_LogFileV.ErrorCodeLogFile := MDD2000MNG_FILE_HANDLING_RETCODE_NOT_SUPPORTED;
        end_if;

        s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::ErrorGetLogFile;
      else
#ifdef DEBUG_DRIVEMNGBASE
        // Unreachable Code
        #pragma message("LanSte 02.06.2022 12:43 \ TODO Remove for release Version")
        ((0)$^USINT)^ := 0;
#endif
      end_if;
      
//*****************************************************************************
    t_e_GetLogFileSSW::wait4GetLogFile:
      // Wait for User to call GetFileState
  
//*****************************************************************************
    t_e_GetLogFileSSW::ErrorGetLogFile:
      // Wait for User to call GetFileState
    
  end_case;

END_FUNCTION

FUNCTION VIRTUAL MDD2000MngBase::GetLogFileWrParam
	VAR_INPUT
		pParaIndex 	: ^HINT;
		pParaSubIndex 	: ^HSINT;
		pParaVal 	: ^DINT;
		pParaTimeout 	: ^UDINT;
		FileSelect 	: UDINT;
	END_VAR
  VAR
  	ParaIDX 	: HINT;
    ParaSubIdx: HSINT;
		ParaVal 	: DINT;
		ParaTimeout : UDINT;
  END_VAR
  
  case FileSelect of
  
    MDD2000MNG_FILESELECT_LOGFILE:
      ParaIDX     := MDD2000_PID_SIGMATEKPARA_INDEX_INFO;
      ParaSubIdx  := MDD2000_SPID_K_START;
      ParaVal     := 1006;
      ParaTimeout := MDD2000MNG_FILE_HANDLING_TIMEOUT_LOG_PARAM;
    
    MDD2000MNG_FILESELECT_DEBUGLOGFILE:
      ParaIDX     := MDD2000_PID_SIGMATEKPARA_INDEX_INFO;
      ParaSubIdx  := MDD2000_SPID_K_START;
      ParaVal     := 1006;
      ParaTimeout := MDD2000MNG_FILE_HANDLING_TIMEOUT_LOG_PARAM;
    
    else    
      // Not supported
      ParaIDX     := 0;
      ParaSubIdx  := 0;
      ParaVal     := 0;
      ParaTimeout := MDD2000MNG_FILE_HANDLING_TIMEOUT_LOG_PARAM;
  
  end_case;
  
  // Default Implementation
  if pParaIndex then
    pParaIndex^ := ParaIDX;
  end_if;

  if pParaSubIndex then
    pParaSubIndex^ := ParaSubIdx;
  end_if;
  
  if pParaVal then
    pParaVal^ := ParaVal;
  end_if;
  
  if pParaTimeout then
    pParaTimeout^ := MDD2000MNG_FILE_HANDLING_TIMEOUT_LOG_PARAM;
  end_if;
  
END_FUNCTION

FUNCTION VIRTUAL MDD2000MngBase::GetLogFileRdParam
	VAR_INPUT
		pParaIndex 	: ^HINT;
		pParaSubIndex 	: ^HSINT;
		pParaVal 	: ^DINT;
		pParaTimeout 	: ^UDINT;
		FileSelect 	: UDINT;
	END_VAR
  VAR
  	ParaIDX 	: HINT;
    ParaSubIdx: HSINT;
		ParaVal 	: DINT;
		ParaTimeout : UDINT;
  END_VAR

  case FileSelect of
  
    MDD2000MNG_FILESELECT_LOGFILE:
      ParaIDX     := MDD2000_PID_SIGMATEKPARA_INDEX_INFO;
      ParaSubIdx  := MDD2000_SPID_K_START;
      ParaVal     := 1;
      ParaTimeout := MDD2000MNG_FILE_HANDLING_TIMEOUT_LOG_PARAM;
    
    MDD2000MNG_FILESELECT_DEBUGLOGFILE:
      ParaIDX     := MDD2000_PID_SIGMATEKPARA_INDEX_INFO;
      ParaSubIdx  := MDD2000_SPID_K_START;
      ParaVal     := 1;
      ParaTimeout := MDD2000MNG_FILE_HANDLING_TIMEOUT_LOG_PARAM;
    
    else    
      // Not supported
      ParaIDX     := 0;
      ParaSubIdx  := 0;
      ParaVal     := 0;
      ParaTimeout := MDD2000MNG_FILE_HANDLING_TIMEOUT_LOG_PARAM;
  
  end_case;

  
  if pParaIndex then
    pParaIndex^ := ParaIDX;
  end_if;
  
  if pParaSubIndex then
    pParaSubIndex^ := ParaSubIdx;
  end_if;  
  
  if pParaVal then
    pParaVal^ := ParaVal;
  end_if;
  
  if pParaTimeout then
    pParaTimeout^ := MDD2000MNG_FILE_HANDLING_TIMEOUT_LOG_PARAM;
  end_if;

END_FUNCTION

FUNCTION VIRTUAL MDD2000MngBase::GetDefaultLogFileDestinationDPNE
	VAR_INPUT
		pDPNE 	: ^CHAR;
		FileSelect 	: UDINT;(* := 0 *)
	END_VAR
  VAR
    aSerialNo         : ARRAY [0..10] OF CHAR;
  END_VAR

  if pDPNE then
  
    if FileSelect = MDD2000MNG_FILESELECT_DEBUGLOGFILE then
      _strcpy(dest:=pDPNE, src:=MDD2000MNG_DEFAULT_CPU_DEBUGLOGFILENAME_PATH );
    else
      _strcpy(dest:=pDPNE, src:=MDD2000MNG_DEFAULT_CPU_LOGFILENAME_PATH);
    end_if;
    
    //add serialno as string to filename
    _memset(dest:=#aSerialNo[0], usByte:=0, cntr:=sizeof(aSerialNo));
    sigclib_sprintfST(pd:=#aSerialNo[0], format:="%08d", p0:=#SerialNo);
    _strcat(dest:=pDPNE, src:=#aSerialNo[0]);
    
    _strcat(dest:=pDPNE, src:=MDD2000MNG_DEFAULT_CPU_LOGFILENAME_EXTENSION);
  end_if;  

END_FUNCTION


FUNCTION VIRTUAL MDD2000MngBase::GetDefaultLogFileNameDrive
	VAR_INPUT
		pFileName 	: ^CHAR;
		FileSelect 	: UDINT;
	END_VAR
  
  if pFileName then
  
    if FileSelect = MDD2000MNG_FILESELECT_DEBUGLOGFILE then
      _strcpy(dest:=pFileName, src:=MDD2000MNG_DEFAULT_DRIVE_DEBUGLOGFILENAME_NAME);
    else
      //Copy default name of Drive logfiles into buffer
      _strcpy(dest:=pFileName, src:=MDD2000MNG_DEFAULT_DRIVE_LOGFILENAME_NAME);
    end_if;
    
  end_if;
  
  

END_FUNCTION


FUNCTION VIRTUAL MDD2000MngBase::GetDefaultLogFilePathDrive
	VAR_INPUT
		pFilePath 	: ^CHAR;
		FileSelect 	: UDINT;
	END_VAR
  
  if pFilePath then
    //Copy default name of Drive logfile path/directory into buffer
    _strcpy(dest:=pFilePath, src:=MDD2000MNG_DEFAULT_DRIVE_LOGFILENAME_PATH);
  end_if;

END_FUNCTION

FUNCTION VIRTUAL MDD2000MngBase::CheckFileHandlingAvailable
	VAR_INPUT
		pdError 	: ^DINT;(* := nil *)
		ReserveID 	: UDINT;(* := MDD2000MNG_FILE_RESERVE_IDDEFAULT *)
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR
  
  // Default 
  retcode := ERROR;  
      
  if Online.read() = 0 then
    //Drive is not online
    if pdError then
      pdError^ := MDD2000MNG_FILE_HANDLING_RETCODE_NOT_ONLINE;
    end_if;
    return;
  end_if;
  
  if ReserveFileHandling(ReserveID) = TRUE then

    retcode := READY;
    
    // Reset ErrorCode
    if pdError then
      pdError^ := MDD2000MNG_FILE_HANDLING_RETCODE_NOERROR;
    end_if;
  
  elsif pdError then
    pdError^ := MDD2000MNG_FILE_HANDLING_RETCODE_FILEHANDLING_BUSY;
  end_if;
  
END_FUNCTION

FUNCTION VIRTUAL MDD2000MngBase::ReserveFileHandling
	VAR_INPUT
		ReserveID 	: UDINT;(* := DRIVEMNG_FILE_RESERVE_IDDEFAULT *)
	END_VAR
	VAR_OUTPUT
		bReserverdOK 	: BOOL;
	END_VAR
  VAR
  	ud_FileHandlingReservedOld : UDINT;
  END_VAR
  
  bReserverdOK := FALSE;
  
  ud_FileHandlingReservedOld := sigclib_atomic_cmpxchgU32(pValue:=#ud_FileHandlingReserved, cmpVal:=MDD2000MNG_FILE_RESERVE_IDFREE, newVal:=ReserveID);
  
  if ud_FileHandlingReservedOld = MDD2000MNG_FILE_RESERVE_IDFREE then
    bReserverdOK := TRUE;
  end_if;

END_FUNCTION

FUNCTION VIRTUAL MDD2000MngBase::ReleaseFileHandling

  sigclib_atomic_setU32(pValue:=#ud_FileHandlingReserved, value:=MDD2000MNG_FILE_RESERVE_IDFREE); //unlock method

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MDD2000MngBase::StrDriveType::Read
	VAR_OUTPUT
		output (EAX) 	: UDINT;
	END_VAR

	StrDriveType := DriveTypeStr.Data.Read();
	output := StrDriveType;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::StrDriveType::Write
	VAR_INPUT
		input (EAX) 	: UDINT;
	END_VAR
	VAR_OUTPUT
		result (EAX) 	: UDINT;
	END_VAR

	StrDriveType := input;
	result := (DriveTypeStr.Data.Write(StrDriveType))$UDINT;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::FwVersionDrive::Read
	VAR_OUTPUT
		output (EAX) 	: UDINT;
	END_VAR

	FwVersionDrive := FwNumString.Data.Read();
	output := FwVersionDrive;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::FwVersionDrive::Write
	VAR_INPUT
		input (EAX) 	: UDINT;
	END_VAR
	VAR_OUTPUT
		result (EAX) 	: UDINT;
	END_VAR

	FwVersionDrive := input;
	result := (FwNumString.Data.Write(FwVersionDrive))$UDINT;

END_FUNCTION


FUNCTION MDD2000MngBase::ConvertLC2ParaFormatToDS402Format
	VAR_INPUT
		ParaNo 	: DINT;
		phParaIndex 	: ^HINT;
		phsParaSubIndex 	: ^HSINT;
	END_VAR
  
  if ParaNo >= MDD2000_PID_SIGMATEKPARA_INDEX_SET_MAX_NR  then
    phParaIndex^      := MDD2000_PID_SIGMATEKPARA_INDEX_INFO$UINT;
    phsParaSubIndex^  := TO_USINT(ParaNo - (MDD2000_PID_SIGMATEKPARA_INDEX_SET_MAX_NR - 1));
  else
    phParaIndex^    := MDD2000_PID_SIGMATEKPARA_INDEX_SET$UINT;
    phsParaSubIndex^ := TO_USINT(ParaNo);
  end_if;

END_FUNCTION


FUNCTION MDD2000MngBase::ConvertDS402ParaFormatToLC2Format
	VAR_INPUT
		hParaIndex 	: HINT;
		hsParaSubIndex 	: HSINT;
		ParaNo 	: ^DINT;
	END_VAR
    
  if hParaIndex = MDD2000_PID_SIGMATEKPARA_INDEX_INFO then
    ParaNo^ := hsParaSubIndex + MDD2000_PID_SIGMATEKPARA_INDEX_SET_MAX_NR - 1;

  elsif hParaIndex = MDD2000_PID_SIGMATEKPARA_INDEX_SET then
    ParaNo^ := hsParaSubIndex;
    
  elsif hParaIndex = DS402_ASYNCPARA_DEFAULT_LASALPARA_INDEX then  //Already old format
    ParaNo^ := hsParaSubIndex;
  end_if;

END_FUNCTION

FUNCTION VIRTUAL MDD2000MngBase::AddParaObjects
	VAR_INPUT
		Index 	: USINT;
		pThis 	: ^void;
	END_VAR
	VAR_OUTPUT
		retcode 	: BOOL;
	END_VAR
  VAR
  	idx : DINT;
    maxidx : DINT;
  END_VAR

  retcode := FALSE;
  if (pThis <> NIL) & (index <> 0) then
  
    // Search for Free space in List
    maxidx := (sizeof(sParaObjectList)/sizeof(t_MDD2000Mng_ParaObjectListEntry)) - 1;
    for idx := 0 to maxidx do
    
      if sParaObjectList[idx].pObject = NIL then
      
        sParaObjectList[idx].pObject := pThis$pVirtualBase;
        sParaObjectList[idx].udIndex := to_udint(Index);
        retcode := TRUE;
        exit;
      
      end_if;
    
    end_for;
    
    if sParaObjectList[idx].pObject <> pThis then
      HWC_LogPrintf(this,"@08C4 (MDD2000MngBase::AddParaObjects) Failed to add parameter object with index %d and this pointer %x" , #Index, #pthis$DINT);
    end_if;
    
  else
    HWC_LogPrintf(this,"@08C4 (MDD2000MngBase::AddParaObjects) Failed to add parameter object with index %d and this pointer %x" , #Index, #pthis$DINT);
  end_if;

END_FUNCTION

FUNCTION MDD2000MngBase::SetParaState
	VAR_INPUT
		ActState 	: UINT;
		StateInfo 	: DINT;(* := 0 *)
	END_VAR
  VAR
    UserPara      : CmdStruct;
    UserResult    : Results;      
  	idx : DINT;
    maxidx : DINT;  
  END_VAR
  
  // Send the same command to all
  UserPara.uiCmd    := MDD2000MNG_IF_UPDATEPARACLASS_STATE;
  UserPara.aPara[0] := MDD2000MNG_IF_UPDATEPARACLASS_STATE_VER_1;
  UserPara.aPara[1] := ActState;
  UserPara.aPara[2] := StateInfo;
  
  // Send to all Para Classes
  maxidx := (sizeof(sParaObjectList)/sizeof(t_MDD2000Mng_ParaObjectListEntry)) - 1;
  for idx := 0 to maxidx do
  
    if sParaObjectList[idx].pObject then
      sParaObjectList[idx].pObject^.NewInst(#UserPara, #UserResult);
    else
      exit;
    end_if;
    
  end_for;
  
  // Send to all Axis Classes
  for idx := 0 to (MDD2000MNG_MAXENTRIES - 1) do
    
    // axis object available
    if AxBuffer[idx].pThis <> NIL then
        
      AxBuffer[idx].pThis$^VirtualBase^.NewInst(#UserPara, #UserResult);

    else
      exit;
    end_if;
    
  end_for;

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MDD2000MngBase::FwVersionSafety::Read
	VAR_OUTPUT
		output (EAX) 	: UDINT;
	END_VAR

	FwVersionSafety := FwSafeNumString.Data.Read();
	output := FwVersionSafety;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::FwVersionSafety::Write
	VAR_INPUT
		input (EAX) 	: UDINT;
	END_VAR
	VAR_OUTPUT
		result (EAX) 	: UDINT;
	END_VAR

	FwVersionSafety := input;
	result := (FwSafeNumString.Data.Write(FwVersionSafety))$UDINT;

END_FUNCTION


FUNCTION VIRTUAL MDD2000MngBase::SendSafteyConfigChanged
  VAR
    MyPara 	  : CmdStruct;
		MyResult  : results;
  END_VAR

  MyPara.uiCmd          := MDD2000MNG_IF_SAFETYCONFIG_CHANGED;
  MyPara.aPara[0]       := MDD2000MNG_IF_SAFETYCONFIG_CHANGED_VER_1;
  MyPara.aPara[1]$HDINT := sSafetyCfgChg.SafetyCFGCRC;
  MyPara.aPara[2]       := sSafetyCfgChg.SafetyLenOutFSoEFrame;
  MyPara.aPara[3]       := sSafetyCfgChg.SafetyLenInFSoEFrame;
  
  ToBusIF.NewInst(#MyPara,#MyResult);
    
END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::HWVersion::Read
	VAR_OUTPUT
		output (EAX) 	: UDINT;
	END_VAR

	HWVersion := HWNumString.Data.Read();
	output := HWVersion;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000MngBase::HWVersion::Write
	VAR_INPUT
		input (EAX) 	: UDINT;
	END_VAR
	VAR_OUTPUT
		result (EAX) 	: UDINT;
	END_VAR

	HWVersion := input;
	result := (HWNumString.Data.Write(HWVersion))$UDINT;

END_FUNCTION
