//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 MDD2000_AXISBASE_AXISSTATE_ERRORMASK       0x0F //Which bits of the axisstate server are "errors"  (NoHW,NoParameter,NotOnline,NotInitialized)

#define MDD2000_AXISBASE_SPEED_SFFLIMITATION_USERINFO_0   32767
#define MDD2000_AXISBASE_SPEED_SFFLIMITATION_USERINFO_1    1000
#define MDD2000_AXISBASE_TORQUE_LIMITATION_VALUE           1000
 
//*****************************************************************************
// Define for reading the encoder memory

#define MDD2000_AXISBASE_DRIVEENCMEM_ASYCALLID  0xEC12 // Identifer for asy commndos used for reading the encoder memory 

#define MDD2000_AXISBASE_DRIVEENCMEM_PARAVAL_RD_ENCMEMSIZE   28 // Select encoder mem size to be read.

#define MDD2000_AXISBASE_DRIVEENCMEM_K_FBRW_LOCK     98
#define MDD2000_AXISBASE_DRIVEENCMEM_K_FBRW_UNLOCK   99

#define MDD2000_AXISBASE_DRIVEENCMEM_ASYCOMERR_RETRY         6 // This error is returned if DRIVEENCMEM_KASTART_LOCK_SCOPE failes because someone else has got the lock.
                                              // See _DriveASyncPara for the errocoeds; 6 =    object cannot be changed in this mode, 

#define MDD2000_AXISBASE_DRIVEENCMEM_DELAY_RETRYLOCK       500
#define MDD2000_AXISBASE_DRIVEENCMEM_DELAY_FILECREATE      200 // Minimum known time it takes to create the file. Depends on the encoder

#define MDD2000_AXISBASE_DRIVEENCMEM_MEMBLOCK_SIZE         128 
#define MDD2000_AXISBASE_DRIVEENCMEM_MEMBLOCK_ID_OFFSET    100 // Memory blocks 0 - 63 have the id 100-163

#define MDD2000_AXISBASE_DRIVEENCMEM_FILENPATH         "C:\A%d"               // Filepath/name for the encoder is "C:\A<x>\feedback.dat" ; x = axisno
#define MDD2000_AXISBASE_DRIVEENCMEM_FILENAME          "feedback.dat"

#define MDD2000_AXISBASE_DRIVEENCMEM_K_FBRW_OK         0
#define MDD2000_AXISBASE_DRIVEENCMEM_K_FBRW_BUSY     100 // DRIVEENCMEM_MEMBLOCK_ID_OFFSET was written, not yet reset by FW

#define MDD2000_AXISBASE_DRIVEENCMEM_P_S_INDEX_VALOFFSET 600 // Offset used by FW do distinguish access from scope accesses

//}}LSL_DEFINES

//{{LSL_DECLARATION
#include "..\..\Class\HwControl\HwControl.h"
#include "..\..\Class\MDD2000MngBase\MDD2000MngBase.h"
#include "..\..\class\_drivemngbase\drivemngbase.h"
#include "..\..\Class\_DriveEncoderMemory\_DriveEncoderMemory.h"

(*!
<Class
	Name               = "MDD2000_AxisBase"
	Revision           = "1.1"
	GUID               = "{1E817989-FFE0-40DB-B63F-453547B741D6}"
	RealtimeTask       = "false"
	CyclicTask         = "false"
	BackgroundTask     = "false"
	Sigmatek           = "true"
	OSInterface        = "false"
	HighPriority       = "false"
	Automatic          = "false"
	UpdateMode         = "Prescan"
	IconPath           = ".\Class\MDD2000_Mng\MDD2000SafetyDrive.ico"
	SharedCommandTable = "true"
	Objectsize         = "(494,120)"
	Comment            = "this class prepare the actual values and the incomming setpoints">
	<Channels>
		<Server Name="ActCurrent" GUID="{B6D3C2DF-5B02-4E2C-9DA4-E2DC559E9A9C}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Actual Current [mA]"/>
		<Server Name="ActPos" GUID="{BE8D6041-1392-472D-A774-20D833CA3239}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Actual position"/>
		<Server Name="ActSpeed" GUID="{D9EB7458-09B9-4ABA-8B14-6D24A4321FE4}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Actual speed"/>
		<Server Name="ActXw" GUID="{C59478CF-FF9F-4286-9841-F775D263FC13}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Position Error"/>
		<Server Name="AxEnable" GUID="{87B86CE0-CC05-45BB-B692-5E3CBAC1D056}" Visualized="true" Initialize="false" WriteProtected="false" Retentive="false" Comment="server to enable the axle"/>
		<Server Name="AxError" GUID="{42820B69-C247-425C-8FA7-19E2686C2E19}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="0 .. no error&#13;&#10;1 .. Axis has an error"/>
		<Server Name="AxErrorQuit" GUID="{A2344F42-1FDB-414C-B214-CBA303E3313A}" Visualized="true" Initialize="false" WriteProtected="false" Retentive="false" Comment="A write command quits the actual error state of the axle&#13;&#10;If applicable, the following safety errors are quit:&#13;&#10;* Safety function quit via &quot;Error-Acknowledge&quot;&#13;&#10;* Quit of an error of the safety-related drive FW. (Operation mode / &quot;MDD2000_Mng.SafetyRunState&quot; = &quot;_ERROR&quot;)"/>
		<Server Name="AxisState" GUID="{15427E77-E71B-4AED-960C-70217BCFB944}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Displays the status-bits from the axle&#13;&#10;&#13;&#10;Bit01 .. NoHW =&gt; there is no hardware connected on this Place or AxNo&#13;&#10;Bit02 .. NoParameter =&gt; there are no parameters &#13;&#10;Bit03 .. NotOnline =&gt; the _DriveMng is not online&#13;&#10;Bit04 .. NotInitialized =&gt; the axle has not initialized yet&#13;&#10;Bit05 .. SFFLimitationActive =&gt; Limitation of the speed pre-control active (see description Server SetSpeed)&#13;&#10;Bit06 .. DiagModeActive =&gt; The object is locked by the _DriveAxisDiag class.&#13;&#10;Bit07 .. SafeAxisNotVerified =&gt; The axis has not yet been Safety verified or the verification status of the axis has not yet been read out&#13;&#10;Bit08 .. .&#10;SafeAxisZeroPosNotSet =&gt; The axis has not yet been Safety referenced or the referencing status of the axis has not yet been read out&#13;&#10;Bit09 .. .&#10;SafeMngNotVerified =&gt; Verification and referencing of all axes of the drive has not yet been completed. Only rotations with reduced speed are possible&#13;&#10;Bit10 .. .&#10;SafeMngNotReady =&gt; The safety system in the drive is not ready."/>
		<Server Name="AxTorqueControl" GUID="{8AAE54F7-FD3F-419F-837F-845FAACD9FE8}" Visualized="true" Initialize="false" WriteProtected="false" Retentive="false" Comment="the torque limit is set here, the actual limit depends on the controlword.&#13;&#10;16bit Controlword - 0 until 1000 from Peak Current&#13;&#10;32bit Controlword - 0 until 4500 from Stall Current"/>
		<Server Name="CmdState" GUID="{551A1544-A5F4-418D-9A62-32DD5669695A}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Displays the actual state of the Class&#13;&#10;(QUIT = disabled by client AxisNo)"/>
		<Server Name="ControlWord" GUID="{37719AEE-FD4A-4AED-8DDD-FA5DDA505C34}" Visualized="true" Initialize="false" WriteProtected="false" Retentive="false" Comment="Controlword with DS402 Standard :&#13;&#10;&#13;&#10;Bit00 .. SwitchOn&#13;&#10;Bit01 .. DisableVoltage&#13;&#10;Bit02 .. QuickStop&#13;&#10;Bit03 .. EnableOperation&#13;&#10;Bit04 .. OperationModeSpecific1&#13;&#10;Bit05 .. OperationModeSpecific2&#13;&#10;Bit06 .. OperationModeSpecific3&#13;&#10;Bit07 .. ResetFault&#13;&#10;Bit08 .. Halt&#13;&#10;Bit09 .. Reserved1&#13;&#10;Bit10 .. Reserved2&#13;&#10;Bit11 .. Manufacture Specific1&#13;&#10;Bit12 .. Manufacture Specific2&#13;&#10;Bit13 .. Manufacture Specific3&#13;&#10;Bit14 .. Manufacture Specific4&#13;&#10;Bit15 .. Manufacture Specific5"/>
		<Server Name="MDD2000CmdIntfc" GUID="{EC1E8815-2515-4495-B834-1D141B181BA8}" Visualized="true" Initialize="false" WriteProtected="false" Retentive="false" Comment="Server for user commands to the drive:&#13;&#10;_SDDIDLE     .. default command&#13;&#10;_SDDREADALL  .. read all parameters of the drive &#13;&#10;  and save the parameters in the SRAM or in the file.&#13;&#10;  If any parameter classes are connected to the class SDDMngBase,&#13;&#10;  the servers of the parameter classes are refreshed.&#13;&#10;_SDDINIT     .. Initialize the drive with the saved parameters.&#13;&#10;_SDDURINIT   .. Initialize the drive with the parameters of the table.&#13;&#10;  (Lasal2 table, User Table or default table)&#13;&#10;_SDDEXDATA   .. Export the actual drive parameter into an excel formatted file.&#13;&#10;_SDDEXDATAXML   .. Export the actual drive parameter into an xml formatted file.&#13;&#10;_SDDIMDATAXML   .. Imports the drive parameter from an xml formatted file. User commands &quot;_SDDINIT&quot; must be called to transfer the data to the drive.&#13;&#10;_SDDERROR    .. This value is shown, when the user commands &quot;_SDDEXDATAXML&quot; or &quot;_SDDIMDATAXML&quot; failed. See Log-File for details. New user commands can be set in this state.&#13;&#10;&#13;&#10;User commands are only processed if the server &apos;Online&apos; displays 1. &#13;&#10;If the server &apos;Online&apos; is 0, the execution of the command is delayed until the server &apos;Online&apos; becomes 1."/>
		<Server Name="Online" GUID="{EBE33CBE-3FFD-4816-AFDA-015D27D63E87}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="displays if the class is ready to work with the application"/>
		<Server Name="SetCurrent" GUID="{51B8A4E1-D19E-4CAE-8A01-B8ECA4A22D2B}" Visualized="true" Initialize="false" WriteProtected="false" Retentive="false" Comment="Current setpoint [mA]&#13;&#10;or&#13;&#10;Torque Feed Forward [mA] in G-MODE 3 (depending on A-VALRT1/2)"/>
		<Server Name="SetPos" GUID="{7121A2DF-5052-40E0-A4C5-9D190619D925}" Visualized="true" Initialize="false" WriteProtected="false" Retentive="false" Comment="Position setpoint"/>
		<Server Name="SetSpeed" GUID="{B812B00C-42FF-461A-BA52-41AB0BEE578A}" Visualized="true" Initialize="false" WriteProtected="false" Retentive="false" Comment="Speed setpoint&#13;&#10;or&#13;&#10;SpeedFeedForward (depending on A-VALRT1/2)&#13;&#10;&#13;&#10;In case of 2 Bytes for the SpeedFeedForward, this value gets limited to an INT value."/>
		<Server Name="SetVerified" GUID="{1C30DBFC-00E0-4DF7-AD9F-658B67AB3F1B}" Visualized="true" Initialize="false" WriteProtected="false" Retentive="false" Comment="Changes the Safe Verified State of the axis&#13;&#10;0 .. Only read VerifiedState of the axis&#13;&#10;-1 .. Reset VerifiedState of all axes and Reset ReferenceState of this axis&#13;&#10;-2 .. Reset VerifiedState of all axes, else SetVerified and Read VerifiedState from Drive&#13;&#10;1 .. Set the axis verified and read VerifiedState from Drive&#13;&#10;&#13;&#10;"/>
		<Server Name="SetVerifiedRsp" GUID="{D744542D-E1BB-4C5C-91A4-74DB3AA39150}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Shows the response state of the SetVerified command."/>
		<Server Name="StateWord" GUID="{049BE19B-B649-4FB4-B8E5-4A06C72D2CE0}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Statusword with DS402 Standard :&#13;&#10;&#13;&#10;Bit00 .. ReadyToSwitchOn&#13;&#10;Bit01 .. SwitchedOn&#13;&#10;Bit02 .. OperationEnabled&#13;&#10;Bit03 .. Fault&#13;&#10;Bit04 .. VoltageDisabled&#13;&#10;Bit05 .. QuickStop&#13;&#10;Bit06 .. SwitchOnDisabled&#13;&#10;Bit07 .. Warning&#13;&#10;Bit08 .. ManufactureSpecific1&#13;&#10;Bit09 .. Remote&#13;&#10;Bit10 .. TargetReached&#13;&#10;Bit11 .. InternalLimitActive&#13;&#10;Bit12 .. OperationModeSpecific1&#13;&#10;Bit13 .. OperationModeSpecific2&#13;&#10;Bit14 .. Manufacture Specific2&#13;&#10;Bit15 .. Manufacture Specific3"/>
		<Server Name="VerifiedState" GUID="{BD2B2B14-582B-4D3A-840F-6ACAB26A6D37}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Shows the verification state of the drive."/>
		<Server Name="ZPulsLatch" GUID="{116EF41E-3738-4412-89A5-619DEA2BEB55}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="latched Zero-Impulse of the axle&#13;&#10;(reset on read-out)&#13;&#10;depends on P-PSCALE"/>
		<Client Name="AxisNo" Required="true" Internal="false" Comment="1 - 3: select axis&#13;&#10;&lt;1 or &gt;3: object disabled (Server CmdState will be set to QUIT)"/>
		<Client Name="coLinker" Required="false" Internal="false" Comment="Object Channel to the _Linker"/>
		<Client Name="coStdLib" Required="false" Internal="false" Comment="Object Channel to the _StdLib"/>
		<Client Name="DriveAxisSet" Required="true" Internal="false" Comment="Object Channel to the _DriveAxisSet"/>
		<Client Name="DriveMng" Required="true" Internal="false" Comment="Object Channel to the _DriveMng"/>
		<Client Name="EncoderBufferSize" Required="true" Internal="false" DefValue="0" Comment="Size of the Buffer in this class to store the copy of the encoder memory. &#13;&#10;This configuration is used to allocate the necessary memory.&#13;&#10;This value must be set as init value.&#13;&#10;CAUTION: When the allocated buffer size is smaller than the encoder memory size which is read the class will return an error when attempting to read the encoder memory."/>
		<Client Name="MDD2000GeneralPara" Required="true" Internal="false"/>
	</Channels>
	<Separators>
		<Servers>
			<SepChn Position="18"/>
		</Servers>
	</Separators>
	<Dependencies>
		<Files>
			<File Path=".\Class\HwControl\HwControl.h" Include="true"/>
			<File Path=".\Class\MDD2000MngBase\MDD2000MngBase.h" Include="true"/>
			<File Path=".\class\_drivemngbase\drivemngbase.h" Include="true"/>
			<File Path=".\Class\_DriveEncoderMemory\_DriveEncoderMemory.h" Include="true"/>
		</Files>
	</Dependencies>
	<RevDoku>
		<Owner Company="Sigmatek" Author="LanSte"/>
		<Dokumentation Revision="1.1" Date="22.04.2024" Author="ZoePat" Company="Sigmatek" Description="Corrected possible compiler error, if function FetchEncoderData is called without input parameters (there where invalid characters in the init value definition)."/>
		<Dokumentation Revision="1.0" Date="28.08.2023" Author="LanSte" Company="Sigmatek" Description="First library version."/>
	</RevDoku>
</Class>
*)
MDD2000_AxisBase : CLASS
	TYPE
	  _MDD2000AXISSTATE : BDINT  //! <Type Public="true" Name="_MDD2000AXISSTATE"/>
	  [
	    1 NoHW,
	    2 NoParameter,
	    3 NotOnline,
	    4 NotInitialized,
	    5 SFFLimitationActive,
	    6 DiagModeActive,
	    7 SafeAxisNotVerified,
	    8 SafeAxisZeroPosNotSet,
	    9 SafeMngNotVerified,
	    10 SafeMngNotReady,
	  ];
#pragma pack(push, 1)
	  _MDD2000MEMHEADER : STRUCT  //! <Type Public="true" Name="_MDD2000MEMHEADER"/>
	    udCRC32 : UDINT;
	    udLen : UDINT;
	    udVersion : UDINT;
	    AxOffset : DINT;
	    AxLength : UDINT;
	    AxName : ARRAY [0..20] OF CHAR;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  _MDD2000MParaBuffer : STRUCT
	    NoItems : DINT;
	    MBuffer : ARRAY [0..255] OF USINT;
	  END_STRUCT;
#pragma pack(pop)
	  _MDD2000STATEWORD : BSINT  //! <Type Comment="Structure for Pdo read stateword.&#13;&#10;If structure changes, also the version number in the newinst command SDD_NEWINSTPDO has to be incremented." Name="_MDD2000STATEWORD"/>
	  [
	    1 ReadyToSwitchOn,
	    2 SwitchedOn,
	    3 OperationEnabled,
	    4 Fault,
	  ];
#pragma pack(push, 1)
	  _MDD2000PDOREAD : STRUCT  //! <Type Comment="Structure for PDO Read Data.&#13;&#10;If structure changes, also the version number in the newinst command SDD_NEWINSTPDO has to be incremented." Name="_MDD2000PDOREAD"/>
	    Online : BOOL;
	    StateWord : _MDD2000STATEWORD;
	    ActPos : DINT;
	    ActXw : DINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  _MDD2000PDOWRITENTRY : STRUCT  //! <Type Comment="Structure for PDO Write Entry Data.&#13;&#10;If structure changes, also the version number in the newinst command SDD_NEWINSTPDO has to be incremented." Name="_MDD2000PDOWRITENTRY"/>
	    Active : UINT;
	    Value : DINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  _MDD2000PDOWRITE : STRUCT  //! <Type Comment="Structure for PDO Write Data.&#13;&#10;If structure changes, also the version number in the newinst command SDD_NEWINSTPDO has to be incremented." Name="_MDD2000PDOWRITE"/>
	    SetPos : _MDD2000PDOWRITENTRY;
	    Enable : _MDD2000PDOWRITENTRY;
	    SetSpeed : _MDD2000PDOWRITENTRY;
	  END_STRUCT;
#pragma pack(pop)
	  _MDD2000SAVTYPE :
	  (
	    _MDD2000_STDTABLE,
	    _MDD2000_L2TABLE,
	    _MDD2000_RAMEX,
	    _MDD2000_FILE
	  )$UDINT;
	  _MDD2000USERCMD :  //! <Type Public="true" Comment="Type for user commands to the drive. See Server &apos;MDD2000CmdIntfc&apos; of the &apos;_DriveAxis&apos; class." Name="_MDD2000USERCMD"/>
	  (
	    _MDD2000IDLE,  //! <Type Comment="default command" Name="_MDD2000USERCMD._MDD2000IDLE"/>
	    _MDD2000READALL,  //! <Type Comment="read all parameters of the drive &#13;&#10;  and save the parameters in the SRAM or in the file.&#13;&#10;  If any parameter classes are connected to the class MDD2000_Axis&#13;&#10;  the servers of the parameter classes are refreshed." Name="_MDD2000USERCMD._MDD2000READALL"/>
	    _MDD2000INIT,  //! <Type Comment="Initialize the drive with the saved parameters." Name="_MDD2000USERCMD._MDD2000INIT"/>
	    _MDD2000URINIT,  //! <Type Comment="Initialize the drive with the parameters of the table.&#13;&#10;  (Lasal2 table, User Table or default table)" Name="_MDD2000USERCMD._MDD2000URINIT"/>
	    _MDD2000EXDATA,  //! <Type Comment="Export the actual drive parameter into an excel formatted file." Name="_MDD2000USERCMD._MDD2000EXDATA"/>
	    _MDD2000EXDATAXML:=6,  //! <Type Comment="Export the actual drive parameter into an xml formatted file." Name="_MDD2000USERCMD._MDD2000EXDATAXML"/>
	    _MDD2000IMDATAXML,  //! <Type Comment="Imports the drive parameter from an xml formatted file. User commands &quot;_MDD2000INIT&quot; must be called to transfer the data to the drive." Name="_MDD2000USERCMD._MDD2000IMDATAXML"/>
	    _MDD2000ERROR,  //! <Type Comment="This value is shown, when the user commands &quot;_MDD2000EXDATAXML&quot;, &quot;_MDD2000IMDATAXML&quot;  or &quot;_MDD2000EXLOGFILE&quot; failed. See Log-File for details. New user commands can be set in this state." Name="_MDD2000USERCMD._MDD2000ERROR"/>
	    _MDD2000EXLOGFILE  //! <Type Comment="Reads the Log File from the drive and writes it to the CPU under: &quot;C:\sysmsg\DriveLog&lt;Serial No&gt;.txt&quot;" Name="_MDD2000USERCMD._MDD2000EXLOGFILE"/>
	  )$UDINT;
	  eSSW_GetEncoderMain :
	  (
	    _Start,
	    _CheckFileHandling,
	    _Idle,
	    _ReadEncMemSize,
	    _ReadEncMemAsync,
	    _ReadEncMemAsyncErrorHandling,
	    _ReadEncMemFile,
	    _Error
	  )$UDINT;
	  eSSW_GetEncoderMemAsync :
	  (
	    _Start,
	    _SelectStartBlockOffset,
	    _LockScopeAccesses,
	    _Wait4_LockScopeAccesses,
	    _Wait4Lock,
	    _SelectBlock,
	    _Wait4SelectBlockRsp,
	    _Wait4SelectBlock,
	    _StartReadBlock,
	    _Wait4StartReadBlock,
	    _ReadBlock,
	    _Wait4ReadBlockRsp,
	    _Wait4ReadBlock,
	    _SelectNextBlock,
	    _ReleaseScopeAccesses,
	    _Wait4ReleaseScopeAccesses,
	    _Done,
	    _Error
	  )$UDINT;
	  eSSW_GetEncoderMemFile :
	  (
	    _Start,
	    _CreateEncoderMemFile,
	    _Wait4CreateEncoderMemFile,
	    _Wait4EncoderMemFileUnlock,
	    _Wait4EncoderMemFileCreate,
	    _CheckEncoderMemFileCreate,
	    _Wait4CheckEncoderMemFileCreate,
	    _ReadEncoderMemFile,
	    _Wait4EncoderMemFile,
	    _Done,
	    _Error
	  )$UDINT;
	  eSSW_GetEncoderMemSize :
	  (
	    _Start,
	    _SendWrPara,
	    _Wait4SendWrPara,
	    _SendRdPara,
	    _Wait4SendRdPara,
	    _Done,
	    _Error
	  )$UDINT;
	  gb_MDD2000ActiveSafeFkt : BDINT  //! <Type Public="true" Name="gb_MDD2000ActiveSafeFkt"/>
	  [
	    1 STO,
	    2 SS1,
	    3 SS2,
	    4 SOS,
	    5 SBC,
	    6 SBT,
	    7 SLS,
	    8 SLP,
	    9 SLA,
	    10 SLT,
	    11 SLI,
	    12 SDI,
	    13 SMS,
	    14 SMP,
	    15 SMA,
	    16 SMT,
	    17 SSM,
	    18 SCA,
	    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,
	  ];
	  RequiredReferenceToSigClib : ^SigCLib;  //! <Type Public="true" Name="RequiredReferenceToSigClib"/>
#pragma pack(push, 1)
	  SyncSet : STRUCT
	    ptr : ^DINT;
	    size : USINT;
	    userinfo : USINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  SyncPara_type : STRUCT
	    SetPos : SyncSet;
	    SetSpeed : SyncSet;
	    SetCurrent : SyncSet;
	    SetTorque : SyncSet;
	    ControlWord : SyncSet;
	    ActPos : SyncSet;
	    ActSpeed : SyncSet;
	    ActCurrent : SyncSet;
	    StateWord : SyncSet;
	    Xw : SyncSet;
	    DigInputs : SyncSet;
	    SafeControlWord : SyncSet;
	    SafeStateWord : SyncSet;
	    SafePos : SyncSet;
	    SafeSpeed : SyncSet;
	    SafeAcceleration : SyncSet;
	    SafeCurrent : SyncSet;
	  END_STRUCT;
#pragma pack(pop)
	  t_e_AxisInitSSW :
	  (
	    _MDD2000_IDLE,
	    _MDD2000_STARTINIT,
	    _MDD2000_GETDRIVEINFO,
	    _MDD2000_WAIT4GETDRIVEINFO,
	    _MDD2000_CHKFEEDBACK,
	    _MDD2000_SENDPARA,
	    _MDD2000_GETSYNCSETTINGS,
	    _MDD2000_CHECKSYNCSETTINGS,
	    _MDD2000_SENDPARAFINISH,
	    _MDD2000_ERRORININIT
	  )$UDINT;
	  t_e_SafeReferencedState :  //! <Type Public="true" Name="t_e_SafeReferencedState"/>
	  (
	    Unkown,
	    Reading:=11,
	    NotReferenced:=445406843,
	    AxisReferenced:=731737996,
	    NotNeeded:=805306368,
	    WaitMovement:=805306369,
	    AckPending:=805306370,
	    ReferenceDone:=805306371,
	    AsyCommError:=2147483649
	  )$UDINT;
	  t_e_SafeReferenceRsp :  //! <Type Public="true" Name="t_e_SafeReferenceRsp"/>
	  (
	    CmdIdle,
	    CmdOk:=1073741824,
	    CmdBusy:=11,
	    ProgrammingFailed:=1073741826,
	    ErrWrongRunState:=1073741827,
	    RefNotNeeded:=1073741828,
	    NotAllowed:=1073741840,
	    NoMovement:=1073741841,
	    WrongPostion:=1073741842,
	    AsyCommError:=2147483649
	  )$UDINT;
	  t_e_SafeVerifiedState :  //! <Type Public="true" Name="t_e_SafeVerifiedState"/>
	  (
	    Unkown:=0,
	    Reading:=11,
	    NotVerified:=445406843,
	    NotUsed:=805306368,
	    VerifyPending:=805306369,
	    AxisVerified:=805306370,
	    SystemVerified:=731737996,
	    AsyCommError:=2147483649
	  )$UDINT;
	  t_e_SetVerifiedRsp :  //! <Type Public="true" Name="t_e_SetVerifiedRsp"/>
	  (
	    CmdIdle:=0,
	    CmdOk:=1073741824,
	    CmdBusy:=11,
	    CmdExecuting:=1073741835,
	    ErrWrongRunState:=1073741827,
	    VerifyNotNeeded:=1073741828,
	    ProgrammingFailed:=1073741829,
	    Incomplete:=1073741825,
	    CmdError:=1073741826,
	    AsyCommError:=2147483649
	  )$UDINT;
#pragma pack(push, 1)
	  t_s_EncoderData : STRUCT
	    bValid : BOOL;
	    pData : pVoid;
	    Size : UDINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_s_EncoderFetch : STRUCT
	    reqOffset : UDINT;
	    reqSize : UDINT;
	    currOffset : UDINT;
	    currBlock : UDINT;
	    noByteRead : UDINT;
	    pDst : pVoid;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_s_EncoderVar : STRUCT
	    State : DINT;
	    EncoderMemSize : UDINT;
	    pBuffer : pVoid;
	    Progress : UDINT;
	    LastErrorCode : DINT;
	    AsyCommErrCode : DINT;
	    ud_TimeMark : UDINT;
	    AsyVal : DINT;
	    SSWMain : eSSW_GetEncoderMain;
	    SSWMain_StepGetMem : eSSW_GetEncoderMain;
	    SSWGetEncoderMemSize : eSSW_GetEncoderMemSize;
	    SSWGetEncoderMemSizeLast : eSSW_GetEncoderMemSize;
	    SSWGetEncoderMemAsync : eSSW_GetEncoderMemAsync;
	    SSWGetEncoderMemAsyncLast : eSSW_GetEncoderMemAsync;
	    SSWGetEncoderMemFile : eSSW_GetEncoderMemFile;
	    SSWGetEncoderMemFileLast : eSSW_GetEncoderMemFile;
	    strFilePathDrv : ARRAY [0..7] OF CHAR;
	    strFileNameDrv : ARRAY [0..15] OF CHAR;
	    sEncoderFetch : t_s_EncoderFetch;
	    sEncoderData : t_s_EncoderData;
	    bdUserRequest : BDINT
	    [
	      1 GetFeedbackDataSize,
	      2 FetchEncoderData,
	      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,
	    ];
	    bEncoderMemSizeRead : BOOL;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_s_SafeBrakeState : STRUCT
	    BrakeTestStatus : DINT;
	    SafeBrakeTestStatus : DINT;
	    TimeTilNextTest : DINT;
	    BrakeTestErrorInfo : DINT;
	    bdWait4Para : BDINT
	    [
	      1 BrakeTestStatus,
	      2 SafeBrakeTestStatus,
	      3 TimeTilNextTest,
	      4 SetBrakeTest,
	      5 BrakeTestErrorInfo,
	      6 Bit6,
	      7 Bit7,
	      8 Bit8,
	      9 ErrBrakeTestStatus,
	      10 ErrSafeBrakeTestStatus,
	      11 ErrTimeTilNextTest,
	      12 ErrSetBrakeTest,
	      13 ErrBrakeTestErrorInfo,
	      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)
	  ts_BitMasksSafeFktCfg : STRUCT
	    STO : BINT
	    [
	      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,
	    ];
	    SS1 : BINT
	    [
	      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,
	    ];
	    SS2 : BINT
	    [
	      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,
	    ];
	    SOS : BINT
	    [
	      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,
	    ];
	    SBC : BINT
	    [
	      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,
	    ];
	    SBT : BINT
	    [
	      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,
	    ];
	    SLS : BINT
	    [
	      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,
	    ];
	    SLP : BINT
	    [
	      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,
	    ];
	    SLA : BINT
	    [
	      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,
	    ];
	    SLT : BINT
	    [
	      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,
	    ];
	    SLI : BINT
	    [
	      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,
	    ];
	    SDI : BINT
	    [
	      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,
	    ];
	    SMS : BINT
	    [
	      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,
	    ];
	    SMP : BINT
	    [
	      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,
	    ];
	    SMA : BINT
	    [
	      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,
	    ];
	    SMT : BINT
	    [
	      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,
	    ];
	    SSM : BINT
	    [
	      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,
	    ];
	    SCA : BINT
	    [
	      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,
	    ];
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  ts_SafeFktUpdateElement : STRUCT
	    pBitMask : ^HINT;
	    SetBit : HDINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_s_SafeFktVar : STRUCT
	    BitMasksSafeFktCfgCtrl : ts_BitMasksSafeFktCfg;
	    BitMasksSafeFktCfgState : ts_BitMasksSafeFktCfg;
	    aSafeFktUpdateListCtrl : ARRAY [0..MDD2000_AXISSAFE_MAX_IDX_SAFEFKT] OF ts_SafeFktUpdateElement;
	    aSafeFktUpdateListState : ARRAY [0..MDD2000_AXISSAFE_MAX_IDX_SAFEFKT] OF ts_SafeFktUpdateElement;
	    bSafeFktUpdateListValid : BOOL;
	    oldSafeControlWord : 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,
	    ];
	    oldSafeStateWord : 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,
	    ];
	    oldActiveSafeFkt : gb_MDD2000ActiveSafeFkt;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_s_SafeFuncErrInfo : STRUCT
	    SafeErrorWord : DINT;
	    SafeFunctionErrorID : DINT;
	    SafeFunctionInErrID : DINT;
	    SafeFunctionInErrSubID : DINT;
	    SafeFunctionErrReactID : DINT;
	    SafeFunctionErrReactSubID : DINT;
	    SafeFunctionErrorInfo1 : DINT;
	    SafeFunctionErrorInfo2 : DINT;
	    SafeFunctionErrorInfo3 : DINT;
	    bdAsyFlags : BDINT
	    [
	      1 w4SafeErrorWord,
	      2 w4SafeFunctionErrorID,
	      3 w4SafeFunctionInErrID,
	      4 w4SafeFunctionErrReact,
	      6 w4SafeFunctionErrorInfo1,
	      7 w4SafeFunctionErrorInfo2,
	      8 w4SafeFunctionErrorInfo3,
	      9 errSafeErrorWord,
	      10 errSafeFunctionErrorID,
	      11 errSafeFunctionInErrID,
	      12 errSafeFunctionErrReact,
	      14 errSafeFunctionErrorInfo1,
	      15 errSafeFunctionErrorInfo2,
	      16 errSafeFunctionErrorInfo3,
	      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_SafeRefState : STRUCT
	    CmdState : HDINT;
	    RefState : HDINT;
	  END_STRUCT;
#pragma pack(pop)
	END_TYPE
  //Servers:
	CmdState 	: SvrChCmd_iprStates;
	Online 	: SvrCh_DINT;
	AxisState 	: SvrCh__MDD2000AXISSTATE_PTofCls_MDD2000_AxisBase;
	ActPos 	: SvrCh_DINT;
	SetPos 	: SvrCh_DINT;
	ActSpeed 	: SvrCh_DINT;
	SetSpeed 	: SvrCh_DINT;
	ActCurrent 	: SvrCh_DINT;
	SetCurrent 	: SvrCh_DINT;
	ActXw 	: SvrCh_DINT;
	StateWord 	: SvrCh_DS402_State;
	ControlWord 	: SvrCh_DS402_Control;
	AxEnable 	: SvrCh_DINT;
	AxError 	: SvrCh_DINT;
	AxErrorQuit 	: SvrCh_DINT;
	ZPulsLatch 	: SvrCh_DINT;
	AxTorqueControl 	: SvrCh_UDINT;
	MDD2000CmdIntfc 	: SvrCh__MDD2000USERCMD_PTofCls_MDD2000_AxisBase;
	SetVerified 	: SvrCh_DINT;
	SetVerifiedRsp 	: SvrCh_t_e_SetVerifiedRsp_PTofCls_MDD2000_AxisBase;
	VerifiedState 	: SvrCh_t_e_SafeVerifiedState_PTofCls_MDD2000_AxisBase;
  //Clients:
	DriveMng 	: CltChCmd_MDD2000MngBase;
	AxisNo 	: CltCh_DINT;
	DriveAxisSet 	: CltChCmd_MDD2000AxisSet;
	coStdLib 	: CltChCmd__StdLib;
	coLinker 	: CltChCmd__Linker;
	EncoderBufferSize 	: CltCh_DINT;
	MDD2000GeneralPara 	: CltChCmd_iprStates;
  //Variables:
		InitSSW 	: t_e_AxisInitSSW;
		DriveInitType 	: _MDD2000SAVTYPE;
		szObjName : ARRAY [0..199] OF CHAR;

		pMDD2000Data 	: ^_MDD2000MEMHEADER;
		bdSettings : BDINT
		[
		  1 bFirsttime,
		  2 bAxInUse,
		  5 bDriveInit,
		  6 bDriveInitialized,
		  7 bGotFeedBackType,
		  8 bFeedbackSend,
		  9 bWaitInitFinished,
		  11 bNoAbsEnc,
		  12 bSendMPara,
		  14 bParaError,
		  15 bAxSetPara,
		  16 bSyncSettings,
		  17 bInitRamAxis,
		  20 bParaInit,
		  21 bStartRead,
		  22 bReadAxFin,
		  23 bReadAx,
		  24 bSetAbsPos,
		  25 bSetAbsPosEncoder,
		  26 bFirstFeedbackTest,
		  27 bFeedbackOkay,
		  29 bReadSafeVerifyState,
		  30 bReadSafeRefState,
		];

		tUpdate 	: UDINT;
		MParaBuffer 	: _MDD2000MParaBuffer;
		usAxisIndex 	: USINT;			//! <Variable Comment="laufende Achsnummer" Name="usAxisIndex"/>
		SyncPara 	: SyncPara_type;
		ActValuePtr 	: ^MDD2000VVBase::t_ReadValuePtr;
		SetValuePtr 	: ^MDD2000VVBase::t_WriteValuePtr;
		SetValues : ARRAY [0..6] OF USINT;

		ActValues : ARRAY [0..6] OF USINT;

		sParaObjectList : ARRAY [0..MDD2000MNG_MAX_PARAIDX_CNT-1] OF t_MDD2000Mng_ParaObjectListEntry;

		OldMDD2000CmdIntfc 	: _MDD2000USERCMD;
		ParaReadCmdAx 	: DINT;
		FirstErrorReset 	: USINT;
		FirstPosition 	: BOOL;
		maskZImpulse 	: UDINT;
		oldRevolutions 	: DINT;
		ppscale 	: USINT;
		SyncParaObject 	: DINT;
		ErrorQuitTime 	: UDINT;
		Init_Again 	: BOOL;
		tUpdateZPulse 	: UDINT;
		first_feedback 	: DINT;
		bOnlineFinished 	: BOOL;
		bOnlineState 	: BOOL;
		pDiagThis 	: ^void;
		FwVersionInt 	: DINT;
		bdGetASyncEntry : BDINT
		[
		  2 I_FW,
		];

		pAsyPipeHandle 	: ^void;
		bdWait4SyncSettings : BDINT
		[
		  1 A_VALTT1,
		  2 A_VALTT2,
		  3 A_VALRT1,
		  4 A_VALRT2,
		  5 P_PSCALE,
		];

		sEncVar 	: t_s_EncoderVar;
		sSafeRefState 	: t_s_SafeRefState;
		sSafeBreakState 	: t_s_SafeBrakeState;
		sSafeFuncErrInfo 	: t_s_SafeFuncErrInfo;
		sSafeFuncVar 	: t_s_SafeFktVar;
  //Functions:
	
	FUNCTION VIRTUAL GLOBAL Init;
	
	FUNCTION VIRTUAL GLOBAL CyWork
		VAR_INPUT
			EAX 	: UDINT;
		END_VAR
		VAR_OUTPUT
			state (EAX) 	: UDINT;
		END_VAR;
				//! <Function Comment="With this methode the parameterobjects for the axis gets added" Name="AddParaObjects"/>
	FUNCTION VIRTUAL AddParaObjects
		VAR_INPUT
			Index 	: USINT;			//! <Variable Comment="Type of the parameterobject. For a detailed description take a look in the headerfile SDDDefinitions.h" Name="AddParaObjects.Index"/>
			pThis 	: ^void;			//! <Variable Comment="This-Pointer of the parameterclass." Name="AddParaObjects.pThis"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: BOOL;			//! <Variable Comment="Returncode for this methode&#13;&#10;&#13;&#10;0..failed&#13;&#10;1..successful" Name="AddParaObjects.retcode"/>
		END_VAR;
				//! <Function Comment="With this methode a new synchronous command can be added" Name="AddSyncEntry"/>
	FUNCTION VIRTUAL AddSyncEntry
		VAR_INPUT
			pThis 	: ^void;			//! <Variable Comment="This-Pointer of the object.&#13;&#10;&#13;&#10;With the NewInst-methode the actual state of the communication gets delivered to the addressed object.&#13;&#10;Also the CyWork-methode gets called by the class _DriveAxis" Name="AddSyncEntry.pThis"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: BOOL;			//! <Variable Comment="Returncode for this methode&#13;&#10;&#13;&#10;0..failed&#13;&#10;1..successful" Name="AddSyncEntry.retcode"/>
		END_VAR;
				//! <Function Comment="Returns the state of the axis (server AxisState)" Name="AxOkay"/>
	FUNCTION VIRTUAL AxOkay
		VAR_OUTPUT
			retcode 	: DINT;			//! <Variable Comment="Returns the state of the axis&#13;&#10;&#13;&#10;0..Axis is not Ok&#13;&#10;1..Axis is Ok" Name="AxOkay.retcode"/>
		END_VAR;
				//! <Function Comment="With this methode an error quit for the axis can be executed." Name="ErrorQuitHandling"/>
	FUNCTION VIRTUAL GLOBAL ErrorQuitHandling
		VAR_INPUT
			input 	: DINT;			//! <Variable Comment="With the inputvalue the Bit FAULT RESET in the ControlWord gets set.&#13;&#10;&#13;&#10;1..Set Bit FAULT RESET&#13;&#10;0, else..Reset Bit FAULT RESET" Name="ErrorQuitHandling.input"/>
		END_VAR
		VAR_OUTPUT
			result 	: DINT;			//! <Variable Comment="Returns the actual state of the Bit FAULT RESET." Name="ErrorQuitHandling.result"/>
		END_VAR;
				//! <Function Comment="With this methode a synchronous parameter can be read." Name="GetSyncEntry"/>
	FUNCTION VIRTUAL GetSyncEntry
		VAR_INPUT
			usValue 	: USINT;			//! <Variable Comment="Index of synchronous value" Name="GetSyncEntry.usValue"/>
			usPData 	: ^DINT;			//! <Variable Comment="Pointer to memory, where the data should be written to." Name="GetSyncEntry.usPData"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;			//! <Variable Comment="Returncode for the methode&#13;&#10;&#13;&#10; 0..successful&#13;&#10;-1..Drive is not ready&#13;&#10;-2..usvalue &gt; 4&#13;&#10;-3..wrong axis number&#13;&#10;-4..usvalue &gt; 1 &amp; AxisExtend = 0" Name="GetSyncEntry.retcode"/>
		END_VAR;
				//! <Function Comment="Methode is used to get the actual values" Name="GetSynchronPara"/>
	FUNCTION VIRTUAL GetSynchronPara;
				//! <Function Comment="Call this methode to get the actual state of the ZPulse (no latch!)" Name="GetZImpulse"/>
	FUNCTION VIRTUAL GetZImpulse
		VAR_OUTPUT
			retcode 	: USINT;
		END_VAR;
				//! <Function Comment="With this methode the actual state of the Drive can be read" Name="IsOnline"/>
	FUNCTION VIRTUAL GLOBAL IsOnline
		VAR_OUTPUT
			retcode 	: BOOL;			//! <Variable Comment="Actual state of the Drive&#13;&#10;&#13;&#10;0..Drive is not online / initialized&#13;&#10;1..Drive is initialized and online" Name="IsOnline.retcode"/>
		END_VAR;
	
	FUNCTION VIRTUAL MDD2000IntfProcess;
				//! <Function Comment="With this methode a synchronous parameter can be set." Name="SetSyncEntry"/>
	FUNCTION VIRTUAL SetSyncEntry
		VAR_INPUT
			usValue 	: USINT;			//! <Variable Comment="Index of synchronous value" Name="SetSyncEntry.usValue"/>
			usPData 	: DINT;			//! <Variable Comment="Value for the paramter" Name="SetSyncEntry.usPData"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;			//! <Variable Comment="Returncode for the methode&#13;&#10;&#13;&#10; 0..successful&#13;&#10;-1..Drive is not ready&#13;&#10;-2..usvalue &gt; 4&#13;&#10;-3..wrong axis number&#13;&#10;-4..usvalue &gt; 1 &amp; AxisExtend = 0" Name="SetSyncEntry.retcode"/>
		END_VAR;
				//! <Function Comment="Methode is used to set the synchronous parameter." Name="SetSynchronPara"/>
	FUNCTION VIRTUAL SetSynchronPara;
	
	FUNCTION AllocMemPara
		VAR_OUTPUT
			retcode 	: BOOL;
		END_VAR;
	
	FUNCTION InitASyncPara;
	
	FUNCTION InitMDDHeader
		VAR_INPUT
			pMDDHeader 	: ^_MDD2000MEMHEADER;
		END_VAR;
	
	FUNCTION UpdateSvr;
	
	FUNCTION GetFeedBackType;
	
	FUNCTION SendDataToDrive;
	
	FUNCTION DataOfStdTable;
	
	FUNCTION DataOfL2table;
	
	FUNCTION DataOfFile;
	
	FUNCTION DataOfRamEx;
	
	FUNCTION GetTabAdress
		VAR_INPUT
			TabType 	: DINT;
			bMotorPara 	: BOOL;
			pTabLength 	: ^DINT;
		END_VAR
		VAR_OUTPUT
			pTabAdress 	: ^DINT;
		END_VAR;
	
	FUNCTION LoadDataRam;
	
	FUNCTION DriveInitReady
		VAR_OUTPUT
			retcode 	: BOOL;
		END_VAR;
	
	FUNCTION SetParaState
		VAR_INPUT
			ActState 	: UINT;
			StateInfo 	: DINT := 0;
		END_VAR;
	
	FUNCTION SavParaValue
		VAR_INPUT
			ParaNo 	: USINT;
			Value 	: DINT;
			bSavSRAM 	: BOOL;
		END_VAR
		VAR_OUTPUT
			retcode 	: BOOL;
		END_VAR;
	
	FUNCTION ParaNrExist
		VAR_INPUT
			ParaNr 	: USINT;
		END_VAR
		VAR_OUTPUT
			udOffset 	: UDINT;
		END_VAR;
	
	FUNCTION InsNewParaNr
		VAR_INPUT
			ParaNr 	: USINT;
			ParaValue 	: DINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: BOOL;
		END_VAR;
				//! <Function Comment="Checks if an absolute encoder is not in use." Name="ChkFb"/>
	FUNCTION ChkFb
		VAR_INPUT
			FbType 	: DINT;			//! <Variable Comment="feedbacktype of the axis" Name="ChkFb.FbType"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: BOOL;			//! <Variable Comment="no absolute encoder in use" Name="ChkFb.retcode"/>
		END_VAR;
	
	FUNCTION CreateDefMPara;
	
	FUNCTION TorqueCalculation
		VAR_INPUT
			cBuffer 	: BDINT;
			input 	: UDINT;
		END_VAR
		VAR_OUTPUT
			result 	: BDINT;
		END_VAR;
	
	FUNCTION LoadDrivePara;
	
	FUNCTION SetListToParObj
		VAR_INPUT
			pData 	: ^DINT;
			udLen 	: UDINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: BOOL;
		END_VAR;
	
	FUNCTION ChkParaRead
		VAR_INPUT
			ChkType 	: DINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: BOOL;
		END_VAR;
	
	FUNCTION ParaReadProc;
	
	FUNCTION SaveDrivePara;
	
	FUNCTION CalcCRC32
		VAR_INPUT
			pData 	: ^UDINT;
			udLen 	: UDINT;
		END_VAR
		VAR_OUTPUT
			CRC32 	: UDINT;
		END_VAR;
	
	FUNCTION SetZPulseMask;
				//! <Function Comment="Refresh Important Asychron Parameters:&#13;&#10;-if there is a change in the following values, first we set the pointers to zero, and then we initialize them, allready with the new value" Name="RefreshIASP"/>
	FUNCTION RefreshIASP
		VAR_INPUT
			hParaIndex 	: HINT;
			hsParasubIndex 	: HSINT;
			Value 	: DINT;
		END_VAR;
				//! <Function Comment="Methode to evaluate ErrorBit in StateWord" Name="GetAxError"/>
	FUNCTION VIRTUAL GetAxError
		VAR_OUTPUT
			AxError 	: DINT;			//! <Variable Comment="Equal to ErrorBit in StateWord." Name="GetAxError.AxError"/>
		END_VAR;
	
	FUNCTION SetAxTorque
		VAR_INPUT
			NewTorque 	: UDINT;
		END_VAR;
	
	FUNCTION IsOnlineFinished
		VAR_OUTPUT
			bOnline 	: BOOL;
		END_VAR;
	
	FUNCTION Write_SetSpeed
		VAR_INPUT
			valueIn 	: DINT;
		END_VAR
		VAR_OUTPUT
			valueOut 	: DINT;
		END_VAR;
	
	FUNCTION Write_Enable
		VAR_INPUT
			valueIn 	: DINT;
		END_VAR
		VAR_OUTPUT
			valueOut 	: DINT;
		END_VAR;
	
	FUNCTION IsAnyAxisEnabled
		VAR_OUTPUT
			bEnabled 	: BOOL;
		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
			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 	: DINT := 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 VIRTUAL LogError
		VAR_INPUT
			pMsg 	: ^CHAR;
		END_VAR;
	
	FUNCTION VIRTUAL LogValue
		VAR_INPUT
			pString 	: ^CHAR;
			udValue 	: UDINT;
			udValue2 	: UDINT := 16#FFFFFFFF;
			udValue3 	: UDINT := 16#FFFFFFFF;
		END_VAR;
				//! <Function Comment="Methode to set diag mode to block other accesses. " Name="SetDiagMode"/>
	FUNCTION SetDiagMode
		VAR_INPUT
			bStartDiagMode 	: BOOL;			//! <Variable Comment="0 .. unlock class&#13;&#10;1 .. lock class for diag mode" Name="SetDiagMode.bStartDiagMode"/>
			pThisObj 	: ^void;			//! <Variable Comment="this pointer to diag mode class" Name="SetDiagMode.pThisObj"/>
		END_VAR
		VAR_OUTPUT
			dRetCode 	: DINT;			//! <Variable Comment="  1 .. diag mode activate or deactivate ok&#13;&#10;-1 .. axis is not online or init is not finished&#13;&#10;-2 .. diag mode is already set by other instance&#13;&#10;-3 .. deactivate of diag mode is not possible because&#13;&#10;        it was activated by other instance&#13;&#10;-4 .. pThisObj pointer is not valid" Name="SetDiagMode.dRetCode"/>
		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 Comment="Sets a request to fetch the encoder memory to the HW class. &#13;&#10;The data is fetched asynchronously from the drive over a period of time. &#13;&#10;The status of the readout process can be read out via the &quot;CheckFetchEncoderData&quot; method. &#13;&#10;After the data has been read out, it can be fetched with the method &quot;GetEncoderData&quot;.&#13;&#10;" Name="FetchEncoderData"/>
	FUNCTION VIRTUAL GLOBAL FetchEncoderData
		VAR_INPUT
			Offset 	: UDINT := 0;			//! <Variable Comment="Offset from which the memory is to be read out in bytes. (Optional, if nothing is passed, 0 is used for the offset)." Name="FetchEncoderData.Offset"/>
			Size 	: UDINT := 0;			//! <Variable Comment="Number of bytes that are read from the memory. (Optional, if nothing is passed &quot;Size of encoder memory&quot; - offset is used)." Name="FetchEncoderData.Size"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="Return status:&#13;&#10;READY ... Command was accepted&#13;&#10;ERROR ... Error. See method &quot;GetEncoderErrorCode&quot;&#13;&#10;(HW Offline, Drive Enabled, Data is already being read out)." Name="FetchEncoderData.retcode"/>
		END_VAR;
				//! <Function Comment="Returns the status of the encoder memory readout." Name="CheckFetchEncoderData"/>
	FUNCTION VIRTUAL GLOBAL CheckFetchEncoderData
		VAR_INPUT
			pProgress 	: ^UDINT := nil;			//! <Variable Comment="Optional, if a valid pointer is passed,&#13;&#10;the progress of the encoder memory upload in percentage 0-1000 [0-100.0%] is safed to this pointer." Name="CheckFetchEncoderData.pProgress"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="Return status:&#13;&#10;READY ... Data has been read out successfully. Class is ready to read out new data. &#13;&#10;BUSY ... Data is being read. &#13;&#10;ERROR ... Error. See method &quot;GetEncoderErrorCode&quot;&#13;&#10;(Timeout, error code from the drive...)" Name="CheckFetchEncoderData.retcode"/>
		END_VAR;
				//! <Function Comment="Returns the last error code that occurred while accessing the encoder." Name="GetEncoderErrorCode"/>
	FUNCTION VIRTUAL GLOBAL GetEncoderErrorCode
		VAR_OUTPUT
			ErrorCode 	: DINT;			//! <Variable Comment="last error code that occurred&#13;&#10;Check the error codes in _DriveEncoderMemory.h for a more detailed description of the error." Name="GetEncoderErrorCode.ErrorCode"/>
		END_VAR;
				//! <Function Comment="Returns the status of the encoder memory readout." Name="GetEncoderDataSize"/>
	FUNCTION VIRTUAL GLOBAL GetEncoderDataSize
		VAR_INPUT
			pSize 	: ^UDINT;			//! <Variable Comment="The size of the encoder memory is written to this pointer when the retcode = READY." Name="GetEncoderDataSize.pSize"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="Return status:&#13;&#10;READY ... Size of the encoder memory is valid. &#13;&#10;BUSY ... Size of the encoder memory has not yet been read out. Call method again later.&#13;&#10;ERROR ... Error. See method &quot;GetEncoderErrorCode&quot;" Name="GetEncoderDataSize.retcode"/>
		END_VAR;
				//! <Function Comment="Returns a pointer to the previously read encoder data. &#13;&#10;See method &quot;FetchEncoderData&quot;. &#13;&#10;Attention: The validity of the data expires if &quot;FetchEncoderData&quot; is called again!" Name="GetEncoderData"/>
	FUNCTION VIRTUAL GLOBAL GetEncoderData
		VAR_INPUT
			pSize 	: ^UDINT := NIL;			//! <Variable Comment="Returns a pointer to the previously read encoder data. &#13;&#10;See method &quot;FetchEncoderData&quot;. &#13;&#10;Attention: The validity of the data expires if &quot;FetchEncoderData&quot; is called again!" Name="GetEncoderData.pSize"/>
		END_VAR
		VAR_OUTPUT
			pData 	: pVoid;			//! <Variable Comment="Returns a pointer to the previously read encoder data. &#13;&#10;See method &quot;FetchEncoderData&quot;. &#13;&#10;Attention: The validity of the data expires if &quot;FetchEncoderData&quot; is called again!" Name="GetEncoderData.pData"/>
		END_VAR;
	
	FUNCTION VIRTUAL GetEncoderMemFile
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GetEncoderMemAsync
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GetEncoderMemSize
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL ResetIntVariables;
	
	FUNCTION VIRTUAL EncoderCylic;
	
	FUNCTION RefreshParameterObjects
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION IsCommandoParameter
		VAR_INPUT
			hIndex 	: HINT;
			hsSubIndex 	: HSINT;
		END_VAR
		VAR_OUTPUT
			bCommandoParameter 	: BOOL;
		END_VAR;
	
	FUNCTION VIRTUAL GetEncoderMemNewInst
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION GetThisPointerOfParaClassViaParam
		VAR_INPUT
			hIndex 	: HINT;
			hsSubIndex 	: HSINT;
		END_VAR
		VAR_OUTPUT
			pThisNewInst 	: ^void;
		END_VAR;
	
	FUNCTION GetThisPointerOfParaClassViaIndex
		VAR_INPUT
			udParaClassIndex 	: UDINT;
		END_VAR
		VAR_OUTPUT
			pThisNewInst 	: ^void;
		END_VAR;
				//! <Function Comment="Changes the Safe Verified State of the axis&#13;&#10;NewSetVerified:&#13;&#10;0 .. Only read VerifiedState of the axis&#13;&#10;-1 .. Reset VerifiedState of all axes and Reset ReferenceState of this axis&#13;&#10;-2 .. Reset VerifiedState off all axes&#13;&#10;1 .. Set the axis verified and read VerifiedState from Drive" Name="SetSafeVerified"/>
	FUNCTION VIRTUAL GLOBAL SetSafeVerified
		VAR_INPUT
			NewSetVerified 	: DINT;			//! <Variable Comment="0 .. Only read VerifiedState of the axis&#13;&#10;-1 .. Reset VerifiedState of all axis and Reset ReferenceState of this axis&#13;&#10;-2 .. Reset VerifiedState of all axis&#13;&#10;1 .. Set the axis verified and read VerifiedState from Drive" Name="SetSafeVerified.NewSetVerified"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="ERROR ... Axis is not online / internal async error / Value NewSetVerified is not supported" Name="SetSafeVerified.retcode"/>
		END_VAR;
				//! <Function Comment="Changes the safe position reference of the axis&#13;&#10;NewSetReference:&#13;&#10;0 .. Only read safe position reference state of the axis&#13;&#10;-1 .. Reset the safe position reference state of the axis&#13;&#10;1 .. Set the current position as the safe position reference and read the safe position reference state of the axis" Name="SetSafeReference"/>
	FUNCTION VIRTUAL GLOBAL SetSafeReference
		VAR_INPUT
			NewSetReference 	: DINT;			//! <Variable Comment="0 .. Only read safe position reference state of the axis&#13;&#10;-1 .. Reset the safe position reference state of the axis&#13;&#10;1 .. Set the current position as the safe position reference and read the safe position reference state of the axis" Name="SetSafeReference.NewSetReference"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="READY ... OK&#13;&#10;ERROR ... Axis is not online /internal async error / Value NewSetReference is not supported" Name="SetSafeReference.retcode"/>
		END_VAR;
				//! <Function Comment="Method is used to acknowledge the zero position.&#13;&#10;NewAckZeroposition:&#13;&#10;0 ... Only read out the zero positions.&#13;&#10;-1 ... abort the reference process&#13;&#10;1 ... Acknowledge the zero position" Name="SetSafeAckZeroposition"/>
	FUNCTION VIRTUAL GLOBAL SetSafeAckZeroposition
		VAR_INPUT
			NewAckZeroposition 	: DINT;			//! <Variable Comment="0 ... Only read out the zero positions.&#13;&#10;-1 ... abort the reference process&#13;&#10;1 ... Acknowledge the zero position" Name="SetSafeAckZeroposition.NewAckZeroposition"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="READY ... Ok&#13;&#10;ERROR ... Axis is not online / internal async error / Value NewAckZeroposition is not supported" Name="SetSafeAckZeroposition.retcode"/>
		END_VAR;
				//! <Function Comment="Method is used to quit axis safety errors." Name="SafetyAxErrorQuit"/>
	FUNCTION VIRTUAL GLOBAL SafetyAxErrorQuit
		VAR_INPUT
			AxErrorQuit 	: DINT;			//! <Variable Comment="1 ... Restart Ackknowledge, used for STO, SOS, SS1, SS2&#13;&#10;2 ... Error Ackknowledge, used when an error occoured during a safety function&#13;&#10;4 ... Quits an safety error on the drive, example: MDD2000_Mng.SafetyRunState = _ERROR&#13;&#10;" Name="SafetyAxErrorQuit.AxErrorQuit"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="READY ... Command to quit error was OK&#13;&#10;ERROR ... Axis is not online or internal async error " Name="SafetyAxErrorQuit.retcode"/>
		END_VAR;
				//! <Function Comment="Method is used to start the safe brake test or to refresh the teststates.&#13;&#10;NewSBTState:&#13;&#10;-1 .. Cancel the brakte test&#13;&#10;0 .. Refresh teststates from the safety brake test&#13;&#10;1 .. Start a new safety brake test" Name="SetSafeSBTState"/>
	FUNCTION VIRTUAL SetSafeSBTState
		VAR_INPUT
			NewSBTState 	: DINT;			//! <Variable Comment="-1 .. Cancel the brakte test&#13;&#10;0 .. Refresh teststates from the safety brake test&#13;&#10;1 .. Start a new safety brake test" Name="SetSafeSBTState.NewSBTState"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="READY ... Ok&#13;&#10;ERROR ... Axis is not online / internal async error / Value NewSBTState is not supported" Name="SetSafeSBTState.retcode"/>
		END_VAR;
	
	FUNCTION VIRTUAL SafetyChanged
		VAR_INPUT
			StateInfo 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL SetSafeCtrlWordBitmask
		VAR_INPUT
			SafeFktId 	: HDINT;
			BitIdx 	: DINT;
			bStateCfg 	: BOOL;
		END_VAR;
	
	FUNCTION VIRTUAL SetSafeFktUpdateList;
	
	FUNCTION VIRTUAL UpdateActiveSafeFunctions
		VAR_INPUT
			sControlWord 	: BDINT;
			sStateWord 	: BDINT;
		END_VAR
		VAR_OUTPUT
			ActiveSafeFunctions 	: gb_MDD2000ActiveSafeFkt;
		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 Online::Read
		VAR_OUTPUT
			output (EAX) 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL ActPos::Read
		VAR_OUTPUT
			output (EAX) 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL SetPos::Write
		VAR_INPUT
			input (EAX) 	: DINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL ActSpeed::Read
		VAR_OUTPUT
			output (EAX) 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL SetSpeed::Write
		VAR_INPUT
			input (EAX) 	: DINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL ActCurrent::Read
		VAR_OUTPUT
			output (EAX) 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL SetCurrent::Write
		VAR_INPUT
			input (EAX) 	: DINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL ActXw::Read
		VAR_OUTPUT
			output (EAX) 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL StateWord::Read
		VAR_OUTPUT
			output (EAX) 	: DS402_State;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL ControlWord::Write
		VAR_INPUT
			input (EAX) 	: DS402_Control;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: DS402_Control;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL AxEnable::Write
		VAR_INPUT
			input (EAX) 	: DINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL AxError::Read
		VAR_OUTPUT
			output (EAX) 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL AxErrorQuit::Write
		VAR_INPUT
			input (EAX) 	: DINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL ZPulsLatch::Read
		VAR_OUTPUT
			output (EAX) 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL AxTorqueControl::Write
		VAR_INPUT
			input (EAX) 	: UDINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL MDD2000CmdIntfc::Write
		VAR_INPUT
			input (EAX) 	: MDD2000_AxisBase::_MDD2000USERCMD;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: MDD2000_AxisBase::_MDD2000USERCMD;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL SetVerified::Write
		VAR_INPUT
			input (EAX) 	: DINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: DINT;
		END_VAR;
  //Tables:
	FUNCTION @STD
		VAR_OUTPUT
			ret_code	: CONFSTATES;
		END_VAR;
	FUNCTION GLOBAL TAB @CT_;
END_CLASS;

#pragma usingLtd _Linker
#pragma usingLtd _StdLib
#pragma usingLtd MDD2000AxisSet
#pragma usingLtd MDD2000MngBase


//}}LSL_DECLARATION


FUNCTION GLOBAL TAB MDD2000_AxisBase::@CT_
0$UINT,
2#0100000000000000$UINT, //TY_MDD2000_AXISBASE
1$UINT, 1$UINT, (SIZEOF(::MDD2000_AxisBase))$UINT, 
21$UINT, 7$UINT, 0$UINT, 
TO_UDINT(955250484), "MDD2000_AxisBase", //Class
TO_UDINT(0), 0, 0$UINT, 0$UINT, //Baseclass
//Servers:
(::MDD2000_AxisBase.CmdState.pMeth)$UINT, _CH_CMD$UINT, 2#0000000000000000$UINT, TO_UDINT(3787497970), "CmdState", 
(::MDD2000_AxisBase.Online.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1858763116), "Online", 
(::MDD2000_AxisBase.AxisState.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1615808060), "AxisState", 
(::MDD2000_AxisBase.ActPos.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(3351625522), "ActPos", 
(::MDD2000_AxisBase.SetPos.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(110881026), "SetPos", 
(::MDD2000_AxisBase.ActSpeed.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1555690308), "ActSpeed", 
(::MDD2000_AxisBase.SetSpeed.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(33026088), "SetSpeed", 
(::MDD2000_AxisBase.ActCurrent.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(3663451001), "ActCurrent", 
(::MDD2000_AxisBase.SetCurrent.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2317024038), "SetCurrent", 
(::MDD2000_AxisBase.ActXw.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(3335054416), "ActXw", 
(::MDD2000_AxisBase.StateWord.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1307193485), "StateWord", 
(::MDD2000_AxisBase.ControlWord.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2412184912), "ControlWord", 
(::MDD2000_AxisBase.AxEnable.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(582292701), "AxEnable", 
(::MDD2000_AxisBase.AxError.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(4083589877), "AxError", 
(::MDD2000_AxisBase.AxErrorQuit.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(157825597), "AxErrorQuit", 
(::MDD2000_AxisBase.ZPulsLatch.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1574207087), "ZPulsLatch", 
(::MDD2000_AxisBase.AxTorqueControl.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1527467955), "AxTorqueControl", 
(::MDD2000_AxisBase.MDD2000CmdIntfc.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1221712402), "MDD2000CmdIntfc", 
(::MDD2000_AxisBase.SetVerified.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1906469483), "SetVerified", 
(::MDD2000_AxisBase.SetVerifiedRsp.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2311854582), "SetVerifiedRsp", 
(::MDD2000_AxisBase.VerifiedState.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(3353571576), "VerifiedState", 
//Clients:
(::MDD2000_AxisBase.DriveMng.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000010$UINT, TO_UDINT(2977008139), "DriveMng", TO_UDINT(4153957792), "MDD2000MngBase", 1$UINT, 2$UINT, 
(::MDD2000_AxisBase.AxisNo.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000010$UINT, TO_UDINT(2111456692), "AxisNo", 
(::MDD2000_AxisBase.DriveAxisSet.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000010$UINT, TO_UDINT(1810900605), "DriveAxisSet", TO_UDINT(3685268210), "MDD2000AxisSet", 1$UINT, 0$UINT, 
(::MDD2000_AxisBase.coStdLib.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000000$UINT, TO_UDINT(3815072667), "coStdLib", TO_UDINT(3689364044), "_StdLib", 2$UINT, 0$UINT, 
(::MDD2000_AxisBase.coLinker.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000000$UINT, TO_UDINT(1382361455), "coLinker", TO_UDINT(1793552568), "_Linker", 0$UINT, 5$UINT, 
(::MDD2000_AxisBase.EncoderBufferSize.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000010$UINT, TO_UDINT(3229760660), "EncoderBufferSize", 
(::MDD2000_AxisBase.MDD2000GeneralPara.pCh)$UINT, _CH_CLT_CMD$UINT, 2#0000000000000010$UINT, TO_UDINT(135848273), "MDD2000GeneralPara", 
END_FUNCTION


#define USER_CNT_MDD2000_AxisBase 35

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#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;
	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;
	ActPos.pMeth			:= StoreMethod( #ActPos::Read(), #M_NO_F() );
	IF ActPos.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	SetPos.pMeth			:= StoreMethod( #M_RD_DIRECT(), #SetPos::Write() );
	IF SetPos.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	ActSpeed.pMeth			:= StoreMethod( #ActSpeed::Read(), #M_NO_F() );
	IF ActSpeed.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	SetSpeed.pMeth			:= StoreMethod( #M_RD_DIRECT(), #SetSpeed::Write() );
	IF SetSpeed.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	ActCurrent.pMeth			:= StoreMethod( #ActCurrent::Read(), #M_NO_F() );
	IF ActCurrent.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	SetCurrent.pMeth			:= StoreMethod( #M_RD_DIRECT(), #SetCurrent::Write() );
	IF SetCurrent.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	ActXw.pMeth			:= StoreMethod( #ActXw::Read(), #M_NO_F() );
	IF ActXw.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	StateWord.pMeth			:= StoreMethod( #StateWord::Read(), #M_NO_F() );
	IF StateWord.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	ControlWord.pMeth			:= StoreMethod( #M_RD_DIRECT(), #ControlWord::Write() );
	IF ControlWord.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	AxEnable.pMeth			:= StoreMethod( #M_RD_DIRECT(), #AxEnable::Write() );
	IF AxEnable.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	AxError.pMeth			:= StoreMethod( #AxError::Read(), #M_NO_F() );
	IF AxError.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	AxErrorQuit.pMeth			:= StoreMethod( #M_RD_DIRECT(), #AxErrorQuit::Write() );
	IF AxErrorQuit.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	ZPulsLatch.pMeth			:= StoreMethod( #ZPulsLatch::Read(), #M_NO_F() );
	IF ZPulsLatch.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	AxTorqueControl.pMeth			:= StoreMethod( #M_RD_DIRECT(), #AxTorqueControl::Write() );
	IF AxTorqueControl.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	MDD2000CmdIntfc.pMeth			:= StoreMethod( #M_RD_DIRECT(), #MDD2000CmdIntfc::Write() );
	IF MDD2000CmdIntfc.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	SetVerified.pMeth			:= StoreMethod( #M_RD_DIRECT(), #SetVerified::Write() );
	IF SetVerified.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;

END_FUNCTION

#pragma usingLtd SigCLib

//{{LSL_IMPLEMENTATION
FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::Init
  VAR
    retcode         : BOOL;
    tmpPara         : CmdStruct;
    tmpResult       : results;
  END_VAR
    
  if bdSettings.bFirsttime = FALSE then
  
    bdSettings.bFirsttime       := TRUE;
    bdSettings.bDriveInit       := TRUE;
    bdSettings.bFeedbackSend    := FALSE;
    bdSettings.bGotFeedBackType := FALSE;
    
    // read the clients
    AxisNo := AxisNo.read();
    
    // check for valid axis no
    if (AxisNo < 1) | (AxisNo > 3) then
      // disable object
      AxisNo := -1;
      CmdState := QUIT;
      AxisState.NotInitialized := true;
      return;
    end_if;

    //Initialize pipe for asynchronous parameter handling    
    pAsyPipeHandle := cPipe_CTor(record_size:=sizeof(t_MDD2000Mng_AsyncPara_Entry), record_no:=MDD2000MNG_ASY_BUFFERENTRY);
    
    if pAsyPipeHandle = NIL then
      HWC_LogPrintf(pThis:=this, format:="@08C5 (MDD2000_AxisBase::Init) Failed to create pipe for asynchronous parameter handling.");
      return;
    end_if;
    
    // add the object into the list of the sddmanager   
    tmpPara.uiCmd := MDD2000MNG_IF_LOGINAXISOBJECT;
    tmpPara.aPara[0]$DINT := MDD2000MNG_IF_LOGINAXISOBJECT_VER_1;
    tmpPara.aPara[1]$DINT := this$DINT;
    tmpPara.aPara[2]$DINT := AxisNo;
    tmpPara.aPara[3]$DINT := pAsyPipeHandle$DINT;
    
    if DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult) <> READY then
      HWC_LogPrintf(pThis:=this, format:="@08C6 (MDD2000_AxisBase::Init) Failed to login axis object at drive manager.");    
    end_if;
    
    _GetObjName(this, #szObjName[0]); // get the object name
    
    InitSSW := _MDD2000_STARTINIT;
    
    usAxisIndex := 16#FF; // initialize the AxisIndex
    
  end_if;
  

  if _firstscan & (AxisNo <> -1) then
    //********************************************\\
    //** check the type of saving the parameter **\\
    //********************************************\\
    DriveInitType$DINT := DriveAxisSet.GetInitType();
    
    if DriveInitType = _MDD2000_FILE then
      retcode := DriveAxisSet.ChkFileHandle();
      if retcode = FALSE then
        DriveInitType := _MDD2000_L2TABLE;
        LogValue("@04C1 (MDD2000_AxisBase::Init) No file handling for object '{0}' available! Saving type is changed!", szObjName[0]);
      end_if;
    end_if;

    if (DriveInitType = _MDD2000_RAMEX) | (DriveInitType = _MDD2000_FILE) then
      retcode := AllocMemPara();
      if retcode = FALSE then
        DriveInitType := _MDD2000_L2TABLE;
        LogValue("@04C2 (MDD2000_AxisBase::Init) No memory for object '{0}' available! Saving type is changed!", szObjName[0]);
      end_if;
    end_if;
    
    AxTorqueControl := 4500;  // set the torque control
    
    // 25.08.2023 Definition RauAnd and KoeAnd:
    // An automatic quit of a safety Error during startup of the SPS though the HW-Class is ok
    // (Drive has not been in Operation)
    FirstErrorReset := 1;     //0...no error to handle , 1...quit the first error
    FirstPosition   := FALSE;
    ppscale         := 16;    // initialize p-pscale
    CmdState        := ERROR;
    Init_Again      := FALSE;
    
    SetZPulseMask();          // initialize the ZImpulse-Mask
    AxisState.NotInitialized := true;
    

    // Initialisze Vars for reading encoder memory
    EncoderBufferSize := EncoderBufferSize.Read();
    
    sEncVar.State := -2;
    sEncVar.LastErrorCode := DRIVEENCMEM_RETERR_CREATEBUFFER_FAILED;
    
    // Don't log error if user does not want to use encoder memory accesses.
    if EncoderBufferSize > 0 then
    
      sEncVar.pBuffer := coStdLib.Malloc(size:=EncoderBufferSize$UDINT);
      
      if sEncVar.pBuffer then
        _strcpy(dest:=#sEncVar.strFileNameDrv[0], src:=MDD2000_AXISBASE_DRIVEENCMEM_FILENAME);
        sEncVar.State := 0;
      else
        HWC_LogPrintf(this,"@089E (MDD2000_AxisBase::Init) Failed to allocate memory for encoder data!");
      end_if;
      
    end_if;
        
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::CmdState::NewInst
	VAR_INPUT
		pPara 	: ^CmdStruct;
		pResult 	: ^results;
	END_VAR
	VAR_OUTPUT
		ret_code 	: iprStates;
	END_VAR
  VAR
    pPDORead      : ^_MDD2000PDOREAD;
    pPDOWrite     : ^_MDD2000PDOWRITE;
    hIndex        : HINT;
    hsSubIndex    : HSINT;
    bRW           : BOOL;
    dValue        : DINT;    
    dTmpParaNo    : DINT;
    dCallID       : DINT;
    dErrorCode    : DINT;
    MyPara 	      : CmdStruct;
		MyResult 	    : results;
  END_VAR
  
  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;
      dValue      := pPara^.aPara[6]$^DINT^;
      dCallID     := pPara^.aPara[7]$DINT;
      
      if dCallID = MDD2000_AXISBASE_DRIVEENCMEM_ASYCALLID then
        ret_code := GetEncoderMemNewInst(pPara:=pPara, pResult:=pResult);
        return;
      end_if;

      //Check index
      case hIndex of
        //*****************************************************************************
        MDD2000_PID_SIGMATEKPARA_INDEX_SET:
        
          case hsSubIndex of
          
            //*****************************************************************************
            MDD2000_SPID_M_TYPE :
              // was the command a read or a write command
              if (bRW = 0) then
              
                bdSettings.bGotFeedBackType := FALSE;
                
                if bdSettings.bFirstFeedbackTest = FALSE then
                  first_feedback := dValue;
                  bdSettings.bFirstFeedbackTest := TRUE;
                  bdSettings.bFeedBackSend := FALSE; //catch an M-TYPE once more
                elsif first_feedback = dValue then //two times the same value for the M-TYPE?
                  bdSettings.bFeedbackOkay := TRUE;
                else //there was a difference => we need a value once more
                  bdSettings.bFeedbackOkay := FALSE;
                  first_feedback := dValue;
                  bdSettings.bFeedBackSend := FALSE;
                end_if;

                if bdSettings.bFeedbackOkay = TRUE then
                  if ChkFb(dValue) = TRUE then
                    bdSettings.bNoAbsEnc := TRUE; // kein Absolutwertgeber in Verwendung
                  else
                    bdSettings.bNoAbsEnc := FALSE;
                  end_if;
                  bdSettings.bGotFeedBackType := TRUE;
                end_if;      
              end_if;
          
            //*****************************************************************************
            MDD2000_SPID_A_VALRT1 :
              
              if (bRW = 0) then
                // read command
                // save the value in the array SetValues is done in RefreshIASP
                RefreshIASP(hIndex,hsSubIndex,dValue); //that is just to init the servers of a connected SyncExtend class
                bdWait4SyncSettings.A_VALRT1 := FALSE;
                
              end_if;
              
            //*****************************************************************************
            MDD2000_SPID_A_VALRT2 :
              
              if (bRW = 0) then
                // read command
                
                // save the value in the array SetValues is done in RefreshIASP
                RefreshIASP(hIndex,hsSubIndex,dValue); //that is just to init the servers of a connected SyncExtend class
                bdWait4SyncSettings.A_VALRT2 := FALSE;
              end_if;
            
            //*****************************************************************************
            MDD2000_SPID_A_VALTT1 :
              
              if (bRW = 0) then
                // read command
                // save the value in the array ActValues  is done in RefreshIASP
                RefreshIASP(hIndex,hsSubIndex,dValue); //that is just to init the servers of a connected SyncExtend class
                bdWait4SyncSettings.A_VALTT1 := FALSE;
              end_if;
            
            //*****************************************************************************
            MDD2000_SPID_A_VALTT2 :
              
              if (bRW = 0) then
                // read command

                // save the value in the array ActValues  is done in RefreshIASP
                RefreshIASP(hIndex,hsSubIndex,dValue); //that is just to init the servers of a connected SyncExtend class
                bdWait4SyncSettings.A_VALTT2 := FALSE;
              end_if;
              
            //*****************************************************************************
            MDD2000_SPID_P_PSCALE:
            
              if (bRW = 0) then
                ppscale:=to_usint(dValue);
                bdWait4SyncSettings.P_PSCALE := FALSE;
                SetZPulseMask();
              end_if;
            
          end_case;
        
        //*****************************************************************************
        MDD2000_PID_SIGMATEKPARA_INDEX_INFO:
        
          // check the subindex number
          case hsSubIndex of
        
            //*****************************************************************************
            MDD2000_SPID_K_FBRW :
              if (bRW = 1) then     // command was a write command
              
                if dValue = 3 then     // command was to marry the motor with the drive
                  bdSettings.bSetAbsPos := FALSE;
                elsif dValue = 2 then   //command was to calculate the offsetposition and save it to the feedbacksystem
                  bdSettings.bSetAbsPosEncoder := FALSE;
                end_if;
                
              end_if;
              
            //*****************************************************************************
            MDD2000_SPID_I_FW:
            
              if (bRW = 0) then // command was a read command
                FwVersionInt := dValue;
                bdGetASyncEntry.I_FW  := FALSE;
              end_if;
          
            //*****************************************************************************
            MDD2000_SPID_K_SBT:
              sSafeBreakState.bdWait4Para.SetBrakeTest := FALSE;
          
          end_case;
        
        //*****************************************************************************
        MDD2000_PID_SAFETY_AXIS_INFO:
          
          // check the subindex number
          case hsSubIndex of
          
            MDD2000_SPID_SAFETY_AXIS_VERIFY_FEEDBACK: 
              if (bRW = 0) then // command was a read command
                SetVerifiedRsp := dValue$t_e_SetVerifiedRsp;
                
                if SetVerifiedRsp = t_e_SetVerifiedRsp::CmdExecuting then 
                  // Read again as safety has not yet completet executing the command
                  bdSettings.bReadSafeVerifyState := TRUE;
                end_if;

              end_if;
            
            MDD2000_SPID_SAFETY_AXIS_FEEDBACK_STATE:
              
              VerifiedState := dValue$t_e_SafeVerifiedState;
              if (dValue = DRIVESAFETYIF_VERSTATE_NOT_USED)        |
                 (dValue = DRIVESAFETYIF_VERSTATE_AXIS_VERIFIED)   |
                 (dValue = DRIVESAFETYIF_VERSTATE_SYSTEM_VERIFIED) then
                AxisState.SafeAxisNotVerified := FALSE;
                
                // InformMng that axis is Verified
                MyPara.uiCmd := MDD2000MNG_IF_AXISINITFINISHED;
                MyPara.aPara[0] := MDD2000MNG_IF_AXISINITFINISHED_VER_1;
                MyPara.aPara[1] := TO_DINT(usAxisIndex);
                MyPara.aPara[2] := MDD2000MNG_IF_AXISINITFINISHED_SAFEVERIFIY;
                
                DriveMng.NewInst(pPara:=#MyPara, pResult:=#MyResult);
                
              else
                AxisState.SafeAxisNotVerified := TRUE;
                if dValue = DRIVESAFETYIF_VERSTATE_VERIFICATION_PENDING then
                  // Read Parameter again
                  bdSettings.bReadSafeVerifyState := TRUE;
                end_if;

              end_if;
              
            MDD2000_SPID_SAFETY_AXIS_SETZEROPOS:
              if (bRW = 0) then // command was a read command
                sSafeRefState.CmdState := dValue$HDINT;
              end_if;        
            
            MDD2000_SPID_SAFETY_AXIS_POSSREFTATE:
            
              sSafeRefState.RefState := dValue$HDINT;
              
              if (sSafeRefState.RefState = DRIVESAFETYIF_STATE_NOT_NEEDED)      |
                 (sSafeRefState.RefState = DRIVESAFETYIF_STATE_REFERENCE_DONE)  |
                 (sSafeRefState.RefState = DRIVESAFETYIF_STATE_AXIS_REFERENCED) then
                
                AxisState.SafeAxisZeroPosNotSet := FALSE;
                
                // InformMng that axis zero pos is set
                MyPara.uiCmd := MDD2000MNG_IF_AXISINITFINISHED;
                MyPara.aPara[0] := MDD2000MNG_IF_AXISINITFINISHED_VER_1;
                MyPara.aPara[1] := TO_DINT(usAxisIndex);
                MyPara.aPara[2] := MDD2000MNG_IF_AXISINITFINISHED_SAFEZEROPOS;
                
                DriveMng.NewInst(pPara:=#MyPara, pResult:=#MyResult);
                
              else
                AxisState.SafeAxisZeroPosNotSet := TRUE;
              end_if;
              
          end_case;
          
        //*****************************************************************************
        MDD2000_PID_SAFETY_AXIS_FUNC_INFO: 
          
          // check the subindex number
          case hsSubIndex of
          
            MDD2000_SPID_SAFETY_AXIS_ERROR_WORD:
              sSafeFuncErrInfo.bdAsyFlags.w4SafeErrorWord           := FALSE;
              sSafeFuncErrInfo.SafeErrorWord := dValue;
            MDD2000_SPID_SAFETY_AXIS_ERR_ID:
              sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionErrorID     := FALSE;
              sSafeFuncErrInfo.SafeFunctionErrorID := dValue;
            MDD2000_SPID_SAFETY_AXIS_ERR_SOURCE:
              sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionInErrID     := FALSE;
              sSafeFuncErrInfo.SafeFunctionInErrID    := (dValue AND 16#FFFF);
              sSafeFuncErrInfo.SafeFunctionInErrSubID := ((dValue SHR 16) AND 16#FFFF);
            MDD2000_SPID_SAFETY_AXIS_ERR_REACT:
              sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionErrReact    := FALSE;
              sSafeFuncErrInfo.SafeFunctionErrReactID     := (dValue AND 16#FFFF);
              sSafeFuncErrInfo.SafeFunctionErrReactSubID  := ((dValue SHR 16) AND 16#FFFF);
            MDD2000_SPID_SAFETY_AXIS_ERR_INFO1:
              sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionErrorInfo1  := FALSE;
              sSafeFuncErrInfo.SafeFunctionErrorInfo1 := dValue;
            MDD2000_SPID_SAFETY_AXIS_ERR_INFO2:
              sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionErrorInfo2  := FALSE;
              sSafeFuncErrInfo.SafeFunctionErrorInfo2 := dValue;
            MDD2000_SPID_SAFETY_AXIS_ERR_INFO3:
              sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionErrorInfo3  := FALSE;
              sSafeFuncErrInfo.SafeFunctionErrorInfo3 := dValue;
          
          end_case;
        
        //*****************************************************************************
        MDD2000_PID_SAFETY_BRAKE_TEST:
          
          // check the subindex number
          case hsSubIndex of
            
            MDD2000_SPID_SAFETY_BRAKE_TEST_CNTDOWN:
              
              sSafeBreakState.TimeTilNextTest := dValue;
              sSafeBreakState.bdWait4Para.TimeTilNextTest     := FALSE;
              
            MDD2000_SPID_SAFETY_BRAKE_TEST_STATE:
            
              sSafeBreakState.SafeBrakeTestStatus := dValue;
              sSafeBreakState.bdWait4Para.SafeBrakeTestStatus   := FALSE;
              
            MDD2000_SPID_FUNCT_BRAKE_TEST_STATE:
              
              sSafeBreakState.BrakeTestStatus := dValue;
              sSafeBreakState.bdWait4Para.BrakeTestStatus     := FALSE;
              
              if sSafeBreakState.BrakeTestStatus >= 90 then 
                
                // Error Occoured in the test, read the additional error info                
                if AddASyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_BRAKE_TEST, usParaSubID:=MDD2000_SPID_FUNCT_BRAKE_ERROR_INFO, usRdWr:=0, pValue:=nil, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) = 0 then
                  sSafeBreakState.bdWait4Para.BrakeTestErrorInfo    := TRUE;
                else
                  sSafeBreakState.bdWait4Para.ErrBrakeTestErrorInfo := TRUE;
                end_if;
              
              else
                sSafeBreakState.BrakeTestErrorInfo := 0;  // No Error, Reset Error Info
              end_if;
              
            MDD2000_SPID_FUNCT_BRAKE_ERROR_INFO:
            
              sSafeBreakState.BrakeTestErrorInfo := dValue;
              sSafeBreakState.bdWait4Para.BrakeTestErrorInfo    := FALSE;
              
          end_case;
          
        //*****************************************************************************
        MDD2000_PID_SFKTCFG_CTRLWORD_FKTMAPPING:
          SetSafeCtrlWordBitmask(SafeFktId:=dValue$HDINT, BitIdx:=hsSubIndex, bStateCfg:=FALSE);
        
        //*****************************************************************************
        MDD2000_PID_SFKTCFG_STATEWORD_FKTMAPPING:
          SetSafeCtrlWordBitmask(SafeFktId:=dValue$HDINT, BitIdx:=hsSubIndex, bStateCfg:=TRUE);
          if hsSubIndex = MDD2000_SPIDMAX_SFKTCFG_CTRLSTATEWORD_FKTMAPPING then  // Last mapping info recieved
            SetSafeFktUpdateList();
          end_if;
          
        //*****************************************************************************
        DS402_ASYNCPARA_DEFAULT_LASALPARA_INDEX:
          
          dValue := hsSubIndex;
          HWC_LogPrintf(pThis:=this, format:="@08C7 (MDD2000_AxisBase::CmdState::NewInst) Detected old parameter index 16#FFFF. Subindex %d", #dValue);      
      
      end_case;
    
    else
      HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::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;
      dValue      := pPara^.aPara[6]$^DINT^;
      
      dCallID     := pPara^.aPara[7]$DINT;
      dErrorCode  := pPara^.aPara[8]$DINT;
      
      if dCallID = MDD2000_AXISBASE_DRIVEENCMEM_ASYCALLID then
        ret_code := GetEncoderMemNewInst(pPara:=pPara, pResult:=pResult);
        return;
      end_if;
      
      //Check index
      case hIndex of
        //*****************************************************************************
        MDD2000_PID_SIGMATEKPARA_INDEX_SET:
        
          case hsSubIndex of
          
            //*****************************************************************************
            MDD2000_SPID_M_TYPE :
              if (bRW = 0) then
                bdSettings.bGotFeedBackType := TRUE;
              end_if;
                        
            //*****************************************************************************
            MDD2000_SPID_A_VALRT1 :
              
              // Reset the value in the array SetValues
              SetValues[0] := 0;
              SetValues[1] := 0;
              bdWait4SyncSettings.A_VALRT1 := FALSE;
              
            //*****************************************************************************
            MDD2000_SPID_A_VALRT2 :
              
              // Reset the value in the array SetValues
              SetValues[2] := 0;
              SetValues[3] := 0;
              SetValues[4] := 0;
              SetValues[5] := 0;
              SetValues[6] := 0;
              bdWait4SyncSettings.A_VALRT2 := FALSE;
            
            //*****************************************************************************
            MDD2000_SPID_A_VALTT1 :
              
              // Reset the value in the array ActValues
              ActValues[0] := 0;
              ActValues[1] := 0;
              bdWait4SyncSettings.A_VALTT1 := FALSE;
            
            //*****************************************************************************
            MDD2000_SPID_A_VALTT2 :
              
              // Reset the value in the array ActValues
              ActValues[2] := 0;
              ActValues[3] := 0;
              ActValues[4] := 0;
              ActValues[5] := 0;
              ActValues[6] := 0;
              bdWait4SyncSettings.A_VALTT2 := FALSE;

            //*****************************************************************************
            MDD2000_SPID_P_PSCALE:
            
              bdWait4SyncSettings.P_PSCALE := FALSE;
          
          end_case;
        
        //*****************************************************************************
        MDD2000_PID_SIGMATEKPARA_INDEX_INFO:
        
          // check the subindex number
          case hsSubIndex of
        
            //*****************************************************************************
            MDD2000_SPID_K_FBRW :
            
              if (bRW = 1) then  // was a write command
                if dValue = 3 then  // command was to marry the motor with the drive
                  bdSettings.bSetAbsPos := FALSE;
                elsif dValue = 2 then   //command was to calculate the offsetposition and save it to the feedbacksystem
                  bdSettings.bSetAbsPosEncoder := FALSE;
                end_if;
              elsif (bRW = 3) & (dValue = 5) then
                //axis enabled => cannot change value
                bdSettings.bSetAbsPosEncoder := FALSE;
              end_if;
              
            //*****************************************************************************
            MDD2000_SPID_I_FW:
            
              bdGetASyncEntry.I_FW := FALSE;
            
            //*****************************************************************************
            MDD2000_SPID_K_SBT:
              sSafeBreakState.bdWait4Para.SetBrakeTest    := FALSE;
              sSafeBreakState.bdWait4Para.ErrSetBrakeTest := TRUE;
              
          end_case;
          
        //*****************************************************************************
        MDD2000_PID_SAFETY_AXIS_INFO:
          
          // check the subindex number
          case hsSubIndex of
          
            MDD2000_SPID_SAFETY_AXIS_VERIFY_FEEDBACK:
            
              // Feedback the Set Verified failed
              SetVerifiedRsp$HDINT := DRIVESAFETYIF_COMM_ERROR;
              
            MDD2000_SPID_SAFETY_AXIS_FEEDBACK_STATE:
            
              // Reading Feedback State Failed
              VerifiedState$HDINT := DRIVESAFETYIF_COMM_ERROR;
              
            MDD2000_SPID_SAFETY_AXIS_SETZEROPOS:
              
              // Setting the Refstate command failed
              sSafeRefState.CmdState := DRIVESAFETYIF_COMM_ERROR;
              
            MDD2000_SPID_SAFETY_AXIS_POSSREFTATE:
              
              // Reading reference State Failed
              sSafeRefState.RefState := DRIVESAFETYIF_COMM_ERROR;
          
          end_case;
          
        //*****************************************************************************
        MDD2000_PID_SAFETY_AXIS_FUNC_INFO: 
          
          // check the subindex number
          case hsSubIndex of
          
            MDD2000_SPID_SAFETY_AXIS_ERROR_WORD:
              sSafeFuncErrInfo.bdAsyFlags.w4SafeErrorWord           := FALSE;
              sSafeFuncErrInfo.bdAsyFlags.errSafeErrorWord          := TRUE;
            MDD2000_SPID_SAFETY_AXIS_ERR_ID:
              sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionErrorID     := FALSE;
              sSafeFuncErrInfo.bdAsyFlags.errSafeFunctionErrorID    := TRUE;
            MDD2000_SPID_SAFETY_AXIS_ERR_SOURCE:
              sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionInErrID     := FALSE;
              sSafeFuncErrInfo.bdAsyFlags.errSafeFunctionInErrID    := TRUE;
            MDD2000_SPID_SAFETY_AXIS_ERR_REACT:
              sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionErrReact    := FALSE;
              sSafeFuncErrInfo.bdAsyFlags.errSafeFunctionErrReact   := TRUE;
            MDD2000_SPID_SAFETY_AXIS_ERR_INFO1:
              sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionErrorInfo1  := FALSE;
              sSafeFuncErrInfo.bdAsyFlags.errSafeFunctionErrorInfo1 := TRUE;
            MDD2000_SPID_SAFETY_AXIS_ERR_INFO2:
              sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionErrorInfo2  := FALSE;
              sSafeFuncErrInfo.bdAsyFlags.errSafeFunctionErrorInfo2 := TRUE;
            MDD2000_SPID_SAFETY_AXIS_ERR_INFO3:
              sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionErrorInfo3  := FALSE;
              sSafeFuncErrInfo.bdAsyFlags.errSafeFunctionErrorInfo3 := TRUE;
          
          end_case;
        
        //*****************************************************************************
        MDD2000_PID_SAFETY_BRAKE_TEST:
          
          // check the subindex number
          case hsSubIndex of
            
            MDD2000_SPID_SAFETY_BRAKE_TEST_CNTDOWN:
              
              sSafeBreakState.bdWait4Para.ErrTimeTilNextTest      := TRUE;
              sSafeBreakState.bdWait4Para.TimeTilNextTest         := FALSE;
              
            MDD2000_SPID_SAFETY_BRAKE_TEST_STATE:
            
              sSafeBreakState.bdWait4Para.ErrSafeBrakeTestStatus  := TRUE;
              sSafeBreakState.bdWait4Para.SafeBrakeTestStatus     := FALSE;
              
            MDD2000_SPID_FUNCT_BRAKE_TEST_STATE:
              
              sSafeBreakState.bdWait4Para.ErrBrakeTestStatus      := TRUE;
              sSafeBreakState.bdWait4Para.BrakeTestStatus         := FALSE;
              
            MDD2000_SPID_FUNCT_BRAKE_ERROR_INFO:
              
              sSafeBreakState.bdWait4Para.ErrBrakeTestErrorInfo   := TRUE;
              sSafeBreakState.bdWait4Para.BrakeTestErrorInfo      := FALSE;
              
              
          end_case;
          
        //*****************************************************************************
        DS402_ASYNCPARA_DEFAULT_LASALPARA_INDEX:
        
          dValue := hsSubIndex;
          HWC_LogPrintf(pThis:=this, format:="@08C7 (MDD2000_AxisBase::CmdState::NewInst) Detected old parameter index 16#FFFF. Subindex %d", #dValue);      
      
      end_case;      

    else
      HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_ASYNC_ERROR detected", #pPara^.aPara[0]);      
    end_if;
    
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  MDD2000MNG_IF_SET_AXIS_STATE :
  //*************************************************************************
  //** set the state of the axis                                           **
  //*************************************************************************

    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_SET_STATE_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_SET_STATE_VER_1 then
                                          
      ret_code := READY;                        
      
      //Check for error
      if pPara^.aPara[2] = 1 then
      
        //OK
         CmdState := READY;
         usAxisIndex := to_usint(pPara^.aPara[1]);
         bdSettings.bAxInUse := TRUE;
         AxisState.NotInitialized := false;
        
      else
      
        CmdState := ERROR;
        Online := 0; //HasHan
        bOnlineFinished := FALSE;
        bOnlineState    := FALSE;
        //reset diagnose mode if online state is set to zero
        if pDiagThis <> NIL then
          SetDiagMode(bStartDiagMode:=FALSE, pThisObj:=pDiagThis);
        end_if;

        AxisState.NoHW := 1;
        AxisState.NotInitialized := false;
        
        SetParaState(MDD2000MNG_IF_UPDATEPARACLASS_STATE_GENERAL_ERROR);
      
      end_if;               
    else
      HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_SET_AXIS_STATE detected", #pPara^.aPara[0]);      
    end_if;
      
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  MDD2000MNG_IF_SET_STATE:
  
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_SET_STATE_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_SET_STATE_VER_1 then
                                          
      ret_code := READY;                        
      
      //Check for error
      if pPara^.aPara[1] = 0 then
        SetParaState(MDD2000MNG_IF_UPDATEPARACLASS_STATE_GENERAL_READY);
      else
        SetParaState(MDD2000MNG_IF_UPDATEPARACLASS_STATE_GENERAL_ERROR);
      end_if;               
    else
      HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_SET_STATE detected", #pPara^.aPara[0]);      
    end_if;

  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
  MDD2000MNG_IF_SAVE_PARAMETER :
    
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_SAVE_PARAMETER_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_SAVE_PARAMETER_VER_1 then
      
      hIndex      := pPara^.aPara[1]$HINT;
      hsSubIndex  := pPara^.aPara[2]$HSINT;
      bRW         := pPara^.aPara[3]$BOOL;      
      dValue      := pPara^.aPara[6]$^DINT^;
      
      //Check if the given parameter is a "K-" Parameter -> K Parameters are not stored
      if IsCommandoParameter(hIndex,hsSubIndex) = FALSE then
      
        //Convert to LC2 format (this format is used for storing the parameters at the moment)
        ConvertDS402ParaFormatToLC2Format(hParaIndex:=hIndex, hsParaSubIndex:=hsSubIndex, ParaNo:=#dTmpParaNo);
        
        //Save para value
        SavParaValue( ParaNo    := dTmpParaNo$USINT
                    , Value     := dValue
                    , bSavSRAM  := to_bool(pPara^.aPara[8]));
      
      end_if;
      
      //Check if the parameter is written
      if bRW = TRUE then
        //Check if it is a important asy parameter
        if hIndex = MDD2000_PID_SIGMATEKPARA_INDEX_SET then
          if ((hsSubIndex = MDD2000_SPID_A_VALTT1) | (hsSubIndex = MDD2000_SPID_A_VALRT1) |
              (hsSubIndex = MDD2000_SPID_A_VALTT2) | (hsSubIndex = MDD2000_SPID_A_VALRT2) | 
              (hsSubIndex = MDD2000_SPID_P_PSCALE)) then
            
            //Refresh them
            RefreshIASP(hParaIndex:=hIndex, hsParasubIndex:=hsSubIndex, Value:=dValue);
          end_if;
        end_if;
      end_if;
      
      ret_code := READY;                        
                             
    else
      HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_SAVE_PARAMETER detected", #pPara^.aPara[0]);      
    end_if;
    
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
  MDD2000MNG_IF_REFRESH_PARAMETER_FINISHED :
    
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_REFRESH_PARAMETER_FINISHED_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_REFRESH_PARAMETER_FINISHED_VER_1 then
      
      bdSettings.bReadAxFin := TRUE;
                                    
      ret_code := READY;                        
                             
    else
      HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_REFRESH_PARAMETER_FINISHED detected", #pPara^.aPara[0]);      
    end_if;
    
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  MDD2000MNG_NEWINST_INITAXLE :
    
    Init_Again:=true;
    bdSettings.bDriveInitialized := false;
    AxisState.NotInitialized:=false;
    
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  MDD2000MNG_NEWINST_URINITAXLE :
    
    Init_Again:=true;
    bdSettings.bDriveInitialized := true;
    AxisState.NotInitialized:=false;
  
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  MDD2000MNG_IF_REFRESH_PARA_OBJECTS :

    ret_code := RefreshParameterObjects(pPara,pResult);
    
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  MDD2000MNG_IF_IS_AXIS_ENABLED : 
  
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_IS_AXIS_ENABLED_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_IS_AXIS_ENABLED_VER_1 then
                                          
      ret_code := READY;                        
      
      pResult^.uiLng := 8;
      if AxEnable | StateWord.OperationEnabled then
        pResult^.aData[4]$DINT := 1; //Return state of axis enabled  
      else
        pResult^.aData[4]$DINT := 0;
      end_if;
      
    else
      HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_IS_AXIS_ENABLED detected", #pPara^.aPara[0]);      
    end_if;
  
//*****************************************************************************
  CMD_GET_HARDWARE_DIAGNOSIS : 

    pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR;
    ret_code := ERROR;
    
    // Get AxisNo --------------------------------------------------------------------------------------------
    pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.ud_AxisNo := AxisNo$UDINT;
                 
    if Online = 0 then
      ret_code := ERROR;
      pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_ERROR_CLASS_NOT_ONLINE;
    else
      ret_code := READY;
      pResult^.aData$t_HWCGetHardwareDiagnosisOut.retcode := _HWC_RETVAL_OK;
    end_if;
    
//*****************************************************************************
  DRIVESAFETYIF_NEWINSTPDO :
    
    pResult^.uiLng := 1;
    
    //We use this as version request in DrivePosControl to ensure that both classes have the same structure type (_MDD2000PDOREAD, _MDD2000PDOWRITE)
    //If the structure is changed, we need to increment the version number in pResult^.aData[0]
    pResult^.aData[0] := 1; //Version 1
  
//*****************************************************************************
  DRIVESAFETYIF_READPDODATA :
    pPDORead := pPara^.aPara[0]$^_MDD2000PDOREAD;
    if bOnlineFinished = TRUE then
      pPDORead^.Online := TRUE;
      
      // StatusWord (nur die ersten 4 Bits      
      pPdoRead^.StateWord := to_usint(StateWord.Read()) AND 2#00001111;  // Only include the 1st 4 Bits
      
      // ActPos
      pPdoRead^.ActPos := ActPos.Read();
      
      // XW
      pPdoRead^.ActXw := ActXw.Read();
      
    else
      pPdoRead^.Online := FALSE;
    end_if;
    
//*****************************************************************************
  DRIVESAFETYIF_WRITEPDODATA :
    pPDOWrite := pPara^.aPara[0]$^_MDD2000PDOWRITE;
    if bOnlineFinished = TRUE then
    
      // SetPos
      if (pPDOWrite^.SetPos.Active = 1) then
        SetPos.Write(input:=pPDOWrite^.SetPos.Value);
      end_if;
      
      // Enable 
      if (pPDOWrite^.Enable.Active = 1) then
        AxEnable.Write(input:=pPDOWrite^.Enable.Value);
      end_if;      
      
      // SetSpeed
      if (pPDOWrite^.SetSpeed.Active = 1) then
        SetSpeed.Write(input:=pPDOWrite^.SetSpeed.Value);
        
      end_if;
    end_if;
 
//*****************************************************************************
  MDD2000MNG_IF_GET_AXIS_STATE:
  
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_GET_AXIS_STATE_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_GET_AXIS_STATE_VER_1 then
      
      pResult^.uiLng := 8;
      pResult^.aData[4]$DINT := (AxisState.Read())$DINT;
                                    
      ret_code := READY;                        
                             
    else
      HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_GET_AXIS_STATE detected", #pPara^.aPara[0]);      
    end_if;

//*****************************************************************************
  MDD2000MNG_IF_IS_ONLINE:
    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:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_IS_ONLINE detected", #pPara^.aPara[0]);      
    end_if;

//*****************************************************************************
  MDD2000MNG_IF_ADD_ASYNC_ENTRY_DS402:
  
    //Forward these newinst to the drivemng and insert the correct ax index
    pPara^.uiCmd    := MDD2000MNG_IF_ADD_ASYNC_ENTRY_DS402;
    pPara^.aPara[1] := TO_DINT(usAxisIndex);
    
    ret_code := DriveMng.NewInst(pPara:=pPara, pResult:=pResult);

//*****************************************************************************
  MDD2000MNG_IF_GET_CLASS_STATE:

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

//*****************************************************************************
  MDD2000MNG_IF_IS_HARDWARE_AVAILABLE:
  
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_IS_HARDWARE_AVAILABLE_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_IS_HARDWARE_AVAILABLE_VER_1 then
      
      pResult^.uiLng := 8;
      pResult^.aData[4]$DINT := TO_DINT(NOT AxisState.NoHW);
      
      ret_code := READY;                        
                             
    else
      HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_IS_HARDWARE_AVAILABLE 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:="@08B2 (MDD2000_AxisBase::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 IsOnline() & AxOkay() then
        pResult^.aData[4]$DINT := TRUE;
      else
        pResult^.aData[4]$BOOL := FALSE;
      end_if;
      
      ret_code := READY;                        
                             
    else
      HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_IS_AXIS_READY_4_ASYPARA detected", #pPara^.aPara[0]);      
    end_if;

//*****************************************************************************
  MDD2000MNG_IF_SET_DIAG_MODE:
  
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_SET_DIAG_MODE_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_SET_DIAG_MODE_VER_1 then
      
      pResult^.uiLng := 8; 
      pResult^.aData[4]$DINT := SetDiagMode(bStartDiagMode:=pPara^.aPara[1]$BOOL, pThisObj:=pPara^.aPara[2]$^void);;
      
      ret_code := READY;                        
                             
    else
      HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_SET_DIAG_MODE detected", #pPara^.aPara[0]);      
    end_if;
    
//*****************************************************************************
  MDD2000MNG_IF_ADD_SYNC_ENTRY:
  
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := MDD2000MNG_IF_ADD_SYNC_ENTRY_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = MDD2000MNG_IF_ADD_SYNC_ENTRY_VER_1 then
      
      pResult^.uiLng := 8; 
      pResult^.aData[4]$DINT := AddSyncEntry(pThis:=pPara^.aPara[1]$^void);
      
      ret_code := READY;                        
                             
    else
      HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_ADD_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 1
    if pPara^.aPara[0] = MDD2000MNG_IF_SET_SYNC_ENTRY_VER_1 then
      
      pResult^.uiLng := 8; 
      pResult^.aData[4]$DINT := SetSyncEntry(usValue:=pPara^.aPara[2]$USINT, usPData:=pPara^.aPara[3]);
      
      ret_code := READY;                        
                             
    else
      HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_SET_SYNC_ENTRY 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 1
    if pPara^.aPara[0] = MDD2000MNG_IF_GET_SYNC_ENTRY_VER_1 then
      
      pResult^.uiLng := 8; 
      pResult^.aData[4]$DINT := GetSyncEntry(usValue:=pPara^.aPara[2]$USINT, usPData:=pPara^.aPara[3]$^DINT);
      
      ret_code := READY;                        
                             
    else
      HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_GET_SYNC_ENTRY detected", #pPara^.aPara[0]);      
    end_if;

//*****************************************************************************    
      //+++++++++++++++++++++++++++++++++++++
      //#define DRIVEENCMEM_CMD_FETCHENCODERDATA        0x8550
      // Sets a request to fetch the encoder memory to the HW class. 
      // The data is fetched asynchronously from the drive over a period of time. 
      // The status of the readout process can be read out via "DRIVEENCMEM_CMD_CHECKFETCHENCODERDATA" command. 
      // After the data has been read out, it can be fetched with the command "DRIVEENCMEM_CMD_GETENCODERDATA".

      // aPara[0] = version of command
      // Parameter of Version 1:
      // aPara[1]$UDINT          : Offset from which the memory is to be read out in bytes.
      // aPara[2]$UDINT          : Number of bytes that are read from the memory.
        
      // result of version 1
      // uiLng := 8;
      // aData[0]$DINT   : return code. Reason command Failed. 0 Ok, Else ErrorCode
      // aData[4]$DINT   : version
    DRIVEENCMEM_CMD_FETCHENCODERDATA:
    
      pResult^.uiLng         := 8;
      pResult^.aData[0]$DINT := DRIVEENCMEM_RETERR_CMD_VERSION;
      pResult^.aData[4]$DINT := 1;
      
      if pPara^.aPara[0] = 1 then
      
        ret_code := FetchEncoderData( Offset := pPara^.aPara[1]$UDINT
                                    , Size   := pPara^.aPara[2]$UDINT);
        
        pResult^.aData[0]$DINT := GetEncoderErrorCode();
        if ret_code = READY then
          pResult^.aData[0]$DINT := DRIVEENCMEM_RETOK;
        elsif ret_code = BUSY then
          pResult^.aData[0]$DINT := DRIVEENCMEM_RETBUSY;
        end_if;
        
      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVEENCMEM_CMD_FETCHENCODERDATA detected", #pPara^.aPara[0]);      
      end_if;
      
//*****************************************************************************
      //+++++++++++++++++++++++++++++++++++++
      //#define DRIVEENCMEM_CMD_CHECKFETCHENCODERDATA   0x8551
      // Returns the status of the encoder memory readout.

      // aPara[0] = version of command
      // Parameter of Version 1:
      // aPara[1]$^UDINT         :  If a vaild pointer is passed, the progress of the encoder memory upload in percentage 0-1000 [0-100.0%] is safed to this pointer.

      // result of version 1
      // uiLng := 8;
      // aData[0]$DINT   : return code. Reason command Failed. 0 Ok, Else ErrorCode
      // aData[4]$DINT   : version

    DRIVEENCMEM_CMD_CHECKFETCHENCODERDATA:
    
      pResult^.uiLng         := 8;
      pResult^.aData[0]$DINT := DRIVEENCMEM_RETERR_CMD_VERSION;
      pResult^.aData[4]$DINT := 1;
      
      if pPara^.aPara[0] = 1 then
      
        ret_code := CheckFetchEncoderData(pProgress := (pPara^.aPara[1])$^UDINT );
        
        pResult^.aData[0]$DINT := GetEncoderErrorCode();
        if ret_code = READY then
          pResult^.aData[0]$DINT := DRIVEENCMEM_RETOK;
        elsif ret_code = BUSY then
          pResult^.aData[0]$DINT := DRIVEENCMEM_RETBUSY;
        end_if;
      
      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVEENCMEM_CMD_CHECKFETCHENCODERDATA detected", #pPara^.aPara[0]);      
      end_if;

//*****************************************************************************
      //+++++++++++++++++++++++++++++++++++++
      //#define DRIVEENCMEM_CMD_GETERRORCODE            0x8552
      // Returns the last error code that occurred.

      // aPara[0] = version of command
      // Parameter of Version 1:

      // result of version 1
      // uiLng := 8;
      // aData[0]$DINT   : last error code that occurred
      // aData[4]$DINT   : version

//*****************************************************************************
    DRIVEENCMEM_CMD_GETERRORCODE:
    
      pResult^.uiLng         := 8;
      pResult^.aData[0]$DINT := DRIVEENCMEM_RETERR_CMD_VERSION;
      pResult^.aData[4]$DINT := 1;
      
      if pPara^.aPara[0] = 1 then
      
        pResult^.aData[0]$DINT := GetEncoderErrorCode();
        ret_code := READY;
      
      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVEENCMEM_CMD_GETERRORCODE detected", #pPara^.aPara[0]);      
      end_if;

//*****************************************************************************
      //+++++++++++++++++++++++++++++++++++++
      //#define DRIVEENCMEM_CMD_GETENCODERDATASIZE      0x8553
      // Returns the size of the encoder memory from the drive.

      // aPara[0] = version of command
      // Parameter of Version 1:
      // aPara[1]$^UDINT         : The size of the encoder memory is written to this pointer when the retcode = READY.
      
      // result of version 1
      // uiLng := 8;
      // aData[0]$DINT   : last error code that occurred
      // aData[4]$DINT   : version

//*****************************************************************************
    DRIVEENCMEM_CMD_GETENCODERDATASIZE:
    
      pResult^.uiLng         := 8;
      pResult^.aData[0]$DINT := DRIVEENCMEM_RETERR_CMD_VERSION;
      pResult^.aData[4]$DINT := 1;
      
      if pPara^.aPara[0] = 1 then
      
        ret_code := GetEncoderDataSize(pSize:=pPara^.aPara[1]$^UDINT);
        
        pResult^.aData[0]$DINT := GetEncoderErrorCode();
        if ret_code = READY then
          pResult^.aData[0]$DINT := DRIVEENCMEM_RETOK;
        elsif ret_code = BUSY then
          pResult^.aData[0]$DINT := DRIVEENCMEM_RETBUSY;
        end_if;
      
      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVEENCMEM_CMD_GETENCODERDATASIZE detected", #pPara^.aPara[0]);      
      end_if;

//*****************************************************************************
      //+++++++++++++++++++++++++++++++++++++
      //#define DRIVEENCMEM_CMD_GETENCODERDATA          0x8554
      // Returns a pointer to the previously read encoder data. 
      // See method "FetchEncoderData". 
      // Attention: The validity of the data expires if "FetchEncoderData" is called again!

      // aPara[0] = version of command
      // Parameter of Version 1:
      // aPara[1]$^UDINT         : Optional. The size of the read encoder memory is written to this memory if the pointer <> NIL. 
      
      // result of version 1
      // uiLng := 12;
      // aData[0]$DINT   : last error code that occurred
      // aData[4]$DINT   : version
      // aData[8]$DINT   : <> NIL ...  Pointer to the encoder data, Error See last error code

//*****************************************************************************
    DRIVEENCMEM_CMD_GETENCODERDATA:
    
      pResult^.uiLng           := 12;
      pResult^.aData[0]$DINT   := DRIVEENCMEM_RETERR_CMD_VERSION;
      pResult^.aData[4]$DINT   := 1;
      pResult^.aData[8]$pVoid  := NIL;
      
      if pPara^.aPara[0] = 1 then
      
        pResult^.aData[8]$pVoid  := GetEncoderData(pSize:=pPara^.aPara[1]$^UDINT);
        
        pResult^.aData[0]$DINT := GetEncoderErrorCode();
        if pResult^.aData[8]$pVoid <> NIL then
        
          ret_code := READY;
          pResult^.aData[0]$DINT := DRIVEENCMEM_RETOK;
          
        end_if;
      
      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVEENCMEM_CMD_GETENCODERDATA detected", #pPara^.aPara[0]);      
      end_if;

//*****************************************************************************
    MDD2000MNG_IF_UPDATEPARACLASS_STATE:
    
      ret_code := ERROR; //unsupported version
      
      pResult^.uiLng := 4;
      pResult^.aData[0]$DINT := MDD2000MNG_IF_UPDATEPARACLASS_STATE_VER_MAX;  //max supported version
      
      //Check version 1
      if pPara^.aPara[0] = MDD2000MNG_IF_UPDATEPARACLASS_STATE_VER_1 then
        
        case pPara^.aPara[1] of

          MDD2000MNG_IF_UPDATEPARACLASS_STATE_GENERAL_ERROR:
            ret_code := READY;
          MDD2000MNG_IF_UPDATEPARACLASS_STATE_ASYNC_BUSY:
            ret_code := READY;
          MDD2000MNG_IF_UPDATEPARACLASS_STATE_GENERAL_READY: 
            ret_code := READY;
          MDD2000MNG_IF_UPDATEPARACLASS_STATE_SAFETY_READY:
            // Info Safety is active at Mng
            AxisState.SafeMngNotReady       := TRUE;
            ret_code := READY;
          MDD2000MNG_IF_UPDATEPARACLASS_STATE_SAFETY_ERROR:
            
            AxisState.SafeAxisNotVerified   := TRUE;
            AxisState.SafeAxisZeroPosNotSet := TRUE;
            AxisState.SafeMngNotVerified    := TRUE;            
            // Safety Err Mng. 
            AxisState.SafeMngNotReady       := TRUE;
            
            // Reread the Verified States
            bdSettings.bReadSafeVerifyState := TRUE;
            bdSettings.bReadSafeRefState    := TRUE;
                
            ret_code := READY;
            
          MDD2000MNG_IF_UPDATEPARACLASS_STATE_SAFETY_CHANGED:
          
            SafetyChanged(StateInfo:= pPara^.aPara[2]);
            
        end_case;
        
        //Provide status update from manager also at the parameter classes from which are only connected to the axis class
        SetParaState(ActState:=pPara^.aPara[1]$UINT, StateInfo:=pPara^.aPara[2]);
        ret_code := READY;
        
      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando MDD2000MNG_IF_UPDATEPARACLASS_STATE detected", #pPara^.aPara[0]);      
      end_if;

//*****************************************************************************
  DRIVESAFETYIF_READAXISSTATE:
  
      ret_code := ERROR; //unsupported version
      
      pResult^.uiLng := 4;
      pResult^.aData[0]$DINT := DRIVESAFETYIF_READAXISSTATE_VER_MAX;  //max supported version
      
      //Check version 1
      if pPara^.aPara[0] = DRIVESAFETYIF_READAXISSTATE_VER_1 then
        pResult^.uiLng := 8;
        pResult^.aData[4]$_MDD2000AXISSTATE := AxisState;
        ret_code := READY;
      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVESAFETYIF_READAXISSTATE detected", #pPara^.aPara[0]);            
      end_if;
      
//*****************************************************************************
  DRIVESAFETYIF_DOAXERRORQUIT:
  
      ret_code := ERROR; //unsupported version
      
      pResult^.uiLng := 4;
      pResult^.aData[0]$DINT := DRIVESAFETYIF_DOAXERRORQUIT_VER_MAX;  //max supported version
      
      //Check version 1
      if pPara^.aPara[0] = DRIVESAFETYIF_DOAXERRORQUIT_VER_1 then
        pResult^.uiLng := 8;
        pResult^.aData[4]$DINT := AxErrorQuit.Write(input:=pPara^.aPara[1]);
        ret_code := READY;
      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVESAFETYIF_DOAXERRORQUIT 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 1
      if pPara^.aPara[0] = DRIVESAFETYIF_DOSAFETYAXERRORQUIT_VER_1 then
        
        ret_code := SafetyAxErrorQuit(AxErrorQuit:=pPara^.aPara[1]);        
        
      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVESAFETYIF_DOSAFETYAXERRORQUIT detected", #pPara^.aPara[0]);            
      end_if;
      
//*****************************************************************************
  DRIVESAFETYIF_SETVERIFYAXIS:
  
      ret_code := ERROR; //unsupported version
      
      pResult^.uiLng := 4;
      pResult^.aData[0]$DINT := DRIVESAFETYIF_SETVERIFYAXIS_VER_MAX;  //max supported version
      
      //Check version 1
      if pPara^.aPara[0] = DRIVESAFETYIF_SETVERIFYAXIS_VER_1 then
      
        ret_code := SetSafeVerified(NewSetVerified:=pPara^.aPara[1]);
        
      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVESAFETYIF_SETVERIFYAXIS detected", #pPara^.aPara[0]);            
      end_if;
      
//*****************************************************************************
  DRIVESAFETYIF_GETVERIFYSTATE:
  
      ret_code := ERROR; //unsupported version
      
      pResult^.uiLng := 4;
      pResult^.aData[0]$DINT := DRIVESAFETYIF_GETVERIFYSTATE_VER_MAX;  //max supported version
      
      //Check version 1
      if pPara^.aPara[0] = DRIVESAFETYIF_GETVERIFYSTATE_VER_1 then
        pResult^.uiLng  := 20;
        
        if (SetVerifiedRsp = t_e_SetVerifiedRsp::CmdBusy) | (SetVerifiedRsp = t_e_SetVerifiedRsp::CmdExecuting) then
          pResult^.aData[4]$iprStates := BUSY;
        elsif SetVerifiedRsp = t_e_SetVerifiedRsp::AsyCommError then
          pResult^.aData[4]$iprStates := ERROR;
        else
          pResult^.aData[4]$iprStates := READY;
        end_if;        
        pResult^.aData[8]$t_e_SetVerifiedRsp  := SetVerifiedRsp;
        
        if (VerifiedState = t_e_SafeVerifiedState::Reading) | (VerifiedState = t_e_SafeVerifiedState::VerifyPending) then
          pResult^.aData[12]$iprStates := BUSY;
        elsif VerifiedState = t_e_SafeVerifiedState::AsyCommError then
          pResult^.aData[12]$iprStates := ERROR;
        else
          pResult^.aData[12]$iprStates := READY;
        end_if;        
        pResult^.aData[16]$t_e_SafeVerifiedState   := VerifiedState;
        
        ret_code := READY;
      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVESAFETYIF_GETVERIFYSTATE detected", #pPara^.aPara[0]);            
      end_if;
      
//*****************************************************************************
  DRIVESAFETYIF_SETREFERENCEAXIS:
  
      ret_code := ERROR; //unsupported version
      
      pResult^.uiLng := 4;
      pResult^.aData[0]$DINT := DRIVESAFETYIF_SETREFERENCEAXIS_VER_MAX;  //max supported version
      
      //Check version 1
      if pPara^.aPara[0] = DRIVESAFETYIF_SETREFERENCEAXIS_VER_1 then
      
        ret_code := SetSafeReference(NewSetReference:=pPara^.aPara[1]);
        
      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVESAFETYIF_SETREFERENCEAXIS detected", #pPara^.aPara[0]);            
      end_if;
      
//*****************************************************************************
  DRIVESAFETYIF_GETREFERENCESTATE:
  
      ret_code := ERROR; //unsupported version
      
      pResult^.uiLng := 4;
      pResult^.aData[0]$DINT := DRIVESAFETYIF_GETREFERENCESTATE_VER_MAX;  //max supported version
      
      //Check version 1
      if pPara^.aPara[0] = DRIVESAFETYIF_GETREFERENCESTATE_VER_1 then
        pResult^.uiLng  := 20;
        
        if sSafeRefState.CmdState = DRIVESAFETYIF_REFCMD_BUSY then
          pResult^.aData[4]$iprStates := BUSY;
        elsif sSafeRefState.CmdState = DRIVESAFETYIF_COMM_ERROR then
          pResult^.aData[4]$iprStates := ERROR;
        else
          pResult^.aData[4]$iprStates := READY;
        end_if;        
        pResult^.aData[8]$HDINT := sSafeRefState.CmdState;
        
        if sSafeRefState.RefState = DRIVESAFETYIF_REFSTATE_BUSY then
          pResult^.aData[12]$iprStates := BUSY;
        elsif sSafeRefState.RefState = DRIVESAFETYIF_COMM_ERROR then
          pResult^.aData[12]$iprStates := ERROR;
        else
          pResult^.aData[12]$iprStates := READY;
        end_if;        
        pResult^.aData[16]$HDINT := sSafeRefState.RefState;
        
        ret_code := READY;
      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVESAFETYIF_GETREFERENCESTATE detected", #pPara^.aPara[0]);            
      end_if;
      
//*****************************************************************************
  DRIVESAFETYIF_SETACKZEROPOSITION:
  
      ret_code := ERROR; //unsupported version
      
      pResult^.uiLng := 4;
      pResult^.aData[0]$DINT := DRIVESAFETYIF_SETACKZEROPOSITION_VER_MAX;  //max supported version
      
      //Check version 1
      if pPara^.aPara[0] = DRIVESAFETYIF_SETACKZEROPOSITION_VER_1 then
      
        ret_code := SetSafeAckZeroposition(NewAckZeroposition:=pPara^.aPara[1]);
        
      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVESAFETYIF_SETACKZEROPOSITION detected", #pPara^.aPara[0]);            
      end_if;
      
//*****************************************************************************
  DRIVESAFETYIF_GETSBTSTATE:
  
      ret_code := ERROR; //unsupported version
      
      pResult^.uiLng := 4;
      pResult^.aData[0]$DINT := DRIVESAFETYIF_GETSBTSTATE_VER_MAX;  //max supported version
      
      //Check version 1
      if pPara^.aPara[0] = DRIVESAFETYIF_GETSBTSTATE_VER_1 then
      
        ret_code := READY;  // Cmd is ok, Return values may be BUSY or Error
        
        if sSafeBreakState.bdWait4Para = 0 then // All Bits 0 and no error          
        
          pResult^.uiLng := 24;
          pResult^.aData[4]$iprStates := READY;
          pResult^.aData[8]$DINT  := sSafeBreakState.SafeBrakeTestStatus;
          pResult^.aData[12]$DINT := sSafeBreakState.BrakeTestStatus;
          pResult^.aData[16]$DINT := sSafeBreakState.TimeTilNextTest;
          pResult^.aData[20]$DINT := sSafeBreakState.BrakeTestErrorInfo;
        
        elsif (sSafeBreakState.bdWait4Para.ErrBrakeTestStatus     ) |  
              (sSafeBreakState.bdWait4Para.ErrSafeBrakeTestStatus ) |  
              (sSafeBreakState.bdWait4Para.ErrTimeTilNextTest     ) |  
              (sSafeBreakState.bdWait4Para.ErrSetBrakeTest        ) | 
              (sSafeBreakState.bdWait4Para.ErrBrakeTestErrorInfo  ) then  // At Least 1 Error bit is set          
          
          pResult^.uiLng := 8;
          pResult^.aData[4]$DINT := ERROR;
          
        else  // At least on of the busy bits is set
          
          pResult^.uiLng := 8;
          pResult^.aData[4]$DINT := BUSY;
          
        end_if;

      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVESAFETYIF_GETSBTSTATE detected", #pPara^.aPara[0]);            
      end_if;
      
//*****************************************************************************
  DRIVESAFETYIF_SETSBTSTATE:
  
      ret_code := ERROR; //unsupported version
      
      pResult^.uiLng := 4;
      pResult^.aData[0]$DINT := DRIVESAFETYIF_SETSBTSTATE_VER_MAX;  //max supported version
      
      //Check version 1
      if pPara^.aPara[0] = DRIVESAFETYIF_SETSBTSTATE_VER_1 then
        ret_code := SetSafeSBTState(NewSBTState:=pPara^.aPara[1]);
      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVESAFETYIF_SETSBTSTATE detected", #pPara^.aPara[0]);            
      end_if;
      
//*****************************************************************************
  DRIVESAFETYIF_GETGENERALPARA:
  
      ret_code := MDD2000GeneralPara.NewInst(pPara, pResult);
      
//*****************************************************************************
  DRIVESAFETYIF_GETSAFETYERRORINFOS:
  
      // Pass on to manager, command is not dependent on AxisNo 
      ret_code := DriveMng.NewInst(pPara, pResult);
      
//*****************************************************************************
  DRIVESAFETYIF_GETSAFEFUNCTIONERRORINFOS:
  
      ret_code := ERROR; //unsupported version
      
      pResult^.uiLng := 4;
      pResult^.aData[0]$DINT := DRIVESAFETYIF_GETSAFEFUNCTIONERRORINFOS_VER_MAX;  //max supported version
      
      //Check version 1
      if pPara^.aPara[0] = DRIVESAFETYIF_GETSAFEFUNCTIONERRORINFOS_VER_1 then
      
        if pPara^.aPara[1] <> 0 then  // ReRead Error Info:
        
          ret_code := READY;
          sSafeFuncErrInfo.bdAsyFlags := 0;  // Reset Flags
          
          if (AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_AXIS_FUNC_INFO, usParaSubID:=MDD2000_SPID_SAFETY_AXIS_ERROR_WORD,  usRdWr:=0, pValue:=NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
            sSafeFuncErrInfo.bdAsyFlags.w4SafeErrorWord := TRUE;
          else
            sSafeFuncErrInfo.bdAsyFlags.errSafeErrorWord := TRUE;
            ret_code := ERROR;
          end_if;
          if (AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_AXIS_FUNC_INFO, usParaSubID:=MDD2000_SPID_SAFETY_AXIS_ERR_ID, usRdWr:=0, pValue:=NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
            sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionErrorID := TRUE;
          else
            sSafeFuncErrInfo.bdAsyFlags.errSafeFunctionErrorID := TRUE;
            ret_code := ERROR;
          end_if;
          if (AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_AXIS_FUNC_INFO, usParaSubID:=MDD2000_SPID_SAFETY_AXIS_ERR_SOURCE, usRdWr:=0, pValue:=NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
            sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionInErrID := TRUE;
          else
            sSafeFuncErrInfo.bdAsyFlags.errSafeFunctionInErrID := TRUE;
            ret_code := ERROR;
          end_if;
          if (AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_AXIS_FUNC_INFO, usParaSubID:=MDD2000_SPID_SAFETY_AXIS_ERR_REACT, usRdWr:=0, pValue:=NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
            sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionErrReact := TRUE;
          else
            sSafeFuncErrInfo.bdAsyFlags.errSafeFunctionErrReact := TRUE;
            ret_code := ERROR;
          end_if;
          if (AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_AXIS_FUNC_INFO, usParaSubID:=MDD2000_SPID_SAFETY_AXIS_ERR_INFO1,  usRdWr:=0, pValue:=NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
            sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionErrorInfo1 := TRUE;
          else
            sSafeFuncErrInfo.bdAsyFlags.errSafeFunctionErrorInfo1 := TRUE;
            ret_code := ERROR;
          end_if;
          if (AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_AXIS_FUNC_INFO, usParaSubID:=MDD2000_SPID_SAFETY_AXIS_ERR_INFO2, usRdWr:=0, pValue:=NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
            sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionErrorInfo2 := TRUE;
          else
            sSafeFuncErrInfo.bdAsyFlags.errSafeFunctionErrorInfo2 := TRUE;
            ret_code := ERROR;
          end_if;
          if (AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_AXIS_FUNC_INFO, usParaSubID:=MDD2000_SPID_SAFETY_AXIS_ERR_INFO3, usRdWr:=0, pValue:=NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
            sSafeFuncErrInfo.bdAsyFlags.w4SafeFunctionErrorInfo3 := TRUE;
          else
            sSafeFuncErrInfo.bdAsyFlags.errSafeFunctionErrorInfo3 := TRUE;
            ret_code := ERROR;
          end_if;
        
        else  // Return read Error info
        
          if sSafeFuncErrInfo.bdAsyFlags = 0 then // All flags 0, data valid
          
            pResult^.uiLng := 40;
            pResult^.aData[4]$DINT  := sSafeFuncErrInfo.SafeErrorWord;
            pResult^.aData[8]$DINT  := sSafeFuncErrInfo.SafeFunctionErrorID;
            pResult^.aData[12]$DINT := sSafeFuncErrInfo.SafeFunctionInErrID;
            pResult^.aData[16]$DINT := sSafeFuncErrInfo.SafeFunctionInErrSubID;
            pResult^.aData[20]$DINT := sSafeFuncErrInfo.SafeFunctionErrReactID;
            pResult^.aData[24]$DINT := sSafeFuncErrInfo.SafeFunctionErrReactSubID;
            pResult^.aData[28]$DINT := sSafeFuncErrInfo.SafeFunctionErrorInfo1;
            pResult^.aData[32]$DINT := sSafeFuncErrInfo.SafeFunctionErrorInfo2;
            pResult^.aData[36]$DINT := sSafeFuncErrInfo.SafeFunctionErrorInfo3;
            
            ret_code := READY;
            
          else
          
            if ((sSafeFuncErrInfo.bdAsyFlags AND 16#FF00) <> 0) then // One of the bits errSafeErrorWord to errSafeFunctionErrorInfo3 is set
              ret_code := ERROR;
            else  // One of the bits w4SafeErrorWord to w4SafeFunctionErrorInfo3 is set
              ret_code := BUSY;
            end_if;
            
          end_if;
        end_if;
      else
        HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVESAFETYIF_GETSAFEFUNCTIONERRORINFOS detected", #pPara^.aPara[0]);            
      end_if;

//*****************************************************************************
  DRIVESAFETYIF_GETSAFECONTROLSTATEWORD:
      
      ret_code := ERROR; //unsupported version
      
      pResult^.uiLng := 4;
      pResult^.aData[0]$DINT := DRIVESAFETYIF_GETSAFECONTROLSTATEWORD_VER_MAX;  //max supported version
      
      //Check version 1
      if pPara^.aPara[0] = DRIVESAFETYIF_GETSAFECONTROLSTATEWORD_VER_1 then
      
        if (SyncPara.SafeControlWord.ptr <> NIL) & 
           (SyncPara.SafeStateWord.ptr <> NIL) then
          
          pResult^.uiLng := 12;
          
          pResult^.aData[4]$UDINT := to_UDINT(SyncPara.SafeControlWord.ptr^$UINT);
          pResult^.aData[8]$UDINT := to_UDINT(SyncPara.SafeStateWord.ptr^$UINT);
          
          pResult^.aData[12]$gb_MDD2000ActiveSafeFkt := 0;
          if sSafeFuncVar.bSafeFktUpdateListValid then
            pResult^.uiLng := 16;
            
            if (sSafeFuncVar.oldSafeControlWord <> pResult^.aData[4]$BDINT) |  
               (sSafeFuncVar.oldSafeStateWord   <> pResult^.aData[8]$BDINT) then
               
              sSafeFuncVar.oldSafeControlWord := pResult^.aData[4]$BDINT;
              sSafeFuncVar.oldSafeStateWord   := pResult^.aData[8]$BDINT;
              
              // Only call UpdateActiveSafeFunctions if oldSafeControlWord or SafeStateWord have changed
              pResult^.aData[12]$gb_MDD2000ActiveSafeFkt := sSafeFuncVar.oldActiveSafeFkt := UpdateActiveSafeFunctions(sControlWord:= pResult^.aData[4]$BDINT, sStateWord:= pResult^.aData[8]$BDINT);
            else
              pResult^.aData[12]$gb_MDD2000ActiveSafeFkt := sSafeFuncVar.oldActiveSafeFkt;
            end_if;
            
          end_if;
          
          ret_code := READY;
        end_if;
      
      end_if;

//*****************************************************************************
  DRIVESAFETYIF_CHANGESAFESERVICEMODE:
      //Forward command to manager
      ret_code := DriveMng.NewInst(pPara:=pPara, pResult:=pResult);
      
//*****************************************************************************

  DRIVESAFETYIF_GET_AXISERROR:
    ret_code := ERROR; //unsupported version
    
    pResult^.uiLng := 4;
    pResult^.aData[0]$DINT := DRIVESAFETYIF_GET_AXISERROR_VER_MAX;  //max supported version
    
    //Check version 1
    if pPara^.aPara[0] = DRIVESAFETYIF_GET_AXISERROR_VER_1 then
      
      pResult^.uiLng := 8;
      pResult^.aData[4]$DINT := AxError.Read();
      
      ret_code := READY;
      
    else
      HWC_LogPrintf(pThis:=this, format:="@08B2 (MDD2000_AxisBase::CmdState::NewInst) Unsupported version %d of commando DRIVESAFETYIF_GET_AXISERROR detected", #pPara^.aPara[0]);
    end_if;
    
  else
    
      //Forward unknown commands to manager
      ret_code := DriveMng.NewInst(pPara:=pPara, pResult:=pResult);
  
  END_CASE;

END_FUNCTION


FUNCTION MDD2000_AxisBase::AllocMemPara
	VAR_OUTPUT
		retcode 	: BOOL;
	END_VAR
	
  retcode := FALSE;
	pMDD2000Data$^void := DriveAxisSet.GetMemPtr();
	if pMDD2000Data <> NIL then
		InitMDDHeader(pMDD2000Data); // initialize the data of the header
		retcode := TRUE;
	end_if;

END_FUNCTION


FUNCTION MDD2000_AxisBase::InitMDDHeader
	VAR_INPUT
		pMDDHeader 	: ^_MDD2000MEMHEADER;
	END_VAR
  //Preparation of Data headerfor the Excel data exportation
  
  pMDDHeader^.udCRC32 := 0;
  pMDDHeader^.udLen := sizeof(_MDD2000MEMHEADER);
  pMDDHeader^.udVersion := 1;
  pMDDHeader^.AxOffset := sizeof(_MDD2000MEMHEADER);
  pMDDHeader^.AxLength := 0;

END_FUNCTION


FUNCTION MDD2000_AxisBase::InitASyncPara
    
  //Read out entries of pipe until no entry is left in the pipe
  if pAsyPipeHandle then
    while cPipe_GetUsed(p:=pAsyPipeHandle) do
      cPipe_Get(pd:=NIL, p:=pAsyPipeHandle);
    end_while;
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::CyWork
	VAR_INPUT
		EAX 	: UDINT;
	END_VAR
	VAR_OUTPUT
		state (EAX) 	: UDINT;
	END_VAR
  VAR
    retZImpuls : USINT;
    tmpPara : CmdStruct;
    tmpResult : results;
    DriveMngCommunicationState : DINT;
    DriveMngRdy4AxisConfig : DINT;
  END_VAR  

  // Get communication state from manager
  tmpPara.uiCmd := MDD2000MNG_IF_GET_COMM_STATE;
  tmpPara.aPara[0]$DINT := MDD2000MNG_IF_GET_COMM_STATE_VER_1;
  
  if DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult) = READY then
    DriveMngCommunicationState := tmpResult.aData[4]$DINT;
  else
    DriveMngCommunicationState := 0;
  end_if;
  
  if (DriveMngCommunicationState = 0) | (Init_Again = true) then
    if bdSettings.bDriveInitialized = TRUE then
      InitASyncPara(); // to initialize the buffer only once time
    end_if;
    
    CmdState                      := ERROR;
    bdSettings.bDriveInitialized  := FALSE;
    bdSettings.bGotFeedBackType   := FALSE;
    bdSettings.bFeedbackSend      := FALSE;
    bdSettings.bDriveInit         := TRUE;
    bdSettings.bSyncSettings      := FALSE;
    bdSettings.bParaInit          := FALSE;
    InitSSW                       := _MDD2000_STARTINIT;
    AxisState.NotOnline           := 1;
    AxisState.NotInitialized      := 1;
    
    // Do not quit the first error on reconnect because that would also quit Safety Error!
    // 25.08.2023 Definition RauAnd and KoeAnd:
    // A quit of a safety Error, after the Drive was in operation, requires a user input. 
    // Other Error than "FSoE Connection lost" may happen! 
    // These would be lost if "Quit the first error" would be done auotmatically by HW-Class
    FirstErrorReset               := 0; //0...no error to handle , 1...quit the first error
        
    FirstPosition                 := FALSE; //that is for Hot-Plug 
    Init_Again                    := FALSE;
    Online                        := 0;
    bOnlineFinished               := FALSE;
    bOnlineState                  := FALSE;
    
    //reset diagnose mode if online state is set to zero
    if pDiagThis <> NIL then
      SetDiagMode(bStartDiagMode:=FALSE, pThisObj:=pDiagThis);
    end_if;
    
    // disable drive and reset speed (no online check, directly in the PDO data)
    AxEnable                     := 0;
    SetSpeed := 0;
    Write_Enable(0);
    Write_SetSpeed(0);
  end_if;
  
  if (bdSettings.bDriveInitialized = TRUE) then
  
    //***********************************************\\
    //** minimal 4 ms refresh time of all servers	**\\
    //***********************************************\\
    if (ops.tabsolute - tUpdate >= MDD2000MNG_MINTIMESVRUPDATE) then
      UpdateSvr(); // update all server parameters
      tUpdate := ops.tabsolute;
    end_if;

    //*************************************\\
    //** update the ZPulse just all 10ms **\\
    //*************************************\\
    if (ops.tabsolute - tUpdateZPulse >= 10) then
      if (FirstPosition = false) then //when it is the first time, we check out the actual position
        oldRevolutions := (ActPos.Read() and maskZImpulse$DINT);	
        ZPulsLatch.Read();
        FirstPosition:=true;
      end_if;

      //Here we check the ZImpulse every 10ms
      retZImpuls:=GetZImpulse();
      if retZImpuls=1 then
        ZPulsLatch:=retZImpuls;
      end_if;
      tUpdateZPulse := ops.tabsolute;
    end_if;
  end_if;
  
// *********************************************************************************************************
// ** check if a successfully HW Connect was given
// ** and we have to initialize the axis
// *********************************************************************************************************

  // Get communication state from manager
  tmpPara.uiCmd := MDD2000MNG_IF_GET_MNGRDY_4_AXISCONFIG;
  tmpPara.aPara[0]$DINT := MDD2000MNG_IF_GET_MNGRDY_4_AXISCONFIG_VER_1;
  
  DriveMngRdy4AxisConfig := 0;
  if DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult) = READY then
    DriveMngRdy4AxisConfig := tmpResult.aData[4]$DINT;
  end_if;  
  
  if (DriveMngCommunicationState = 1) & (bdSettings.bAxInUse = TRUE) & (DriveMngRdy4AxisConfig > 0) then

    AxisState.NotOnline := 0;
    if bdSettings.bDriveInit = TRUE then
      case InitSSW of
      
      //*****************************************************************************
      _MDD2000_IDLE :
        // do nothing :
        
      //*****************************************************************************
      _MDD2000_STARTINIT,
      _MDD2000_GETDRIVEINFO :
      
        // Get FW Version
        // Values MDD2000_SPID_I_FW are needed for step _MDD2000_CHKFEEDBACK
        AddASyncEntryDS402(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);
        bdGetASyncEntry := 0;
        bdGetASyncEntry.I_FW  := TRUE;
        
        InitSSW := _MDD2000_WAIT4GETDRIVEINFO;
      
      //*****************************************************************************
      _MDD2000_WAIT4GETDRIVEINFO :
      
        if bdGetASyncEntry = 0 then
          InitSSW := _MDD2000_CHKFEEDBACK;
        end_if;
        
      //*****************************************************************************
      _MDD2000_CHKFEEDBACK :
        // überprüfen welches Feedback vorhanden ist
        if bdSettings.bGotFeedBackType = FALSE then 
          GetFeedBackType();
        else
          InitSSW := _MDD2000_SENDPARA;
        end_if;
        
      //*****************************************************************************
      _MDD2000_SENDPARA :
      
        if bdSettings.bWaitInitFinished = FALSE then
          // Send all parameters to the drive
          SendDataToDrive();
          bdSettings.bWaitInitFinished := TRUE;
        else
          if DriveInitReady() = TRUE then
            InitSSW := _MDD2000_GETSYNCSETTINGS; 
          end_if;
        end_if;    
      
      //*****************************************************************************
       _MDD2000_GETSYNCSETTINGS :
        
        if bdSettings.bSyncSettings = FALSE then
          
          bdWait4SyncSettings := 0;
          
          if AddASyncEntryDS402(uiParaID    :=  MDD2000_PID_SIGMATEKPARA_INDEX_SET
                              , usParaSubID :=  MDD2000_SPID_A_VALTT1
                              , usRdWr      :=  0
                              , pValue      :=  NIL
                              , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                              , pThisObj    :=  this
                              , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                              , udTimeout   :=  0) = 0 then
            bdWait4SyncSettings.A_VALTT1 := TRUE;
          else
            HWC_LogPrintf(this,"@08C8 (MDD2000AxisBase::Cywork) Failed to read Parameter A-VALTT1.");
          end_if;

          if AddASyncEntryDS402(uiParaID    :=  MDD2000_PID_SIGMATEKPARA_INDEX_SET
                              , usParaSubID :=  MDD2000_SPID_A_VALTT2
                              , usRdWr      :=  0
                              , pValue      :=  NIL
                              , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                              , pThisObj    :=  this
                              , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                              , udTimeout   :=  0) = 0 then
            bdWait4SyncSettings.A_VALTT2 := TRUE;
          else
            HWC_LogPrintf(this,"@08C9 (MDD2000AxisBase::Cywork) Failed to read Parameter A-VALTT2.");
          end_if;

          if AddASyncEntryDS402(uiParaID    :=  MDD2000_PID_SIGMATEKPARA_INDEX_SET
                              , usParaSubID :=  MDD2000_SPID_A_VALRT1
                              , usRdWr      :=  0
                              , pValue      :=  NIL
                              , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                              , pThisObj    :=  this
                              , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                              , udTimeout   :=  0) = 0 then
            bdWait4SyncSettings.A_VALRT1 := TRUE;
          else
            HWC_LogPrintf(this,"@08CA (MDD2000AxisBase::Cywork) Failed to read Parameter A-VALRT1.");
          end_if;

          if AddASyncEntryDS402(uiParaID    :=  MDD2000_PID_SIGMATEKPARA_INDEX_SET
                              , usParaSubID :=  MDD2000_SPID_A_VALRT2
                              , usRdWr      :=  0
                              , pValue      :=  NIL
                              , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                              , pThisObj    :=  this
                              , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                              , udTimeout   :=  0) = 0 then
            bdWait4SyncSettings.A_VALRT2 := TRUE;
          else
            HWC_LogPrintf(this,"@08CB (MDD2000AxisBase::Cywork) Failed to read Parameter A-VALRT2.");
          end_if;

          if AddASyncEntryDS402(uiParaID    :=  MDD2000_PID_SIGMATEKPARA_INDEX_SET
                              , usParaSubID :=  MDD2000_SPID_P_PSCALE
                              , usRdWr      :=  0
                              , pValue      :=  NIL
                              , bsDataInfo  :=  MDD2000MNG_DATASIZE_4BYTE
                              , pThisObj    :=  this
                              , usEntry     :=  MDD2000MNG_ENTRY_TYPE_DEFAULT
                              , udTimeout   :=  0) = 0 then
            bdWait4SyncSettings.P_PSCALE := TRUE;
          else
            HWC_LogPrintf(this,"@08CC (MDD2000AxisBase::Cywork) Failed to read Parameter P-PSCALE.");
          end_if;
         
          bdSettings.bSyncSettings := TRUE;
          
        else
          if bdWait4SyncSettings = 0 then //when we got all parameters we can go on
            SetSynchronPara(); //here all the pointers will be set to the right place
            GetSynchronPara(); //here all the pointers will be set to the right place            
            InitSSW := _MDD2000_SENDPARAFINISH;
          end_if;
        end_if;
      
      //*****************************************************************************
      _MDD2000_CHECKSYNCSETTINGS :

        if bdWait4SyncSettings = 0 then //when we got all parameters we can go on
           
          InitSSW := _MDD2000_SENDPARAFINISH;
            
        end_if;
      
      //*****************************************************************************
      _MDD2000_SENDPARAFINISH : 
      
        bdSettings.bDriveInit        := FALSE;
        bdSettings.bWaitInitFinished := FALSE;
        bdSettings.bDriveInitialized := TRUE;
        AxisState.NotInitialized     := FALSE;
        CmdState                     := READY;
        
        // set the torque reduction
//        AxTorqueControl.Write(4500); //it does not matter which controlword we have, because the internal function reduced this amount to the top limit
        SetAxTorque(4500);
        
        tmpPara.uiCmd := MDD2000MNG_IF_AXISINITFINISHED;
        tmpPara.aPara[0] := MDD2000MNG_IF_AXISINITFINISHED_VER_1;
        tmpPara.aPara[1] := TO_DINT(usAxisIndex);
        tmpPara.aPara[2] := MDD2000MNG_IF_AXISINITFINISHED_FUNCT;
        DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult);
        
        // Set finish info to the parameter classes
        bdSettings.bParaError := FALSE;
                
        MDD2000CmdIntfc := _MDD2000IDLE; 
        InitSSW     := _MDD2000_IDLE;
        
      end_case;
    end_if;
  end_if;
      
// *********************************************************************************************************
// ** Drive is initialized and ok                                               												  **
// *********************************************************************************************************
  
  if bdSettings.bDriveInitialized = TRUE then
    
    // Update Parameter Classes
    SetParaState(ActState:=MDD2000MNG_IF_UPDATEPARACLASS_STATE_UPDATE_CY, 0);
      
    case FirstErrorReset of
      0: //it is nothing to do for the error quit
      1:
        if IsOnline() = TRUE then
          if (GetAxError() = 1)  then
            ErrorQuitTime:=ops.tAbsolute; 
            FirstErrorReset := 2;
          else
            FirstErrorReset := 0;
          end_if;
        end_if;
      2:
        if ((ops.tAbsolute - ErrorQuitTime) > 100) then
          ErrorQuitHandling(input := 1);
          ErrorQuitTime:=ops.tAbsolute;
          FirstErrorReset := 3;
        end_if;
      3:
        if ((ops.tAbsolute - ErrorQuitTime) > 100) then
          ErrorQuitHandling(input:= 0);
          FirstErrorReset:=0;
        end_if;
      4: //that is for resetting the AxErrorQuit after 100ms, when a user writes a 1 on it
        if ((ops.tAbsolute - ErrorQuitTime) > 100) | (GetAxError() = 0) then
          ErrorQuitHandling(input:= 0);
          FirstErrorReset:=0;
        end_if;
    end_case;
    
    if (SyncParaObject<>NIL) then //it is time for the SyncExtend class
      SyncParaObject$^VirtualBase^.CyWork(EAX);
    end_if;
    
    //Check if safety parameter needs to be read
    if bdSettings.bReadSafeVerifyState then
    
      if AddASyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_AXIS_INFO, usParaSubID := MDD2000_SPID_SAFETY_AXIS_FEEDBACK_STATE, usRdWr:=0, pValue:=NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) = 0 then
        if VerifiedState <> t_e_SafeVerifiedState::VerifyPending then
          VerifiedState  := t_e_SafeVerifiedState::Reading;
        end_if;
        
        bdSettings.bReadSafeVerifyState := FALSE;
      end_if;
      
      if AddASyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_AXIS_INFO, usParaSubID := MDD2000_SPID_SAFETY_AXIS_VERIFY_FEEDBACK,  usRdWr:=0, pValue:= NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) = 0 then
        if (SetVerifiedRsp <> t_e_SetVerifiedRsp::CmdExecuting) then
          SetVerifiedRsp := t_e_SetVerifiedRsp::CmdBusy;
        end_if;
        
      end_if;      
    end_if;
    
    if bdSettings.bReadSafeRefState then
    
      if AddASyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_AXIS_INFO, usParaSubID := MDD2000_SPID_SAFETY_AXIS_POSSREFTATE, usRdWr:=0, pValue:= NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) = 0 then
        sSafeRefState.RefState := DRIVESAFETYIF_REFSTATE_BUSY;
        bdSettings.bReadSafeRefState := FALSE;
      end_if;
      
      if AddASyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_AXIS_INFO, usParaSubID := MDD2000_SPID_SAFETY_AXIS_SETZEROPOS,  usRdWr:=0, pValue:= NIL, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) = 0 then
        sSafeRefState.CmdState := DRIVESAFETYIF_REFCMD_BUSY;
      end_if;
      
    end_if;

// *********************************************************************************************************
// ** Save the drive parameter in the ramex or in the file											                      	  **
// *********************************************************************************************************
    if bdSettings.bInitRamAxis = TRUE then
      SaveDrivePara();
      bdSettings.bInitRamAxis := FALSE;
    end_if;
    
    //write the actual datas to the parameter objects
    if bdSettings.bParaInit = FALSE & IsOnline() = TRUE then
      //check if we use absolute feedback or not
      if bdSettings.bNoAbsEnc = TRUE then
        //no absolute feedback -> get parameters from file or ram to set it to the parameterclasses
        LoadDrivePara();
      else
        //absolute feedback -> get parameters from drive and set it to the parameterclasses
        MDD2000CmdIntfc := _MDD2000READALL;
      end_if;
      bdSettings.bParaInit := TRUE;
    end_if;

// *********************************************************************************************************
// ** Handle reading encoder logic                        											                      	  **
// *********************************************************************************************************
    EncoderCylic();
    
// *********************************************************************************************************
// ** command interface for the drive                                           												  **
// *********************************************************************************************************
    MDD2000IntfProcess();
  end_if;
  
  state := READY;
  
END_FUNCTION


FUNCTION MDD2000_AxisBase::UpdateSvr
  
  if (IsOnlineFinished() = 1) then    
    bOnlineState := TRUE;
    //disable set online finished flag if diag mode is active
    if AxisState.DiagModeActive = FALSE then  
      bOnlineFinished := TRUE;
    end_if;  
  end_if;
  
  Online.read();
  ActPos.Read();
  ActSpeed.Read();
  ActCurrent.Read();
  StateWord.Read();
  AxError.Read();
  ActXw.Read();

END_FUNCTION


FUNCTION MDD2000_AxisBase::GetFeedBackType

  // Es wird zwischen Absolutwertgebern und sonstigen Rückführungssystem unterschieden.
  // Grund : bei Absolutwertgebern dürfen die Motorparameter nicht gesendet werden
  
  if bdSettings.bFeedbackSend = FALSE then
    // get the feedbacktype for the axis
    if bdSettings.bAxInUse = TRUE then
    
      AddASyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:=MDD2000_SPID_M_TYPE, usRdWr:=0, pValue:=NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this, usEntry:= MDD2000MNG_ENTRY_TYPE_DEFAULT, udTimeout:=0);

    else
      bdSettings.bGotFeedBackType := TRUE;
    end_if;

    bdSettings.bFeedBackSend := TRUE;
  end_if;
  
END_FUNCTION


FUNCTION MDD2000_AxisBase::SendDataToDrive

  
  CreateDefMPara(); // now check if an absolute encoder is used

  case  DriveInitType of
  
    _MDD2000_STDTABLE:       // Standard Table check if a UserTable is given or not

      DataOfStdTable(); 
    
    _MDD2000_L2TABLE:        // Lasal 2 Table check if the tables are available, 
                        // is there no Lasal2 table available, use the standard table (see step 0)
      DataOfL2table();
    
    _MDD2000_RAMEX:          // Data of the RamEx
      DataOfRamEx();
    
    _MDD2000_FILE:           // Data of the file
      DataOfFile();
  
  end_case;

END_FUNCTION



FUNCTION MDD2000_AxisBase::CreateDefMPara
  VAR
    tmpPara : CmdStruct;
    tmpResult : results;
  END_VAR

  case DriveAxisSet.GetFeedBackInfo() of
    
    0 : // When using absolutefeedback don't download the Motorparameters
      if bdSettings.bNoAbsEnc = TRUE then
        bdSettings.bSendMPara := TRUE;
      else
        bdSettings.bSendMPara := FALSE;
      end_if;
    
    1 : // When using absolutefeedback all parameters except the M-ROFF will be downloaded
      bdSettings.bSendMPara := TRUE;
      
      // Set what motorparameter we can't send to the drive when absolutefeedback is used
      if bdSettings.bNoAbsEnc = FALSE then
        MParaBuffer.NoItems := 1;
        MParaBuffer.MBuffer[0] := MDD2000MNG_LC2PARA_M_ROFF;  //Use old paramete format here
        
        tmpPara.uiCmd := MDD2000MNG_IF_CREATE_DEF_PARA_BASE;
        tmpPara.aPara[0] := MDD2000MNG_IF_CREATE_DEF_PARA_BASE_VER_1;
          
        tmpPara.aPara[1]  := 1;  // This is the command for avoid sending parameters
        tmpPara.aPara[2]  := (#MParaBuffer.MBuffer[0])$DINT;
        tmpPara.aPara[3]  := MParaBuffer.NoItems;
        tmpPara.aPara[4]  := usAxisIndex;
        DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult);
          
      end_if;

    99 : // When using absolutefeedback all motorparameters will be downloaded, including the M-ROFF
         // this should not be used!
        bdSettings.bSendMPara := TRUE;
         
    else
    
      // When using absolutefeedback, no motorparameters will be downloaded
      if bdSettings.bNoAbsEnc = TRUE then
        bdSettings.bSendMPara := TRUE;
      else
        bdSettings.bSendMPara := FALSE;
      end_if;

  end_case;

END_FUNCTION


FUNCTION MDD2000_AxisBase::DataOfStdTable 
  VAR
    TabAdress  : ^DINT;
    TabLength   : DINT;
    tmpPara : CmdStruct;
    tmpResult : results;
  END_VAR

  TabAdress := GetTabAdress(TabType:=0, bMotorPara:=bdSettings.bSendMPara, #TabLength);
  
  tmpPara.uiCmd           := MDD2000MNG_IF_SET_PARALIST;
  tmpPara.aPara[0]        := MDD2000MNG_IF_SET_PARALIST_VER_1;
  tmpPara.aPara[1]        := TO_DINT(usAxisIndex);
  tmpPara.aPara[2]$^DINT  := TabAdress;
  tmpPara.aPara[3]        := (TabLength)/5;
  DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult);
  
  bdSettings.bInitRamAxis := TRUE;
  
END_FUNCTION


FUNCTION MDD2000_AxisBase::DataOfL2table 
  VAR
    TabAdress  : ^DINT;
    TabLength   : DINT;
    tmpPara : CmdStruct;
    tmpResult : results;    
  END_VAR

  // check if a L2 table for the axis exists
  TabAdress := GetTabAdress(TabType:= 1, bMotorPara := bdSettings.bSendMPara, #TabLength);
  
  tmpPara.uiCmd           := MDD2000MNG_IF_SET_PARALIST;
  tmpPara.aPara[0]        := MDD2000MNG_IF_SET_PARALIST_VER_1  ;
  tmpPara.aPara[1]        := TO_DINT(usAxisIndex);
  tmpPara.aPara[2]$^DINT  := TabAdress;
  tmpPara.aPara[3]        := (TabLength)/5;
  DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult);
  
  bdSettings.bInitRamAxis := TRUE;
  
END_FUNCTION


FUNCTION MDD2000_AxisBase::DataOfRamEx 
  VAR
    udRamExLength	: UDINT;
  END_VAR

  // first check if RamEx Data is available
  udRamExLength := DriveAxisSet.GetRamExLength();
  if (udRamExLength > 0) & (MDD2000CmdIntfc <> _MDD2000URINIT) then 
    LoadDataRam();
  else
    // load the table info to the drive
    DataOfL2Table();
    bdSettings.bInitRamAxis := TRUE;
  end_if;

END_FUNCTION


FUNCTION MDD2000_AxisBase::DataOfFile
  VAR
    udRamFileLen	: UDINT;
  END_VAR

  // first check if RamEx Data is available
  udRamFileLen := DriveAxisSet.GetRamFileLen();
  if (udRamFileLen > 0) & (MDD2000CmdIntfc <> _MDD2000URINIT) then 
    LoadDataRam();
  else
    // load the table info to the drive
    DataOfL2Table();
    bdSettings.bInitRamAxis := TRUE;
  end_if;
  
END_FUNCTION


FUNCTION MDD2000_AxisBase::GetTabAdress
	VAR_INPUT
		TabType 	: DINT;
		bMotorPara 	: BOOL;
		pTabLength 	: ^DINT;
	END_VAR
	VAR_OUTPUT
		pTabAdress 	: ^DINT;
	END_VAR
  VAR
    tmpPara : CmdStruct;
    tmpResult : results;      	
  END_VAR

 
  if TabType = 0 then
    pTabAdress := DriveAxisSet.GetUserTab(bMotorPara, pTabLength);
  elsif TabType = 1 then
    pTabAdress := DriveAxisSet.GetL2Tab(this$^void,bMotorPara,pTabLength);
    if pTabAdress = NIL then
      pTabAdress := DriveAxisSet.GetUserTab(bMotorPara,pTabLength);
    end_if; 
  end_if;

  if pTabAdress = NIL then
  
    // errorcode setzen
    CmdState := ERROR;
    AxisState.NoParameter := TRUE;
    AxisState.NotInitialized := FALSE;
    bdSettings.bDriveInit := FALSE;
    bdSettings.bWaitInitFinished := FALSE;
    bdSettings.bDriveInitialized := TRUE;

    tmpPara.uiCmd := MDD2000MNG_IF_AXISINITFINISHED;
    tmpPara.aPara[0] := MDD2000MNG_IF_AXISINITFINISHED_VER_1;
    tmpPara.aPara[1] := TO_DINT(usAxisIndex);
    tmpPara.aPara[2] := MDD2000MNG_IF_AXISINITFINISHED_FUNCT;
    
    DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult);

    InitSSW := _MDD2000_IDLE;

  end_if;

END_FUNCTION


FUNCTION MDD2000_AxisBase::LoadDataRam
  VAR
    udCRC32		: UDINT;
    pHlp		: ^DINT;
    retcode		: BOOL;
    tmpPara : CmdStruct;
    tmpResult : results;
  END_VAR	
	// get actual ramex data
	
  retcode := FALSE;
  
  if DriveInitType = _MDD2000_RAMEX then
    retcode := DriveAxisSet.CpyRamExMem();
  elsif DriveInitType = _MDD2000_FILE then
    retcode := DriveAxisSet.CpyRamFileMem();
  end_if;
  
  if retcode = FALSE then
    return;
  end_if;
  // get the actual ptr of the memory
  pMDD2000Data$^void := DriveAxisSet.GetMemPtr();	

  if pMDD2000Data <> NIL then	
    // if the length is at least enough for the CRC
    if pMDD2000Data^.udLen > sizeof(UDINT) then
      // check the crc32 of the ramex
      udCRC32 := DriveAxisSet.CalcCRC32(pData:=(pMDD2000Data + sizeof(UDINT))$^UDINT, udLen:=pMDD2000Data^.udLen - sizeof(UDINT));
    end_if;
    
    // if the length is not ok or the CRC doesn't match
    if (pMDD2000Data^.udLen <= sizeof(UDINT)) | (udCRC32 <> pMDD2000Data^.udCRC32) then
      // invalid CRC32 or wrong length information
      DataOfL2Table();
      bdSettings.bInitRamAxis := TRUE;
      return;
    end_if;

    pHlp$DINT := pMDD2000Data$DINT + pMDD2000Data^.AxOffset; 
    
    // set the parameters
    tmpPara.uiCmd         := MDD2000MNG_IF_SET_PARALIST;
    tmpPara.aPara[0]      := MDD2000MNG_IF_SET_PARALIST_VER_1;
    tmpPara.aPara[1]      := TO_DINT(usAxisIndex);
    tmpPara.aPara[2]$^DINT:= pHlp;
    tmpPara.aPara[3]      := TO_DINT((pMDD2000Data^.AxLength/5));
    DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult);
    
  else
    // load the table info to the drive
    DataOfL2Table();
    bdSettings.bInitRamAxis := TRUE;	
  end_if;

END_FUNCTION


FUNCTION MDD2000_AxisBase::DriveInitReady
	VAR_OUTPUT
		retcode 	: BOOL;
	END_VAR
  VAR
    dTmpParaState       : DINT;
    tmpPara : CmdStruct;
    tmpResult : results;
  END_VAR
   
  retcode := FALSE;
  
  if bdSettings.bAxInUse then
    
    tmpPara.uiCmd     := MDD2000MNG_IF_GET_PARA_STATE;
    tmpPara.aPara[0]  := MDD2000MNG_IF_GET_PARA_STATE_VER_1;
    tmpPara.aPara[1]  := TO_DINT(usAxisIndex);
        
    if DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult) = READY then
      dTmpParaState := tmpResult.aData[4]$DINT;
    else
      dTmpParaState     := 1; //Init as not ready
    end_if;

    if dTmpParaState = 0 then
      retcode := TRUE;
    end_if;
  else
    retcode := TRUE;
  end_if;

END_FUNCTION


FUNCTION MDD2000_AxisBase::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;
  
  if SyncParaObject<>NIL then //Tell the SyncExtend class also the news
    SyncParaObject$^VirtualBase^.pSvrChCmd.NewInst(#UserPara, #UserResult);
  end_if;

END_FUNCTION


FUNCTION MDD2000_AxisBase::SavParaValue
	VAR_INPUT
		ParaNo 	: USINT;
		Value 	: DINT;
		bSavSRAM 	: BOOL;
	END_VAR
	VAR_OUTPUT
		retcode 	: BOOL;
	END_VAR
  VAR
    udOffset    : UDINT;
    pHlp        : ^DINT;
  END_VAR
  
  retcode := FALSE;
    
  // check the saving type
  case DriveInitType of
  
  _MDD2000_STDTABLE,
  _MDD2000_L2TABLE :
    
    retcode := TRUE;
    
  _MDD2000_RAMEX :
    
    // now check if the parameter exists
    udOffset := ParaNrExist(ParaNo); 
    // get the actual ptr of the memory
    pMDD2000Data$^void := DriveAxisSet.GetMemPtr();	
    
    if udOffset <> 16#FFFFFFFF then
      // entry is already available
      pHlp$UDINT := pMDD2000Data$UDINT + udOffset;
      pHlp^$DINT := Value;
      // now calculate the checksum
      pMDD2000Data^.udCRC32 := DriveAxisSet.CalcCRC32((pMDD2000Data + sizeof(UDINT))$^UDINT, pMDD2000Data^.udLen - sizeof(UDINT));
      if bSavSRAM = TRUE then
        // save the new value
        DriveAxisSet.SaveRamExData(pData:=#Value, udLen:=sizeof(DINT), udOffset:=udOffset);
        // save the new chksum
        DriveAxisSet.SaveRamExData(pData:=#pMDD2000Data^.udCRC32, udLen:=sizeof(DINT), udOffset:=0);
      end_if;
    else
      // new entry in the buffer
      if InsNewParaNr(ParaNo, Value) = TRUE then
    
        // get the actual ptr of the memory
        pMDD2000Data$^void := DriveAxisSet.GetMemPtr();	
        
        // now calculate the checksum
        pMDD2000Data^.udCRC32 := DriveAxisSet.CalcCRC32((pMDD2000Data + sizeof(UDINT))$^UDINT, pMDD2000Data^.udLen - sizeof(UDINT));
        if bSavSRAM = TRUE then
          DriveAxisSet.SaveRamExData(pData:= pMDD2000Data, udLen:= pMDD2000Data^.udLen, udOffset:= 0);
        end_if;
      end_if;
    end_if;
    
  _MDD2000_FILE :
    
    // now check if the parameter exists
    udOffset := ParaNrExist(ParaNo);
    // get the actual ptr of the memory
    pMDD2000Data$^void := DriveAxisSet.GetMemPtr();	
    
    if udOffset <> 16#FFFFFFFF then
      // entry is already available
      pHlp$UDINT := pMDD2000Data$UDINT + udOffset;
      pHlp^$DINT := Value;
      // now calculate the checksum
      pMDD2000Data^.udCRC32 := DriveAxisSet.CalcCRC32((pMDD2000Data + sizeof(UDINT))$^UDINT, pMDD2000Data^.udLen - sizeof(UDINT));
      if bSavSRAM = TRUE then
        // save the new value
        DriveAxisSet.SaveRamFileData(pData:= #Value, udLen:= sizeof(DINT), udOffset:= udOffset);
        // save the new chksum
        DriveAxisSet.SaveRamFileData(pData:= #pMDD2000Data^.udCRC32, udLen:= sizeof(DINT), udOffset:= 0);
      end_if;
    else
      // new entry in the buffer
      if InsNewParaNr(ParaNo, Value) = TRUE then
    
        // get the actual ptr of the memory
        pMDD2000Data$^void := DriveAxisSet.GetMemPtr();	
        
        // now calculate the checksum
        pMDD2000Data^.udCRC32 := DriveAxisSet.CalcCRC32((pMDD2000Data + sizeof(UDINT))$^UDINT, pMDD2000Data^.udLen - sizeof(UDINT));
        if bSavSRAM = TRUE then
          DriveAxisSet.SaveRamFileData(pData:= pMDD2000Data, udLen:= pMDD2000Data^.udLen, udOffset:= 0);
        end_if;
      end_if;
    end_if;
  end_case;
  
END_FUNCTION


FUNCTION MDD2000_AxisBase::ParaNrExist
	VAR_INPUT
		ParaNr 	: USINT;
	END_VAR
	VAR_OUTPUT
		udOffset 	: UDINT;
	END_VAR
  VAR
    pHlp    : ^DINT;
    x       : UDINT;
  END_VAR
  
  udOffset := 16#FFFFFFFF;
  // get the actual ptr of the memory
  pMDD2000Data$^void := DriveAxisSet.GetMemPtr();

  if bdSettings.bAxInUse = TRUE then
    pHlp$DINT := pMDD2000Data$DINT + pMDD2000Data^.AxOffset;
    x := 0;
    while x < pMDD2000Data^.AxLength$UDINT do
      if pHlp^$USINT = ParaNr then
        udOffset := pMDD2000Data^.AxOffset$UDINT + x + sizeof(USINT);
        return;
      end_if;
      pHlp += MDD2000MNG_PARAENTRYSIZE;
      x += MDD2000MNG_PARAENTRYSIZE;
    end_while;
  end_if;
  
END_FUNCTION


FUNCTION MDD2000_AxisBase::InsNewParaNr
	VAR_INPUT
		ParaNr 	: USINT;
		ParaValue 	: DINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: BOOL;
	END_VAR
  VAR
    pMove     : ^DINT;
    udLen     : UDINT;
  END_VAR
  
  retcode := FALSE;
  
  // get the actual ptr of the memory
  pMDD2000Data$^void := DriveAxisSet.GetMemPtr();	
  
  if (pMDD2000Data^.udLen + MDD2000MNG_PARAENTRYSIZE) >= MDD2000MNG_MAXMEM then
    return;
  end_if;
  
  if bdSettings.bAxInUse = TRUE then
    pMove$DINT := pMDD2000Data$DINT + pMDD2000Data^.AxOffset + pMDD2000Data^.AxLength$DINT;
    udLen := pMDD2000Data^.udLen - (pMove$UDINT - pMDD2000Data$UDINT); 
    _memmove((pMove + MDD2000MNG_PARAENTRYSIZE)$^void, pMove$^void, udLen);
    pMove^$USINT := ParaNr;
    pMove += sizeof(USINT);
    pMove^$DINT := ParaValue;
    pMDD2000Data^.udLen += MDD2000MNG_PARAENTRYSIZE;
    pMDD2000Data^.AxLength += MDD2000MNG_PARAENTRYSIZE;
    
    retcode := TRUE;
  end_if;
  
END_FUNCTION


FUNCTION MDD2000_AxisBase::ChkFb
	VAR_INPUT
		FbType 	: DINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: BOOL;
	END_VAR
  VAR
    FbInfo  : DINT;
  END_VAR
  
  retcode := TRUE;
  // get the first Byte of the Feedback info
  FbInfo := FbType AND 16#FF;
  
  case FbInfo of
    0 : // Resolver
        
    1 : // Resolver with multi turn feedback
    
    2 : // Endat
      retcode := FALSE;
      
    3 : // Hiperface
      retcode := FALSE;
      
    4 : // Sin/Cos Encoder
      
    5 : // sensorless
    
    6 : // incremental encoder
    
    7 : // EnDat with Drive multi turn extension
      retcode := FALSE;
      
    15 :// HiperfaceDLS
      
      // The MDD2000 supports the reading of encoder parameters for HiperfaceDSL encoders starting with FW version v1.30.      
      if ( abs(FwVersionInt) >= MDD2000MNGBASE_FWVERSION_HIPERFACEDSL) then
        retcode := FALSE;
      end_if;
    
  end_case;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::IsOnline
	VAR_OUTPUT
		retcode 	: BOOL;
	END_VAR
  VAR
    tmpPara : CmdStruct;
    tmpResult : results;        
  END_VAR
  
  //Check if manager is online
  tmpPara.uiCmd := MDD2000MNG_IF_IS_ONLINE;
  tmpPara.aPara[0] := MDD2000MNG_IF_IS_ONLINE_VER_1;
  DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult);
  retcode := to_bool(tmpResult.aData[4]$DINT);
  
END_FUNCTION


FUNCTION VIRTUAL MDD2000_AxisBase::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) 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);
        bdSettings.bAxSetPara := TRUE;
        retcode := TRUE;
        exit;
      
      end_if;
    
    end_for;
    
    if sParaObjectList[idx].pObject <> pThis then
      HWC_LogPrintf(this,"@08CD (MDD2000_AxisBase::AddParaObjects) Failed to add parameter object with index %d and this pointer %x" , #Index, #pthis$DINT);
    end_if;
    
  else
    HWC_LogPrintf(this,"@08CD (MDD2000_AxisBase::AddParaObjects) Failed to add parameter object with index %d and this pointer %x" , #Index, #pthis$DINT);
  end_if;
  

END_FUNCTION


FUNCTION VIRTUAL MDD2000_AxisBase::SetSynchronPara
  VAR
  	x           : DINT;
    SetAVALRT   : HSINT;
    tmpPara     : CmdStruct;
    tmpResult   : results;
    WrLen       : DINT;
    MaxParaIdx  : DINT;
  END_VAR
  
  MaxParaIdx := 0;
  
  tmpPara.uiCmd := MDD2000MNG_IF_GET_AXIS_RD_WR_PTR;
  tmpPara.aPara[0] := MDD2000MNG_IF_GET_AXIS_RD_WR_PTR_VER_1;
  tmpPara.aPara[1] := 1; //0 .. get Read pointer, 1 .. get write pointer
  tmpPara.aPara[2] := TO_DINT(usAxisIndex);
  
  if DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult) = READY then
    // Zeiger auf die Sollwerte von der Struktur t_WriteValuePtr
    SetValuePtr$^void := tmpResult.aData[4]$^void;
    
    WrLen := tmpResult.aData[8]$DINT;
    
    if WrLen > sizeof(DINT) then
    
      MaxParaIdx := (WrLen / sizeof(DINT)); // SetValues are 1 Byte vals
      
      if MaxParaIdx > sizeof(SetValues) then  
        MaxParaIdx := sizeof(SetValues);  // Limit to mem size
      end_if;
      
      MaxParaIdx -= 1;  // -1 because we need the index
      
    end_if;

  end_if;
  
  for x := MaxParaIdx to 0 by -1 do

    SetAVALRT:=SetValues[x]; //A-VALRT values
    
    case SetAVALRT of
    
      16#01: //-> Current setpoint in mA
      
        SyncPara.SetCurrent.size      := 4;
        SyncPara.SetCurrent.ptr       := #SetValuePtr^.a_SyncValues[x];
        SyncPara.SetCurrent.userinfo  := 0;
        
      16#02: //-> Velocity set point in rpm 
      
        SyncPara.SetSpeed.size      := 4;
        SyncPara.SetSpeed.ptr       := #SetValuePtr^.a_SyncValues[x];
        SyncPara.SetSpeed.userinfo  := 0;
        
      16#03: //-> Position set point in counts 
      
        SyncPara.SetPos.size      := 4;
        SyncPara.SetPos.ptr       := #SetValuePtr^.a_SyncValues[x];
        SyncPara.SetPos.userinfo  := 0;
        
      16#04: //-> Speed feed forward of the position controller in counts per cycle time
      
        SyncPara.SetSpeed.size      := 4;
        SyncPara.SetSpeed.ptr       := #SetValuePtr^.a_SyncValues[x];
        SyncPara.SetSpeed.userinfo  := 0;
      
      16#05: //-> controlword + Current setpoint in cA 
      
        SyncPara.SetCurrent.size      := 2;
        SyncPara.SetCurrent.ptr       := #SetValuePtr^.a_SyncValues[x];
        SyncPara.SetCurrent.userinfo  := 1;
        
        SyncPara.ControlWord.size     := 2;
        SyncPara.ControlWord.ptr      := #SetValuePtr^.a_SyncValues[x] + sizeof(UINT);
        SyncPara.ControlWord.userinfo := 0;
        
        SyncPara.SetTorque.size     := 2;
        SyncPara.SetTorque.ptr      := #SetValuePtr^.a_SyncValues[x] + sizeof(UINT);
        SyncPara.SetTorque.userinfo := 0;
        
      16#06: //-> controlword + Velocity set point in rpm 
      
        SyncPara.SetSpeed.size      := 2;
        SyncPara.SetSpeed.ptr       := #SetValuePtr^.a_SyncValues[x];
        SyncPara.SetSpeed.userinfo  := 0;
        
        SyncPara.ControlWord.size     := 2;
        SyncPara.ControlWord.ptr      := #SetValuePtr^.a_SyncValues[x] + sizeof(UINT);
        SyncPara.ControlWord.userinfo := 0;
        
        SyncPara.SetTorque.size     := 2;
        SyncPara.SetTorque.ptr      := #SetValuePtr^.a_SyncValues[x] + sizeof(UINT);
        SyncPara.SetTorque.userinfo := 0;
        
      16#07: //-> controlword + Speed feed forward of the position controller in counts per cycle time 
      
        SyncPara.SetSpeed.size      := 2;
        SyncPara.SetSpeed.ptr       := #SetValuePtr^.a_SyncValues[x];
        SyncPara.SetSpeed.userinfo  := 0; 
        
        SyncPara.ControlWord.size     := 2;
        SyncPara.ControlWord.ptr      := #SetValuePtr^.a_SyncValues[x] + sizeof(UINT);
        SyncPara.ControlWord.userinfo := 0;
        
        SyncPara.SetTorque.size := 2;
        SyncPara.SetTorque.ptr := #SetValuePtr^.a_SyncValues[x] + sizeof(UINT);
        SyncPara.SetTorque.userinfo := 0;
        
      16#08: //-> Velocity set point in mrpm 
        
        SyncPara.SetSpeed.size      := 4;
        SyncPara.SetSpeed.ptr       := #SetValuePtr^.a_SyncValues[x];
        SyncPara.SetSpeed.userinfo  := 0; 
        
      16#09: //32 bit controlword
        
        SyncPara.ControlWord.size     := 2;
        SyncPara.ControlWord.ptr      := #SetValuePtr^.a_SyncValues[x] + sizeof(UINT);
        SyncPara.ControlWord.userinfo := 1; 
        
        SyncPara.SetTorque.size     := 2;
        SyncPara.SetTorque.ptr      := #SetValuePtr^.a_SyncValues[x];
        SyncPara.SetTorque.userinfo := 1; 
        
      16#0D: //13 -> controlword + Current feed forward in cA 
      
        SyncPara.SetCurrent.size      := 2;
        SyncPara.SetCurrent.ptr       := #SetValuePtr^.a_SyncValues[x];
        SyncPara.SetCurrent.userinfo  := 1;
        
        SyncPara.ControlWord.size     := 2;
        SyncPara.ControlWord.ptr      := #SetValuePtr^.a_SyncValues[x] + sizeof(UINT);
        SyncPara.ControlWord.userinfo := 0;
        
        SyncPara.SetTorque.size     := 2;
        SyncPara.SetTorque.ptr      := #SetValuePtr^.a_SyncValues[x] + sizeof(UINT);
        SyncPara.SetTorque.userinfo := 0;
                
      16#1B: //27-> PWM setvalue for G-MODE=7 + controlword
        //PWM from -1000 to 1000 for -100% to 100% is preset via SetSpeed
        SyncPara.SetSpeed.size      := 2;
        SyncPara.SetSpeed.ptr       := #SetValuePtr^.a_SyncValues[x];
        SyncPara.SetSpeed.userinfo  := 1; 

        SyncPara.ControlWord.size     := 2;
        SyncPara.ControlWord.ptr      := #SetValuePtr^.a_SyncValues[x] + sizeof(UINT);
        SyncPara.ControlWord.userinfo := 0;

        SyncPara.SetTorque.size     := 2;
        SyncPara.SetTorque.ptr      := #SetValuePtr^.a_SyncValues[x] + sizeof(UINT);
        SyncPara.SetTorque.userinfo := 0;
                
    end_case;

  end_for;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::SetPos::Write
	VAR_INPUT
		input (EAX) 	: DINT;
	END_VAR
	VAR_OUTPUT
		result (EAX) 	: DINT;
	END_VAR
  
  if (SyncPara.SetPos.ptr <> NIL) & bOnlineFinished then
    SetPos:=input;
    SyncPara.SetPos.ptr^:=input; 
  end_if;
  
 	result := SetPos;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::SetSpeed::Write
	VAR_INPUT
		input (EAX) 	: DINT;
	END_VAR
	VAR_OUTPUT
		result (EAX) 	: DINT;
	END_VAR

  if bOnlineFinished then
    SetSpeed := Write_SetSpeed(input);  //write value to PDO data, and set possible statusflags.
  end_if;
  result := SetSpeed;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::SetCurrent::Write
	VAR_INPUT
		input (EAX) 	: DINT;
	END_VAR
	VAR_OUTPUT
		result (EAX) 	: DINT;
	END_VAR

  if (SyncPara.SetCurrent.ptr <> NIL) & bOnlineFinished then
    SetCurrent:=input;
    if (SyncPara.SetCurrent.size=4) then
      SyncPara.SetCurrent.ptr^:=input;
    elsif (SyncPara.SetCurrent.size=2) then
      if SyncPara.SetCurrent.userinfo = 1 then
        SyncPara.SetCurrent.ptr^$INT:=to_int(input / 10); //because we always get mA and in one case we must send cA
      else
        SyncPara.SetCurrent.ptr^$INT:=to_int(input); //32-Bit-Steuerwort
      end_if;
    end_if;
  end_if;
  
  result := SetCurrent;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::ControlWord::Write
	VAR_INPUT
		input (EAX) 	: DS402_Control;
	END_VAR
	VAR_OUTPUT
		result (EAX) 	: DS402_Control;
	END_VAR
  VAR
  	cBuffer : BDINT; //ControlWord Buffer
  END_VAR
  
  cBuffer := 0; // local variable 
  
  if (SyncPara.ControlWord.ptr <> NIL) & bOnlineFinished then
    
    if (SyncPara.ControlWord.userinfo=0) then //normal controlword
            
      cBuffer.1  :=input.EnableOperation;   //DRIVE ENABLE
      cBuffer.2  :=input.ResetFault;        //FAULT RESET
      cBuffer.3  :=input.ManufactureSpec1;  //AMODE2
      cBuffer.4  :=input.ManufactureSpec2;  //KFBRW3
      cBuffer.5  :=input.ManufactureSpec4;  //Output1
      cBuffer.6  :=input.ManufactureSpec5;  //Output2
      cBuffer.7  :=input.ManufactureSpec3;  //KBRAKE
      cBuffer.8  :=input.Reserved1;         //ECHO
      cBuffer.9  :=input.OperationModeSpec1;//SINGLE CAPTURE
      
      cBuffer:=TorqueCalculation(cBuffer, AxTorqueControl); //cBuffer -> we must add TorqueControl
      
      SyncPara.ControlWord.ptr^$INT:=to_int(cBuffer);
      
    elsif(SyncPara.ControlWord.userinfo=1)then
      
      cBuffer.1 :=input.SwitchOn;   
      cBuffer.2 :=input.EnableVoltage;        
      cBuffer.3 :=input.QuickStop;  
      cBuffer.4 :=input.EnableOperation;    //DRIVE ENABLE
      cBuffer.5 :=input.OperationModeSpec1;  
      cBuffer.6 :=input.OperationModeSpec2; 
      cBuffer.7 :=input.OperationModeSpec3;  
      cBuffer.8 :=input.ResetFault;         //FAULT RESET
      cBuffer.9 :=input.Halt;
      cBuffer.10 :=input.Reserved1;
      cBuffer.11 :=input.Reserved2;
      cBuffer.12 :=input.ManufactureSpec1;  //AMODE2
      cBuffer.13 :=input.ManufactureSpec2;  //KFBRW3
      cBuffer.14 :=input.ManufactureSpec3;  //KBRAKE
      cBuffer.15 :=input.ManufactureSpec4;  //Output1
      cBuffer.16 :=input.ManufactureSpec5;  //Output2
      
      SyncPara.ControlWord.ptr^$INT:=to_int(cBuffer);
      
    end_if;
    
  end_if;
  
  ControlWord := input;
  result := ControlWord;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::AxEnable::Write
	VAR_INPUT
		input (EAX) 	: DINT;
	END_VAR
	VAR_OUTPUT
		result (EAX) 	: DINT;
	END_VAR
  
  if (SyncPara.ControlWord.ptr <> NIL) & bOnlineFinished then
    AxEnable:= Write_Enable( input AND 1 );
  end_if;
  result:=AxEnable;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::AxErrorQuit::Write
	VAR_INPUT
		input (EAX) 	: DINT;
	END_VAR
	VAR_OUTPUT
		result (EAX) 	: DINT;
	END_VAR
  
  if SyncPara.ControlWord.ptr & (FirstErrorReset = 0) & bOnlineFinished then

    if (AxError = 1) then

      ErrorQuitHandling(input);

    end_if;
    
  end_if;
  
  result := AxErrorQuit;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::AxTorqueControl::Write
	VAR_INPUT
		input (EAX) 	: UDINT;
	END_VAR
	VAR_OUTPUT
		result (EAX) 	: UDINT;
	END_VAR

  if (SyncPara.SetTorque.ptr <> NIL) & bOnlineFinished then
    SetAxTorque(input);    
  end_if;
  
  result := AxTorqueControl;
  
END_FUNCTION


FUNCTION MDD2000_AxisBase::TorqueCalculation
	VAR_INPUT
		cBuffer 	: BDINT;
		input 	: UDINT;
	END_VAR
	VAR_OUTPUT
		result 	: BDINT;
	END_VAR
  VAR
  	IReduce   : UDINT;
  END_VAR

  IReduce := ((MDD2000_AXISBASE_TORQUE_LIMITATION_VALUE - input) * 63) / MDD2000_AXISBASE_TORQUE_LIMITATION_VALUE; // calculate the bits for the current reducing
  
  IReduce := IReduce SHL 10 ;
  cBuffer := cBuffer AND 16#3FF;
  cBuffer+=IReduce$BDINT;
      
  result:=cBuffer;
      
END_FUNCTION


//****************************************************************************************************\\
//**################################################################################################**\\
//**************************** everything for getting the actual values!! ****************************\\
//**################################################################################################**\\
//****************************************************************************************************\\

FUNCTION VIRTUAL MDD2000_AxisBase::GetSynchronPara
  VAR
  	x           : DINT;
    SetAVALTT   : HSINT;
    tmpPara     : CmdStruct;
    tmpResult   : results;
    RdLen       : DINT;
    MaxParaIdx  : DINT;
  END_VAR
  
  tmpPara.uiCmd := MDD2000MNG_IF_GET_AXIS_RD_WR_PTR;
  tmpPara.aPara[0] := MDD2000MNG_IF_GET_AXIS_RD_WR_PTR_VER_1;
  tmpPara.aPara[1] := 0; //0 .. get Read pointer, 1 .. get write pointer
  tmpPara.aPara[2] := TO_DINT(usAxisIndex);
  
  if DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult) = READY then
    // Zeiger auf die Sollwerte von der Struktur t_ReadValuePtr
    ActValuePtr$^void := tmpResult.aData[4]$^void;
    
    RdLen := tmpResult.aData[8]$DINT;
    
    if RdLen > sizeof(DINT) then
      
      MaxParaIdx := (RdLen / sizeof(DINT)); // ActValues are 1 Byte vals
      
      if MaxParaIdx > sizeof(ActValues) then  
        MaxParaIdx := sizeof(ActValues);  // Limit to mem size
      end_if;
      
      MaxParaIdx -= 1;  // -1 because we need the index
      
    end_if;
    
  end_if;
  
  for x := MaxParaIdx to 0 by -1 do
    SetAVALTT:=ActValues[x];
      
    case SetAVALTT of
      
      16#01: //1 -> I-N
        SyncPara.ActSpeed.ptr       := #ActValuePtr^.a_SyncValues[x];
        SyncPara.ActSpeed.size      := 4;
        SyncPara.ActSpeed.userinfo  := 0;
      
      16#02: //2 -> I-NFILT
        SyncPara.ActSpeed.ptr       := #ActValuePtr^.a_SyncValues[x];
        SyncPara.ActSpeed.size      := 4;
        SyncPara.ActSpeed.userinfo  := 0;
                  
//      16#03:
//      
//        SyncPara.SetPos
                 
      16#05: //5 -> I-IQ
        SyncPara.ActCurrent.ptr      := #ActValuePtr^.a_SyncValues[x];
        SyncPara.ActCurrent.size     := 4; 
        SyncPara.ActCurrent.userinfo := 0;
      
      16#07: //7 -> I-POS
        SyncPara.ActPos.ptr       := #ActValuePtr^.a_SyncValues[x];
        SyncPara.ActPos.size      := 4;
        SyncPara.ActPos.userinfo  := 0;
      
      16#09: //9 -> I-PE 
        SyncPara.Xw.ptr       := #ActValuePtr^.a_SyncValues[x];
        SyncPara.Xw.size      := 4;
        SyncPara.Xw.userinfo  := 0;
        
      16#0A: //10 -> I-IQ + stateword (cA!)
        SyncPara.ActCurrent.ptr       := #ActValuePtr^.a_SyncValues[x]; 
        SyncPara.ActCurrent.size      := 2;
        SyncPara.ActCurrent.userinfo  := 1;
        
        SyncPara.StateWord.ptr      := #ActValuePtr^.a_SyncValues[x]+sizeof(UINT); 
        SyncPara.StateWord.size     := 2;
        SyncPara.StateWord.userinfo := 0;
      
      16#0E: //14 -> I-PE + stateword
        SyncPara.Xw.ptr       := #ActValuePtr^.a_SyncValues[x];
        SyncPara.Xw.size      := 2;
        SyncPara.Xw.userinfo  := 0;
        
        SyncPara.StateWord.ptr      := #ActValuePtr^.a_SyncValues[x]+sizeof(UINT);
        SyncPara.StateWord.size     := 2;
        SyncPara.StateWord.userinfo := 0;
      
      16#14: //20 -> Current in Promille + stateword
        SyncPara.ActCurrent.ptr       := #ActValuePtr^.a_SyncValues[x];
        SyncPara.ActCurrent.size      := 2;
        SyncPara.ActCurrent.userinfo  := 0;
        
        SyncPara.StateWord.ptr      := #ActValuePtr^.a_SyncValues[x]+sizeof(UINT);
        SyncPara.StateWord.size     := 2;
        SyncPara.StateWord.userinfo := 1;

      16#15: //21 -> I-POS 2 position of optional encoder
        if (SyncPara.ActPos.ptr = NIL) then
          SyncPara.ActPos.ptr       := #ActValuePtr^.a_SyncValues[x];
          SyncPara.ActPos.size      := 4;
          SyncPara.ActPos.userinfo  := 0;
        end_if;

      16#17: //23 -> digital inputs + stateword
        SyncPara.DigInputs.ptr      := #ActValuePtr^.a_SyncValues[x];
        SyncPara.DigInputs.size     := 8; //no inputs
        SyncPara.DigInputs.userinfo := 0;
        
        SyncPara.StateWord.ptr      := #ActValuePtr^.a_SyncValues[x]+sizeof(UINT);
        SyncPara.StateWord.size     := 2;
        SyncPara.StateWord.userinfo := 0;
        
      16#1C: //28 -> MultiTurn Pos VSDC151
        SyncPara.ActPos.ptr       := #ActValuePtr^.a_SyncValues[x];
        SyncPara.ActPos.size      := 4;
        SyncPara.ActPos.userinfo  := 0;
        
      16#28: //40 -> Safety Controlword + Safety Statusword
        SyncPara.SafeControlWord.ptr      := #ActValuePtr^.a_SyncValues[x];
        SyncPara.SafeControlWord.size     := 2;
        SyncPara.SafeControlWord.userinfo := 0;
        
        SyncPara.SafeStateWord.ptr      := #ActValuePtr^.a_SyncValues[x] + sizeof(UINT);
        SyncPara.SafeStateWord.size     := 2;
        SyncPara.SafeStateWord.userinfo := 0;
        
      16#29: //41 -> Safety Position
        SyncPara.SafePos.ptr      := #ActValuePtr^.a_SyncValues[x];
        SyncPara.SafePos.size     := 4;
        SyncPara.SafePos.userinfo := 0;
      
      16#2A: //42 -> Safety Velocity
        SyncPara.SafeSpeed.ptr      := #ActValuePtr^.a_SyncValues[x];
        SyncPara.SafeSpeed.size     := 4;
        SyncPara.SafeSpeed.userinfo := 0;
      
      16#2B: //43 -> Safety Acceleration
        SyncPara.SafeAcceleration.ptr       := #ActValuePtr^.a_SyncValues[x];
        SyncPara.SafeAcceleration.size      := 4;
        SyncPara.SafeAcceleration.userinfo  := 0;
      
      16#2C: //44 -> Safety Current
        SyncPara.SafeCurrent.ptr      := #ActValuePtr^.a_SyncValues[x];
        SyncPara.SafeCurrent.size     := 4;
        SyncPara.SafeCurrent.userinfo := 0;
        
    end_case;

  end_for;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::ActPos::Read
	VAR_OUTPUT
		output (EAX) 	: DINT;
	END_VAR

  if (SyncPara.ActPos.ptr <> NIL) & bOnlineFinished then
    ActPos:=SyncPara.ActPos.ptr^;
  else
    ActPos:=0;
  end_if;
  
  output := ActPos;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::ActSpeed::Read
	VAR_OUTPUT
		output (EAX) 	: DINT;
	END_VAR
  
  if (SyncPara.ActSpeed.ptr <> NIL) & bOnlineFinished then
    ActSpeed:=SyncPara.ActSpeed.ptr^;
  else
    ActSpeed:=0;
  end_if;
  
  output := ActSpeed;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::ActCurrent::Read
	VAR_OUTPUT
		output (EAX) 	: DINT;
	END_VAR

  if (SyncPara.ActCurrent.ptr <> NIL) & bOnlineFinished then
    if SyncPara.ActCurrent.size = 4 then
      ActCurrent:=SyncPara.ActCurrent.ptr^;
    
    elsif SyncPara.ActCurrent.size = 2 then
      if SyncPara.ActCurrent.userinfo = 1 then 
        ActCurrent := to_dint(SyncPara.ActCurrent.ptr^$INT) * 10; //because we want to see mA and not cA
      else
        ActCurrent := to_dint(SyncPara.ActCurrent.ptr^$INT); 
      end_if;
    end_if;
  else
    ActCurrent:=0;
  end_if;

  output := ActCurrent;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::ActXw::Read
	VAR_OUTPUT
		output (EAX) 	: DINT;
	END_VAR
  
  if (SyncPara.Xw.ptr <> NIL) & bOnlineFinished then
    if SyncPara.Xw.size = 4 then
      ActXw:=SyncPara.Xw.ptr^;
    elsif SyncPara.Xw.size = 2 then
      ActXw := to_dint(SyncPara.Xw.ptr^$INT); 
    end_if;
  else
    ActXw:=0;
  end_if;

  output := ActXw;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::StateWord::Read
	VAR_OUTPUT
		output (EAX) 	: DS402_State;
	END_VAR
  VAR
  	sBuffer : BDINT; //StateWord Buffer
  END_VAR

  if (SyncPara.StateWord.ptr <> NIL) & bOnlineFinished then
    sBuffer := SyncPara.StateWord.ptr^$BDINT; //normales Statuswort

    if (SyncPara.StateWord.userinfo=0) then
      StateWord.ReadyToSwitchOn     :=  sBuffer.1;  //READY TO SWITCH ON 
      StateWord.SwitchedOn          :=  sBuffer.2;  //EXT ENABLE LOCKED&ENABLE
      StateWord.OperationEnabled    :=  sBuffer.3;  //OPERATION_ENABLE
      StateWord.Fault               :=  sBuffer.4;  //ERROR
      StateWord.Warning             :=  sBuffer.5;  //WARNING
      StateWord.Remote              :=  sBuffer.6;  //PLL Bit0
      StateWord.VoltageEnabled      :=  sBuffer.7;  //PLL Bit1
      StateWord.SwitchOnDisabled    :=  sBuffer.8;  //ECHO
      StateWord.OperationModeSpec1  :=  sBuffer.9;  //Capture Toggle Bit (I-CAP)
      StateWord.OperationModeSpec2  :=  sBuffer.10; //Capture 4 Toggle Bit (I-CAP4)
      StateWord.InternalLimitActive :=  sBuffer.11; //MULTITURN REVOLUTION ERROR 
      StateWord.ManufactureSpec1    :=  sBuffer.12; //Digital Input 1
      StateWord.ManufactureSpec2    :=  sBuffer.13; //Digital Input 2
      StateWord.ManufactureSpec3    :=  sBuffer.14; //Digital Input 3
      StateWord.QuickStop           :=  sBuffer.15; //Digital Input 4
      StateWord.TargetReached       :=  sBuffer.16; //Digital Input 5
      
    elsif(SyncPara.StateWord.userinfo=1) then
      StateWord.ReadyToSwitchOn     :=  sBuffer.1;  //READY TO SWITCH ON 
      StateWord.SwitchedOn          :=  sBuffer.2;  //EXT.ENABLE=LOCKED&ENABLE
      StateWord.OperationEnabled    :=  sBuffer.3;  //OPERATION_ENABLE
      StateWord.Fault               :=  sBuffer.4;  //ERROR
      StateWord.Warning             :=  sBuffer.5;  //WARNING
      StateWord.QuickStop           :=  sBuffer.6;  
      StateWord.SwitchOnDisabled    :=  sBuffer.7;  
      StateWord.VoltageEnabled      :=  sBuffer.8; 
      StateWord.ManufactureSpec1    :=  sBuffer.9;  
      StateWord.ManufactureSpec2    :=  sBuffer.10; 
      StateWord.TargetReached       :=  sBuffer.11; 
      StateWord.ManufactureSpec3    :=  sBuffer.12; 
      StateWord.OperationModeSpec1  :=  sBuffer.13; 
      StateWord.OperationModeSpec2  :=  sBuffer.14; 
      StateWord.Remote              :=  sBuffer.15; //PLL nicht eingerastet
      StateWord.InternalLimitActive :=  sBuffer.16; //MULTITURN REVOLUTION ERROR
    end_if;
   
  else
    StateWord := 0;
  end_if;

  output := StateWord;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::AxError::Read
	VAR_OUTPUT
		output (EAX) 	: DINT;
	END_VAR

  //Error of Axis gets only shown, if Axis is Online
  if bOnlineFinished then
    AxError := GetAxError();
  else
    AxError := 0;
  end_if;

  output := AxError;

END_FUNCTION


FUNCTION MDD2000_AxisBase::LoadDrivePara
  VAR
    pTabAdress : ^DINT;
    TabLength   : DINT;
  END_VAR

  // load the parameter data to the para objects
  case DriveInitType of

    _MDD2000_STDTABLE :
      
     pTabAdress := GetTabAdress(TabType:= 0, bdSettings.bSendMPara, #TabLength);
     SetListToParObj(pData:= (pTabAdress)$^DINT, udLen:=TabLength$UDINT);
      

    _MDD2000_L2TABLE :	
    // load the data of the table
      pTabAdress := GetTabAdress(TabType:= 1, bdSettings.bSendMPara, #TabLength);
      SetListToParObj(pData:= (pTabAdress)$^DINT, udLen:=TabLength$UDINT);
    
    _MDD2000_RAMEX,	
    _MDD2000_FILE :	
      pMDD2000Data$^void := DriveAxisSet.GetMemPtr();	
      if pMDD2000Data <> NIL then
        // load the data of the memory
        SetListToParObj(pData:= (pMDD2000Data$DINT + pMDD2000Data^.AxOffset)$^DINT, udLen:=pMDD2000Data^.AxLength);
      end_if;
    
  end_case;
  
END_FUNCTION


FUNCTION MDD2000_AxisBase::SetListToParObj
	VAR_INPUT
		pData 	: ^DINT;
		udLen 	: UDINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: BOOL;
	END_VAR
  VAR
    pHlp          : ^DINT;
    x             : UDINT;
    pThisNewInst  : ^void;
    usParaNr      : USINT;
    ParaValue     : DINT;
    UserPara      : CmdStruct;
    UserResult    : Results;
    hIndex        : HINT;
    hsSubIndex    : HSINT;
  END_VAR
  
  retcode := FALSE;
    
  if (bdSettings.bAxSetPara = FALSE) | (pData = NIL) then
    return;
  end_if;
    
  x := 0;
  pHlp := pData;
    
  while x < udLen do
    
    usParaNr := pHlp^$USINT;
    pHlp += sizeof(USINT);
    x += sizeof(USINT);
    
    //Convert to DS402 parameter format
    ConvertLC2ParaFormatToDS402Format(ParaNo:=to_dint(usParaNr), phParaIndex:=#hIndex, phsParaSubIndex:=#hsSubIndex);
    
    //Get this pointer of the parameterclass we have to refresh
    pThisNewInst := GetThisPointerOfParaClassViaParam(hIndex:=hIndex, hsSubIndex:=hsSubIndex);   
          
    ParaValue := pHlp^$DINT;
    
    if pThisNewInst <> NIL then
      UserPara.uiCmd    := MDD2000MNG_IF_REFRESH_PARA_OBJECTS;
      UserPara.aPara[0] := MDD2000MNG_IF_REFRESH_PARA_OBJECTS_VER_1;
      UserPara.aPara[1] := hIndex;
      UserPara.aPara[2] := hsSubIndex;
      UserPara.aPara[3] := 0;
      UserPara.aPara[4] := AxisNo;
      UserPara.aPara[5] := MDD2000MNG_DATASIZE_4BYTE;
      UserPara.aPara[6] := (#ParaValue)$DINT;
      UserPara.aPara[7] := 0;
      pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
    end_if;
      
    pHlp += sizeof(UDINT);
    x += sizeof(UDINT);
      
  end_while;
  
END_FUNCTION


FUNCTION VIRTUAL MDD2000_AxisBase::MDD2000IntfProcess
  VAR
    tmpStr : array [0..20] of char;
    retcode : iprStates;
    dError : DINT;
    tmpPara         : CmdStruct;
    tmpResult       : results;
  END_VAR
  
  if Online = 1 then
    
    case MDD2000CmdIntfc of
    
    _MDD2000IDLE :
      // do nothing
      
    _MDD2000READALL :
      if bdSettings.bStartRead = FALSE then
        bdSettings.bStartRead := TRUE;
        // check if a read is possible
        if ChkParaRead(0) = FALSE then
          MDD2000CmdIntfc := _MDD2000IDLE;
        else
          ParaReadProc();
        end_if;
      else
        // überprüfen ob alle Parameter schon vorhanden sind
        ParaReadProc();
        if (bdSettings.bReadAxFin = TRUE) then
          MDD2000CmdIntfc := _MDD2000IDLE;
          bdSettings.bStartRead := FALSE;
        end_if;
      end_if;
    
    _MDD2000INIT :
      
      if (AxEnable = 0)  then
        if OldMDD2000CmdIntfc <> MDD2000CmdIntfc then
        
          //Start the initialisation of the drive
          tmpPara.uiCmd := MDD2000MNG_IF_INIT_DRIVE;
          tmpPara.aPara[0] := MDD2000MNG_IF_INIT_DRIVE_VER_1;
          tmpPara.aPara[1] := 0;  //0 .. Init, 1 .. Urinit
          DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult);
        
          Init_Again:=true;
        end_if;
      else
        MDD2000CmdIntfc := _MDD2000IDLE;
      end_if;
      
    _MDD2000URINIT :
      
      if (AxEnable = 0) then
        if OldMDD2000CmdIntfc <> MDD2000CmdIntfc then

          //Start the initialisation of the drive
          tmpPara.uiCmd := MDD2000MNG_IF_INIT_DRIVE;
          tmpPara.aPara[0] := MDD2000MNG_IF_INIT_DRIVE_VER_1;
          tmpPara.aPara[1] := 1;  //0 .. Init, 1 .. Urinit
          DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult);

          InitASyncPara(); // initialize the structure
          Init_Again:=true;
        end_if;
      else
        MDD2000CmdIntfc := _MDD2000IDLE;
      end_if;
      
    _MDD2000EXDATA, 
    _MDD2000EXDATAXML:
    
      // only if a object of the correct class is connected
      if DriveAxisSet.ChkFileHandle() then
     
        if OldMDD2000CmdIntfc <> MDD2000CmdIntfc then
          pMDD2000Data$^void := DriveAxisSet.GetMemPtr();
          
          // Always Call SetDriveType incause GetDriveTypeStr fails or an older Version of _DriveFileHandling is used
          DriveAxisSet.SetDriveType( eDriveType := _DRIVETYPE::_MDD_2000);
          
          _strcpy(#pMDD2000Data^.AxName[0],#szObjName[0]); //here the name of the object is set to the struct
          
          // Set tmpStr to 0 incase GetDriveTypeStr does not return a valid string.
          tmpStr[0] := 0;
          
          tmpPara.uiCmd    := MDD2000MNG_IF_GET_DRIVE_TYP_STR;
          tmpPara.aPara[0] := MDD2000MNG_IF_GET_DRIVE_TYP_STR_VER_1;
          tmpPara.aPara[1] := (#tmpStr[0])$DINT;
          tmpPara.aPara[2] := (sizeof(tmpStr))$DINT;
          DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult);          
          
          if tmpStr[0] then
            DriveAxisSet.SetDriveTypeStr(pDriveTypeStr:= #tmpStr[0]);
          end_if; 
          DriveAxisSet.SetUserSSDCmd(MDD2000CmdIntfc, pMDD2000Data);
          
        else
          MDD2000CmdIntfc := DriveAxisSet.GetUserSSDCmd();
        end_if;
      else
        LogError(pMsg:="@06F3 (MDD2000_AxisBase::MDD2000IntfProcess) Failed export drive parameters. Check if client 'FileHandle' is connected.");
        MDD2000CmdIntfc := _MDD2000ERROR;
      end_if;
      
    _MDD2000IMDATAXML:
    
      if DriveAxisSet.ChkFileHandle() then
     
        if OldMDD2000CmdIntfc <> MDD2000CmdIntfc then
          pMDD2000Data$^void := DriveAxisSet.GetMemPtr();
          
          _strcpy(#pMDD2000Data^.AxName[0],#szObjName[0]); //here the name of the object is set to the struct
          DriveAxisSet.SetUserSSDCmd(MDD2000CmdIntfc, pMDD2000Data);          
          
        else
          
          if DriveAxisSet.GetUserSSDCmd() = _MDD2000IDLE then
            // Read xml file done
            
            // Insert Crc into the imported Data
            pMDD2000Data^.udCRC32 := DriveAxisSet.CalcCRC32((pMDD2000Data + sizeof(UDINT))$^UDINT, pMDD2000Data^.udLen - sizeof(UDINT));
            
            // now save all parameters in the SRAM / FILE
            if DriveInitType = _MDD2000_RAMEX then
              pMDD2000Data$^void := DriveAxisSet.GetMemPtr();
              DriveAxisSet.SaveRamExData(pData:= pMDD2000Data, udLen:= pMDD2000Data^.udLen, udOffset:= 0);
              
            elsif DriveInitType = _MDD2000_FILE then
              pMDD2000Data$^void := DriveAxisSet.GetMemPtr();
              DriveAxisSet.SaveRamFileData(pData:= pMDD2000Data, udLen:= pMDD2000Data^.udLen, udOffset:= 0);
            
            end_if;
            
            // Use _MDD2000INIT to tranfer Parametera from ramfile/sram to drive
            MDD2000CmdIntfc := _MDD2000INIT;  // Set after SaveRamExData, SaveRamFileData because Filehandling may suspend task
            
            return; // Return needed here so that _MDD2000INIT is registered as a new command
          end_if;

        end_if;
      else
        LogError(pMsg:="@06F5 (MDD2000_AxisBase::MDD2000IntfProcess) Failed import drive parameters. Check if client 'FileHandle' is connected.");
        MDD2000CmdIntfc := _MDD2000ERROR;
      end_if;
    
      _MDD2000EXLOGFILE:
        
        // First call since MDD2000CmdIntfc was set.
        if OldMDD2000CmdIntfc <> MDD2000CmdIntfc then
        
          tmpPara.uiCmd    := MDD2000MNG_NEWINST_GETLOGFILE;
          tmpPara.aPara[0] := MDD2000MNG_NEWINST_GETLOGFILE_VER_1;
          tmpPara.aPara[1] := 0;  //NIL
          tmpPara.aPara[2] := (#dError)$DINT;  //NIL
          retcode := DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult);
          
          if retcode = ERROR then
            LogValue("@0846 (MDD2000_AxisBase::MDD2000IntfProcess) Failed to start read logfile. Error code: -0x{0}", (-dError)$UDINT);
            MDD2000CmdIntfc := _MDD2000ERROR;
          end_if;
          
        else
        
          tmpPara.uiCmd    := MDD2000MNG_NEWINST_GETFILESTATE;
          tmpPara.aPara[0] := MDD2000MNG_NEWINST_GETFILESTATE_VER_1;
          tmpPara.aPara[1] := (#dError)$DINT;
          tmpPara.aPara[2]$^void := NIL;
          tmpPara.aPara[3]$^void := NIL;
          retcode := DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult);
                  
          if retcode = READY then
          
            MDD2000CmdIntfc := _MDD2000IDLE;
            
          elsif retcode = ERROR then
            
            LogValue("@0847 (MDD2000_AxisBase::MDD2000IntfProcess) Failed read logfile. Error code: -0x{0}", (-dError)$UDINT);
            MDD2000CmdIntfc := _MDD2000ERROR;
        
          end_if;          
        
        end_if;
        
        
    end_case;
    
    OldMDD2000CmdIntfc := MDD2000CmdIntfc;
  
  end_if;
   
END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::MDD2000CmdIntfc::Write
	VAR_INPUT
		input (EAX) 	: MDD2000_AxisBase::_MDD2000USERCMD;
	END_VAR
	VAR_OUTPUT
		result (EAX) 	: MDD2000_AxisBase::_MDD2000USERCMD;
	END_VAR

  if ((MDD2000CmdIntfc = _MDD2000IDLE) | 
      (MDD2000CmdIntfc = _MDD2000ERROR)) then
    MDD2000CmdIntfc := input;
    result := MDD2000CmdIntfc;
  else
    result$DINT := ACCESS_DENIED;
  end_if;

END_FUNCTION


FUNCTION MDD2000_AxisBase::ChkParaRead
	VAR_INPUT
		ChkType 	: DINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: BOOL;
	END_VAR
  
  retcode := FALSE;

  case ChkType of
    0 : // check if a reading command is allowed
    
      bdSettings.bReadAx := FALSE;
    
      bdSettings.bReadAxFin := FALSE;
      
      if (bdSettings.bAxSetPara = TRUE)then
        bdSettings.bReadAx := TRUE;
        ParaReadCmdAx := 1;
        retcode := TRUE;
      else
        bdSettings.bReadAxFin := TRUE;
      end_if;

    1 : // check if we can send the next reading commands
      if ParaReadCmdAx = 2 then
        if cPipe_GetUsed(p:=pAsyPipeHandle) < 10 then
          retcode := TRUE;
        end_if;
      end_if;

  end_case;
  
END_FUNCTION


FUNCTION MDD2000_AxisBase::ParaReadProc
  VAR
    dValue      : DINT;
    pThis       : ^void;
  END_VAR
  
  // Start laden aller Parameter vom Drive
  // folgender Ablauf :
  // 1. Es wird für jede Achse die Anforderung in den Ringbuffer geschrieben (30mal).(Eigene Kennung erforderlich ?);
  // 2. Warten bis nur mehr 10 Einträge vorhanden sind, und dann die nächsten Einträge absetzen
  // 3. wenn alle Einträge abgesetzt sind, (letzter Eintrag muss eine extra Kennung haben), wird überprüft wann alle Daten vorhanden sind
  // 4. Wenn ein Wert eines Parameters ankommt, wird dieser in den Speicher geschrieben, dies ist abhängig von der Sicherungsauswahl. Ist eine Tabelle ausgewählt
  //    werden die Daten sofort an die Parameterklassen gesendet, sind keine Parameterobjekte vorhanden, so wird der Vorgang gar nicht durchgeführt.
  // 5. Wenn der letzte Wert des Parameters kommt, wird die Chksumme neu berechnet, die Daten weggesichert, und die Parameterobjekte aktualisiert

  dValue := 0;
  
  if bdSettings.bReadAx = TRUE then
    case ParaReadCmdAx of
  
    0 : //idle step
      
    1 : // set the first entries in the buffer 
    
      // set the info busy to all para classes
      SetParaState(ActState:=MDD2000MNG_IF_UPDATEPARACLASS_STATE_ASYNC_BUSY);
                        
      pThis := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_MOTOR);
      if pThis then
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_BRAKE, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_BRDIS, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_BREN, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_BRI, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_IMAG, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_IFWEAK, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_INULL, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_IPEAK, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_J, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_L, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_NAME1, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_NAME2, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_NAME3, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_NMAX, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_POL, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_R, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_ROFF, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_RPOL, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_RPULSE, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_RTEMP, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_SER, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_TORQUE, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_TROT, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_TYPE, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_UBOOST, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_M_UN, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_E_I2TT, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_E_TISO, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_E_INENN, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_E_NNENN, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        
        
      end_if;
      
      pThis := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_DRIVE);
      
      if pThis then
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_G_CETIME, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_G_DELAY, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_G_EMRAMP, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_G_MBAL, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_G_MODE, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_G_MTEMPE, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_G_MTEMPK, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_G_PWM, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_G_RBAL, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_G_SRAMP, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_G_VMAINS, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_G_VRAMP, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_G_MASKD, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_G_MASKE1, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_G_MASKE2, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_G_MASKW, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);        
      end_if;
      
      ParaReadCmdAx := 2;
      
        
    2 :
      // wait until only 10 entries in the buffer
      
      if ChkParaRead(ChkType:= 1) = TRUE then
        ParaReadCmdAx := 3;
      end_if;
      
    3 :
      // send the rest
      
      pThis := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_CURRENT);
      
      if pThis then
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_C_ICONT, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_C_IFWEAK, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_C_IPEAK, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_C_IPEAKN, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_C_KFWEAK, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_C_KPDREL, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_C_KPNULL, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_C_KPPEAK, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_C_KPQ, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_C_TN, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
      end_if;                 
                             
      pThis := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_VEL);
      
      if pThis then
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_V_FILT, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_V_GF, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_V_GSH, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_V_GSL, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_V_KP, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_V_NMAX, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_V_T, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_V_T2, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_V_TN, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
      end_if;

      pThis := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_POS);
      
      if pThis then
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_P_KV, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_P_PEMAX, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_P_PSCALE, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_P_SFF, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_P_SMODE, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_P_SSCALE, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_P_TFF, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
      end_if;
      
      pThis := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_FD);
      
      if pThis then
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_F_BCONF, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_F_BW, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_F_FF, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_F_FFILT, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_F_RK, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
      end_if;
      
      pThis := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_APPLI);
      
      if pThis then
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_CME, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);  
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_BVR, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);   
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_BIQCD, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_BIQCF, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_BIQDR, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_BIQFR, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_BTC, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_BTMP, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_BTTR, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_BTTS, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_CAP1, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_CAP2, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_CMIN, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_CTIME, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_DNAME1, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_DNAME2, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_DNAME3, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_EIMAX, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_FB2, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_I2TERR, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_ICOM, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_ICOMP, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_INT1, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_INT2, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_JRATIO, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_TEMPMW, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_TRAMP, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_VALRT1, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_VALRT2, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_VALTT1, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_A_VALTT2, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
      end_if;
      
      pThis := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_ERRORHANDLING);
      
      if pThis then
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_INFO, usParaSubID:= MDD2000_SPID_I_STATUS, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_INFO, usParaSubID:= MDD2000_SPID_I_DERR1, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_INFO, usParaSubID:= MDD2000_SPID_I_DERR2, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_INFO, usParaSubID:= MDD2000_SPID_I_DERR3, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
      end_if;

      pThis := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_OPTIONAL);
      
      if pThis then
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_O_TYPE, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_O_RPULSE, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_O_RPOL, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_O_BW, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_O_RK, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_O_FILT, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_O_BCONF, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
        AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_SET, usParaSubID:= MDD2000_SPID_O_PSCALE, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= pThis, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA);
      end_if;

      
      // get the number of parameters in the drive (only to know if we are at the end of the reading process, Thisptr is nil otherwise last parameter class would be called
      AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_INFO, usParaSubID:= 0, usRdWr:= 0, pValue:= NIL, bsDataInfo:= MDD2000MNG_DATASIZE_4BYTE, pThisObj:= NIL, usEntry:= MDD2000MNG_ENTRY_TYPE_REFRESH_DRIVE_PARA_LAST);
      
      ParaReadCmdAx := 4;
    4 :
      
      if bdSettings.bReadAxFin = TRUE then
      // wait until the last entry is send the value back
        
        // now save all parameters in the SRAM / FILE
        if DriveInitType = _MDD2000_RAMEX then
          pMDD2000Data$^void := DriveAxisSet.GetMemPtr();
          DriveAxisSet.SaveRamExData(pData:= pMDD2000Data, udLen:= pMDD2000Data^.udLen, udOffset:= 0);
          
        elsif DriveInitType = _MDD2000_FILE then
          pMDD2000Data$^void := DriveAxisSet.GetMemPtr();
          DriveAxisSet.SaveRamFileData(pData:= pMDD2000Data, udLen:= pMDD2000Data^.udLen, udOffset:= 0);
        
        end_if;
        ParaReadCmdAx := 0;
        
      end_if;
    end_case;
  end_if;
  
END_FUNCTION


FUNCTION MDD2000_AxisBase::SaveDrivePara
  VAR
    TabAddress 	: ^DINT;
    pHlpMDD		: ^void;
    TabLength   : DINT;
  END_VAR
	
  // get the actual ptr of the memory
  pMDD2000Data$^void := DriveAxisSet.GetMemPtr();	

  if pMDD2000Data <> NIL then	
    
    pMDD2000Data^.udLen := sizeof(_MDD2000MEMHEADER); // initialize the length of the data 
    pMDD2000Data^.AxOffset := sizeof(_MDD2000MEMHEADER); // set the offset
    TabAddress := GetTabAdress(1, bdSettings.bSendMPara, #TabLength);
    
    if TabAddress = NIL then
      return;
    end_if;
    
    pMDD2000Data^.AxLength := TabLength$UDINT;
  
    pHlpMDD := pMDD2000Data + pMDD2000Data^.AxOffset;
        
    _memcpy(pHlpMDD, (TabAddress)$^void, (TabLength)$UDINT);

    pMDD2000Data^.udLen += pMDD2000Data^.AxLength;

    // calculate the crc of the parameters
    pMDD2000Data^.udCRC32 := CalcCRC32((pMDD2000Data + sizeof(UDINT))$^UDINT, pMDD2000Data^.udLen - sizeof(UDINT));
   
    case DriveInitType of
    
    _MDD2000_RAMEX :
    
      // save the data in the ramex
      DriveAxisSet.SaveRamExData(pMDD2000Data, pMDD2000Data^.udLen, 0);
          
    _MDD2000_FILE :
      // save the data in the ramfile
      DriveAxisSet.SaveRamFileData(pMDD2000Data, pMDD2000Data^.udLen, 0);
      
    end_case;
  end_if;
  
END_FUNCTION


FUNCTION MDD2000_AxisBase::CalcCRC32
	VAR_INPUT
		pData 	: ^UDINT;
		udLen 	: UDINT;
	END_VAR
	VAR_OUTPUT
		CRC32 	: UDINT;
	END_VAR
	
	CRC32 := coLinker.CRC32(0, pData$^void, udLen);

END_FUNCTION


FUNCTION VIRTUAL MDD2000_AxisBase::GetZImpulse
	VAR_OUTPUT
		retcode 	: USINT;
	END_VAR
  
  retcode:=0;
  
  if ( ( ActPos and maskZImpulse$DINT ) <> oldRevolutions ) then
    retcode := 1;
    oldRevolutions := (ActPos and maskZImpulse$DINT);
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::ZPulsLatch::Read
	VAR_OUTPUT
		output (EAX) 	: DINT;
	END_VAR
  
  if bOnlineFinished then
  
    if ZPulsLatch = 0 then
      output := ZPulsLatch := GetZImpulse();
    else
      output := ZPulsLatch;
      ZPulsLatch := 0;
    end_if;
  
  else
    ZPulsLatch := 0;
    output := ZPulsLatch;
  end_if;

END_FUNCTION


FUNCTION MDD2000_AxisBase::SetZPulseMask
  
  maskZImpulse:=16#FFFFFFFF;
  maskZImpulse:=maskZImpulse SHL (32-ppscale);

  //P-PSCALE  0: 00000000 00000000 00000000 00000000
  //P-PSCALE 10: 11111111 11000000 00000000 00000000
  //P-PSCALE 16: 11111111 11111111 00000000 00000000
      
END_FUNCTION


FUNCTION VIRTUAL MDD2000_AxisBase::GetSyncEntry
	VAR_INPUT
		usValue 	: USINT;
		usPData 	: ^DINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR
    tmpPara         : CmdStruct;
    tmpResult       : results;  	
  END_VAR
  
  tmpPara.uiCmd := MDD2000MNG_IF_GET_SYNC_ENTRY;
  tmpPara.aPara[0] := MDD2000MNG_IF_GET_SYNC_ENTRY_VER_1;
  
  tmpPara.aPara[1]      := TO_DINT(usAxisIndex);
  tmpPara.aPara[2]      := TO_DINT(usValue);
  tmpPara.aPara[3]$^DINT:= usPData;
  
  if DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult) = READY then
    retcode := tmpResult.aData[4]$DINT;
  else
    retcode := -99;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL MDD2000_AxisBase::AddSyncEntry
	VAR_INPUT
		pThis 	: ^void;
	END_VAR
	VAR_OUTPUT
		retcode 	: BOOL;
	END_VAR
    
  retcode := FALSE;
  
  if pThis <> NIL then
    SyncParaObject := pThis$DINT;
    retcode := TRUE;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL MDD2000_AxisBase::SetSyncEntry
	VAR_INPUT
		usValue 	: USINT;
		usPData 	: DINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR
  	tmpPara         : CmdStruct;
    tmpResult       : results;
  END_VAR
  
  tmpPara.uiCmd := MDD2000MNG_IF_SET_SYNC_ENTRY;
  tmpPara.aPara[0] := MDD2000MNG_IF_SET_SYNC_ENTRY_VER_1;
  
  tmpPara.aPara[1] := TO_DINT(usAxisIndex);
  tmpPara.aPara[2] := TO_DINT(usValue);
  tmpPara.aPara[3] := TO_DINT(usPData);
  
  if DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult) = READY then
    retcode := tmpResult.aData[4]$DINT;
  else
    retcode := -99;
  end_if;

END_FUNCTION


FUNCTION MDD2000_AxisBase::RefreshIASP
	VAR_INPUT
		hParaIndex 	: HINT;
		hsParasubIndex 	: HSINT;
		Value 	: DINT;
	END_VAR
  
  // if there is a change in the following values, first we set the pointers to zero, and then we initialize them, allready with the new value

  if AxEnable = 0 then //just do some changes when the axis does not run
    case hsParasubIndex of
      MDD2000_SPID_A_VALTT1:
                
        _memset(#SyncPara.ActCurrent,       0,sizeof(SyncPara.ActCurrent));
        _memset(#SyncPara.ActPos,           0,sizeof(SyncPara.ActPos));
        _memset(#SyncPara.ActSpeed,         0,sizeof(SyncPara.ActSpeed));
        _memset(#SyncPara.Xw,               0,sizeof(SyncPara.Xw));
        _memset(#SyncPara.StateWord,        0,sizeof(SyncPara.StateWord));
        _memset(#SyncPara.DigInputs,        0,sizeof(SyncPara.DigInputs));
        _memset(#SyncPara.SafeControlWord,  0,sizeof(SyncPara.SafeControlWord));
        _memset(#SyncPara.SafeStateWord,    0,sizeof(SyncPara.SafeStateWord));
        
        ActValues[0] := to_usint( Value$HDINT AND 16#000000FF);
        ActValues[1] := to_usint((Value$HDINT AND 16#0000FF00) SHR  8);

        GetSynchronPara();
        
      MDD2000_SPID_A_VALTT2:
                
        _memset(#SyncPara.ActCurrent,       0,sizeof(SyncPara.ActCurrent));
        _memset(#SyncPara.ActPos,           0,sizeof(SyncPara.ActPos));
        _memset(#SyncPara.ActSpeed,         0,sizeof(SyncPara.ActSpeed));
        _memset(#SyncPara.Xw,               0,sizeof(SyncPara.Xw));
        _memset(#SyncPara.StateWord,        0,sizeof(SyncPara.StateWord));
        _memset(#SyncPara.DigInputs,        0,sizeof(SyncPara.DigInputs));
        _memset(#SyncPara.SafeControlWord,  0,sizeof(SyncPara.SafeControlWord));
        _memset(#SyncPara.SafeStateWord,    0,sizeof(SyncPara.SafeStateWord));
        
        ActValues[2] := to_usint( Value$HDINT AND 16#000000FF);
        ActValues[3] := to_usint((Value$HDINT AND 16#0000FF00) SHR 8);
        ActValues[4] := to_usint((Value$HDINT AND 16#00FF0000) SHR 16);
        ActValues[5] := 0;  // Reserved
        ActValues[6] := 40; // Safety Control/Status Word fix configured in the FW 
        
        GetSynchronPara();
        
      MDD2000_SPID_A_VALRT1:
                
        _memset(#SyncPara.SetCurrent, 0,sizeof(SyncPara.SetCurrent));
        _memset(#SyncPara.SetPos,     0,sizeof(SyncPara.SetPos));
        _memset(#SyncPara.SetSpeed,   0,sizeof(SyncPara.SetSpeed));
        _memset(#SyncPara.SetTorque,  0,sizeof(SyncPara.SetTorque));
        _memset(#SyncPara.ControlWord,0,sizeof(SyncPara.ControlWord));
        
        SetValues[0] := to_usint( Value$HDINT AND 16#000000FF);
        SetValues[1] := to_usint((Value$HDINT AND 16#0000FF00) SHR  8);
        
        SetSynchronPara();
//        AxTorqueControl.Write(4500); //it does not matter which controlword we have, because the internal function reduced this amount to the top limit
        SetAxTorque(4500);

        
      MDD2000_SPID_A_VALRT2:
        
        _memset(#SyncPara.SetCurrent, 0,sizeof(SyncPara.SetCurrent));
        _memset(#SyncPara.SetPos,     0,sizeof(SyncPara.SetPos));
        _memset(#SyncPara.SetSpeed,   0,sizeof(SyncPara.SetSpeed));
        _memset(#SyncPara.SetTorque,  0,sizeof(SyncPara.SetTorque));
        _memset(#SyncPara.ControlWord,0,sizeof(SyncPara.ControlWord));
        
        SetValues[2] := to_usint( Value$HDINT AND 16#000000FF);
        SetValues[3] := to_usint((Value$HDINT AND 16#0000FF00) SHR 8);
        SetValues[4] := to_usint((Value$HDINT AND 16#00FF0000) SHR 16);
        SetValues[5] := 0; // Reserved
        SetValues[6] := 0; // Reserved
        
        SetSynchronPara();
//        AxTorqueControl.Write(4500); //it does not matter which controlword we have, because the internal function reduced this amount to the top limit
        SetAxTorque(4500);
        
      MDD2000_SPID_P_PSCALE:
        ppscale:=to_usint(Value);
        SetZPulseMask();
        
    end_case;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL MDD2000_AxisBase::AxOkay
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  
  retcode := false;
  
  if (AxisState AND MDD2000_AXISBASE_AXISSTATE_ERRORMASK) = 0 then
    retcode := TRUE;
  end_if;

END_FUNCTION


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

  //--- if DriveMng is online, we have no internal error, and the error-reset after startup is ready, we say Online = 1
//  Online := bOnlineFinished;
  Online := bOnlineState;

  output := Online;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::ErrorQuitHandling
	VAR_INPUT
		input 	: DINT;
	END_VAR
	VAR_OUTPUT
		result 	: DINT;
	END_VAR

  if input then
    AxErrorQuit := 1;
  else
    AxErrorQuit := 0;
  end_if;
  
  // check if there is a control word mapped, before accessing the data
  if SyncPara.ControlWord.ptr then
    if (SyncPara.ControlWord.userinfo=0) then 
      SyncPara.ControlWord.ptr^$BINT.2:=AxErrorQuit$BOOL; //FAULT RESET
    elsif(SyncPara.ControlWord.userinfo=1) then
      SyncPara.ControlWord.ptr^$BINT.8:=AxErrorQuit$BOOL; //FAULT RESET
    end_if;
  end_if;
  
  if AxErrorQuit = 1 then
    FirstErrorReset := 4;
    ErrorQuitTime:=ops.tAbsolute;
  end_if;

  Controlword.ResetFault := AxErrorQuit$BOOL;

  result := AxErrorQuit;

END_FUNCTION


FUNCTION VIRTUAL MDD2000_AxisBase::GetAxError
	VAR_OUTPUT
		AxError 	: DINT;
	END_VAR
  VAR
  	sBuffer      : BDINT; //StateWord Buffer
  END_VAR

  if SyncPara.StateWord.ptr<>NIL  then
    sBuffer := SyncPara.StateWord.ptr^$BDINT; 
    AxError:=sBuffer.4; //the error is at both control words on the same place
  else
    AxError:=0;
  end_if;

END_FUNCTION


FUNCTION MDD2000_AxisBase::SetAxTorque
	VAR_INPUT
		NewTorque 	: UDINT;
	END_VAR
  VAR
    cBuffer       : BDINT; //ControlWord Buffer
  END_VAR

  // if we have a 16-Bit Controlword
  if SyncPara.SetTorque.userinfo = 0 then

    if NewTorque < 0 then
      NewTorque := 0;
    end_if;
      
    if NewTorque > MDD2000_AXISBASE_TORQUE_LIMITATION_VALUE then
      NewTorque := MDD2000_AXISBASE_TORQUE_LIMITATION_VALUE;
    end_if;
    
    AxTorqueControl := NewTorque;
    
    //Check if pointer is valid
    if SyncPara.ControlWord.ptr then
      cBuffer:=SyncPara.ControlWord.ptr^$BDINT;
      SyncPara.SetTorque.ptr^$INT:= to_int(TorqueCalculation(cBuffer,NewTorque));
    end_if;

  elsif SyncPara.SetTorque.userinfo=1 then //that is for the 32-Bit Controlword
    
    if NewTorque < 0 then
      NewTorque := 0;
    end_if;
      
    if NewTorque > 4500 then
      NewTorque := 4500;
    end_if;
    
    AxTorqueControl := NewTorque;
    
    if SyncPara.SetTorque.ptr then
      SyncPara.SetTorque.ptr^$INT:=to_int(NewTorque);
    end_if;
    
  end_if;

END_FUNCTION

FUNCTION MDD2000_AxisBase::IsOnlineFinished
	VAR_OUTPUT
		bOnline 	: BOOL;
	END_VAR

  if (IsOnline() = TRUE) & (CmdState <> ERROR) & ((FirstErrorReset = 0) | (FirstErrorReset >= 4)) then
    bOnline := 1;
  else
    bOnline := 0;
  end_if;
  
END_FUNCTION

FUNCTION VIRTUAL MDD2000_AxisBase::AddASyncEntryDS402
	VAR_INPUT
		uiParaID 	: UINT;
		usParaSubID 	: USINT;
		usRdWr 	: USINT;
		pValue 	: ^void;
		bsDataInfo 	: BSINT;
		pThisObj 	: ^void;
		usEntry 	: USINT;(* := 0 *)
		udTimeout 	: DINT;(* := 0 *)
		dCallID 	: DINT;(* := 0 *)
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR
  	tmpPara : CmdStruct;
    tmpResult : results;
  END_VAR
  
  //check if diag mode is activated, block all other accesses if it is active
  if AxisState.DiagModeActive = FALSE | pThisObj = pDiagThis then
  
    //Send Async commando to manager
    tmpPara.uiCmd           := MDD2000MNG_IF_ADD_ASYNC_ENTRY_DS402;
    tmpPara.aPara[0]$DINT   := MDD2000MNG_IF_ADD_ASYNC_ENTRY_DS402_VER_1;
    tmpPara.aPara[1]$DINT   := TO_DINT(usAxisIndex);
    tmpPara.aPara[2]$DINT   := TO_DINT(uiParaID);
    tmpPara.aPara[3]$DINT   := TO_DINT(usParaSubID);
    tmpPara.aPara[4]$DINT   := TO_DINT(usRdWr);
    tmpPara.aPara[5]$DINT   := pValue$DINT;
    tmpPara.aPara[6]$DINT   := TO_DINT(bsDataInfo);
    tmpPara.aPara[7]$DINT   := pThisObj$DINT;
    tmpPara.aPara[8]$DINT   := TO_DINT(usEntry);
    tmpPara.aPara[9]$DINT   := udTimeout$DINT;
    tmpPara.aPara[10]$DINT  := dCallID;

    if DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult) = READY then
      retcode := tmpResult.aData[4]$DINT;
    else
      retcode := -12;
    end_if;
  else 
    retcode := -11;
  end_if;
  
END_FUNCTION
#pragma warning(disable: 73);
FUNCTION VIRTUAL MDD2000_AxisBase::LogError
	VAR_INPUT
		pMsg 	: ^CHAR;
	END_VAR

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

END_FUNCTION


FUNCTION VIRTUAL MDD2000_AxisBase::LogValue
	VAR_INPUT
		pString 	: ^CHAR;
		udValue 	: UDINT;
		udValue2 	: UDINT;(* := 16#FFFFFFFF *)
		udValue3 	: UDINT;(* := 16#FFFFFFFF *)
	END_VAR

#ifdef HWC_LogValue3
  HWC_LogValue3(this, pString, udValue, udValue2, udValue3);
#endif

END_FUNCTION
#pragma warning(default: 73);


FUNCTION MDD2000_AxisBase::SetDiagMode
	VAR_INPUT
		bStartDiagMode 	: BOOL;
		pThisObj 	: ^void;
	END_VAR
	VAR_OUTPUT
		dRetCode 	: DINT;
	END_VAR
  
  // initialize return code with ok
  dRetCode := 1;
  if pThisObj <> NIL then
    if bStartDiagMode = TRUE then
      if AxisState.DiagModeActive = FALSE then
        if bOnlineFinished = TRUE then
          AxisState.DiagModeActive := TRUE;
          pDiagThis       := pThisObj;
          bOnlineFinished := FALSE;
        else
          //axis is not online or init is not finished
          dRetCode := -1;
        end_if;
      else
        if pThisObj <> pDiagThis then
          //diag mode is already set by other instance
          dRetCode := -2; 
        end_if;
      end_if;

    else
      if pThisObj = pDiagThis then
        //diag mode is deactivated - reset values
        AxisState.DiagModeActive := FALSE;
        pDiagThis := NIL;
        //set act state
        bOnlineFinished := IsOnlineFinished();
      else
        //class was locked by other object
        dRetCode := -3;
      end_if;    
    end_if;
  else
    //this pointer is not valid
    dRetCode := -4;
  end_if;


END_FUNCTION


FUNCTION MDD2000_AxisBase::Write_SetSpeed
	VAR_INPUT
		valueIn 	: DINT;
	END_VAR
	VAR_OUTPUT
		valueOut 	: DINT;
	END_VAR

  // writes the value to the PDO data.
  // online is not checked on purpose. It is needed to initialize the PDO data for a reconnect.
  // The value may be truncated to 16bit in the PDO, but is not for the return value.

  valueOut := 0;// zero in case we have no access
	if (SyncPara.SetSpeed.ptr <> NIL) then
    
    if (SyncPara.SetSpeed.size=4) then
      SyncPara.SetSpeed.ptr^ := valueIn;
      valueOut := valueIn;

    elsif (SyncPara.SetSpeed.size=2) then
      if SyncPara.SetSpeed.userinfo = 0 then
        if valueIn > MDD2000_AXISBASE_SPEED_SFFLIMITATION_USERINFO_0 then
          valueIn := MDD2000_AXISBASE_SPEED_SFFLIMITATION_USERINFO_0;
          AxisState.SFFLimitationActive := TRUE;
        elsif valueIn < -MDD2000_AXISBASE_SPEED_SFFLIMITATION_USERINFO_0-1 then
          valueIn := -MDD2000_AXISBASE_SPEED_SFFLIMITATION_USERINFO_0-1;
          AxisState.SFFLimitationActive := TRUE;
        else
          AxisState.SFFLimitationActive := FALSE;
        end_if;
        SyncPara.SetSpeed.ptr^$INT := to_int(valueIn);
        valueOut := valueIn;
      elsif SyncPara.SetSpeed.userinfo = 1 then
        if valueIn > MDD2000_AXISBASE_SPEED_SFFLIMITATION_USERINFO_1 then
          valueIn := MDD2000_AXISBASE_SPEED_SFFLIMITATION_USERINFO_1;
          AxisState.SFFLimitationActive := TRUE;
        elsif valueIn < -MDD2000_AXISBASE_SPEED_SFFLIMITATION_USERINFO_1 then
          valueIn := -MDD2000_AXISBASE_SPEED_SFFLIMITATION_USERINFO_1;
          AxisState.SFFLimitationActive := TRUE;
        else
          AxisState.SFFLimitationActive := FALSE;
        end_if;
        SyncPara.SetSpeed.ptr^$INT := to_int(valueIn);
        valueOut := valueIn;
      end_if;
    end_if;
  end_if;
  
END_FUNCTION


FUNCTION MDD2000_AxisBase::Write_Enable
	VAR_INPUT
		valueIn 	: DINT;
	END_VAR
	VAR_OUTPUT
		valueOut 	: DINT;
	END_VAR

  // writes the value to the PDO data.
  // online is not checked on purpose. It is needed to initialize the PDO data for a reconnect.

  valueOut := 0;// zero in case we have no access
  if (SyncPara.ControlWord.ptr <> NIL) then
    if (SyncPara.ControlWord.userinfo=0) then 
      SyncPara.ControlWord.ptr^$BINT.1:=valueIn$BOOL; //DRIVE ENABLE
    elsif(SyncPara.ControlWord.userinfo=1) then
      SyncPara.ControlWord.ptr^$BINT.4:=valueIn$BOOL; //DRIVE ENABLE
    end_if;
    
    Controlword.EnableOperation := valueIn$BOOL;
    valueOut := to_dint(valueIn$BOOL);
  end_if;

END_FUNCTION


FUNCTION MDD2000_AxisBase::IsAnyAxisEnabled
	VAR_OUTPUT
		bEnabled 	: BOOL;
	END_VAR
  VAR
  	tmpPara : CmdStruct;
    tmpResult : results;
  END_VAR

  tmpPara.uiCmd := MDD2000MNG_IF_IS_ANY_AXIS_ENABLED;
  tmpPara.aPara[0] := MDD2000MNG_IF_IS_ANY_AXIS_ENABLED_VER_1;
  DriveMng.NewInst(pPara:=#tmpPara, pResult:=#tmpResult);
  bEnabled := tmpResult.aData[4]$BOOL;

END_FUNCTION


FUNCTION MDD2000_AxisBase::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 MDD2000_AxisBase::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 MDD2000_AxisBase::EncoderCylic
  VAR
  	tempErrorCode : DINT;
    MyPara   : CmdStruct;
    MyResult : results;  
    myretcode : iprStates;
  END_VAR
  
  // Connect / Disconnect Handling
  if Online then
    
    if sEncVar.State = 0 then
      
      // New Connect of axis
      sEncVar.State := 1;
      
      sEncVar.SSWMain := eSSW_GetEncoderMain::_Start;
      
    end_if;
    
  else 
    sEncVar.State := 0;
  end_if;
  
  if sEncVar.State = 1 then
  
    case sEncVar.SSWMain of
    
      //*****************************************************************************
      eSSW_GetEncoderMain::_Start:
      
          // Reset Internal variables
          ResetIntVariables();
          sEncVar.SSWMain := _CheckFileHandling;
      
      //*****************************************************************************
      eSSW_GetEncoderMain::_CheckFileHandling:
                                    
          MyPara.uiCmd := MDD2000MNG_NEWINST_GETFILE;
          MyPara.aPara[0]$DINT  := MDD2000MNG_NEWINST_GETFILE_VER_1; // Command Version
          MyPara.aPara[1]$^CHAR := NIL;               // Pointer to destination path + name + extension where the file should be saved on the PLC
          MyPara.aPara[2]$^CHAR := NIL;               // Pointer to filename of the drive
          MyPara.aPara[3]$^CHAR := NIL;               // Pointer to the file path/directory of the drive 
          MyPara.aPara[4]$^DINT := #tempErrorCode;    // Pointer to a 4 Byte Error variable where errorcodes will be written when there is an error (optional, can be NIL)
          
          DriveMng.NewInst(#MyPara, #MyResult);

          sEncVar.SSWMain_StepGetMem := _ReadEncMemFile;
          if (tempErrorCode = MDD2000MNG_FILE_HANDLING_RETCODE_NOT_SUPPORTED) then
            sEncVar.SSWMain_StepGetMem := _ReadEncMemAsync;
          end_if;
          
          sEncVar.SSWMain := _Idle;
      
      //*****************************************************************************
      eSSW_GetEncoderMain::_Idle:
      
        // Wait for user request
        if sEncVar.bdUserRequest.GetFeedbackDataSize then
          sEncVar.SSWMain := _ReadEncMemSize;
        elsif sEncVar.bdUserRequest.FetchEncoderData then
          sEncVar.SSWMain := sEncVar.SSWMain_StepGetMem;
        end_if;
      
      //*****************************************************************************
      eSSW_GetEncoderMain::_ReadEncMemSize:
          
          // Get Encoder memory size
          myretcode := GetEncoderMemSize();
          
          if myretcode = READY then
          
            sEncVar.bdUserRequest.GetFeedbackDataSize := 0;
          
            if sEncVar.bdUserRequest.FetchEncoderData then
              sEncVar.SSWMain := sEncVar.SSWMain_StepGetMem;
            else
              sEncVar.SSWMain := _Idle;
            end_if;

          elsif myretcode = ERROR then
          
            sEncVar.bdUserRequest.GetFeedbackDataSize := 0;
            sEncVar.bdUserRequest.FetchEncoderData    := 0; // Reset as well, can never succed if the size of the encoder mem cannot be read
            
            sEncVar.SSWMain := eSSW_GetEncoderMain::_Error;
          end_if;
      
      //*****************************************************************************
      eSSW_GetEncoderMain::_ReadEncMemAsync:
      
          // Get Encoder memory via Async Scope acceses
          myretcode := GetEncoderMemAsync();
          
          if myretcode = READY then
            
            sEncVar.bdUserRequest.FetchEncoderData := 0;
            sEncVar.SSWMain := eSSW_GetEncoderMain::_Idle;
            
          elsif myretcode = ERROR then
          
            sEncVar.bdUserRequest.FetchEncoderData := 0;
            sEncVar.SSWMain := eSSW_GetEncoderMain::_Error;
            
          elsif myretcode = ERROR_BUSY then  
             sEncVar.SSWMain := eSSW_GetEncoderMain::_ReadEncMemAsyncErrorHandling;
          end_if;
          
      //*****************************************************************************
      eSSW_GetEncoderMain::_ReadEncMemAsyncErrorHandling:
      
          // Continue to call in error to release scope Accesses
          myretcode := GetEncoderMemAsync();
          
          if myretcode <> BUSY then
          
            sEncVar.bdUserRequest.FetchEncoderData := 0;
            sEncVar.SSWMain := eSSW_GetEncoderMain::_Error;
            
          end_if;
      
      //*****************************************************************************
      eSSW_GetEncoderMain::_ReadEncMemFile:
      
        // Get Encoder memory via file acceses
        myretcode := GetEncoderMemFile();
          
        if myretcode = READY then
          
          sEncVar.bdUserRequest.FetchEncoderData := 0;
          sEncVar.SSWMain := eSSW_GetEncoderMain::_Idle;
          
        elsif myretcode = ERROR then
        
          sEncVar.bdUserRequest.FetchEncoderData := 0;
          sEncVar.SSWMain := eSSW_GetEncoderMain::_Error;
          
        end_if;
      
      //*****************************************************************************
      eSSW_GetEncoderMain::_Error:
      
        sEncVar.SSWMain := eSSW_GetEncoderMain::_Idle;
      
    end_case;
  
  end_if;

END_FUNCTION

FUNCTION VIRTUAL MDD2000_AxisBase::ResetIntVariables
  
  sEncVar.LastErrorCode := DRIVEENCMEM_RETOK;
  
  sEncVar.SSWGetEncoderMemSize      := eSSW_GetEncoderMemSize::_start;
  sEncVar.SSWGetEncoderMemSizeLast  := eSSW_GetEncoderMemSize::_start;
  sEncVar.bEncoderMemSizeRead       := FALSE;
  
  sEncVar.SSWGetEncoderMemAsync     := eSSW_GetEncoderMemAsync::_start;
  sEncVar.SSWGetEncoderMemAsyncLast := eSSW_GetEncoderMemAsync::_start;
  
  sEncVar.SSWGetEncoderMemFile     := eSSW_GetEncoderMemFile::_start;
  sEncVar.SSWGetEncoderMemFileLast := eSSW_GetEncoderMemFile::_start;
  
  sEncVar.sEncoderData.bValid := FALSE;
  sEncVar.sEncoderData.pData  := NIL;
  sEncVar.sEncoderData.Size   := 0;
  
  sEncVar.EncoderMemSize  := 0;
  sEncVar.Progress        := 0;
  
END_FUNCTION

FUNCTION VIRTUAL MDD2000_AxisBase::GetEncoderMemSize
	VAR_OUTPUT
		ret_code 	: iprStates;
	END_VAR
  VAR
    retval : DINT;
  END_VAR
  
  ret_code := BUSY;
  if sEncVar.SSWGetEncoderMemSize <> eSSW_GetEncoderMemSize::_Error then
    sEncVar.SSWGetEncoderMemSizeLast := sEncVar.SSWGetEncoderMemSize;
  end_if;
  
  case sEncVar.SSWGetEncoderMemSize of
    
    //*****************************************************************************    
    eSSW_GetEncoderMemSize::_Start:
        
        sEncVar.bEncoderMemSizeRead   := FALSE;
        sEncVar.EncoderMemSize        := 0;
        sEncVar.SSWGetEncoderMemSize  := _SendWrPara;
    
    //***************************************************************************** 
    eSSW_GetEncoderMemSize::_SendWrPara:

        sEncVar.AsyVal := MDD2000_AXISBASE_DRIVEENCMEM_PARAVAL_RD_ENCMEMSIZE;
        retval := AddASyncEntryDS402( uiParaID    := MDD2000_PID_SIGMATEKPARA_INDEX_SET
                                    , usParaSubID := MDD2000_SPID_A_INT1
                                    , usRdWr      := 1
                                    , pValue      := #sEncVar.AsyVal
                                    , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                                    , pThisObj    := this
                                    , usEntry     := MDD2000MNG_ENTRY_TYPE_DEFAULT
                                    , udTimeout   := 0
                                    , dCallID     := MDD2000_AXISBASE_DRIVEENCMEM_ASYCALLID
                                    );
        
        if retval = 0 then            
          sEncVar.SSWGetEncoderMemSize := _Wait4SendWrPara;
        else
          sEncVar.LastErrorCode        := DRIVEENCMEM_RETERR_GETENCODERMEMSIZE_ASYWR;
          sEncVar.SSWGetEncoderMemSize := eSSW_GetEncoderMemSize::_Error;
        end_if;
    
    //*****************************************************************************
    eSSW_GetEncoderMemSize::_SendRdPara:
        
        retval := AddASyncEntryDS402( uiParaID    := MDD2000_PID_SIGMATEKPARA_INDEX_INFO
                                    , usParaSubID := MDD2000_SPID_I_INT1
                                    , usRdWr      := 0
                                    , pValue      := NIL
                                    , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                                    , pThisObj    := this
                                    , usEntry     := MDD2000MNG_ENTRY_TYPE_DEFAULT
                                    , udTimeout   := 0
                                    , dCallID     := MDD2000_AXISBASE_DRIVEENCMEM_ASYCALLID
                                    );
        
        if retval = 0 then          
          
          sEncVar.SSWGetEncoderMemSize := _Wait4SendRdPara;

        else
          sEncVar.LastErrorCode        := DRIVEENCMEM_RETERR_GETENCODERMEMSIZE_ASYRD;
          sEncVar.SSWGetEncoderMemSize := eSSW_GetEncoderMemSize::_Error;
        end_if;
        
    eSSW_GetEncoderMemSize::_Wait4SendRdPara:
    
        if sEncVar.bEncoderMemSizeRead = TRUE then
        
          sEncVar.SSWGetEncoderMemSize := eSSW_GetEncoderMemSize::_Done;
          
          if sEncVar.EncoderMemSize = 0 then
            // Set Error if access was succesful but returned 0
            sEncVar.LastErrorCode := DRIVEENCMEM_RETERR_NO_ENCODER_MEM;
            sEncVar.SSWGetEncoderMemSize := eSSW_GetEncoderMemSize::_Error;
          end_if;
        
        end_if;

    //*****************************************************************************
    eSSW_GetEncoderMemSize::_Done:
    
        sEncVar.SSWGetEncoderMemSize := eSSW_GetEncoderMemSize::_Start;
        ret_code := READY;
    
    //*****************************************************************************
  	eSSW_GetEncoderMemSize::_Error:    
        
        HWC_LogPrintf(this,"@08A0 (MDD2000_AxisBase::GetEncoderMemSize) Failed in step %d, Errorcode %d, Asy Comm Errcode %d." , #sEncVar.SSWGetEncoderMemSizeLast , #sEncVar.LastErrorCode, #sEncVar.AsyCommErrCode);
        sEncVar.SSWGetEncoderMemSize := eSSW_GetEncoderMemSize::_Start;
        ret_code := ERROR;
        
  end_case;
  
END_FUNCTION

FUNCTION VIRTUAL MDD2000_AxisBase::GetEncoderMemAsync
	VAR_OUTPUT
		ret_code 	: iprStates;
	END_VAR
  VAR
    retval : DINT;
    byte2copy : UDINT;
  END_VAR
  
  ret_code := BUSY;
  if sEncVar.SSWGetEncoderMemAsync <> eSSW_GetEncoderMemAsync::_Error then
    sEncVar.SSWGetEncoderMemAsyncLast := sEncVar.SSWGetEncoderMemAsync;
  end_if;
  
  case sEncVar.SSWGetEncoderMemAsync of
  
    //*****************************************************************************
    eSSW_GetEncoderMemAsync::_Start:
        
        sEncVar.sEncoderData.bValid       := FALSE;
        sEncVar.Progress                  := 0;
        
        sEncVar.SSWGetEncoderMemAsync := _SelectStartBlockOffset;
    
    //*****************************************************************************
    eSSW_GetEncoderMemAsync::_SelectStartBlockOffset:
    
        // Check Encoder MemSize 
        if (sEncVar.bEncoderMemSizeRead = FALSE) | (sEncVar.EncoderMemSize = 0) then
          sEncVar.LastErrorCode := DRIVEENCMEM_RETERR_ENCODERMEMSIZE_SIZE_INVALID;
          sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Error;
          return;
        end_if;
    
        // Check if requested offset and size are valid.
        if (sEncVar.sEncoderFetch.reqOffset + sEncVar.sEncoderFetch.reqSize) > sEncVar.EncoderMemSize then
          sEncVar.LastErrorCode := DRIVEENCMEM_RETERR_OFFSET_SIZE_OUTOFRANGE;
          sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Error;
          return;
        end_if;
        
        // Check for default size
        if sEncVar.sEncoderFetch.reqSize = 0 then
          // Calculate default size 
          sEncVar.sEncoderFetch.reqSize := sEncVar.EncoderMemSize - sEncVar.sEncoderFetch.reqOffset;
        end_if;
        
        // check if the desired size can be written to the own buffer
        if (sEncVar.sEncoderFetch.reqSize > EncoderBufferSize$UDINT) then
          sEncVar.LastErrorCode := DRIVEENCMEM_RETERR_OFFSET_SIZE_OUTOFBUFFERRANGE;
          sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Error;
          return;
        end_if;
        
        sEncVar.sEncoderFetch.currOffset  := (sEncVar.sEncoderFetch.reqOffset MOD MDD2000_AXISBASE_DRIVEENCMEM_MEMBLOCK_SIZE);
        sEncVar.sEncoderFetch.currBlock   := (sEncVar.sEncoderFetch.reqOffset / MDD2000_AXISBASE_DRIVEENCMEM_MEMBLOCK_SIZE) + MDD2000_AXISBASE_DRIVEENCMEM_MEMBLOCK_ID_OFFSET;
        sEncVar.sEncoderFetch.noByteRead  := 0;
        sEncVar.sEncoderFetch.pDst        := sEncVar.pBuffer;

        sEncVar.SSWGetEncoderMemAsync := _LockScopeAccesses;
        
    //*****************************************************************************
    eSSW_GetEncoderMemAsync::_LockScopeAccesses:
        
        sEncVar.AsyVal := MDD2000_AXISBASE_DRIVEENCMEM_K_FBRW_LOCK;
        retval := AddASyncEntryDS402( uiParaID    := MDD2000_PID_SIGMATEKPARA_INDEX_INFO
                                    , usParaSubID := MDD2000_SPID_K_FBRW
                                    , usRdWr      := 1    // Write Parameter
                                    , pValue      := #sEncVar.AsyVal
                                    , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                                    , pThisObj    := this
                                    , usEntry     := MDD2000MNG_ENTRY_TYPE_DEFAULT
                                    , udTimeout   := 0
                                    , dCallID     := MDD2000_AXISBASE_DRIVEENCMEM_ASYCALLID
                                    );
        
        if retval = 0 then
          sEncVar.SSWGetEncoderMemAsync := _Wait4_LockScopeAccesses;
        else
            
          sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_GETENCODERMEMASYNC_LOCK;
          sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Error;
          
        end_if;
    
    //*****************************************************************************
    eSSW_GetEncoderMemAsync::_Wait4Lock:
    
        if (ops.tAbsolute - sEncVar.ud_TimeMark) > MDD2000_AXISBASE_DRIVEENCMEM_DELAY_RETRYLOCK then
          sEncVar.SSWGetEncoderMemAsync := _LockScopeAccesses;
        end_if;
    
    //*****************************************************************************
    eSSW_GetEncoderMemAsync::_SelectBlock:
        
        sEncVar.AsyVal$UDINT := sEncVar.sEncoderFetch.currBlock;
        retval := AddASyncEntryDS402( uiParaID    := MDD2000_PID_SIGMATEKPARA_INDEX_INFO
                                    , usParaSubID := MDD2000_SPID_K_FBRW
                                    , usRdWr      := 1    // Write Parameter
                                    , pValue      := #sEncVar.AsyVal
                                    , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                                    , pThisObj    := this
                                    , usEntry     := MDD2000MNG_ENTRY_TYPE_DEFAULT
                                    , udTimeout   := 0
                                    , dCallID     := MDD2000_AXISBASE_DRIVEENCMEM_ASYCALLID
                                    );
                                  
        if retval = 0 then
          sEncVar.SSWGetEncoderMemAsync := _Wait4SelectBlockRsp;
        else
          
          sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_SELECT_BLOCK;
          sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Error;
        
        end_if;
    
    //*****************************************************************************
    eSSW_GetEncoderMemAsync::_Wait4SelectBlock:
    
        if (ops.tAbsolute - sEncVar.ud_TimeMark) > MDD2000_AXISBASE_DRIVEENCMEM_DELAY_RETRYLOCK then
          sEncVar.SSWGetEncoderMemAsync := _SelectBlock;
        end_if;
    
    //*****************************************************************************
    eSSW_GetEncoderMemAsync::_StartReadBlock:
        
        sEncVar.AsyVal := sEncVar.sEncoderFetch.currOffset$DINT + MDD2000_AXISBASE_DRIVEENCMEM_P_S_INDEX_VALOFFSET;
        retval := AddASyncEntryDS402( uiParaID    := MDD2000_PID_SIGMATEKPARA_INDEX_INFO
                                    , usParaSubID := MDD2000_SPID_P_S_INDEX
                                    , usRdWr      := 1      // Write Parameter
                                    , pValue      := #sEncVar.AsyVal
                                    , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                                    , pThisObj    := this
                                    , usEntry     := MDD2000MNG_ENTRY_TYPE_DEFAULT
                                    , udTimeout   := 0
                                    , dCallID     := MDD2000_AXISBASE_DRIVEENCMEM_ASYCALLID
                                    );
                                  
        if retval = 0 then
        
          sEncVar.SSWGetEncoderMemAsync := _Wait4StartReadBlock;
        
        else
            
          sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_SELECT_BLOCK_IDX;
          sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Error;
          
        end_if;
       
    //*****************************************************************************
    eSSW_GetEncoderMemAsync::_ReadBlock:
                                  
        retval := AddASyncEntryDS402( uiParaID    := MDD2000_PID_SIGMATEKPARA_INDEX_INFO
                                    , usParaSubID := MDD2000_SPID_P_S_GET1
                                    , usRdWr      := 0          // Read Parameter
                                    , pValue      := NIL
                                    , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                                    , pThisObj    := this
                                    , usEntry     := MDD2000MNG_ENTRY_TYPE_DEFAULT
                                    , udTimeout   := 0
                                    , dCallID     := MDD2000_AXISBASE_DRIVEENCMEM_ASYCALLID
                                    );
        
        if retval = 0 then
        
          sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Wait4ReadBlockRsp;
          
        else
            
          sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_READ_BLOCK;
          sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Error;
          
        end_if;
        
    //*****************************************************************************
    eSSW_GetEncoderMemAsync::_Wait4ReadBlock:
    
          byte2copy := sizeof(DINT);
          sEncVar.sEncoderFetch.currOffset += sizeof(DINT); // Every call with DRIVEENCMEM_P_S_GET1 increases the offset in the drive by 4 byte
          
          if sEncVar.sEncoderFetch.currOffset >= MDD2000_AXISBASE_DRIVEENCMEM_MEMBLOCK_SIZE  then
            // End of block reached
            byte2copy := sizeof(DINT) - (sEncVar.sEncoderFetch.currOffset - MDD2000_AXISBASE_DRIVEENCMEM_MEMBLOCK_SIZE);
            sEncVar.SSWGetEncoderMemAsync := _SelectNextBlock;
          end_if;
          
          if (sEncVar.sEncoderFetch.noByteRead + byte2copy) >= sEncVar.sEncoderFetch.reqSize then
            // End of reqested size reached
            byte2copy := sEncVar.sEncoderFetch.reqSize - sEncVar.sEncoderFetch.noByteRead;
            sEncVar.SSWGetEncoderMemAsync := _ReleaseScopeAccesses;
          end_if;
          
          _memcpy(ptr1:=sEncVar.sEncoderFetch.pDst, ptr2:=#sEncVar.AsyVal, cntr:=byte2copy);
          sEncVar.sEncoderFetch.pDst       += byte2copy;
          sEncVar.sEncoderFetch.noByteRead += byte2copy;
          
          sEncVar.Progress := (sEncVar.sEncoderFetch.noByteRead * 1000 / sEncVar.sEncoderFetch.reqSize);
    
    //*****************************************************************************
    eSSW_GetEncoderMemAsync::_SelectNextBlock:
        
        sEncVar.sEncoderFetch.currOffset := 0;
        sEncVar.sEncoderFetch.currBlock  += 1;
        sEncVar.SSWGetEncoderMemAsync    := _SelectBlock;
    
    //*****************************************************************************
    eSSW_GetEncoderMemAsync::_ReleaseScopeAccesses:
        
        sEncVar.AsyVal := MDD2000_AXISBASE_DRIVEENCMEM_K_FBRW_UNLOCK;
        retval := AddASyncEntryDS402( uiParaID    := MDD2000_PID_SIGMATEKPARA_INDEX_INFO
                                    , usParaSubID := MDD2000_SPID_K_FBRW
                                    , usRdWr      := 1
                                    , pValue      := #sEncVar.AsyVal
                                    , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                                    , pThisObj    := this
                                    , usEntry     := MDD2000MNG_ENTRY_TYPE_DEFAULT
                                    , udTimeout   := 0
                                    , dCallID     := MDD2000_AXISBASE_DRIVEENCMEM_ASYCALLID
                                    );
        
        if retval = 0 then
          sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Wait4ReleaseScopeAccesses;
        else
            
          sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_RELEASEENCODERMEMASYNC_LOCK;
          sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Error;
          
        end_if;
    
    //*****************************************************************************
    eSSW_GetEncoderMemAsync::_Done:
    
        sEncVar.Progress := 1000;                                // Set manual incase of rounding problems
        sEncVar.sEncoderData.pData  := sEncVar.pBuffer;          // Data was copied into buffer from offset
        sEncVar.sEncoderData.Size   := sEncVar.sEncoderFetch.noByteRead;
        sEncVar.sEncoderData.bValid := TRUE;
    
        sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Start;
        ret_code := READY;
   
    //*****************************************************************************
    eSSW_GetEncoderMemAsync::_Error:
    
        HWC_LogPrintf(this,"@08A1 (MDD2000_AxisBase::GetEncoderMemAsync) Failed in step %d, Errorcode %d, Asy Comm Errcode %d." , #sEncVar.SSWGetEncoderMemAsyncLast , #sEncVar.LastErrorCode, #sEncVar.AsyCommErrCode);
        
        if (sEncVar.SSWGetEncoderMemAsyncLast > _LockScopeAccesses) & 
           (sEncVar.SSWGetEncoderMemAsyncLast < _ReleaseScopeAccesses) then
           
          // Attemp to Release ScopeAccess if they have benn locked.
          sEncVar.SSWGetEncoderMemAsync := _ReleaseScopeAccesses;
          ret_code := ERROR_BUSY;
        
        else
        
          sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Start;
          ret_code := ERROR;
          
        end_if;
        
  end_case;

  
END_FUNCTION

FUNCTION VIRTUAL MDD2000_AxisBase::GetEncoderMemFile
	VAR_OUTPUT
		ret_code 	: iprStates;
	END_VAR
  VAR
    retval : DINT;
    MyPara   : CmdStruct;
    MyResult : results;  
    myretcode : iprStates;
    tempAxisNo : DINT;
    tempErrorCode : DINT;
  END_VAR  

  ret_code := BUSY;
  if sEncVar.SSWGetEncoderMemFile <> eSSW_GetEncoderMemFile::_Error then
    sEncVar.SSWGetEncoderMemFileLast := sEncVar.SSWGetEncoderMemFile;
  end_if;
  
  case sEncVar.SSWGetEncoderMemFile of
  
    //*****************************************************************************
    eSSW_GetEncoderMemFile::_Start:
    
        sEncVar.sEncoderData.bValid       := FALSE;
        sEncVar.Progress                  := 0;
    
        // Check Encoder MemSize 
        if (sEncVar.bEncoderMemSizeRead = FALSE) | (sEncVar.EncoderMemSize = 0) then
          sEncVar.LastErrorCode := DRIVEENCMEM_RETERR_ENCODERMEMSIZE_SIZE_INVALID;
          sEncVar.SSWGetEncoderMemFile := eSSW_GetEncoderMemFile::_Error;
          return;
        end_if;
    
        // Check if requested offset and size are valid.
        if (sEncVar.sEncoderFetch.reqOffset + sEncVar.sEncoderFetch.reqSize) > sEncVar.EncoderMemSize then
          sEncVar.LastErrorCode := DRIVEENCMEM_RETERR_OFFSET_SIZE_OUTOFRANGE;
          sEncVar.SSWGetEncoderMemFile := eSSW_GetEncoderMemFile::_Error;
          return;
        end_if;
        
        if (sEncVar.EncoderMemSize > EncoderBufferSize$UDINT) then
          sEncVar.LastErrorCode := DRIVEENCMEM_RETERR_OFFSET_SIZE_OUTOFBUFFERRANGE;
          sEncVar.SSWGetEncoderMemFile := eSSW_GetEncoderMemFile::_Error;
          return;
        end_if;
        
        // Check for default size
        if sEncVar.sEncoderFetch.reqSize = 0 then
          // Calculate default size 
          sEncVar.sEncoderFetch.reqSize := sEncVar.EncoderMemSize - sEncVar.sEncoderFetch.reqOffset;
        end_if;
        
        sEncVar.SSWGetEncoderMemFile := _CreateEncoderMemFile;
    
    //*****************************************************************************
    eSSW_GetEncoderMemFile::_CreateEncoderMemFile:
        
        sEncVar.AsyVal := MDD2000_AXISBASE_DRIVEENCMEM_MEMBLOCK_ID_OFFSET;
        retval := AddASyncEntryDS402( uiParaID    := MDD2000_PID_SIGMATEKPARA_INDEX_INFO
                                    , usParaSubID := MDD2000_SPID_K_FBRW
                                    , usRdWr      := 1          // Write Parameter
                                    , pValue      := #sEncVar.AsyVal
                                    , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                                    , pThisObj    := this
                                    , usEntry     := MDD2000MNG_ENTRY_TYPE_DEFAULT
                                    , udTimeout   := 0
                                    , dCallID     := MDD2000_AXISBASE_DRIVEENCMEM_ASYCALLID
                                    );
                                  
        if retval = 0 then
          sEncVar.ud_TimeMark := ops.tAbsolute;
          sEncVar.SSWGetEncoderMemFile := _Wait4CreateEncoderMemFile;
        else
            
          sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_SELECT_BLOCK;
          sEncVar.SSWGetEncoderMemFile := eSSW_GetEncoderMemFile::_Error;

        end_if;
    
    //*****************************************************************************
    eSSW_GetEncoderMemFile::_Wait4EncoderMemFileUnlock:
    
        if (ops.tAbsolute - sEncVar.ud_TimeMark) > MDD2000_AXISBASE_DRIVEENCMEM_DELAY_RETRYLOCK then
          sEncVar.SSWGetEncoderMemFile := _CreateEncoderMemFile;
        end_if;
    
    //*****************************************************************************
    eSSW_GetEncoderMemFile::_Wait4EncoderMemFileCreate:
    
        if (ops.tAbsolute - sEncVar.ud_TimeMark) > MDD2000_AXISBASE_DRIVEENCMEM_DELAY_FILECREATE then // Minimum known time it takes to create the file. Depends on the encoder
          sEncVar.SSWGetEncoderMemFile := _CheckEncoderMemFileCreate;
        end_if;        
    
    //*****************************************************************************
    eSSW_GetEncoderMemFile::_CheckEncoderMemFileCreate:
        
        // Read back MDD2000_SPID_K_FBRW to check if file has been created
        retval := AddASyncEntryDS402( uiParaID    := MDD2000_PID_SIGMATEKPARA_INDEX_INFO
                                    , usParaSubID := MDD2000_SPID_K_FBRW
                                    , usRdWr      := 0  // Read Parameter
                                    , pValue      := NIL
                                    , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                                    , pThisObj    := this
                                    , usEntry     := MDD2000MNG_ENTRY_TYPE_DEFAULT
                                    , udTimeout   := 0
                                    , dCallID     := MDD2000_AXISBASE_DRIVEENCMEM_ASYCALLID
                                    );
        if retval = 0 then
         
          sEncVar.SSWGetEncoderMemFile  := _Wait4CheckEncoderMemFileCreate;
          
        else
          sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_CHECK_START_FILEREAD;          
          sEncVar.SSWGetEncoderMemFile  := eSSW_GetEncoderMemFile::_Error;
        end_if;
        
    //*****************************************************************************
    eSSW_GetEncoderMemFile::_ReadEncoderMemFile:
      
        tempAxisNo := AxisNo;
        sigclib_sprintfST(pd:=#sEncVar.strFilePathDrv[0], MDD2000_AXISBASE_DRIVEENCMEM_FILENPATH, #tempAxisNo);

        MyPara.uiCmd := MDD2000MNG_NEWINST_GETFILEBUFFER;                    //command to get a specific file from the drive and save it on the PLC
        MyPara.aPara[0]$DINT  := MDD2000MNG_NEWINST_GETFILEBUFFER_VER_1;     // Command Version : 1
        MyPara.aPara[1]$^CHAR := #sEncVar.strFileNameDrv[0];  // Pointer to filename of the drive
        MyPara.aPara[2]$^CHAR := #sEncVar.strFilePathDrv[0];  // Pointer to the file path/directory of the drive 
        MyPara.aPara[3]$UDINT := EncoderBufferSize$UDINT;     // Size of buffer (pDataBuffer) in bytes.
        MyPara.aPara[4]$^void := sEncVar.pBuffer;             // Pointer to buffer where read data will be copied.
        MyPara.aPara[5]$UDINT := sEncVar.EncoderMemSize;      // Can be used if only x-bytes from the file should be read. Otherwise all data from the file will be read out.0 ... Read all bytes from file.x ... Read x bytes from file. (optional, can be NIL)
        MyPara.aPara[6]$^DINT := #tempErrorCode;              // Pointer to a 4 Byte Error variable where errorcodes will be written when there is an error (optional, can be NIL)
        
        myretcode := DriveMng.NewInst(pPara:=#MyPara, pResult:=#MyResult);
        
        if myretcode = READY then
          sEncVar.SSWGetEncoderMemFile := _Wait4EncoderMemFile;
        elsif myretcode = ERROR then
          sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_START_FILEREAD;
          sEncVar.AsyCommErrCode        := tempErrorCode; // Safe for simplified logging
          sEncVar.SSWGetEncoderMemFile := eSSW_GetEncoderMemFile::_Error;
        end_if;
    
    //*****************************************************************************
    eSSW_GetEncoderMemFile::_Wait4EncoderMemFile:
    
        MyPara.uiCmd := MDD2000MNG_NEWINST_GETFILESTATE;                     // Command to check the current MDD2000MNG_NEWINST_GETFILE, MDD2000MNG_NEWINST_GETLOGFILE, MDD2000MNG_NEWINST_SETFILE, MDD2000MNG_NEWINST_GETFILESIZE, MDD2000MNG_NEWINST_GETFILEBUFFER progress
        MyPara.aPara[0]$DINT    := MDD2000MNG_NEWINST_GETFILESTATE_VER_1;    // Command Version : 1  
        MyPara.aPara[1]$^DINT   := #tempErrorCode;            // Pointer to a 4 Byte Error variable where errorcodes will be written when there is an error (optional, can be NIL)
        MyPara.aPara[2]$^DINT   := (#sEncVar.Progress)$^DINT; // Pointer to a 4 Byte variable where the progress of the file upload or download will be written in 0.1 percentage (1000 = 100%)
        MyPara.aPara[3]$^UDINT  := NIL;                       // Pointer to where the amount of read bytes will be copied (optional, can be NIL)

        myretcode := DriveMng.NewInst(pPara:=#MyPara, pResult:=#MyResult);

        if myretcode = READY then
          sEncVar.SSWGetEncoderMemFile := eSSW_GetEncoderMemFile::_Done;
        elsif myretcode = ERROR then
          sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_FILEREAD;
          sEncVar.AsyCommErrCode        := tempErrorCode; // Safe for simplified logging
          sEncVar.SSWGetEncoderMemFile  := eSSW_GetEncoderMemFile::_Error;
        end_if;
    
    //*****************************************************************************
    eSSW_GetEncoderMemFile::_Done:
    
        sEncVar.Progress := 1000;                                           // Set manual incase of rounding problems
        sEncVar.sEncoderData.pData  := sEncVar.pBuffer + sEncVar.sEncoderFetch.currOffset;  // All data was read, apply offset
        sEncVar.sEncoderData.Size   := sEncVar.sEncoderFetch.reqSize;               // All data was read, apply size
        sEncVar.sEncoderData.bValid := TRUE;
        
        sEncVar.SSWGetEncoderMemFile := eSSW_GetEncoderMemFile::_Start;
        ret_code := READY;
    
    //*****************************************************************************
    eSSW_GetEncoderMemFile::_Error:
    
        HWC_LogPrintf(this,"@08A2 (MDD2000_AxisBase::GetEncoderMemFile) Failed in step %d, Errorcode %d, Asy Comm Errcode %d." , #sEncVar.SSWGetEncoderMemFileLast , #sEncVar.LastErrorCode, #sEncVar.AsyCommErrCode);
        sEncVar.SSWGetEncoderMemFile := eSSW_GetEncoderMemFile::_Start;
        ret_code := ERROR;
        
  end_case;
  
END_FUNCTION

FUNCTION VIRTUAL MDD2000_AxisBase::GetEncoderMemNewInst
	VAR_INPUT
		pPara 	: ^CmdStruct;
		pResult 	: ^results;
	END_VAR
	VAR_OUTPUT
		ret_code 	: iprStates;
	END_VAR
  VAR
    hIndex        : HINT;
    hsSubIndex    : HSINT;
    bRW           : BOOL;
    dValue        : DINT;    
    dCallID       : DINT;
    dErrorCode    : DINT;
  END_VAR
  
  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;
      dValue      := pPara^.aPara[6]$^DINT^;
      dCallID     := pPara^.aPara[7]$DINT;

      //Check index
      case hIndex of
        //*****************************************************************************
        MDD2000_PID_SIGMATEKPARA_INDEX_SET:
        
          case hsSubIndex of           
              
            //*****************************************************************************
            MDD2000_SPID_A_INT1:              
            
              //Check if it was a write command
              if (bRW = 1) then                
                
                sEncVar.SSWGetEncoderMemSize := _SendRdPara;
                
              end_if;
          
          end_case;
          
        //*****************************************************************************
        MDD2000_PID_SIGMATEKPARA_INDEX_INFO:
        
          // check the subindex number
          case hsSubIndex of
          
            //*****************************************************************************          
            MDD2000_SPID_I_INT1:
            
              if (bRW = 0) then // command was a read command
                sEncVar.bEncoderMemSizeRead := TRUE;
                if dValue > 0 then
                  sEncVar.EncoderMemSize := dValue$UDINT;
                else
                  sEncVar.EncoderMemSize := 0;
                end_if;
                
              end_if;
        
            //*****************************************************************************          
            MDD2000_SPID_K_FBRW :
              if (bRW = 1) then     // command was a write command
                
                if dValue = MDD2000_AXISBASE_DRIVEENCMEM_K_FBRW_LOCK then
                  sEncVar.SSWGetEncoderMemAsync := _SelectBlock;
                elsif dValue =  MDD2000_AXISBASE_DRIVEENCMEM_K_FBRW_UNLOCK then 
                  sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Done;
                elsif dValue = MDD2000_AXISBASE_DRIVEENCMEM_MEMBLOCK_ID_OFFSET then
                  sEncVar.SSWGetEncoderMemFile := _Wait4EncoderMemFileCreate;
                elsif dValue$UDINT = sEncVar.sEncoderFetch.currBlock then
                  sEncVar.SSWGetEncoderMemAsync := _StartReadBlock;
                end_if;
              
              elsif (bRW = 0) then     // command was a read command
              
                if dValue = MDD2000_AXISBASE_DRIVEENCMEM_K_FBRW_OK then
                  sEncVar.SSWGetEncoderMemFile := _ReadEncoderMemFile;        // File created Ok, continue with read
                elsif dValue = MDD2000_AXISBASE_DRIVEENCMEM_K_FBRW_BUSY then
                  sEncVar.ud_TimeMark := ops.tAbsolute;
                  sEncVar.SSWGetEncoderMemFile := _Wait4EncoderMemFileCreate; // File is beeing created, try again later
                else
                  sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_CHECK_START_FILEREAD_RETVAL;
                  sEncVar.AsyCommErrCode        := dValue; // Safe for simplified logging
                  sEncVar.SSWGetEncoderMemFile  := eSSW_GetEncoderMemFile::_Error;
                end_if;
                
              end_if;
              
            //*****************************************************************************          
            MDD2000_SPID_P_S_INDEX:
              
              if (bRW = 1) then  // was a write command
                sEncVar.SSWGetEncoderMemAsync := _ReadBlock;
              end_if;
            
            //*****************************************************************************          
            MDD2000_SPID_P_S_GET1:              
              
              if (bRW = 0) then // command was a read command
                sEncVar.AsyVal := dValue;
                sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Wait4ReadBlock;
              end_if;
              
          end_case;
       end_case;
       
    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;
      dValue      := pPara^.aPara[6]$^DINT^;
      
      dCallID     := pPara^.aPara[7]$DINT;
      dErrorCode  := pPara^.aPara[8]$DINT;
      
      //Check index
      case hIndex of
        
        //*****************************************************************************
        MDD2000_PID_SIGMATEKPARA_INDEX_SET:
        
          case hsSubIndex of
            
            //*****************************************************************************
            MDD2000_SPID_A_INT1:
            
              //Check if it was a write command
              if (bRW = 1) then
                
                sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_GETENCODERMEMSIZE_ASYWR;
                sEncVar.SSWGetEncoderMemSize  := eSSW_GetEncoderMemSize::_Error;
                sEncVar.AsyCommErrCode        := dErrorCode;  // Errorcode
                
              end_if;
              
          end_case;
          
        //*****************************************************************************
        MDD2000_PID_SIGMATEKPARA_INDEX_INFO:
        
          // check the subindex number
          case hsSubIndex of
          
            //*****************************************************************************          
            MDD2000_SPID_I_INT1:
            
              if (bRW = 0) then // command was a read command
                sEncVar.bEncoderMemSizeRead := TRUE;
                sEncVar.EncoderMemSize      := 0;
                sEncVar.AsyCommErrCode        := dErrorCode;  // Errorcode
              end_if;
        
            //*****************************************************************************          
            MDD2000_SPID_K_FBRW :
            
              if (bRW = 1) then  // was a write command
                
                if dValue = MDD2000_AXISBASE_DRIVEENCMEM_K_FBRW_LOCK then
                  
                  sEncVar.AsyCommErrCode := dErrorCode;  // Errorcode
                  if sEncVar.AsyCommErrCode = MDD2000_AXISBASE_DRIVEENCMEM_ASYCOMERR_RETRY then
                    // Asy returned an error because some else already got the lock
                    sEncVar.ud_TimeMark := ops.tAbsolute;
                    sEncVar.SSWGetEncoderMemAsync := _Wait4Lock;
                    
                  else
                    
                    sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_GETENCODERMEMASYNC_LOCK;
                    sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Error;
                  
                  end_if;
                
                elsif dValue =  MDD2000_AXISBASE_DRIVEENCMEM_K_FBRW_UNLOCK then 
                
                  sEncVar.AsyCommErrCode := dErrorCode;  // Errorcode
                  sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_RELEASEENCODERMEMASYNC_LOCK;
                  sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Error;
                
                elsif dValue = MDD2000_AXISBASE_DRIVEENCMEM_MEMBLOCK_ID_OFFSET then
                  
                  sEncVar.AsyCommErrCode := dErrorCode;  // Errorcode
                  if sEncVar.AsyCommErrCode = MDD2000_AXISBASE_DRIVEENCMEM_ASYCOMERR_RETRY then
                    
                    // Asy returned an error because some else already selects the block
                    sEncVar.SSWGetEncoderMemFile := _Wait4EncoderMemFileUnlock;
                    
                  else
                  
                    sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_SELECT_BLOCK;
                    sEncVar.SSWGetEncoderMemFile := eSSW_GetEncoderMemFile::_Error;
          
                  end_if;
            
                elsif dValue$UDINT = sEncVar.sEncoderFetch.currBlock then
                  
                  sEncVar.AsyCommErrCode := dErrorCode;  // Errorcode
                  if sEncVar.AsyCommErrCode = MDD2000_AXISBASE_DRIVEENCMEM_ASYCOMERR_RETRY then
                    // Asy returned an error because some else already selects the block
                    sEncVar.ud_TimeMark := ops.tAbsolute;
                    sEncVar.SSWGetEncoderMemAsync := _Wait4SelectBlock;
                    
                  else
                    
                    sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_SELECT_BLOCK;
                    sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Error;                  
                  
                  end_if;
                  
                end_if;
              elsif (bRW = 2) then // was a read command
                sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_CHECK_START_FILEREAD;          
                sEncVar.SSWGetEncoderMemFile  := eSSW_GetEncoderMemFile::_Error;
              
              end_if;
              
            //*****************************************************************************          
            MDD2000_SPID_P_S_INDEX:
            
              if (bRW = 1) then  // was a write command
                sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_SELECT_BLOCK;
                sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Error;
                sEncVar.AsyCommErrCode        := dErrorCode;  // Errorcode
              end_if;
              
            //*****************************************************************************          
            MDD2000_SPID_P_S_GET1:
              
              if (bRW = 0) then // command was a read command
                sEncVar.LastErrorCode         := DRIVEENCMEM_RETERR_READ_BLOCK;
                sEncVar.SSWGetEncoderMemAsync := eSSW_GetEncoderMemAsync::_Error;
                sEncVar.AsyCommErrCode        := dErrorCode;  // Errorcode
              end_if;
              
          end_case;
      end_case;

    end_if;
    
  end_case;
    
END_FUNCTION

FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::FetchEncoderData
	VAR_INPUT
		Offset 	: UDINT;(* := 0 *)
		Size 	: UDINT;(* := 0 *)
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR
  
  retcode := Error;  
  if sEncVar.State = 1 then
  
    // Check if request is aleady active
    if sEncVar.bdUserRequest.FetchEncoderData then
      retcode := Busy;
      return;
    end_if;
    
    sEncVar.sEncoderData.bValid       := FALSE;
  
    // Check if passed values fit in Buffer - Only size must fit into EncoderBufferSize
    if (Size > EncoderBufferSize$UDINT) then
      sEncVar.LastErrorCode := DRIVEENCMEM_RETERR_OFFSET_SIZE_OUTOFBUFFERRANGE;
      return;
    end_if;
    
    // Check if requested offset and size are valid.
    if sEncVar.bEncoderMemSizeRead then // Check is only possible, if encoder size has already been read
    
      if sEncVar.EncoderMemSize = 0 then
        sEncVar.LastErrorCode := DRIVEENCMEM_RETERR_ENCODERMEMSIZE_SIZE_INVALID;
        return;
      elsif (Offset + Size) > sEncVar.EncoderMemSize then
        sEncVar.LastErrorCode := DRIVEENCMEM_RETERR_OFFSET_SIZE_OUTOFRANGE;
        return;
      end_if;
      
    else
    
      // Encoder size has not been read yet, must be done before data can be fetched.
      sEncVar.bdUserRequest.GetFeedbackDataSize := 1;
    
    end_if;  
    
    // Set request
    sEncVar.sEncoderFetch.reqOffset := Offset;
    sEncVar.sEncoderFetch.reqSize   := Size;      // Correcting size = 0 ist done at the start of GetEncoderMemAsync, GetEncoderMemFile because a valid EncoderMemSize is needed 
    
    sEncVar.bdUserRequest.FetchEncoderData := 1;
    retcode := READY; 
    
  end_if;

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::CheckFetchEncoderData
	VAR_INPUT
		pProgress 	: ^UDINT;(* := nil *)
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR
  
  retcode := Error;
  if sEncVar.State = 1 then  
    
    if sEncVar.sEncoderData.bValid then
      retcode := READY;
    elsif sEncVar.bdUserRequest then
      retcode := BUSY;
    else
      if sEncVar.LastErrorCode = DRIVEENCMEM_RETOK then
        // Only overwrite if no error was set
        sEncVar.LastErrorCode := DRIVEENCMEM_RETERR_ENCODER_MEM_NOTREAD;  // User has not yet called FetchEncoderData
      end_if;
    end_if;
    
    if pProgress then
      pProgress^ := sEncVar.Progress;
    end_if;
  
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::GetEncoderErrorCode
	VAR_OUTPUT
		ErrorCode 	: DINT;
	END_VAR
  
  ErrorCode := sEncVar.LastErrorCode;
  
  if (sEncVar.LastErrorCode = DRIVEENCMEM_RETOK) & (sEncVar.State = 0) then
    
    // Return not online because all other methods return ERROR when Axis is not online.
    // Do not overwrite the ErrorCode for negative ClassStates as these are set in the Init()
    ErrorCode := DRIVEENCMEM_RETERR_AXISNOTONLINE;
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::GetEncoderDataSize
	VAR_INPUT
		pSize 	: ^UDINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR
  
  retcode := Error;
  if sEncVar.State = 1 then
  
    if pSize then
      
      if sEncVar.bEncoderMemSizeRead then
      
        pSize^ := to_udint(sEncVar.EncoderMemSize);
        
        if sEncVar.EncoderMemSize then
          retcode := READY;
        else
          // Encoder mem was read ok but returned 0
          sEncVar.LastErrorCode := DRIVEENCMEM_RETERR_NO_ENCODER_MEM;
        end_if;
      
      else
        
        // Encoder mem was not yet read, set request
        sEncVar.bdUserRequest.GetFeedbackDataSize := 1;
        retcode := BUSY;
      
      end_if;
    
    else
    
      sEncVar.LastErrorCode := DRIVEENCMEM_RETERR_CMD_PARAMETER_NIL;
      
    end_if;
  
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::GetEncoderData
	VAR_INPUT
		pSize 	: ^UDINT;(* := NIL *)
	END_VAR
	VAR_OUTPUT
		pData 	: pVoid;
	END_VAR
  
  pData := NIL;
  if sEncVar.State = 1 then
    
    if sEncVar.sEncoderData.bValid then
    
      pData := sEncVar.sEncoderData.pData;
      
      if pSize then
        pSize^ := sEncVar.sEncoderData.Size;
      end_if;
    
    else
      
      if sEncVar.LastErrorCode = DRIVEENCMEM_RETOK then
        // Only overwrite if no error was set
        sEncVar.LastErrorCode := DRIVEENCMEM_RETERR_ENCODER_MEM_NOTREAD;
      end_if;
      
    end_if;
  
  end_if;
  
END_FUNCTION


FUNCTION MDD2000_AxisBase::RefreshParameterObjects
	VAR_INPUT
		pPara 	: ^CmdStruct;
		pResult 	: ^results;
	END_VAR
	VAR_OUTPUT
		ret_code 	: iprStates;
	END_VAR
  VAR
    pThisNewInst    : ^void;
    hIndex          : HINT;
    hsSubIndex      : HSINT;
    LogVal1         : DINT;
  END_VAR
  
  ret_code := ERROR;  //unsupported version

  pResult^.uiLng := 4;
  pResult^.aData[0]$DINT := MDD2000MNG_IF_REFRESH_PARA_OBJECTS_VER_MAX;  //max supported version
  
  //Check version 1
  if pPara^.aPara[0] = MDD2000MNG_IF_REFRESH_PARA_OBJECTS_VER_1 then
                                            
    hIndex     := pPara^.aPara[1]$HINT;
    hsSubIndex := pPara^.aPara[2]$HSINT;
    
    pThisNewInst := GetThisPointerOfParaClassViaParam(hIndex, hsSubIndex);
    
    //Forward newinst to the correct class
    if pThisNewInst <> NIL then
      ret_code := pThisNewInst$^VirtualBase^.NewInst(pPara, pResult);
    else
      
      // Do not Log. Refresh Parameter is called when the Drivetool updates Parameter. Parameter Class does not need to be place => No Error!
//      LogVal1 := TO_DINT(hIndex);
//      Logval2 := TO_DINT(hsSubIndex);
//      HWC_LogPrintf(pThis:=this, format:="@08CE (MDD2000_AxisBase::RefreshParameterObjects) Can't find a parameter class to refresh the parameter with index 0x%X and subindex 0x%X", p0:=#LogVal1, p1:=#LogVal2);
    end_if;
  else
    LogVal1 := pPara^.aPara[0];
    HWC_LogPrintf(pThis:=this, format:="@08CF (MDD2000_AxisBase::RefreshParameterObjects) Version %d of Newinst command MDD2000MNG_IF_REFRESH_PARA_OBJECTS is not supported by this class", p0:=#LogVal1);
  end_if;   

END_FUNCTION


FUNCTION MDD2000_AxisBase::IsCommandoParameter
	VAR_INPUT
		hIndex 	: HINT;
		hsSubIndex 	: HSINT;
	END_VAR
	VAR_OUTPUT
		bCommandoParameter 	: BOOL;
	END_VAR
  
  bCommandoParameter := FALSE;  //No commando parameter as default
  
  //Check if it is a commando parameter
  if hIndex = MDD2000_PID_SIGMATEKPARA_INDEX_INFO then
  
    case hsSubIndex of

      MDD2000_SPID_K_EN,
      MDD2000_SPID_K_CLRF,
      MDD2000_SPID_K_BRAKE,
      MDD2000_SPID_K_FBRW,
      MDD2000_SPID_K_START,
      MDD2000_SPID_K_CI,
      MDD2000_SPID_K_CINC,
      MDD2000_SPID_K_SPEED,
      MDD2000_SPID_K_STEP,
      MDD2000_SPID_K_PMOVE,
      MDD2000_SPID_K_PINC,
      MDD2000_SPID_K_PHI,
      MDD2000_SPID_K_SBT, 
      MDD2000_SPID_T_CMD,
      MDD2000_SPID_K_NETIP,
      MDD2000_SPID_K_NETGW,
      MDD2000_SPID_K_NETSM,
      MDD2000_SPID_K_DATE:
  
        bCommandoParameter := TRUE;
      
    end_case;
  end_if;

END_FUNCTION


FUNCTION MDD2000_AxisBase::GetThisPointerOfParaClassViaParam
	VAR_INPUT
		hIndex 	: HINT;
		hsSubIndex 	: HSINT;
	END_VAR
	VAR_OUTPUT
		pThisNewInst 	: ^void;
	END_VAR

  pThisNewInst := NIL;
  
  //Check for special parameters which are not in the range of the parameter groups anymore
  case hIndex of
    //*****************************************************************************
    MDD2000_PID_SIGMATEKPARA_INDEX_SET:
    
      case hsSubIndex of
        // Extended motor parameter
        MDD2000_SPID_E_I2TT,
        MDD2000_SPID_E_TISO,
        MDD2000_SPID_E_INENN,
        MDD2000_SPID_E_NNENN:
          pThisNewInst := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_MOTOR);
        
        // Optional parameter
        MDD2000_SPID_O_TYPE,
        MDD2000_SPID_O_RPULSE,
        MDD2000_SPID_O_RPOL,
        MDD2000_SPID_O_BW,
        MDD2000_SPID_O_RK,
        MDD2000_SPID_O_FILT,
        MDD2000_SPID_O_BCONF,
        MDD2000_SPID_O_PSCALE:
          pThisNewInst := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_OPTIONAL);

        // current parameter
        MDD2000_SPID_C_IFWEAK:
          pThisNewInst := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_CURRENT);      
      
      end_case;
      
    //*****************************************************************************
    MDD2000_PID_SIGMATEKPARA_INDEX_INFO:
    
      case hsSubIndex of
        MDD2000_SPID_I_STATUS:
          pThisNewInst := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_ERRORHANDLING);      
        MDD2000_SPID_I_DERR1:
          pThisNewInst := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_ERRORHANDLING);      
        MDD2000_SPID_I_DERR2:
          pThisNewInst := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_ERRORHANDLING);      
        MDD2000_SPID_I_DERR3:
          pThisNewInst := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_ERRORHANDLING);      
      end_case;
        
  end_case;

  //IF we already found the correct class, we can skip this block
  if pThisNewInst = NIL then
  
    //Search correct parameter class for this parameter
    if hsSubIndex <= MDD2000MNG_MAX_MOTOR_PARA then
      pThisNewInst := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_MOTOR);
    elsif hsSubIndex <= MDD2000MNG_MAX_DRIVE_PARA then
      pThisNewInst := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_DRIVE);
    elsif hsSubIndex <= MDD2000MNG_MAX_CURRENT_PARA then
      pThisNewInst := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_CURRENT);
    elsif hsSubIndex <= MDD2000MNG_MAX_VEL_PARA then
      pThisNewInst := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_VEL);
    elsif hsSubIndex <= MDD2000MNG_MAX_POS_PARA then
      pThisNewInst := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_POS);
    elsif hsSubIndex <= MDD2000MNG_MAX_FD_PARA then
      pThisNewInst := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_FD);
    elsif hsSubIndex <= MDD2000MNG_MAX_APPLI_PARA then
      pThisNewInst := GetThisPointerOfParaClassViaIndex(udParaClassIndex:=MDD2000MNG_PARAIDX_APPLI);
    end_if;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::SetVerified::Write
	VAR_INPUT
		input (EAX) 	: DINT;
	END_VAR
	VAR_OUTPUT
		result (EAX) 	: DINT;
	END_VAR
  
  SetVerified := input;
  SetSafeVerified(SetVerified);
	result := SetVerified;

END_FUNCTION


FUNCTION MDD2000_AxisBase::GetThisPointerOfParaClassViaIndex
	VAR_INPUT
		udParaClassIndex 	: UDINT;
	END_VAR
	VAR_OUTPUT
		pThisNewInst 	: ^void;
	END_VAR
  VAR
  	idx : DINT;
    maxidx : DINT;  
  END_VAR
  
  pThisNewInst := NIL;  //init as not found
  
  // Go through all para classes
  maxidx := (sizeof(sParaObjectList)/sizeof(t_MDD2000Mng_ParaObjectListEntry)) - 1;
  for idx := 0 to maxidx do
    if sParaObjectList[idx].udIndex = udParaClassIndex then
      pThisNewInst := sParaObjectList[idx].pObject;
      exit;
    end_if;
  end_for;

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::SafetyAxErrorQuit
	VAR_INPUT
		AxErrorQuit 	: DINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR
  VAR
  	dValue : DINT;
    MyPara 	      : CmdStruct;
		MyResult 	    : results;
  END_VAR
  
  retcode := ERROR; // AxErrorQuit invalid / Not online
  
  if Online then
  
    if AxErrorQuit = DRIVESAFETYIF_RESTART_ACK then
      
      // Restart Ackknowledge, used for STO, SOS, SS1, SS2
      // Write the command
      dValue := 1;
      if AddASyncEntryDS402(uiParaID    := MDD2000_PID_SAFETY_AXIS_FUNC_INFO
                          , usParaSubID := MDD2000_SPID_SAFETY_AXIS_RESTARTACK
                          , usRdWr      := 1
                          , pValue      := #dValue
                          , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                          , pThisObj    := this) = 0 then
        
        retcode := READY;
      else
        retcode := ERROR;
      end_if;
      
    elsif AxErrorQuit = DRIVESAFETYIF_ERROR_ACK then
      
      // Error Ackknowledge, used when an error occoured during a safety function
      // Write the command
      dValue := 1;
      if AddASyncEntryDS402(uiParaID    := MDD2000_PID_SAFETY_AXIS_FUNC_INFO
                          , usParaSubID := MDD2000_SPID_SAFETY_AXIS_ERRORACK
                          , usRdWr      := 1
                          , pValue      := #dValue
                          , bsDataInfo  := MDD2000MNG_DATASIZE_4BYTE
                          , pThisObj    := this) = 0 then
      
        retcode := READY;
      else
        retcode := ERROR;
      end_if;
      
    elsif AxErrorQuit = DRIVESAFETYIF_ERROR_QUIT then
      
      // Quits an safety error on the drive, example: MDD2000_Mng.SafetyRunState = _ERROR
      // Pass on to Mng
      
      MyPara.uiCmd    := DRIVESAFETYIF_DOSAFETYAXERRORQUIT;
      MyPara.aPara[0] := DRIVESAFETYIF_DOSAFETYAXERRORQUIT_VER_1;
      MyPara.aPara[1] := DRIVESAFETYIF_ERROR_QUIT;
      MyPara.aPara[2] := TO_DINT(usAxisIndex);
      
      retcode := DriveMng.NewInst(pPara:=#MyPara, pResult:=#MyResult);
      
    end_if;
  end_if;
  
END_FUNCTION

FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::SetSafeVerified
	VAR_INPUT
		NewSetVerified 	: DINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: iprstates;
	END_VAR
  VAR
  	dValue : DINT;
    MyPara 	      : CmdStruct;
		MyResult 	    : results;
  END_VAR
  
  retcode := ERROR;
  if Online then
  
    //  0 .. Read VerifiedState from Drive, 
    // -1 .. Reset VerifiedState of all axes and Reset ReferenceState of this axis, 
    // -2 .. Reset VerifiedState of all axes, 
    //  1 .. SetVerified and Read VerifiedState from Drive
    if NewSetVerified = -1 then // Reset Verify of all axis and reset Reference of this axis
      
      MyPara.uiCmd    := MDD2000MNG_IF_RESET_SAFE_VERIFY_ZEROPOS;
      MyPara.aPara[0] := MDD2000MNG_IF_RESET_SAFE_VERIFY_ZEROPOS_VER_1;
      MyPara.aPara[1] := TO_DINT(usAxisIndex);
      MyPara.aPara[2] := MDD2000MNG_IF_RESET_SAFE_VERIFY_ZEROPOS_SAFEVERIFIYZEROPOS;
      retcode := DriveMng.NewInst(#MyPara, #MyResult);
      VerifiedState  := t_e_SafeVerifiedState::Reading; // Start Reading will be triggered by Leave Service Mode
  
    elsif NewSetVerified = -2 then // Reset Verify of all axis
    
      MyPara.uiCmd    := MDD2000MNG_IF_RESET_SAFE_VERIFY_ZEROPOS;
      MyPara.aPara[0] := MDD2000MNG_IF_RESET_SAFE_VERIFY_ZEROPOS_VER_1;
      MyPara.aPara[1] := TO_DINT(usAxisIndex);
      MyPara.aPara[2] := MDD2000MNG_IF_RESET_SAFE_VERIFY_ZEROPOS_SAFEVERIFIY;
      retcode := DriveMng.NewInst(#MyPara, #MyResult);
      VerifiedState  := t_e_SafeVerifiedState::Reading; // Start Reading will be triggered by Leave Service Mode
    
    elsif (NewSetVerified = 0) | (NewSetVerified = 1) then
    
      retcode := READY;
    
      if NewSetVerified <> 0 then
        
        dValue := NewSetVerified;
        // Write the command
        if ( AddASyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_AXIS_INFO, usParaSubID := MDD2000_SPID_SAFETY_AXIS_VERIFY_FEEDBACK, usRdWr:=1, pValue:= #dValue, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) <> 0 then
          retcode := ERROR;
        end_if;
        SetVerifiedRsp := t_e_SetVerifiedRsp::CmdBusy;
      end_if;  
      
      VerifiedState  := t_e_SafeVerifiedState::Reading;
      
      // Reread the Verified States and response
      bdSettings.bReadSafeVerifyState := TRUE;
    
    end_if;
  end_if;
  
END_FUNCTION

FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::SetSafeReference
	VAR_INPUT
		NewSetReference 	: DINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: iprstates;
	END_VAR
  VAR
  	dValue : DINT;
    MyPara 	      : CmdStruct;
		MyResult 	    : results;
  END_VAR
  
  retcode := ERROR;
  if Online then
  
    if (NewSetReference = -1) then
    
      if (sSafeRefState.RefState <> DRIVESAFETYIF_STATE_NOT_NEEDED) & 
         (sSafeRefState.RefState <> DRIVESAFETYIF_STATE_NOT_REFERENCED) then
        
        MyPara.uiCmd    := MDD2000MNG_IF_RESET_SAFE_VERIFY_ZEROPOS;
        MyPara.aPara[0] := MDD2000MNG_IF_RESET_SAFE_VERIFY_ZEROPOS_VER_1;
        MyPara.aPara[1] := TO_DINT(usAxisIndex);
        MyPara.aPara[2] := MDD2000MNG_IF_RESET_SAFE_VERIFY_ZEROPOS_SAFEZEROPOS;
        retcode := DriveMng.NewInst(#MyPara, #MyResult);
        
        sSafeRefState.RefState := DRIVESAFETYIF_REFSTATE_BUSY;  // Start Reading will be triggered by Leave Service Mode
        
      end_if;
      
    elsif (NewSetReference = 1 | NewSetReference = 0) then
    
      retcode := READY;
    
      if NewSetReference = 1 then
        dValue := DRIVESAFETYIF_REFCMD_SETZERO_POS;
        if ( AddASyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_AXIS_INFO, usParaSubID := MDD2000_SPID_SAFETY_AXIS_SETZEROPOS, usRdWr:=1, pValue:= #dValue, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) <> 0 then
          retcode := ERROR;
        end_if;
        if ( AddASyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_AXIS_INFO, usParaSubID := MDD2000_SPID_SAFETY_AXIS_SETZEROPOS, usRdWr:=0, pValue:= #dValue, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) <> 0 then
          retcode := ERROR;
        end_if;
        sSafeRefState.CmdState := DRIVESAFETYIF_REFCMD_BUSY;
      end_if;
      
      sSafeRefState.RefState := DRIVESAFETYIF_REFSTATE_BUSY;
      bdSettings.bReadSafeRefState :=TRUE;
    
    end_if;
  end_if;
  
END_FUNCTION

FUNCTION VIRTUAL GLOBAL MDD2000_AxisBase::SetSafeAckZeroposition
	VAR_INPUT
		NewAckZeroposition 	: DINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: iprstates;
	END_VAR
  VAR
  	dValue : DINT;
  END_VAR
  
  retcode := ERROR;
  if Online then
  
    if (NewAckZeroposition = -1) | (NewAckZeroposition = 0) | (NewAckZeroposition = 1) then
    
      retcode := READY;
      
      if NewAckZeroposition <> 0 then
        dValue := DRIVESAFETYIF_REFCMD_ACKZERO_POS; // Acknowledge the zero pos
      
        if NewAckZeroposition = -1 then
          dValue := DRIVESAFETYIF_REFCMD_ABORT; // Abort the reference process
        end_if;
       
        if ( AddASyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_AXIS_INFO, usParaSubID := MDD2000_SPID_SAFETY_AXIS_SETZEROPOS, usRdWr:=1, pValue:= #dValue, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) <> 0 then
          retcode := ERROR;
        end_if;
       
       sSafeRefState.CmdState := DRIVESAFETYIF_REFCMD_BUSY;
      end_if;
      
      // Reread the Reffied States and response
      sSafeRefState.RefState := DRIVESAFETYIF_REFSTATE_BUSY;
      bdSettings.bReadSafeRefState :=TRUE;
      
    end_if;
  end_if;
  
END_FUNCTION

FUNCTION VIRTUAL MDD2000_AxisBase::SetSafeSBTState
	VAR_INPUT
		NewSBTState 	: DINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR
  VAR
  	dValue : DINT;
  END_VAR
  
  retcode := ERROR;
  if Online then
  
    if (NewSBTState = -1) | (NewSBTState = 0) | (NewSBTState = 1) then
  
      // Reset all bits  
      sSafeBreakState.bdWait4Para := 0;
      
      retcode := READY;
      if NewSBTState <> 0 then
        
        // Start new test
        dValue := 1;
        if NewSBTState = -1 then
          // Cancel Brakte Test
          dValue := 0;
        end_if;

        if ( AddASyncEntryDS402(uiParaID:=MDD2000_PID_SIGMATEKPARA_INDEX_INFO, usParaSubID := MDD2000_SPID_K_SBT, usRdWr:=1, pValue:= #dValue, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
          sSafeBreakState.bdWait4Para.SetBrakeTest    := TRUE;
        else
          sSafeBreakState.bdWait4Para.ErrSetBrakeTest := TRUE;
          retcode := ERROR;
        end_if;
      
      end_if;
      
      // Refresh Teststates
      if ( AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_BRAKE_TEST, usParaSubID:=MDD2000_SPID_SAFETY_BRAKE_TEST_CNTDOWN, usRdWr:=0, pValue:= #dValue, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
        sSafeBreakState.bdWait4Para.TimeTilNextTest     := TRUE;
      else
        sSafeBreakState.bdWait4Para.ErrTimeTilNextTest  := TRUE;
      end_if;
      if ( AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_BRAKE_TEST, usParaSubID:=MDD2000_SPID_SAFETY_BRAKE_TEST_STATE,   usRdWr:=0, pValue:= #dValue, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
        sSafeBreakState.bdWait4Para.SafeBrakeTestStatus   := TRUE;
      else
        sSafeBreakState.bdWait4Para.ErrSafeBrakeTestStatus:= TRUE;
      end_if;
      
      if ( AddAsyncEntryDS402(uiParaID:=MDD2000_PID_SAFETY_BRAKE_TEST, usParaSubID:=MDD2000_SPID_FUNCT_BRAKE_TEST_STATE,    usRdWr:=0, pValue:= #dValue, bsDataInfo:=MDD2000MNG_DATASIZE_4BYTE, pThisObj:=this) ) = 0 then
        sSafeBreakState.bdWait4Para.BrakeTestStatus     := TRUE;
      else
        sSafeBreakState.bdWait4Para.ErrBrakeTestStatus  := TRUE;
      end_if;
      
    end_if;
  
  end_if;
  
END_FUNCTION

FUNCTION VIRTUAL MDD2000_AxisBase::SafetyChanged
	VAR_INPUT
		StateInfo 	: DINT;
	END_VAR
  VAR
  	idx : HSINT;
  END_VAR
  
  case StateInfo$MDD2000MngBase::t_e_MDD2000SafetyRunState of
              
    MDD2000MngBase::t_e_MDD2000SafetyRunState::_INACTIVE,
    MDD2000MngBase::t_e_MDD2000SafetyRunState::_POST,
    MDD2000MngBase::t_e_MDD2000SafetyRunState::_CHK_CFG,
    MDD2000MngBase::t_e_MDD2000SafetyRunState::_PREOP,
    MDD2000MngBase::t_e_MDD2000SafetyRunState::_FSOE_COMSETUPFAILED:
      AxisState.SafeAxisNotVerified   := TRUE;
      AxisState.SafeAxisZeroPosNotSet := TRUE;
      AxisState.SafeMngNotVerified    := TRUE;
      AxisState.SafeMngNotReady       := TRUE;
      
    MDD2000MngBase::t_e_MDD2000SafetyRunState::_TEMP_OP:
      // Reread the Verified States
      bdSettings.bReadSafeVerifyState := TRUE;
      bdSettings.bReadSafeRefState    := TRUE;
     
      AxisState.SafeAxisNotVerified   := TRUE;
      AxisState.SafeAxisZeroPosNotSet := TRUE;
      AxisState.SafeMngNotVerified    := TRUE;
      AxisState.SafeMngNotReady       := FALSE;
    MDD2000MngBase::t_e_MDD2000SafetyRunState::_OP:
      // Reread the Verified States
      bdSettings.bReadSafeVerifyState := TRUE;
      bdSettings.bReadSafeRefState    := TRUE;
    
      // Safety State OP can only be Reached if all axis are verified
      AxisState.SafeAxisNotVerified   := FALSE;
      AxisState.SafeAxisZeroPosNotSet := FALSE;
      AxisState.SafeMngNotVerified    := FALSE;
      AxisState.SafeMngNotReady       := FALSE;
    
    MDD2000MngBase::t_e_MDD2000SafetyRunState::_SERVICE:
    
    MDD2000MngBase::t_e_MDD2000SafetyRunState::_ERROR:
    
      AxisState.SafeAxisNotVerified   := TRUE;
      AxisState.SafeAxisZeroPosNotSet := TRUE;
      AxisState.SafeMngNotVerified    := TRUE;
      AxisState.SafeMngNotReady       := TRUE;
      
      // Reread the Verified States
      bdSettings.bReadSafeVerifyState := TRUE;
      bdSettings.bReadSafeRefState    := TRUE;
    
  end_case;
  
  sSafeFuncVar.bSafeFktUpdateListValid := FALSE;
  
  if (SyncPara.SafeControlWord.ptr <> NIL) & 
     (SyncPara.SafeStateWord.ptr <> NIL) then // Only read Safefunction mapping if SafeControlWord/SafeStateWord are read in the PDO data
  
    if ( (StateInfo$MDD2000MngBase::t_e_MDD2000SafetyRunState = _OP)      |
         (StateInfo$MDD2000MngBase::t_e_MDD2000SafetyRunState = _TEMP_OP) ) then
      
      // Reset Bitmasks 
      _memset(dest:=#sSafeFuncVar.BitMasksSafeFktCfgCtrl, usByte:=0, cntr:=sizeof(sSafeFuncVar.BitMasksSafeFktCfgCtrl));
      // Read the mapping for the safety controlword, 1 Mapping for each of the 16 Bit
      for idx := 1 to MDD2000_SPIDMAX_SFKTCFG_CTRLSTATEWORD_FKTMAPPING do  // idx 0 is no of entries
        AddASyncEntryDS402(uiParaID := MDD2000_PID_SFKTCFG_CTRLWORD_FKTMAPPING, usParaSubID := idx, usRdWr := 0, pValue := NIL, bsDataInfo := MDD2000MNG_DATASIZE_4BYTE, pThisObj := this);
      end_for;
      // Read the mapping for the safety stateword, 1 Mapping for each of the 16 Bit
      for idx := 1 to MDD2000_SPIDMAX_SFKTCFG_CTRLSTATEWORD_FKTMAPPING do  // idx 0 is no of entries      
        AddASyncEntryDS402(uiParaID := MDD2000_PID_SFKTCFG_STATEWORD_FKTMAPPING, usParaSubID := idx, usRdWr := 0, pValue := NIL, bsDataInfo := MDD2000MNG_DATASIZE_4BYTE, pThisObj := this);
      end_for;
      
    end_if;
  end_if;

END_FUNCTION

FUNCTION VIRTUAL MDD2000_AxisBase::SetSafeCtrlWordBitmask
	VAR_INPUT
		SafeFktId 	: HDINT;
		BitIdx 	: DINT;
    bStateCfg : BOOL;
	END_VAR
  VAR
  	SafeFktIndex    : HINT;
    SafeFktSubIndex : HSINT;
    SafeFktBitLen   : USINT;
    pBitMask        : ^BINT;
  END_VAR

  SafeFktBitLen   := (SafeFktId AND 0xFF)$USINT;
  SafeFktId       := SafeFktId shr 8;
  SafeFktSubIndex := (SafeFktId AND 0xFF)$USINT;
  SafeFktId       := SafeFktId shr 8;  
  SafeFktIndex    := (SafeFktId AND 0xFFFF)$UINT;
  
  pBitMask := NIL;
  
  if (BitIdx > 0) & (BitIdx <= MDD2000_SPIDMAX_SFKTCFG_CTRLSTATEWORD_FKTMAPPING) then
    
    while SafeFktIndex > MDD2000_SFKTCFG_IDX_MAX  do
      SafeFktIndex -= MDD2000_SFKTCFG_IDXOFFSET;  // Eliminate axis dependant offset
    end_while;
    
    if bStateCfg = FALSE then
    
      case SafeFktIndex of
      
        // Stop Functions
        MDD2000_PID_SFKTCFG_STO:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.STO)$^BINT;
        MDD2000_PID_SFKTCFG_SS1:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SS1)$^BINT;
        MDD2000_PID_SFKTCFG_SS2:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.ss2)$^BINT;
        MDD2000_PID_SFKTCFG_SOS:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SOS)$^BINT;
          
        // Break Functions
        MDD2000_PID_SFKTCFG_SBC:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SBC)$^BINT;
        MDD2000_PID_SFKTCFG_SBT:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SBT)$^BINT;
          
        // Limit Functions
        MDD2000_PID_SFKTCFG_SLS:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SLS)$^BINT;
        MDD2000_PID_SFKTCFG_SLP:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SLP)$^BINT;
        MDD2000_PID_SFKTCFG_SLA:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SLA)$^BINT;
        MDD2000_PID_SFKTCFG_SLT:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SLT)$^BINT;
        MDD2000_PID_SFKTCFG_SLI:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SLI)$^BINT;
        MDD2000_PID_SFKTCFG_SDI:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SDI)$^BINT;
          
        // Monitoring Functions
        MDD2000_PID_SFKTCFG_SMS:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SMS)$^BINT;
        MDD2000_PID_SFKTCFG_SMP:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SMP)$^BINT;
        MDD2000_PID_SFKTCFG_SMA:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SMA)$^BINT;
        MDD2000_PID_SFKTCFG_SMT:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SMT)$^BINT;
        MDD2000_PID_SFKTCFG_SSM:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SSM)$^BINT;
        MDD2000_PID_SFKTCFG_SCA:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SCA)$^BINT;

      end_case;
      
    else
      
      case SafeFktIndex of
      
        // Stop Functions
        MDD2000_PID_SFKTCFG_STO:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.STO)$^BINT;
        MDD2000_PID_SFKTCFG_SS1:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.SS1)$^BINT;
        MDD2000_PID_SFKTCFG_SS2:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.ss2)$^BINT;
        MDD2000_PID_SFKTCFG_SOS:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.SOS)$^BINT;
          
        // Break Functions
        MDD2000_PID_SFKTCFG_SBC:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.SBC)$^BINT;
        MDD2000_PID_SFKTCFG_SBT:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.SBT)$^BINT;
          
        // Limit Functions
        MDD2000_PID_SFKTCFG_SLS:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.SLS)$^BINT;
        MDD2000_PID_SFKTCFG_SLP:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.SLP)$^BINT;
        MDD2000_PID_SFKTCFG_SLA:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.SLA)$^BINT;
        MDD2000_PID_SFKTCFG_SLT:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.SLT)$^BINT;
        MDD2000_PID_SFKTCFG_SLI:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.SLI)$^BINT;
        MDD2000_PID_SFKTCFG_SDI:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.SDI)$^BINT;
          
        // Monitoring Functions
        MDD2000_PID_SFKTCFG_SMS:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.SMS)$^BINT;
        MDD2000_PID_SFKTCFG_SMP:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.SMP)$^BINT;
        MDD2000_PID_SFKTCFG_SMA:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.SMA)$^BINT;
        MDD2000_PID_SFKTCFG_SMT:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.SMT)$^BINT;
        MDD2000_PID_SFKTCFG_SSM:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.SSM)$^BINT;
        MDD2000_PID_SFKTCFG_SCA:
          pBitMask := (#sSafeFuncVar.BitMasksSafeFktCfgState.SCA)$^BINT;
          
      end_case;
      
    end_if;
    
    if pBitMask then
      BitIdx -= 1;
      pBitMask^ := pBitMask^ OR (1 shl BitIdx);
    end_if;

  end_if;
  
END_FUNCTION

FUNCTION VIRTUAL MDD2000_AxisBase::SetSafeFktUpdateList
VAR
	idx : DINT;
END_VAR

  // Reset old List
  _memset(dest:=#sSafeFuncVar.aSafeFktUpdateListCtrl[0], usByte:=0, cntr:=sizeof(sSafeFuncVar.aSafeFktUpdateListCtrl) );
  _memset(dest:=#sSafeFuncVar.aSafeFktUpdateListState[0], usByte:=0, cntr:=sizeof(sSafeFuncVar.aSafeFktUpdateListState) );
  
  // Control Word Masks *****************************************************************
  idx := 0;
  
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.STO then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.STO)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.STO;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SS1 then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SS1)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SS1;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SS2 then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SS2)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SS2;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SOS then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SOS)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SOS;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SBC then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SBC)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SBC;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SBT then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SBT)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SBT;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SLS then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SLS)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SLS;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SLP then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SLP)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SLP;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SLA then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SLA)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SLA;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SLT then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SLT)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SLT;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SLI then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SLI)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SLI;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SDI then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SDI)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SDI;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SMS then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SMS)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SMS;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SMP then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SMP)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SMP;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SMA then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SMA)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SMA;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SMT then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SMT)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SMT;
    idx += 1;
  end_if;

  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SSM then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SSM)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SSM;
    idx += 1;
  end_if;  
    
  if sSafeFuncVar.BitMasksSafeFktCfgCtrl.SCA then
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgCtrl.SCA)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListCtrl[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SCA;
    idx += 1;
  end_if;
  
  // Status Word Masks *****************************************************************
  idx := 0;
  
  if sSafeFuncVar.BitMasksSafeFktCfgState.STO then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.STO)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.STO;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgState.SS1 then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SS1)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SS1;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgState.SS2 then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SS2)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SS2;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgState.SOS then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SOS)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SOS;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgState.SBC then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SBC)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SBC;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgState.SBT then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SBT)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SBT;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgState.SLS then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SLS)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SLS;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgState.SLP then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SLP)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SLP;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgState.SLA then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SLA)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SLA;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgState.SLT then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SLT)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SLT;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgState.SLI then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SLI)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SLI;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgState.SDI then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SDI)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SDI;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgState.SMS then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SMS)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SMS;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgState.SMP then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SMP)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SMP;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgState.SMA then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SMA)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SMA;
    idx += 1;
  end_if;
  
  if sSafeFuncVar.BitMasksSafeFktCfgState.SMT then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SMT)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SMT;
    idx += 1;
  end_if;

  if sSafeFuncVar.BitMasksSafeFktCfgState.SSM then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SSM)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SSM;
    idx += 1;
  end_if;  
    
  if sSafeFuncVar.BitMasksSafeFktCfgState.SCA then
    sSafeFuncVar.aSafeFktUpdateListState[idx].pBitMask  := (#sSafeFuncVar.BitMasksSafeFktCfgState.SCA)$^HINT;
    sSafeFuncVar.aSafeFktUpdateListState[idx].SetBit    := gb_MDD2000ActiveSafeFkt.SCA;
    idx += 1;
  end_if;
  
  // Reset oldSafeControlWord, oldSafeStateWord to invalid values so change can be detected 
  sSafeFuncVar.oldSafeControlWord := 0xFFFFFFFF;
  sSafeFuncVar.oldSafeStateWord   := 0xFFFFFFFF;
  
  sSafeFuncVar.bSafeFktUpdateListValid := TRUE;
  
END_FUNCTION

FUNCTION VIRTUAL MDD2000_AxisBase::UpdateActiveSafeFunctions
	VAR_INPUT
		sControlWord 	: BDINT;
		sStateWord 	: BDINT;
	END_VAR
	VAR_OUTPUT
		ActiveSafeFunctions 	: gb_MDD2000ActiveSafeFkt;
	END_VAR
  VAR  	
    pSafeFktUpdateElement : ^ts_SafeFktUpdateElement;
  END_VAR
  
  ActiveSafeFunctions := 0;
  if sSafeFuncVar.bSafeFktUpdateListValid then // Return 0 if mask have not been set yet.
  
    // Check in Ctrl Word
    pSafeFktUpdateElement  := #sSafeFuncVar.aSafeFktUpdateListCtrl[0];
    while (pSafeFktUpdateElement <= #sSafeFuncVar.aSafeFktUpdateListCtrl[MDD2000_AXISSAFE_MAX_IDX_SAFEFKT]) &
          (pSafeFktUpdateElement^.pBitMask) do  // Stop when there are no more bitmasks in the list.
    
      if (sControlWord AND pSafeFktUpdateElement^.pBitMask^) then
        ActiveSafeFunctions := ActiveSafeFunctions OR pSafeFktUpdateElement^.SetBit;
      end_if;
      
      pSafeFktUpdateElement += sizeof(ts_SafeFktUpdateElement);

    end_while;
    
    // Check in State Word
    pSafeFktUpdateElement  := #sSafeFuncVar.aSafeFktUpdateListState[0];
    while (pSafeFktUpdateElement <= #sSafeFuncVar.aSafeFktUpdateListState[MDD2000_AXISSAFE_MAX_IDX_SAFEFKT]) &
          (pSafeFktUpdateElement^.pBitMask) do  // Stop when there are no more bitmasks in the list.
    
      if (sStateWord AND pSafeFktUpdateElement^.pBitMask^) then
        ActiveSafeFunctions := ActiveSafeFunctions OR pSafeFktUpdateElement^.SetBit;
      end_if;
      
      pSafeFktUpdateElement += sizeof(ts_SafeFktUpdateElement);

    end_while;
  
  end_if;

END_FUNCTION