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

//{{LSL_DEFINES

#ifndef _T_DRIVEMNGBASE_H
#define _T_DRIVEMNGBASE_H

// DiasDrive Constants
#DEFINE SDDMAXENTRIES   32        // maximale Anzahl an Achsen
#DEFINE SDDMAXPLACE     3         // maximale Anzahl an Achsen pro Steckplatz 

// Device ID for the Drive IF Cards 
#define DRIVEMNG_BUSDEVICEID_VAC011    11
#define DRIVEMNG_BUSDEVICEID_VAC012  1061
#define DRIVEMNG_BUSDEVICEID_VAC013  1075

#define DRIVEMNG_BUSDEVICEID_MDD     1071

// Device ID for the Drive Cards 
#define DRIVEMNG_DRVDEVICEID_SDD_OFFSET 0

#define DRIVEMNG_DRVDEVICEID_SDD305 DRIVEMNG_DRVDEVICEID_SDD_OFFSET + 16
#define DRIVEMNG_DRVDEVICEID_SDD310 DRIVEMNG_DRVDEVICEID_SDD_OFFSET +  3
#define DRIVEMNG_DRVDEVICEID_SDD315 DRIVEMNG_DRVDEVICEID_SDD_OFFSET +  1
#define DRIVEMNG_DRVDEVICEID_SDD335 DRIVEMNG_DRVDEVICEID_SDD_OFFSET + 12

#define DRIVEMNG_DRVDEVICEID_SDD205 DRIVEMNG_DRVDEVICEID_SDD_OFFSET + 22 
#define DRIVEMNG_DRVDEVICEID_SDD210 DRIVEMNG_DRVDEVICEID_SDD_OFFSET +  9
#define DRIVEMNG_DRVDEVICEID_SDD215 DRIVEMNG_DRVDEVICEID_SDD_OFFSET +  5

#define DRIVEMNG_DRVDEVICEID_SDD105 DRIVEMNG_DRVDEVICEID_SDD_OFFSET + 21
#define DRIVEMNG_DRVDEVICEID_SDD115 DRIVEMNG_DRVDEVICEID_SDD_OFFSET + 10
#define DRIVEMNG_DRVDEVICEID_SDD120 DRIVEMNG_DRVDEVICEID_SDD_OFFSET +  7

#define DRIVEMNG_DRVDEVICEID_MDD_OFFSET 16#10000

#define DRIVEMNG_DRVDEVICEID_MDD111 DRIVEMNG_DRVDEVICEID_MDD_OFFSET + 1
#define DRIVEMNG_DRVDEVICEID_MDD121 DRIVEMNG_DRVDEVICEID_MDD_OFFSET + 2

#define DRIVEMNG_DRVDEVICEID_SDIAS_OFFSET 16#20000

#define DRIVEMNG_DRVDEVICEID_DC061 DRIVEMNG_DRVDEVICEID_SDIAS_OFFSET + 16#180 // 1 = 1 Achse 80 SDIAS

#define DRIVEMNG_DRIVESCOPE_GETALL_PARAM    16#2080
#define DRIVEMNG_DRIVESCOPE_SCOPE_BIT       16#60000000
#define DRIVEMNG_DRIVESCOPE_SINDEX_RANGE    511

#define DRIVEMNG_DEFAULT_CPU_LOGFILENAME_PATH           "C:\sysmsg\DriveLog"
#define DRIVEMNG_DEFAULT_CPU_DEBUGLOGFILENAME_PATH      "C:\sysmsg\DriveDebugLog"
#define DRIVEMNG_DEFAULT_CPU_LOGFILENAME_EXTENSION      ".txt"

#define DRIVEMNG_DEFAULT_DRIVE_LOGFILENAME_PATH         "C:\"
#define DRIVEMNG_DEFAULT_DRIVE_LOGFILENAME_NAME         "DriveLog.txt"
#define DRIVEMNG_DEFAULT_DRIVE_DEBUGLOGFILENAME_NAME    "DriveDebugLog.txt"

#define DRIVEMNG_FILE_HANDLING_RETCODE_NOERROR                    0
#define DRIVEMNG_FILE_HANDLING_RETCODE_FILEHANDLING_BUSY         -2   // = DRIVEVVBASE_VANDAL_FILEHANDLING_ERROR_BUSY -2
#define DRIVEMNG_FILE_HANDLING_RETCODE_CMDVERSION_NOTSUPPORTED  -92
#define DRIVEMNG_FILE_HANDLING_RETCODE_WRITEPARA_FAILED         -93
#define DRIVEMNG_FILE_HANDLING_RETCODE_WRITEPARA_TIMEOUT        -94
#define DRIVEMNG_FILE_HANDLING_RETCODE_READBACKPARA_FAILED      -95
#define DRIVEMNG_FILE_HANDLING_RETCODE_READBACKPARA_TIMEOUT     -96
#define DRIVEMNG_FILE_HANDLING_RETCODE_AXIS_ENABLED             -97
#define DRIVEMNG_FILE_HANDLING_RETCODE_NOT_ONLINE               -98
#define DRIVEMNG_FILE_HANDLING_RETCODE_NOT_SUPPORTED            -99

#define DRIVEMNG_FILE_HANDLING_TIMEOUT_LOG_PARAM          10000

#define DRIVEMNG_FILESELECT_LOGFILE       0
#define DRIVEMNG_FILESELECT_DEBUGLOGFILE  1

#define DRIVEMNG_FILE_RESERVE_IDFREE         0
#define DRIVEMNG_FILE_RESERVE_IDDEFAULT     10
#define DRIVEMNG_FILE_RESERVE_IDGETLOGFILE  20


#endif // _T_DRIVEMNGBASE_H
//}}LSL_DEFINES

//{{LSL_DECLARATION
#include "..\..\Class\_DriveMngBase\SDDDefinitions.h"
#include "..\..\class\_drivemngbase\drivemngbase.h"

(*!
<Class
	Name               = "_DriveMngBase"
	Revision           = "1.63"
	GUID               = "{8C853AD9-097C-4EED-8B6F-2AAA594D12AE}"
	RealtimeTask       = "false"
	CyclicTask         = "true"
	BackgroundTask     = "false"
	Sigmatek           = "true"
	OSInterface        = "false"
	HighPriority       = "false"
	Automatic          = "false"
	UpdateMode         = "Prescan"
	IconPath           = ".\Class\_DriveMngBase\Drive.ico"
	SharedCommandTable = "true"
	Objectsize         = "(474,120)"
	Comment            = "this class does the connection between the _VaranDriveBase and the _DriveAxis">
	<Channels>
		<Server Name="AxisAvailable" GUID="{F2906957-0427-4401-A3D2-5531963CE070}" Visualized="true" Initialize="false" WriteProtected="false" Retentive="false" Comment="Displays number of axis available on hardware."/>
		<Server Name="CmdState" GUID="{FFDBDD1F-F79F-4421-82FE-4A79EBC8DDD3}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Displays the State of the Class"/>
		<Server Name="DeviceAddress" GUID="{0504CFA1-7B4F-43CE-87FE-2C411592799A}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="device address of hardware module"/>
		<Server Name="DeviceID" GUID="{231A140A-3E55-46D4-9CF0-02342E5F162B}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Server shows the DeviceID of the Hardware Module."/>
		<Server Name="DriveType" GUID="{2CD724BB-F850-4E23-A992-17AC359D72F0}" Visualized="true" Initialize="false" WriteProtected="false" Retentive="false" Comment="Displays which hardware we have connected"/>
		<Server Name="HWVersion" GUID="{B1DBAB01-D190-40A9-8FF9-84ED0E0E8561}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Display Hardware Version (Parameter I-HC from Drive)."/>
		<Server Name="Online" GUID="{8DD02114-1255-424F-8068-43DB6CF9AA29}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="This server is set as soon as the hardware class is processed properly (when the data are valid, drives synchronized,..) &#13;&#10;The server is reset when an error occurs or when disconnected."/>
		<Server Name="Release" GUID="{A767F68C-C82B-4431-9CC5-48BE683AF508}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="FPGA - Version"/>
		<Server Name="RetryCounter" GUID="{185803BD-6490-49CB-A817-392EC27BB40F}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="retry counter of the varan module"/>
		<Server Name="SerialNo" GUID="{CB763006-5D9B-4E8F-9CD5-51DF099BDB20}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="Displays Drive Serial number"/>
		<Server Name="VendorID" GUID="{D17F952B-C105-4CAC-A019-F96815002F5F}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="This server contains the vendor ID of the hardware modul."/>
		<Client Name="cOnline" Required="true" Internal="false" Comment="Reads if the initialisation was done correctly and if we can start the communication with the drive"/>
		<Client Name="coStdLib" Required="false" Internal="false"/>
		<Client Name="FwDatetr" Required="true" Internal="false" Comment="Provides the value to format the Firmware date"/>
		<Client Name="FwNumStr" Required="true" Internal="false" Comment="Provides the value to format the Firmware number"/>
		<Client Name="To_TaskObjectControl" Required="false" Internal="false"/>
		<Client Name="ToBusIF" Required="false" Internal="false"/>
		<Client Name="toVaran" Required="false" Internal="false" Comment="Connection to the Varan Communication Class&#13;&#10;"/>
	</Channels>
	<Dependencies>
		<Files>
			<File Path=".\Class\_DriveMngBase\SDDDefinitions.h" Include="true"/>
			<File Path=".\Class\_DriveMngBase\DriveComL2.h" Include="false"/>
			<File Path=".\class\_drivemngbase\drivemngbase.h" Include="true"/>
		</Files>
	</Dependencies>
	<RevDoku>
		<Owner Company="Sigmatek" Author="HasHan"/>
		<Dokumentation Revision="1.63" Date="23.01.2025" Author="LanSte" Company="Sigmatek" Description="Add drive types for new module SR011-1"/>
		<Dokumentation Revision="1.62" Date="13.06.2024" Author="ZoePat" Company="Sigmatek" Description="Increased the array &quot;G_SDD_HW_DATA&quot; for the DriveIntegration to 255. Same as the limit in the DriveIntegration itself. Ensure all classes with this array are updated, to avoid different definitions for the same array."/>
		<Dokumentation Revision="1.61" Date="18.10.2023" Author="LanSte" Company="Sigmatek" Description="Improved method comment."/>
		<Dokumentation Revision="1.60" Date="13.06.2022" Author="LanSte" Company="Sigmatek" Description="Generalized File handling for Drives. File handling is now supported with MDD2000 and VSDC15x via the same interfaces."/>
		<Dokumentation Revision="1.55" Date="13.06.2022" Author="LanSte" Company="Sigmatek" Description="Merged the Testversion 0.50 to 0.54 into Version 1.55: Added Filehandling for VSDC15x."/>
		<Dokumentation Revision="1.49" Date="21.12.2021" Author="EisMic" Company="Sigmatek" Description="Read I-Type parameter to determine Drivetype for VSDC15x.&#13;&#10;Added log messages when reading information parameters failed."/>
		<Dokumentation Revision="1.48" Date="14.12.2021" Author="EisMic" Company="Sigmatek" Description="It is now ensured that all server informations are valid as soon as the Server Online is set to 1."/>
		<Dokumentation Revision="1.47" Date="01.12.2021" Author="EisMic" Company="Sigmatek" Description="Added AddAsyncEntryIntHWCValue which is needed by VSDC15x derivations."/>
		<Dokumentation Revision="1.46" Date="30.11.2021" Author="EisMic" Company="Sigmatek" Description="Added support to send system date and drive to firmware (has to be done in derivations if needed)&#13;&#10;Added GetSystemTime method which is used by derivations (MDD2000)."/>
		<Dokumentation Revision="1.45" Date="27.07.2021" Author="LanSte" Company="Sigmatek" Description="Added support for encoder parameters for HiperfaceDSL for the MDD2000.&#13;&#10;Added methods to set DriveType-String when exporting driveparameters to xml-File."/>
		<Dokumentation Revision="1.44" Date="29.09.2020" Author="PieSte" Company="Sigmatek" Description="Add drive type for new module VSDC151 and MDD2000."/>
		<Dokumentation Revision="1.43" Date="01.07.2020" Author="HaeTho" Company="Sigmatek" Description="drive type of DC101 and DC102 is recognized correctly"/>
		<Dokumentation Revision="1.42" Date="19.04.2019" Author="PieSte" Company="Sigmatek" Description="Add drive types for new modules SR011 and SR012."/>
		<Dokumentation Revision="1.41" Date="02.05.2016" Author="EisMic" Company="Sigmatek" Description="Added new NewInst commando for Lasal2 to get Transparent state."/>
		<Dokumentation Revision="1.40" Date="16.03.2016" Author="EisMic" Company="Sigmatek" Description="Improved comment of server HWVersion (to clarify that the shown version corresponds to the parameter I-HC of the drive)."/>
		<Dokumentation Revision="1.39" Date="03.06.2015" Author="PieSte" Company="Sigmatek" Description="Ignore axis number for SDD1X00 drive scope data request from Lasal2 for parameter S-GET2 and S-GET3.&#13;&#10;Check for error buffer or scope data request from Lasal2.&#13;&#10;Add newinst command to call methode DisableDevice() and EnableDevice() to avoid retrys when disconnected."/>
		<Dokumentation Revision="1.38" Date="26.05.2015" Author="RamAnd" Company="Sigmatek" Description="Added possibility to get enabled Axis which is needed to set absolute position of axis."/>
		<Dokumentation Revision="1.37" Date="28.04.2015" Author="PieSte" Company="Sigmatek" Description="Add new parameter to read drive scope faster. It is used for SDD1X00 drives."/>
		<Dokumentation Revision="1.36" Date="26.02.2015" Author="PieSte" Company="Sigmatek" Description="Changed names of businterface commandos for new varan drive hardware.&#13;&#10;Add new businterface commando to get bus type.&#13;&#10;Changed visual state of FwNumString and FwDateString object for lse displaying."/>
		<Dokumentation Revision="1.35" Date="23.01.2015" Author="EisMic" Company="Sigmatek" Description="Implemented commando for lasal 2 to get serial number of drive.&#13;&#10;On SDD210/215 the drive couldn&apos;t be initialized when only the object of the second axis was placed."/>
		<Dokumentation Revision="1.34" Date="16.09.2014" Author="EisMic" Company="Sigmatek" Description="AxIndexL2 Bits are now set only when an axis object is placed."/>
		<Dokumentation Revision="1.33" Date="12.08.2014" Author="LanSte" Company="Sigmatek" Description="Corrected reading Firmwareversion with newinst cmd: CMD_GET_HARDWARE_DIAGNOSE "/>
		<Dokumentation Revision="1.32" Date="07.07.2014" Author="LanSte&#13;&#10;PieSte" Company="Sigmatek" Description="Added support for reading hardware diagnosis via newinst cmd: CMD_GET_HARDWARE_DIAGNOSE &#13;&#10;Added NewInst commando to get series info.&#13;&#10;Corrected internal call of GetParameterState."/>
		<Dokumentation Revision="1.31" Date="26.05.2014" Author="PieSte" Company="Sigmatek" Description="Added NewInst commando for BusInterfaceSdiasDriveMng and added request for connection state.&#13;&#10;Added compatibility for CanOpen parameter."/>
		<Dokumentation Revision="1.30" Date="12.02.2014" Author="ZoePat&#13;&#10;ZoePat" Company="Sigmatek" Description="Added new NewInst comando for Lasal2 to get the list of axis.&#13;&#10;Configuration of FastAxis was stored to a wrong variable."/>
		<Dokumentation Revision="1.20" Date="05.11.2012" Author="RamAnd&#13;&#10;ObeChr&#13;&#10;ObeChr" Company="Sigmatek" Description="A timeout in the asynchronous communication was detected but not forwarded to the application&#13;&#10;In case of activated transparent mode of the drive and deactivated cyclic-task, the wrong state was shown on the server CmdState.&#13;&#10;Corrected calculation of asynchronous timeout."/>
		<Dokumentation Revision="1.16" Date="17.09.2012" Author="RamAnd" Company="Sigmatek" Description="Server SerialNo now shows the serial number of the MDP if a MDD100 is used."/>
		<Dokumentation Revision="1.15" Date="12.07.2012" Author="ObeChr" Company="Sigmatek" Description="In case of Varan_Disconnect, extended DriveInformations (DriveType, HWVersion, SerialNo, FWDate, FWNum) are being resetted now"/>
		<Dokumentation Revision="1.14" Date="13.09.2011" Author="PibPet" Company="Sigmatek" Description="In case the CyWork of the DriveMng is being called manually, the time base of the call has to be set with the new method SetTimeBase() to calculate the correct timeout for asynchronous parameter transfer."/>
		<Dokumentation Revision="1.13" Date="31.05.2011" Author="RamAnd" Company="Sigmatek" Description="Corrected communication to LASAL, where a wrong length was used in the processing of command SDD_GET_PARAMS.&#13;&#10;Corrected format of firmware date and time (now 01.01.2011 09:04 instead of 1.1.2011 9:4)"/>
		<Dokumentation Revision="1.12" Date="15.02.2011" Author="BleErn" Company="Sigmatek" Description="Fixed problems with asynchronous timeout"/>
		<Dokumentation Revision="1.11" Date="30.11.2010" Author="RamAnd" Company="Sigmatek" Description="When LASAL fetches a parameter value, now this value is also refreshed on the corresponding parameter class."/>
		<Dokumentation Revision="1.10" Date="13.12.2010" Author="RamAnd" Company="Sigmatek" Description="Fixed problems in initialisation, when device is plugged in and out within a short time."/>
		<Dokumentation Revision="1.9" Date="29.11.2010" Author="RamAnd" Company="Sigmatek" Description="Overrun of asynchronous buffer is now prevented"/>
		<Dokumentation Revision="1.8" Date="10.08.2010" Author="Ramand" Company="Sigmatek" Description="Added support for SDD115. &#13;&#10;Corrected communication with LASAL, when SDD210 or SDD215 is used (axis 1 and 2 are now shown instead of 1 and 3)"/>
		<Dokumentation Revision="1.7" Date="04.06.2010" Author="RamAnd" Company="Sigmatek" Description="Added support for SDD210"/>
		<Dokumentation Revision="1.6" Date="28.05.2010" Author="RamAnd" Company="Sigmatek" Description="Fixed crash in drive parameter refresh of previous version."/>
		<Dokumentation Revision="1.5" Date="13.04.2010" Author="RamAnd" Company="Sigmatek" Description="New commands added to refresh the parameters in LASAL Drive view."/>
		<Dokumentation Revision="1.4" Date="06.04.2010" Author="HasHan" Company="Sigmatek" Description="Changes to prevent that a wrong AxisNo could cause a memory violation."/>
		<Dokumentation Revision="1.3" Date="15.02.2010" Author="RauAnd" Company="Sigmatek" Description="Class works now also with SDD215"/>
		<Dokumentation Revision="1.2" Date="14.10.2009" Author="RauAnd" Company="Sigmatek" Description="SDDInfc and _Drive can now be in the same project without getting a compiler error."/>
		<Dokumentation Revision="1.1" Date="29.09.2009" Author="RauAnd" Company="Sigmatek" Description="-Correct identification of resolvers in init-phase.&#13;&#10;-Check if data-object for each axis is available and correct"/>
		<Dokumentation Revision="1.0" Date="05.08.2009" Author="HasHan" Company="Sigmatek" Description="Creation"/>
	</RevDoku>
</Class>
*)
_DriveMngBase : CLASS
	TYPE
#pragma pack(push, 1)
	  _SDDBFENTRY : STRUCT  //! <Type Public="true" Name="_SDDBFENTRY"/>
	    bFinished : DINT;
	    uiParaIndex : UINT;
	    usParaSubIndex : USINT;
	    usRDWR : USINT;
	    bsDataInfo : BSINT
	    [
	      1 DataLength1,
	      2 DataLength2,
	      3 res1,
	      4 res2,
	      5 Offset1,
	      6 Offset2,
	      7 res3,
	      8 res4,
	    ];
	    dValue : ARRAY [0..11] OF USINT;
	    pThisObj : ^void;
	    usEntry : USINT;
	    bSent : BOOL;
	    udTimeStamp : UDINT;
	    udTimeoutCycles : UDINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  _SDDRINGBUFFER : STRUCT  //! <Type Public="true" Name="_SDDRINGBUFFER"/>
	    pStart : ^_SDDBFENTRY;
	    pEnd : ^_SDDBFENTRY;
	    pRead : ^_SDDBFENTRY;
	    pWrite : ^_SDDBFENTRY;
	    ActEntries : DINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  _AXDEF : STRUCT
	    pThis : ^void;
	    Place : DINT;
	    AxisNo : DINT;
	    AxisBit : BDINT
	    [
	    ];
	    AxisOk : DINT;
	    AxisIndex : USINT;
	    AxAsyncPara : ^_SDDRINGBUFFER;
	    InitFinished : BOOL;
	    AxisExtend : BOOL;
	    AxisFast : BOOL;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  _ParaRefreshBufEntry : STRUCT
	    AxisNo : USINT;
	    Reserved : USINT;
	    ParaNo : UINT;
	    NewValue : DINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  _ParaRefreshRingBufferType : STRUCT
	    pStart : ^_ParaRefreshBufEntry;
	    pEnd : ^_ParaRefreshBufEntry;
	    pRead : ^_ParaRefreshBufEntry;
	    pWrite : ^_ParaRefreshBufEntry;
	    ActEntries : DINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  _SDDL2BUFFER : STRUCT
	    AxisNo : USINT;
	    ParRW : USINT;
	    ParNo : USINT;
	    ParValue : DINT;
	    ParState : USINT;
	    ParError : SINT;
	    bActive : BOOL;
	  END_STRUCT;
#pragma pack(pop)
	  RequiredReferenceToHWCLogging : ^HwcLogging;
	  RequiredReferenceToSigClib : ^SigCLib;
	  t_e_GetLogFileSSW :
	  (
	    IdleGetLogFile,
	    StartGetLogFileSSW,
	    WriteLOGFileParam,
	    Wait4WrLOGFileResponse,
	    ReadLOGFileParam,
	    Wait4RdLOGFileResponse,
	    StartGetLogFile,
	    wait4GetLogFile,
	    ErrorGetLogFile
	  )$UDINT;
#pragma pack(push, 1)
	  s_LogFileVar : STRUCT
	    eGetLogFileSSW : t_e_GetLogFileSSW;
	    ErrorCodeLogFile : DINT;
	    dParaLogVal : DINT;
	    dParaLogValRd : DINT;
	    udParaLogTimeout : UDINT;
	    udTimeStampLogPara : UDINT;
	    bWait4LogFilePara : BOOL;
	    udFileSelectId : UDINT;
	    usParaLogIdx : USINT;
	    aDestinationLogFile : ARRAY [0..199] OF CHAR;
	  END_STRUCT;
#pragma pack(pop)
	  SDDParam :
	  (
	    SSW_SDD_I_HW,
	    SSW_SDD_I_SER,
	    SSW_SDD_I_FW,
	    SSW_SDD_I_BUILD
	  )$UDINT;
	  ServInitSSW :
	  (
	    IdleInit,
	    CallInit,
	    ChkInit,
	    GetInit
	  )$UDINT;
#pragma pack(push, 1)
	  t_TimeVars : STRUCT
	    tSysTime : SYSTIME;
	    tSysDate : SYSDATE;
	    hdKDATEP241 : HDINT;
	    bTimeIsSet : BOOL;
	    udLastWrite : UDINT;
	  END_STRUCT;
#pragma pack(pop)
	END_TYPE
  //Servers:
	CmdState 	: SvrChCmd_t_e_VaranErrors;
	Online 	: SvrCh_DINT;
	Release 	: SvrCh_HDINT;
	DeviceAddress 	: SvrCh_HDINT;
	VendorID 	: SvrCh_UDINT;
	DeviceID 	: SvrCh_UDINT;
	RetryCounter 	: SvrCh_UDINT;
	DriveType 	: SvrCh__DRIVETYPE;
	AxisAvailable 	: SvrCh_BDINT;
	SerialNo 	: SvrCh_DINT;
	HWVersion 	: SvrCh_DINT;
  //Clients:
	toVaran 	: CltChCmd__VaranDriveBase;
	cOnline 	: CltCh_DINT;
	FwNumStr 	: CltChCmd_String;
	FwDatetr 	: CltChCmd_String;
	coStdLib 	: CltChCmd__StdLib;
	To_TaskObjectControl 	: CltChCmd__TaskObjectControl;
	ToBusIF 	: CltChCmd_DINT;
  //Variables:
		InitCounter 	: DINT;			//! <Variable Comment="Initialisierungszähler" Name="InitCounter"/>
		AxCount 	: DINT;			//! <Variable Comment="Count of available axis" Name="AxCount"/>
		AxBuffer : ARRAY [0..SDDMAXENTRIES-1] OF _AXDEF;

		AxisActive : BDINT
		[
		];

		OldAxisActive : BDINT
		[
		];

		tUpdate 	: UDINT;
		ServersInitialized 	: DINT;
		InitServerSSW 	: ServInitSSW;
		ServerSSW 	: SDDParam;
		bdSettings : BDINT
		[
		  1 HwConnect,
		  2 getHwInfo,
		  3 DriveIsInitialized,
		  4 AxisInit,
		  5 bRingBufferRead,
		  6 bRingBufferWrite,
		  7 GotAllInfos,
		];

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

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

		FWDateInt 	: UDINT;
		FwVersionInt 	: DINT;
		AxisExtendAll : BDINT
		[
		];

		AxisFastAll : BDINT
		[
		];

		ChangesRingBuffer 	: _ParaRefreshRingBufferType;
		LastRetcode 	: results;
		b_IsSDD21x 	: BOOL;
		ud_TimeoutCycles 	: UDINT;
		ud_CycleCounter 	: UDINT;
		bVaranConnected 	: DINT;
		usDataLengthOffset 	: USINT;
		aDriveScopeData : ARRAY [0..2] OF DINT;

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

		Parameter_I_Type 	: DINT;
		udCycleTimems 	: UDINT;
		ud_FileHandlingReserved 	: UDINT;
		s_LogFileV 	: s_LogFileVar;
  //Functions:
	
	FUNCTION _DriveMngBase
		VAR_OUTPUT
			ret_code 	: ConfStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL Init;
	
	FUNCTION VIRTUAL GLOBAL CyWork
		VAR_INPUT
			EAX 	: UDINT;
		END_VAR
		VAR_OUTPUT
			state (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION GLOBAL AddAxObj
		VAR_INPUT
			pThis 	: ^void;
			Place 	: DINT;
			AxisNo 	: DINT;
			pAsyncPara 	: ^_SDDRINGBUFFER;
			AxisExtend 	: DINT;
			AxisFast 	: DINT;
		END_VAR;
	
	FUNCTION InitAxisState;
	
	FUNCTION GLOBAL GetExtendInfo
		VAR_OUTPUT
			retcode 	: BOOL;
		END_VAR;
	
	FUNCTION GLOBAL SetParaList
		VAR_INPUT
			usAxis 	: USINT;
			adress 	: ^void;
			ui_counter 	: UINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION GLOBAL CreateDefParaBase
		VAR_INPUT
			CmdPara 	: ^CmdStruct;
			Results 	: ^results;
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;
		END_VAR;
	
	FUNCTION GLOBAL GetParameterState
		VAR_INPUT
			usAxis 	: USINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION GLOBAL SetParameter
		VAR_INPUT
			usAxis 	: USINT;
			paranr 	: USINT;
			rdwr 	: USINT;
			paravalue 	: DINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION GLOBAL GetParameter
		VAR_INPUT
			usAxis 	: USINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION UpdateSvr;
	
	FUNCTION VIRTUAL GLOBAL AddASyncEntry
		VAR_INPUT
			AxisNo 	: USINT;
			usParaNr 	: USINT;
			usRdWr 	: USINT;
			dValue 	: DINT;
			pThisObj 	: ^void;
			usEntry 	: USINT;
			udTimeout 	: UDINT := 0;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
				//! <Function Comment="Method to read internal values via A-INTHWK and I-INTHWK parameter from drive.&#13;&#10;Only for internal use allowed." Name="AddASyncEntryIntHWCValue"/>
	FUNCTION VIRTUAL GLOBAL AddASyncEntryIntHWCValue
		VAR_INPUT
			AxisNo 	: USINT;			//! <Variable Comment="Number of the axis." Name="AddASyncEntryIntHWCValue.AxisNo"/>
			dIntValueIndex 	: DINT;			//! <Variable Comment="Index of the internal value." Name="AddASyncEntryIntHWCValue.dIntValueIndex"/>
			pThisObj 	: ^void;			//! <Variable Comment="This pointer." Name="AddASyncEntryIntHWCValue.pThisObj"/>
			usEntry 	: USINT;			//! <Variable Comment="Entry number ... Should be 0 (default)" Name="AddASyncEntryIntHWCValue.usEntry"/>
			udTimeout 	: UDINT := 0;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;			//! <Variable Comment="Retcode of method&#13;&#10;0 ... OK&#13;&#10;&lt;&gt; 0 ... Error" Name="AddASyncEntryIntHWCValue.retcode"/>
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL UpdateASync;
	
	FUNCTION GLOBAL DriveInitState
		VAR_OUTPUT
			retcode 	: BOOL;
		END_VAR;
	
	FUNCTION GLOBAL AxisInitFinished
		VAR_INPUT
			AxisNo 	: USINT;
		END_VAR;
	
	FUNCTION ResetAxisInit;
	
	FUNCTION GLOBAL CommunicationState
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION GLOBAL GetAxisWrPtr
		VAR_INPUT
			usAxis 	: USINT;
		END_VAR
		VAR_OUTPUT
			ptr 	: ^_VaranDriveBase::t_WriteValuePtr;
		END_VAR;
	
	FUNCTION GLOBAL GetAxisRdPtr
		VAR_INPUT
			usAxis 	: USINT;
		END_VAR
		VAR_OUTPUT
			ptr 	: ^_VaranDriveBase::t_ReadValuePtr;
		END_VAR;
	
	FUNCTION GLOBAL InitDrive
		VAR_INPUT
			Mode 	: USINT;
		END_VAR;
	
	FUNCTION L2CmdFinished
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION GetAxIndex
		VAR_INPUT
			AxisNo 	: USINT;
		END_VAR
		VAR_OUTPUT
			AxIndex 	: USINT;
		END_VAR;
	
	FUNCTION GetFirstAxIndex
		VAR_OUTPUT
			AxIndex 	: USINT;
		END_VAR;
	
	FUNCTION SetFwVersion;
	
	FUNCTION SetFwDate;
	
	FUNCTION Bin2Ascii
		VAR_INPUT
			pt 	: ^CHAR;
			value 	: DINT;
			format 	: BINT;
		END_VAR;
	
	FUNCTION GLOBAL SetSyncEntry
		VAR_INPUT
			usAxis 	: USINT;
			usValue 	: USINT;
			usPData 	: DINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION GLOBAL GetSyncEntry
		VAR_INPUT
			usAxis 	: USINT;
			usValue 	: USINT;
			usPData 	: ^DINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION GLOBAL GetDriveType
		VAR_INPUT
			HWCode 	: DINT;
		END_VAR
		VAR_OUTPUT
			DriveType 	: _DRIVETYPE;
		END_VAR;
	
	FUNCTION GLOBAL GetVaranDriveState
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
				//! <Function Comment="If no cyclic time is set on the object, because the cyclic is being called from another class, this method should be used to tell the class in which time base it will be called.&#13;&#10;The time base is used to check for a timeout on asynchron methods." Name="SetTimeBase"/>
	FUNCTION GLOBAL SetTimeBase
		VAR_INPUT
			ud_timebase_ms 	: UDINT;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;			//! <Variable Comment=" 0..OK&#13;&#10;-1..Function has been called too early (must be after the 2nd init run)&#13;&#10;-2..Timebase must be bigger than 0" Name="SetTimeBase.sd_retval"/>
		END_VAR;
	
	FUNCTION GetAxIndexByAxisBit
		VAR_INPUT
			AxisBit 	: BDINT;
		END_VAR
		VAR_OUTPUT
			AxIndex 	: USINT;
		END_VAR;
	
	FUNCTION VIRTUAL GetDefaultLogFileDestinationDPNE
		VAR_INPUT
			pDPNE 	: ^CHAR;
			FileSelect 	: UDINT := 0;
		END_VAR;
	
	FUNCTION VIRTUAL GetDefaultLogFileNameDrive
		VAR_INPUT
			pFileName 	: ^CHAR;
			FileSelect 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GetDefaultLogFilePathDrive
		VAR_INPUT
			pFilePath 	: ^CHAR;
			FileSelect 	: UDINT;
		END_VAR;
				//! <Function Comment="Function to disable device." Name="DisableDevice"/>
	FUNCTION GLOBAL DisableDevice
		VAR_OUTPUT
			RetCode 	: DINT;			//! <Variable Comment="return value&#13;&#10;0  .. ok&#13;&#10;-1 .. function not available" Name="DisableDevice.RetCode"/>
		END_VAR;
				//! <Function Comment="Function to enable device." Name="EnableDevice"/>
	FUNCTION GLOBAL EnableDevice
		VAR_OUTPUT
			RetCode 	: DINT;			//! <Variable Comment="return value&#13;&#10;0  .. ok&#13;&#10;-1 .. function not available" Name="EnableDevice.RetCode"/>
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL AddASyncEntryDS402
		VAR_INPUT
			AxisNo 	: USINT;
			uiParaID 	: UINT;
			usParaSubID 	: USINT;
			usRdWr 	: USINT;
			pValue 	: ^USINT;
			bsDataInfo 	: BSINT;
			pThisObj 	: ^void;
			usEntry 	: USINT;
			udTimeout 	: UDINT := 0;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION GLOBAL SetParameterDS402
		VAR_INPUT
			usAxis 	: USINT;
			uiParaID 	: UINT;
			usParaSubID 	: USINT;
			usRdWr 	: USINT;
			pparavalue 	: ^USINT;
			bsDataInfo 	: BSINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION GLOBAL GetParameterDS402
		VAR_INPUT
			usAxis 	: USINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: ^DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GetBusDeviceID
		VAR_OUTPUT
			output 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GetDrvDeviceID
		VAR_OUTPUT
			output 	: UDINT;
		END_VAR;
	
	FUNCTION GLOBAL IsAnyAxisEnabled
		VAR_OUTPUT
			AnyAxisEnabled 	: BOOL;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL GetDriveTypeStr
		VAR_INPUT
			eDriveType 	: _DRIVETYPE;
			pDriveTypeStr 	: ^CHAR;
			DriveTypeStrSize 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GetSystemTime;
				//! <Function Comment="Method has to be called by derivation if needed." Name="SetSystemTimeAtDrive"/>
	FUNCTION VIRTUAL SetSystemTimeAtDrive
		VAR_INPUT
			AxisNo 	: USINT;
		END_VAR;
				//! <Function Comment="Method to start the upload a specific file from the drive and save it on the PLC.&#13;&#10;If retcode is READY the filetransfer is started and running. Use GetFileState() for the state of the file upload." Name="GetFile"/>
	FUNCTION VIRTUAL GLOBAL GetFile
		VAR_INPUT
			pDestinationDPNE 	: ^CHAR;			//! <Variable Comment="Pointer to destination path + name + extension where the logfile should be saved on the SPS" Name="GetFile.pDestinationDPNE"/>
			pFileNameDrive 	: ^CHAR;			//! <Variable Comment="Pointer to filename of the drive" Name="GetFile.pFileNameDrive"/>
			pFilePathDrive 	: ^CHAR;			//! <Variable Comment="Pointer to the file path/directory of the drive " Name="GetFile.pFilePathDrive"/>
			pdError 	: ^DINT := nil;			//! <Variable Comment="Pointer to a 4 Byte Error variable where errorcodes will be written when there is an error (optional, can be NIL)&#13;&#10;Errorcodes: &#13;&#10;0 ... No Error&#13;&#10;-1 ... Mailbox for File Transfer not available&#13;&#10;-2 ... Filetransfer busy (other Upload/Download is still running)&#13;&#10;-3 ... Invalid pointer given&#13;&#10;-4 ... String &quot;Filename of the drive&quot; is too long&#13;&#10;-5 ... String &quot;Filepath of the drive&quot; is too long&#13;&#10;-6 ... String &quot;Destination path + name + extension&quot; is too long&#13;&#10;-7 ... Vandal Communication Error&#13;&#10;-8 ... Vandal Communication Timeout&#13;&#10;-9 ... File was not found on drive&#13;&#10;-10 ... Failed to create local file&#13;&#10;-11 ... Failed to write data to local file&#13;&#10;-12 ... Invalid length&#13;&#10;-13 ... Buffer is to small&#13;&#10;-14 ... An attempt was made to read out more bytes of data than are available in the file.&#13;&#10;-15 ... Failed to create thread for filehandling&#13;&#10;-93 ... The writing of the asynchron parameter for reading out the log file failed.&#13;&#10;-94 ... Timeout when writing the asynchron parameter for reading out the log file.&#13;&#10;-95 ... The read-back of the asynchron parameter for reading out the log file failed.&#13;&#10;-96 ... Timeout when reading back the asynchron parameter for reading out the log file.&#13;&#10;-97 ... Axis must not be enabled.&#13;&#10;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="GetFile.pdError"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="READY ... File Upload was started succesfully (Current progress of upload can be fetched with method GetFileState)&#13;&#10;ERROR ... File Upload Error (see parameter pdError for more information)" Name="GetFile.retcode"/>
		END_VAR;
				//! <Function Comment="Method to start the upload of the logfile from the drive and save it on the PLC. &#13;&#10;If retcode is READY the filetransfer is started and running. Use GetFileState() for the state of the file upload." Name="GetLogFile"/>
	FUNCTION VIRTUAL GLOBAL GetLogFile
		VAR_INPUT
			pDestinationDPNE 	: ^CHAR := NIL;			//! <Variable Comment="Pointer to destination path + name + extension where the logfile should be saved on the SPS&#13;&#10;&#13;&#10;If this parameter is not used, one of the following files, depending on &quot;udFileSelectID&quot;, will be used:&#13;&#10;&quot;C:\sysmsg\DriveLog&lt;Serial No&gt;.txt&quot; or &quot;C:\sysmsg\DriveDebugLog&lt;Serial No&gt;.txt&quot;. " Name="GetLogFile.pDestinationDPNE"/>
			pdError 	: ^DINT := nil;			//! <Variable Comment="Pointer to a 4 Byte Error variable where errorcodes will be written when there is an error (optional, can be NIL)&#13;&#10;Errorcodes: &#13;&#10;0 ... No Error&#13;&#10;-1 ... Mailbox for File Transfer not available&#13;&#10;-2 ... Filetransfer busy (other Upload/Download is still running)&#13;&#10;-3 ... Invalid pointer given&#13;&#10;-4 ... String &quot;Filename of the drive&quot; is too long&#13;&#10;-5 ... String &quot;Filepath of the drive&quot; is too long&#13;&#10;-6 ... String &quot;Destination path + name + extension&quot; is too long&#13;&#10;-7 ... Vandal Communication Error&#13;&#10;-8 ... Vandal Communication Timeout&#13;&#10;-9 ... File was not found on drive&#13;&#10;-10 ... Failed to create local file&#13;&#10;-11 ... Failed to write data to local file&#13;&#10;-12 ... Invalid length&#13;&#10;-13 ... Buffer is to small&#13;&#10;-14 ... An attempt was made to read out more bytes of data than are available in the file.&#13;&#10;-15 ... Failed to create thread for filehandling&#13;&#10;-93 ... The writing of the asynchron parameter for reading out the log file failed.&#13;&#10;-94 ... Timeout when writing the asynchron parameter for reading out the log file.&#13;&#10;-95 ... The read-back of the asynchron parameter for reading out the log file failed.&#13;&#10;-96 ... Timeout when reading back the asynchron parameter for reading out the log file.&#13;&#10;-97 ... Axis must not be enabled.&#13;&#10;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="GetLogFile.pdError"/>
			udFileSelectID 	: UDINT := DRIVEMNG_FILESELECT_LOGFILE;			//! <Variable Comment="Optional: Select which log file is fetched from the drive:&#13;&#10;0 .. Default logfile (Default selection if this parameter is not set.)&#13;&#10;1 .. Debug log file." Name="GetLogFile.udFileSelectID"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="READY ... File Upload was started succesfully (Current progress of upload can be fetched with method GetFileState)&#13;&#10;ERROR ... File Upload Error - see parameter pdError" Name="GetLogFile.retcode"/>
		END_VAR;
				//! <Function Comment="Method to check the current progress of the filetransfer started with e.g. GetFile, GetLogFile or SetFile methods." Name="GetFileState"/>
	FUNCTION VIRTUAL GLOBAL GetFileState
		VAR_INPUT
			pdError 	: ^DINT := nil;			//! <Variable Comment="Pointer to a 4 Byte Error variable where errorcodes will be written when there is an error (optional, can be NIL)&#13;&#10;Errorcodes: &#13;&#10;0 ... No Error&#13;&#10;-1 ... Mailbox for File Transfer not available&#13;&#10;-2 ... Filetransfer busy (other Upload/Download is still running)&#13;&#10;-3 ... Invalid pointer given&#13;&#10;-4 ... String &quot;Filename of the drive&quot; is too long&#13;&#10;-5 ... String &quot;Filepath of the drive&quot; is too long&#13;&#10;-6 ... String &quot;Destination path + name + extension&quot; is too long&#13;&#10;-7 ... Vandal Communication Error&#13;&#10;-8 ... Vandal Communication Timeout&#13;&#10;-9 ... File was not found on drive&#13;&#10;-10 ... Failed to create local file&#13;&#10;-11 ... Failed to write data to local file&#13;&#10;-12 ... Invalid length&#13;&#10;-13 ... Buffer is to small&#13;&#10;-14 ... An attempt was made to read out more bytes of data than are available in the file.&#13;&#10;-15 ... Failed to create thread for filehandling&#13;&#10;-93 ... The writing of the asynchron parameter for reading out the log file failed.&#13;&#10;-94 ... Timeout when writing the asynchron parameter for reading out the log file.&#13;&#10;-95 ... The read-back of the asynchron parameter for reading out the log file failed.&#13;&#10;-96 ... Timeout when reading back the asynchron parameter for reading out the log file.&#13;&#10;-97 ... Axis must not be enabled.&#13;&#10;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="GetFileState.pdError"/>
			pdProgress 	: ^DINT := nil;			//! <Variable Comment="Pointer to a 4 Byte variable where the progress of the fileupload will be written in percentage (0-1000 = 0% - 100%) (optional, can be nil)" Name="GetFileState.pdProgress"/>
			pudBytesRead 	: ^UDINT := nil;			//! <Variable Comment="Pointer to where the amount of read bytes will be copied (optional, can be NIL)" Name="GetFileState.pudBytesRead"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="BUSY  ... File transfer is not finished yet&#13;&#10;READY ... File transfer was not started yet / File transfer is finished&#13;&#10;ERROR ... File transfer Error - see parameter pdError" Name="GetFileState.retcode"/>
		END_VAR;
				//! <Function Comment="Method to write a specific file on the drive.&#13;&#10;If retcode is READY the filetransfer is started and running. Use GetFileState() for the state of the file upload." Name="SetFile"/>
	FUNCTION VIRTUAL GLOBAL SetFile
		VAR_INPUT
			pWriteData 	: ^void;			//! <Variable Comment="Pointer to data which will be written into the selected file." Name="SetFile.pWriteData"/>
			udWriteDataLen 	: UDINT;			//! <Variable Comment="Length of data which will be written to the selected file on the drive." Name="SetFile.udWriteDataLen"/>
			pFilePathDrive 	: ^CHAR;			//! <Variable Comment="Pointer to the file path/directory of the drive " Name="SetFile.pFilePathDrive"/>
			pFileNameDrive 	: ^CHAR;			//! <Variable Comment="Pointer to filename of the drive which should be written" Name="SetFile.pFileNameDrive"/>
			pdError 	: ^DINT := nil;			//! <Variable Comment="Pointer to a 4 Byte Error variable where errorcodes will be written when there is an error (optional, can be NIL)&#13;&#10;Errorcodes: &#13;&#10;0 ... No Error&#13;&#10;-1 ... Mailbox for File Transfer not available&#13;&#10;-2 ... Filetransfer busy (other Upload/Download is still running)&#13;&#10;-3 ... Invalid pointer given&#13;&#10;-4 ... String &quot;Filename of the drive&quot; is too long&#13;&#10;-5 ... String &quot;Filepath of the drive&quot; is too long&#13;&#10;-6 ... String &quot;Destination path + name + extension&quot; is too long&#13;&#10;-7 ... Vandal Communication Error&#13;&#10;-8 ... Vandal Communication Timeout&#13;&#10;-9 ... File was not found on drive&#13;&#10;-10 ... Failed to create local file&#13;&#10;-11 ... Failed to write data to local file&#13;&#10;-12 ... Invalid length&#13;&#10;-13 ... Buffer is to small&#13;&#10;-14 ... An attempt was made to read out more bytes of data than are available in the file.&#13;&#10;-15 ... Failed to create thread for filehandling&#13;&#10;-93 ... The writing of the asynchron parameter for reading out the log file failed.&#13;&#10;-94 ... Timeout when writing the asynchron parameter for reading out the log file.&#13;&#10;-95 ... The read-back of the asynchron parameter for reading out the log file failed.&#13;&#10;-96 ... Timeout when reading back the asynchron parameter for reading out the log file.&#13;&#10;-97 ... Axis must not be enabled.&#13;&#10;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="SetFile.pdError"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="READY ... File Write was started succesfully (Current progress can be fetched with method GetFileState)&#13;&#10;ERROR ... File Write Error (see parameter pdError for more information)" Name="SetFile.retcode"/>
		END_VAR;
				//! <Function Comment="Method to get the size of a specific file from the drive.&#13;&#10;If retcode is READY the filetransfer is started and running. Use GetFileState() for the state of the file upload." Name="GetFileSize"/>
	FUNCTION VIRTUAL GLOBAL GetFileSize
		VAR_INPUT
			pFileNameDrive 	: ^CHAR;			//! <Variable Comment="Pointer to filename of the drive" Name="GetFileSize.pFileNameDrive"/>
			pFilePathDrive 	: ^CHAR;			//! <Variable Comment="Pointer to the file path/directory of the drive " Name="GetFileSize.pFilePathDrive"/>
			pudSize 	: ^UDINT;			//! <Variable Comment="Pointer to where the filesize will be written. The value is valid after &quot;GetFileState&quot; returns READY." Name="GetFileSize.pudSize"/>
			pdError 	: ^DINT := nil;			//! <Variable Comment="Pointer to a 4 Byte Error variable where errorcodes will be written when there is an error (optional, can be NIL)&#13;&#10;Errorcodes: &#13;&#10;0 ... No Error&#13;&#10;-1 ... Mailbox for File Transfer not available&#13;&#10;-2 ... Filetransfer busy (other Upload/Download is still running)&#13;&#10;-3 ... Invalid pointer given&#13;&#10;-4 ... String &quot;Filename of the drive&quot; is too long&#13;&#10;-5 ... String &quot;Filepath of the drive&quot; is too long&#13;&#10;-6 ... String &quot;Destination path + name + extension&quot; is too long&#13;&#10;-7 ... Vandal Communication Error&#13;&#10;-8 ... Vandal Communication Timeout&#13;&#10;-9 ... File was not found on drive&#13;&#10;-10 ... Failed to create local file&#13;&#10;-11 ... Failed to write data to local file&#13;&#10;-12 ... Invalid length&#13;&#10;-13 ... Buffer is to small&#13;&#10;-14 ... An attempt was made to read out more bytes of data than are available in the file.&#13;&#10;-15 ... Failed to create thread for filehandling&#13;&#10;-93 ... The writing of the asynchron parameter for reading out the log file failed.&#13;&#10;-94 ... Timeout when writing the asynchron parameter for reading out the log file.&#13;&#10;-95 ... The read-back of the asynchron parameter for reading out the log file failed.&#13;&#10;-96 ... Timeout when reading back the asynchron parameter for reading out the log file.&#13;&#10;-97 ... Axis must not be enabled.&#13;&#10;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="GetFileSize.pdError"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="READY ... Fetching the filesize  was started succesfully (Current progress can be fetched with method GetFileState)&#13;&#10;ERROR ... get filesize failed (see parameter pdError for more information)&#13;&#10;" Name="GetFileSize.retcode"/>
		END_VAR;
				//! <Function Comment="Method to read data from a specific file from the drive and write data into an user buffer.&#13;&#10;If retcode is READY the filetransfer is started and running. Use GetFileState() for the state of the file upload." Name="GetFileBuffer"/>
	FUNCTION VIRTUAL GLOBAL GetFileBuffer
		VAR_INPUT
			pFileNameDrive 	: ^CHAR;			//! <Variable Comment="Pointer to filename of the drive" Name="GetFileBuffer.pFileNameDrive"/>
			pFilePathDrive 	: ^CHAR;			//! <Variable Comment="Pointer to the file path/directory of the drive " Name="GetFileBuffer.pFilePathDrive"/>
			udBufferSize 	: UDINT;			//! <Variable Comment="Size of buffer (pDataBuffer) in bytes." Name="GetFileBuffer.udBufferSize"/>
			pDataBuffer 	: ^void := nil;			//! <Variable Comment="Pointer to buffer where read data will be copied.&#13;&#10;The data is valid after &quot;GetFileState&quot; returns READY." Name="GetFileBuffer.pDataBuffer"/>
			udDataLenToRead 	: UDINT := 0;			//! <Variable Comment="Optional parameter. Can be used if only x-bytes from the file should be read. Otherwise all data from the file will be read out.&#13;&#10;0 ... Read all bytes from file.&#13;&#10;x ... Read x bytes from file." Name="GetFileBuffer.udDataLenToRead"/>
			pdError 	: ^DINT := nil;			//! <Variable Comment="Pointer to a 4 Byte Error variable where errorcodes will be written when there is an error (optional, can be NIL)&#13;&#10;Errorcodes: &#13;&#10;0 ... No Error&#13;&#10;-1 ... Mailbox for File Transfer not available&#13;&#10;-2 ... Filetransfer busy (other Upload/Download is still running)&#13;&#10;-3 ... Invalid pointer given&#13;&#10;-4 ... String &quot;Filename of the drive&quot; is too long&#13;&#10;-5 ... String &quot;Filepath of the drive&quot; is too long&#13;&#10;-6 ... String &quot;Destination path + name + extension&quot; is too long&#13;&#10;-7 ... Vandal Communication Error&#13;&#10;-8 ... Vandal Communication Timeout&#13;&#10;-9 ... File was not found on drive&#13;&#10;-10 ... Failed to create local file&#13;&#10;-11 ... Failed to write data to local file&#13;&#10;-12 ... Invalid length&#13;&#10;-13 ... Buffer is to small&#13;&#10;-14 ... An attempt was made to read out more bytes of data than are available in the file.&#13;&#10;-15 ... Failed to create thread for filehandling&#13;&#10;-93 ... The writing of the asynchron parameter for reading out the log file failed.&#13;&#10;-94 ... Timeout when writing the asynchron parameter for reading out the log file.&#13;&#10;-95 ... The read-back of the asynchron parameter for reading out the log file failed.&#13;&#10;-96 ... Timeout when reading back the asynchron parameter for reading out the log file.&#13;&#10;-97 ... Axis must not be enabled.&#13;&#10;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="GetFileBuffer.pdError"/>
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;			//! <Variable Comment="READY ... File read was started succesfully (Current progress of read can be fetched with method GetFileState)&#13;&#10;ERROR ... File read Error (see parameter pdError for more information)" Name="GetFileBuffer.retcode"/>
		END_VAR;
	
	FUNCTION VIRTUAL GetLogFileCyclic;
	
	FUNCTION VIRTUAL GetLogFileWrParam
		VAR_INPUT
			pParaIDX 	: ^USINT;
			pParaVal 	: ^DINT;
			pParaTimeout 	: ^UDINT;
			FileSelect 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GetLogFileRdParam
		VAR_INPUT
			pParaIDX 	: ^USINT;
			pParaVal 	: ^DINT;
			pParaTimeout 	: ^UDINT;
			FileSelect 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL ReserveFileHandling
		VAR_INPUT
			ReserveID 	: UDINT := DRIVEMNG_FILE_RESERVE_IDDEFAULT;
		END_VAR
		VAR_OUTPUT
			bReserverdOK 	: BOOL;
		END_VAR;
	
	FUNCTION VIRTUAL ReleaseFileHandling;
	
	FUNCTION VIRTUAL CheckFileHandlingAvailable
		VAR_INPUT
			pdError 	: ^DINT := nil;
			ReserveID 	: UDINT := DRIVEMNG_FILE_RESERVE_IDDEFAULT;
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL CmdState::GetState
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL CmdState::NewInst
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL CmdState::Read
		VAR_OUTPUT
			output (EAX) 	: t_e_VaranErrors;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL Online::Read
		VAR_OUTPUT
			output (EAX) 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL Release::Read
		VAR_OUTPUT
			output (EAX) 	: HDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL DeviceAddress::Read
		VAR_OUTPUT
			output (EAX) 	: HDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL VendorID::Read
		VAR_OUTPUT
			output (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL DeviceID::Read
		VAR_OUTPUT
			output (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL RetryCounter::Read
		VAR_OUTPUT
			output (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL AxisAvailable::Write
		VAR_INPUT
			input (EAX) 	: BDINT;
		END_VAR
		VAR_OUTPUT
			result (EAX) 	: BDINT;
		END_VAR;
  //Tables:
	FUNCTION @STD
		VAR_OUTPUT
			ret_code	: CONFSTATES;
		END_VAR;
	FUNCTION GLOBAL TAB @CT_;
END_CLASS;

#pragma usingLtd _StdLib
#pragma usingLtd _TaskObjectControl
#pragma usingLtd _VaranDriveBase
#pragma usingLtd String


//}}LSL_DECLARATION


FUNCTION GLOBAL TAB _DriveMngBase::@CT_
0$UINT,
2#0100000000000000$UINT, //TY__DRIVEMNGBASE
1$UINT, 63$UINT, (SIZEOF(::_DriveMngBase))$UINT, 
11$UINT, 7$UINT, 0$UINT, 
TO_UDINT(496739206), "_DriveMngBase", //Class
TO_UDINT(0), 0, 0$UINT, 0$UINT, //Baseclass
//Servers:
(::_DriveMngBase.CmdState.pMeth)$UINT, _CH_CMD$UINT, 2#0000000000000000$UINT, TO_UDINT(3787497970), "CmdState", 
(::_DriveMngBase.Online.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1858763116), "Online", 
(::_DriveMngBase.Release.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2701327623), "Release", 
(::_DriveMngBase.DeviceAddress.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(19004412), "DeviceAddress", 
(::_DriveMngBase.VendorID.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2218535187), "VendorID", 
(::_DriveMngBase.DeviceID.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(4261957967), "DeviceID", 
(::_DriveMngBase.RetryCounter.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(3383993698), "RetryCounter", 
(::_DriveMngBase.DriveType.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1915542502), "DriveType", 
(::_DriveMngBase.AxisAvailable.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2910492347), "AxisAvailable", 
(::_DriveMngBase.SerialNo.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1856804640), "SerialNo", 
(::_DriveMngBase.HWVersion.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(3247816137), "HWVersion", 
//Clients:
(::_DriveMngBase.toVaran.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000000$UINT, TO_UDINT(926762845), "toVaran", TO_UDINT(766164962), "_VaranDriveBase", 1$UINT, 69$UINT, 
(::_DriveMngBase.cOnline.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000010$UINT, TO_UDINT(931620949), "cOnline", 
(::_DriveMngBase.FwNumStr.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000010$UINT, TO_UDINT(4113911836), "FwNumStr", TO_UDINT(1850111279), "String", 1$UINT, 11$UINT, 
(::_DriveMngBase.FwDatetr.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000010$UINT, TO_UDINT(4101277167), "FwDatetr", TO_UDINT(1850111279), "String", 1$UINT, 11$UINT, 
(::_DriveMngBase.coStdLib.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000000$UINT, TO_UDINT(3815072667), "coStdLib", TO_UDINT(3689364044), "_StdLib", 2$UINT, 0$UINT, 
(::_DriveMngBase.To_TaskObjectControl.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000000$UINT, TO_UDINT(2751224004), "To_TaskObjectControl", TO_UDINT(1584830088), "_TaskObjectControl", 1$UINT, 1$UINT, 
(::_DriveMngBase.ToBusIF.pCh)$UINT, _CH_CLT_CMD$UINT, 2#0000000000000000$UINT, TO_UDINT(3135692506), "ToBusIF", 
END_FUNCTION


#define USER_CNT__DriveMngBase 24

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#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;
	Release.pMeth			:= StoreMethod( #Release::Read(), #M_NO_F() );
	IF Release.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	DeviceAddress.pMeth			:= StoreMethod( #DeviceAddress::Read(), #M_NO_F() );
	IF DeviceAddress.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	VendorID.pMeth			:= StoreMethod( #VendorID::Read(), #M_NO_F() );
	IF VendorID.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	DeviceID.pMeth			:= StoreMethod( #DeviceID::Read(), #M_NO_F() );
	IF DeviceID.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	RetryCounter.pMeth			:= StoreMethod( #RetryCounter::Read(), #M_NO_F() );
	IF RetryCounter.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	DriveType.pMeth			:= StoreMethod( #M_RD_DIRECT(), #M_WR_DIRECT() );
	IF DriveType.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	AxisAvailable.pMeth			:= StoreMethod( #M_RD_DIRECT(), #AxisAvailable::Write() );
	IF AxisAvailable.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	ret_code	:= _DriveMngBase();

END_FUNCTION

#pragma usingLtd HwcLogging
#pragma usingLtd SigCLib

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

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

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

  // erst im 2.ten Init, da im 1.Init sich die Achsbausteine anmelden
  if InitCounter = 1 then
  
    //Initialize logging
    #ifdef HWC_LogInit
      HWC_LogInit();
    #endif
  
    //look if varan or sdias is connected
    if IsClientConnected(#toVaran) then
      bVaranConnected := 1;
    end_if;
    
    //*****************************************************************************
    //** compute timeout for asynchronous parameters                             **
    //*****************************************************************************
    objinfo.period := 0;
    IF  To_TaskObjectControl.GetObjectInfo(this,  OBJ_CT, #objinfo) = 0 THEN
      IF objinfo.period AND 16#8000_0000 THEN
        objinfo.period := objinfo.period AND 16#7FFF_FFFF;
      ELSE
        objinfo.period := objinfo.period * 1000;
      END_IF;
      IF objinfo.period <> 0 THEN
        udCycleTimems := objinfo.period;
        ud_TimeoutCycles := ( SDD_ASY_TIMEOUT / objinfo.period ) + 5;
      ELSE
        udCycleTimems := 10000;
        ud_TimeoutCycles := 300 + 5;  //Rev. 1.16: Timeout calculated with default Cyclic of 10ms
      END_IF;
    ELSE
      udCycleTimems := 10000;
      ud_TimeoutCycles := 300 + 5;    //Rev. 1.16: Timeout calculated with default Cyclic of 10ms
    END_IF;
        
        
    // Set the extende and the fast axis info
    if bVaranConnected then
      toVaran.StartCommunication(AxisExtendAll, AxisFastAll, #AxisAvailable);
    else
      MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_STARTCOMMUNICATION;
      MyPara.aPara[0] := to_dint(AxisExtendAll);
      MyPara.aPara[1] := to_dint(AxisFastAll);
      MyPara.aPara[2] := (#AxisAvailable)$DINT;
      MyPara.aPara[3] := (AxisActive)$DINT; 
      ToBusIF.NewInst(#MyPara, #MyResult); 
    end_if;    
       
    // Set the callback pointer for diagnosis call
    if bVaranConnected then
      toVaran.SetObjectCallBack(p_DriveMngBaseNew:=this);
    else
      MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_SET_OBJECT_CALLBACK;
      MyPara.aPara[0] := this$DINT; 
      ToBusIF.NewInst(#MyPara, #MyResult); 
    end_if;

    
    // initialize the global variables for the Lasal2 communication
    G_SDD_HW_Count := 0;
    _memset(#G_SDD_HW_DATA[0], 16#00, sizeof(G_SDD_HW_DATA));
    
  end_if;
  
  // necessary for Lasal2 to communicate with the SDDIntfc objects
  if (_firstscan = TRUE) then
    if G_SDD_HW_Count >= (sizeof(G_SDD_HW_DATA) / sizeof(G_SDD_HW_DATA[0])) then
      // maximum count of _DriveMng Objects reached
      HWC_LogError(this,"@094E (_DriveMngBase::Init) Maximum count of drive objects reached for DiasDrive-Tool.");
      G_SDD_HW_Count := 0;
    end_if;
    G_SDD_HW_DATA[G_SDD_HW_Count] := this$UDINT;
    G_SDD_HW_Count += 1;
  end_if;
    
  InitCounter += 1;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL _DriveMngBase::CyWork
	VAR_INPUT
		EAX 	: UDINT;
	END_VAR
	VAR_OUTPUT
		state (EAX)  : UDINT;
	END_VAR
  VAR
  	x           : DINT;
    pThisCyWork : ^void;
    AxisNo      : USINT;
    SerNoLen    : UDINT;
    SerNoStr    : ARRAY [0..10] OF CHAR;
    pAxBuff     : ^_AXDEF;
  END_VAR
  
  ud_CycleCounter += 1;

  // *********************************************************************************************************
  // ** update all server parameters
  // *********************************************************************************************************
  UpdateSvr();
  
  if CmdState <> _CLASSOK then
    if bdSettings.DriveIsInitialized = TRUE then
      // Reset the info AxisInit 
      ResetAxisInit();
    end_if;
    bdSettings.DriveIsInitialized := FALSE;
    bdSettings.getHwInfo          := FALSE;
    bdSettings.AxisInit           := FALSE;
    bdSettings.GotAllInfos        := FALSE;
    Online := 0;
    
    s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::IdleGetLogFile;
    ReleaseFileHandling();
    
    DriveType := _NotFound;
    HWVersion := 0;
    SerialNo := 0;
  
    FwDatetr.Clear();
    FwNumStr.Clear();
    
  end_if;
  
  //Check if we already got the resonse of all needed infos (is used to wait before we have all infos before the online server will be set)
  if bdSettings.getHwInfo = TRUE then
    if bdWait4HwInfoResponse = 0 then
      bdSettings.GotAllInfos := TRUE;
    end_if;
  end_if;
  
  bdSettings.DriveIsInitialized := DriveInitState();
  
  // ***************************************************************************************************************
  // ** Hardware ist verbunden und Varan Kommunikation ist initialisiert.                                         **
  // ** nun können wir schauen welche Achsen nicht nur softwaremässig sondern auch hardwaremässig vorhanden sind  **
  // ***************************************************************************************************************
  if bdSettings.HwConnect = TRUE then
    // set the Axis-objects to the correct state
    InitAxisState();
    bdSettings.HwConnect := FALSE;
  end_if;
  
// *********************************************************************************************************
// ** call the cywork method of all available axis objects                                                **
// *********************************************************************************************************
  for x := 0 to (SDDMAXENTRIES - 1) do
    pAxBuff := #AxBuffer[x];
    if pAxBuff^.pThis <> NIL then
      if pAxBuff^.AxisOk = 1 then
        pThisCyWork := pAxBuff^.pThis;
        pThisCyWork$^VirtualBase^.CyWork(EAX);       
      end_if;
    else
      exit;
    end_if;
  end_for;


  // only if hardware is online 
  if cOnline = 1 then
    
// *********************************************************************************************************
// ** check if asyncronous information is needed	                                                      **
// *********************************************************************************************************
    UpdateASync();    
    
    if (bdSettings.getHwInfo = FALSE) & (bdSettings.DriveIsInitialized = TRUE) & AxisAvailable then
      // get the standard information of the drive
      AxisNo := GetFirstAxIndex();
      
      bdWait4HwInfoResponse := 0;
      
      if AxisNo <> 16#FF then
      
        //Get I-Type parameter (is needed to determine the correct drive type)
        //I-Type only available at newer drives (MDD100 and SDD1xx-SDD3xx does not have I-Type Paramete, there is I-FBB Parameter with this para number)
        //Despite the fact the this is not the I-Type parameter with MDD100 and SDD drives, we read the parameter in every case
        //The value from the parameter is only used at specific drives so the read value can be ignored with MDD100 and SDDxxx drives.
        if AddASyncEntry(AxisNo      := AxisNo, 
                         usParaNr    := SDD_I_TYPE, 
                         usRdWr      := 0,
                         dValue      := 0, 
                         pThisObj    := this,
                         usEntry     := 0) = 0 then
          bdWait4HwInfoResponse.I_Type := TRUE;
        else
          HWC_LogPrintf(this,"@081D (_DriveMngBase::CyWork) Failed to read Parameter I-TYPE.");
        end_if;
                      
        if AddASyncEntry(AxisNo      := AxisNo, 
                         usParaNr    := SDD_I_HW, 
                         usRdWr      := 0,
                         dValue      := 0, 
                         pThisObj    := this,
                         usEntry     := 0) = 0 then
          bdWait4HwInfoResponse.I_HW := TRUE;
        else
          HWC_LogPrintf(this,"@081E (_DriveMngBase::CyWork) Failed to read Parameter I-HW.");
        end_if;
        
        // re-read the device-id to get the drive-type. it may have changed
        DeviceID.Read();
        
        // at the MDD 100 we want to see the serial number of the MDP
        if DriveType = _MDD_100 then
          SerNoLen := toVaran.SerialNoStr.GetLength();
          
          //Check for valid serial number
          if SerNoLen < 10 then
            _memset(dest:=#SerNoStr[0], usByte:=0, cntr:=sizeof(SerNoStr));
            toVaran.SerialNoStr.GetDataAt(pData:=#SerNoStr[0], udSize:=SerNoLen, udAt:=0);
            
            //Convert serial number from ascii to dint
            SerialNo := sigclib_atoi(s:=#SerNoStr[0]);
          end_if;
        else
          // at the other drives we show the serial number of the first axis
          if AddASyncEntry(AxisNo      := AxisNo, 
                           usParaNr    := SDD_I_SER, 
                           usRdWr      := 0,
                           dValue      := 0, 
                           pThisObj    := this,
                           usEntry     := 0) = 0 then
            bdWait4HwInfoResponse.I_SER := TRUE;
          else
            HWC_LogPrintf(this,"@081F (_DriveMngBase::CyWork) Failed to read Parameter I-SER.");
          end_if;
        end_if;

        if AddASyncEntry(AxisNo      := AxisNo, 
                         usParaNr    := SDD_I_FW, 
                         usRdWr      := 0,
                         dValue      := 0, 
                         pThisObj    := this,
                         usEntry     := 0) = 0 then
          bdWait4HwInfoResponse.I_FW := TRUE;
        else
          HWC_LogPrintf(this,"@0820 (_DriveMngBase::CyWork) Failed to read Parameter I-FW.");
        end_if;

        if AddASyncEntry(AxisNo      := AxisNo, 
                         usParaNr    := SDD_I_BUILD, 
                         usRdWr      := 0,
                         dValue      := 0, 
                         pThisObj    := this,
                         usEntry     := 0) = 0 then
          bdWait4HwInfoResponse.I_BUILD := TRUE;
        else
          HWC_LogPrintf(this,"@0821 (_DriveMngBase::CyWork) Failed to read Parameter I-BUILD.");
        end_if;        
        
        bdSettings.getHwInfo := TRUE;
      end_if;  
    end_if;
    
    if (Online.read() ) &
       (s_LogFileV.eGetLogFileSSW <> t_e_GetLogFileSSW::IdleGetLogFile) then
      GetLogFileCyclic();
    end_if;

  end_if;
    
  state := READY;

END_FUNCTION


FUNCTION GLOBAL _DriveMngBase::AddAxObj
	VAR_INPUT
		pThis 	: ^void;
		Place 	: DINT;
		AxisNo 	: DINT;
		pAsyncPara 	: ^_SDDRINGBUFFER;
		AxisExtend 	: DINT;
		AxisFast 	: DINT;
	END_VAR
  VAR
  	AxisBit   : BDINT;
 //   AxisShift : DINT;
  END_VAR

  // check if the place number and the axis number is correct
  if (pThis <> NIL) & (AxCount < SDDMAXENTRIES) & (AxisNo > 0) & (AxisNo <= SDDMAXPLACE) then
  
    AxBuffer[AxCount].pThis   := pThis;
    AxBuffer[AxCount].Place   := Place;
    AxBuffer[AxCount].AxisNo  := AxisNo;
   
    // set the necessary bit for comparison with the real hardware
    AxisBit := 1;
   // AxisShift := ((Place * SDDMAXPLACE) + (AxisNo - 1));  //  only during developing? can be removed? ANDPAT
    AxisBit := AxisBit SHL ((Place * SDDMAXPLACE) + (AxisNo - 1));
    
    AxisActive := AxisActive OR AxisBit;
    
    AxBuffer[AxCount].AxisBit := AxisBit;
    
    AxBuffer[AxCount].AxAsyncPara := pAsyncPara;
    
    // Set Extended Bit
    if AxisExtend = 1 then
      AxBuffer[AxCount].AxisExtend := TRUE;
      AxisExtendAll := AxisExtendAll OR AxisBit;
    end_if;
    
    // set Fast Bit
    if AxisFast = 1 then
      AxBuffer[AxCount].AxisFast := TRUE;
      AxisFastAll := AxisFastAll OR AxisBit;
    end_if;
    
    AxCount += 1;
    
    if AxCount >= SDDMAXENTRIES then
      TRACE("_DriveMngBase : Error while initialising axis objects. -> too many objects available!");
    end_if;
    
  end_if;
  
END_FUNCTION


FUNCTION _DriveMngBase::InitAxisState
VAR
	x                : UDINT;
  pThisNewInst     : ^void;
  ret_code         : iprStates;
  UserPara         : CmdStruct;
  UserResult       : Results;
  retcode          : BOOL;
  TempAxisAvailHW  : BDINT;
  TempAxisAvailSW  : BDINT;
  Count1           : USINT;
  x1                : UDINT;
  TempAxis2         : BDINT;
END_VAR
  
  retcode := FALSE;
  
  Count1 := 0;
  AxIndizesL2 := 0; //hashan
  
  // Check the sw axes with the hw axes and define the correct axindex

  if bVaranConnected then
    b_IsSDD21x := toVaran.IsSDD21x();
  else    
    b_IsSDD21x := FALSE;
  end_if;
  
  if b_IsSDD21x then
    AxisActive := 2#101;
    
    // on SDD210 or SDD215 we fake the axis number of the 2nd axis for external use
//    AxIndizesL2 := 2#11; // RamAnd 22.09.2010 15:08

    for x:= 0 to (SDDMAXENTRIES - 1) do
    
      if AxBuffer[x].AxisBit = 2#01 then
        //Only set bit if axis object is placed
        if AxBuffer[x].pThis <> NIL then
          AxIndizesL2 := AxIndizesL2 OR 2#01;
        end_if;
        
      // if user configured axis 2, we turn it to axis 3
      elsif AxBuffer[x].AxisBit = 2#10 then
        AxBuffer[x].AxisBit := 2#100;
        //Only set bit if axis object is placed
        if AxBuffer[x].pThis <> NIL then
          AxIndizesL2 := AxIndizesL2 OR 2#10;
        end_if;
      
      // if user configured axis 3, we reset the config bit
      elsif AxBuffer[x].AxisBit = 2#100 then
        AxBuffer[x].AxisBit := 2#0;
        
      end_if;
    end_for;
    
  end_if;

  for x:= 0 to (SDDMAXENTRIES - 1) do
    TempAxisAvailSW := (AxisActive SHR x) AND 16#01;
    TempAxisAvailHW := (AxisAvailable SHR x) AND 16#01;
    TempAxis2       :=  TempAxisAvailHW SHL x;   
    
    if (TempAxisAvailHW = 1) then
      if TempAxisAvailHW = TempAxisAvailSW then
        // Achse ist physikalisch und softwaremässig vorhanden
        
         
        if b_IsSDD21x then
          for x1 := 0 to (SDDMAXENTRIES -1) do
            if AxBuffer[x1].pThis <> NIL then
              if (AxBuffer[x1].AxisBit AND TempAxis2) <> 0 then
                AxBuffer[x1].AxisOk := 1;
                
                //On SDD210 or SDD215 the second axis is the 3rd axis in the firmware (fw of sdd21x and sdd31x is the same)
                //We have to manipulate the axisindex of the second axis
                if AxBuffer[x1].AxisNo = 2 then
                  Count1 += 1;
                end_if;
                AxBuffer[x1].AxisIndex := Count1 ;
                
                // on SDD210 or SDD215 we fake the axis number of the 2nd axis for external use (no automatic determination)
                //AxIndizesL2 += 2#1 SHL Count1;  // RamAnd 22.09.2010 15:08
                
                //Count1 += 1;  // RamAnd: we have a hole in the axis (2#101) and so we also skip 1 position in memory
                exit;
              end_if;
            else
              exit;
            end_if;
          end_for;
        else
          for x1 := 0 to (SDDMAXENTRIES -1) do
            if AxBuffer[x1].pThis <> NIL then
              if (AxBuffer[x1].AxisBit AND TempAxis2) <> 0 then
                AxBuffer[x1].AxisOk := 1;
                AxBuffer[x1].AxisIndex := Count1;
                AxIndizesL2 += 2#1 SHL Count1;
                exit;
              end_if;
            else
              exit;
            end_if;
          end_for;
        end_if;
      end_if;
      // nächster Index für Buffer im DPRAM
      Count1 += 1;
    end_if;
  end_for;
    
  // check all axis objects
  for x := 0 to (SDDMAXENTRIES - 1) do
    
    // axis object available
    if AxBuffer[x].pThis <> NIL then
        
      pThisNewInst := AxBuffer[x].pThis;
      // set the actual state of the axis object
      UserPara.uiCmd := SDD_SETHWSTATE;
        
        
      // is the axis really available
      if AxBuffer[x].AxisOk = 1 then
        // set the state READY in the axis object
        UserPara.aPara[0]$iprStates := READY;
        UserPara.aPara[1] := to_dint(x);  // laufende Achsnummer vom internen Buffer
                                          // nicht zu verwechseln mit der laufenden Achsnummer im DPRAM
                                          // diese kann unterschiedlich sein (ist in der Struktur _AXDEF.AXISINDEX zu finden
                                            
        ret_code := pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
      else
        // set the state ERROR in the axis object
        UserPara.aPara[0]$iprStates := ERROR;
        UserPara.aPara[1] := SDD_NO_HW;  
        ret_code := pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
      end_if;
    else
      exit;
    end_if;
    
  end_for;
  
END_FUNCTION


FUNCTION GLOBAL _DriveMngBase::GetExtendInfo
	VAR_OUTPUT
		retcode 	: BOOL;
	END_VAR
  // Rauand abklären wir das extended machen mit Ramböck!!!!!!!!!!!!!!
 // retcode := cSDDSettings.GetExtendInfo();
    Retcode := FALSE;
END_FUNCTION


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

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


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


//***********************************************************************
//***********************************************************************
//******                                                          *******
//******          Get the axis number in the range 0-7            *******
//******                                                          *******
//***********************************************************************
//***********************************************************************




FUNCTION GLOBAL _DriveMngBase::GetParameterState
	VAR_INPUT
		usAxis 	: USINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;   
  END_VAR  
  
  if bVaranConnected then
    retcode := toVaran.GetParameterState(AxBuffer[usAxis].AxisIndex); 
  else      
    MyPara.uiCmd  := BUSIF_DRIVEMNGBASE_GET_PARA_STATE;
    MyPara.aPara[0] := to_dint(AxBuffer[usAxis].AxisIndex);
    ToBusIF.NewInst(#MyPara, #MyResult);
    retcode := MyResult.aData[0]$DINT;
  end_if;
  

END_FUNCTION

FUNCTION GLOBAL _DriveMngBase::SetParameter
	VAR_INPUT
		usAxis 	: USINT;
		paranr 	: USINT;
		rdwr 	: USINT;
		paravalue 	: DINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;   
  END_VAR    
 
  if bVaranConnected then
    retcode := toVaran.SetParameter(us_Axis:=usAxis, us_para_nr:=paranr, us_rdwr:=rdwr, sd_para_value:=paravalue);  
  else 
    MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_SET_PARAMETER;
    MyPara.aPara[0] := to_dint(usAxis);
    MyPara.aPara[1] := to_dint(0xFFFF);
    MyPara.aPara[2] := to_dint(paranr);
    MyPara.aPara[3] := to_dint(rdwr); 
    MyPara.aPara[4] := (#paravalue)$DINT;  
    //byte for datalength and offset, not used for standard parameters
    MyPara.aPara[5] := 0;
    ToBusIF.NewInst(#MyPara, #MyResult);
    retcode := MyResult.aData[0]$DINT;
  end_if;  
  
END_FUNCTION

FUNCTION GLOBAL _DriveMngBase::SetParameterDS402
	VAR_INPUT
		usAxis 	    : USINT;
		uiParaID 	  : UINT;
		usParaSubID : USINT;
		usRdWr 	    : USINT;
		pparavalue 	: ^USINT;
		bsDataInfo 	: BSINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;
  END_VAR 
  
  if bVaranConnected then
   //yet not used over varan
   retcode := 0;
  else 
    MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_SET_PARAMETER;
    MyPara.aPara[0] := to_dint(usAxis);
    MyPara.aPara[1] := to_dint(uiParaID);
    MyPara.aPara[2] := to_dint(usParaSubID);
    MyPara.aPara[3] := to_dint(usRdWr);
    MyPara.aPara[4] := (pparavalue)$DINT;
    MyPara.aPara[5] := to_dint(bsDataInfo);
    ToBusIF.NewInst(#MyPara, #MyResult);
    retcode := MyResult.aData[0]$DINT;
  end_if;  
  
END_FUNCTION



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

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

END_FUNCTION


FUNCTION GLOBAL _DriveMngBase::GetParameter
	VAR_INPUT
		usAxis 	: USINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;
    pTempData: ^USINT;
  END_VAR  
  
  if bVaranConnected then
    retcode := toVaran.GetParameter(usAxis); 
  else      
    MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_PARAMETER;
    MyPara.aPara[0] := to_dint(usAxis);
    ToBusIF.NewInst(#MyPara, #MyResult);
    pTempData := (MyResult.aData[0])$^USINT;
    retcode   := (pTempData)^$DINT;
  end_if;
  
END_FUNCTION


FUNCTION GLOBAL _DriveMngBase::GetParameterDS402
	VAR_INPUT
		usAxis 	: USINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: ^DINT;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;
    pTempData: ^USINT;
  END_VAR
  
  if bVaranConnected then
   //yet not used over varan
   retcode := 0$^DINT;
  else 
    MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_PARAMETER;
    MyPara.aPara[0] := to_dint(usAxis);
    ToBusIF.NewInst(#MyPara, #MyResult);
    pTempData := (MyResult.aData[0])$^USINT;
    retcode   := pTempData$^DINT;
  end_if;
  
END_FUNCTION



FUNCTION VIRTUAL GLOBAL _DriveMngBase::CmdState::Read
	VAR_OUTPUT
		output (EAX) 	: t_e_VaranErrors;
	END_VAR
  VAR
  	oldCmdState   : t_e_VaranErrors;
    x             : UDINT;
    pThisNewInst  : ^void;
    UserPara      : CmdStruct;
    UserResult    : Results;
    MyPara   : CmdStruct;
    MyResult : results;  
  END_VAR

  oldCmdState := CmdState;
  
  if bVaranConnected then
    CmdState := toVaran.Read();
  else      
    MyPara.uiCmd   := BUSIF_DRIVEMNGBASE_GET_CMD_STATE;
    ToBusIF.NewInst(#MyPara, #MyResult);
    CmdState := MyResult.aData[0]$t_e_VaranErrors; 
  end_if;
  
  if oldCmdState <> CmdState then
    
    for x := 0 to (SDDMAXENTRIES - 1) do
      if AxBuffer[x].pThis <> NIL then
          
        pThisNewInst := AxBuffer[x].pThis;
        UserPara.uiCmd := SDD_SETSTATE;  
        pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
      else
        exit;
      end_if;
    end_for;
  end_if;
  
  output := CmdState;

END_FUNCTION


FUNCTION _DriveMngBase::UpdateSvr

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


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

  if bVaranConnected then
    Release := toVaran.Release.Read();
	  output := Release;
  else  
    MyPara.uiCmd  := BUSIF_DRIVEMNGBASE_READ_FPGA_VERSION;
    ToBusIF.NewInst(#MyPara, #MyResult);
    Release := MyResult.aData[0]$HDINT; 
  end_if;

  output := Release;

END_FUNCTION


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

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

END_FUNCTION


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

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

END_FUNCTION


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

  if bVaranConnected then   
    DeviceID := toVaran.DeviceID.Read();
    if DeviceID = DIASDRIVE_MINI_DEVICE_ID then
      DriveType:=_MDD_100;
    end_if;
  else
    MyPara.uiCmd  := BUSIF_DRIVEMNGBASE_READ_DEVICEID;
    ToBusIF.NewInst(#MyPara, #MyResult);    
    DeviceID := MyResult.aData[0]$UDINT; 
  end_if;
  
  output := DeviceID;

END_FUNCTION


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

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

  output := Online;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL _DriveMngBase::AddASyncEntry
	VAR_INPUT
		AxisNo 	: USINT;
		usParaNr 	: USINT;
		usRdWr 	: USINT;
		dValue 	: DINT;
		pThisObj 	: ^void;
		usEntry 	: USINT;
		udTimeout 	: UDINT;(* := 0 *)
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR
  	pWrite      : ^_SDDBFENTRY;
    pRead       : ^_SDDBFENTRY;
  END_VAR
  
  retcode := -1;
  
  // check if the reading of the ringbuffer is already active (different tasks!!!!!)
  if bdSettings.bRingBufferRead = TRUE then
    retcode := -10;
    Trace("Reading of the ringbuffer is active! new Entry is not allowed!");
    return;
  end_if;
  
  // check if the writing of the ringbuffer is already active (different tasks!!!!!)
  if bdSettings.bRingBufferWrite = TRUE then
    retcode := -10;
    Trace("Writing of the ringbuffer is active! new Entry is not allowed!");
    return;
  end_if;
  
  bdSettings.bRingBufferWrite := TRUE;
  
  // check the Axisnumber
  if AxisNo >= 0 & AxisNo < SDDMAXENTRIES then //HasHan
    
    if (AxBuffer[AxisNo].pThis <> NIL) & (AxBuffer[AxisNo].AxAsyncPara^.pStart <> NIL) & 
      (AxBuffer[AxisNo].AxAsyncPara^.ActEntries < SDDBUFFERENTRY) then      
      pWrite := AxBuffer[AxisNo].AxAsyncPara^.pWrite;
      pRead := AxBuffer[AxisNo].AxAsyncPara^.pRead;
      pWrite^.bFinished       := FALSE;
      pWrite^.uiParaIndex     := 0xFFFF;    //for standard lasal parameter
      pWrite^.usParaSubIndex  := usParaNr;
      pWrite^.usRDWR          := usRdWr;
      pWrite^.bsDataInfo      := 0;         //datalength 4byte and offset 0 
      pWrite^.dValue[0]$DINT  := dValue;
      pWrite^.pThisObj        := pThisObj;
      pWrite^.usEntry         := usEntry;
      
      if udTimeout = 0 then
        pWrite^.udTimeoutCycles := ud_TimeoutCycles;
      else
        pWrite^.udTimeoutCycles := udTimeout * 1000 /  udCycleTimems;  
      end_if;
      
      // Changed by Rauand 
      pWrite^.bSent       := FALSE;
      
      // Timestamp for timeout
      pWrite^.udTimeStamp := ud_CycleCounter;
      
      AxBuffer[AxisNo].AxAsyncPara^.ActEntries += 1;
        
      if (pRead = pWrite) &  (((cOnline = 1) & (bdSettings.DriveIsInitialized = TRUE)) 
       | (usParaNr = SDD_M_TYPE) | (usParaNr = SDD_K_FBRW) 
       | (usParaNr = SDD_A_VALTT1) | (usParaNr = SDD_A_VALTT2)
       | (usParaNr = SDD_A_VALRT1) | (usParaNr = SDD_A_VALRT2) | (usParaNr = SDD_I_STATUS)
       | (usParaNr = SDD_I_HW) | (usParaNr = SDD_I_SER) | (usParaNr = SDD_I_TYPE)
       | (usParaNr = SDD_I_FW) | (usParaNr = SDD_I_BUILD)) then
       
        retcode := GetParameterState(usAxis:=AxisNo);
            
        if (retcode <> -1) & (retcode <> -3) then
          IF SetParameter( usAxis        := AxBuffer[AxisNo].AxisIndex,
                           paranr        := pWrite^.usParaSubIndex, 
                           rdwr          := pWrite^.usRdWR,
                           paravalue     := pWrite^.dValue[0]$DINT ) = 0 THEN
            pWrite^.bSent := TRUE;
            retcode := 0;
          END_IF;
   
        end_if;
      else
        retcode := 0;
      end_if;
          
      AxBuffer[AxisNo].AxAsyncPara^.pWrite += sizeof(_SDDBFENTRY);
      if AxBuffer[AxisNo].AxASyncPara^.pWrite >= AxBuffer[AxisNo].AxASyncPara^.pEnd then
        AxBuffer[AxisNo].AxASyncPara^.pWrite := AxBuffer[AxisNo].AxASyncPara^.pStart;
      end_if;
    end_if;
  end_if;
  
  bdSettings.bRingBufferWrite := FALSE;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL _DriveMngBase::AddASyncEntryIntHWCValue
	VAR_INPUT
		AxisNo 	: USINT;
		dIntValueIndex 	: DINT;
		pThisObj 	: ^void;
		usEntry 	: USINT;
		udTimeout 	: UDINT;(* := 0 *)
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR
  	udTempVar : UDINT;
    rc1 : DINT;
    rc2 : DINT;
  END_VAR  
  
  retcode := -1;
  
  //We have to lock this method to be sure that it will not be interupted because it is neccesarry that both AddAsync entries are one after the other in the buffer
  //to be sure that we get the correct value from the I-INT parameter.
  //If we would be interrupted and A-INTHWK would be set to an other value before we start the AddAsyncEntry for the I-INT value it can happen that we get the wrong I-INT value
  
  //0 .. not locked, 1 locked
  udTempVar := sigclib_atomic_cmpxchgU32(pValue:=#udProtectIntHWCValueVar, cmpVal:=0, newVal:=1);
  
  //check if method is locked
  if udTempVar = 0 then
     
    //Not locked at the moment
    
    //Write index of internal parameter to parameter A-INTHWK
    rc1 := AddASyncEntry(AxisNo:=AxisNo, usParaNr:=SDD_A_INTHWK, usRdWr:=1, dValue:=dIntValueIndex, pThisObj:=pThisObj, usEntry:=usEntry, udTimeout:=udTimeout);
    
    if rc1 = 0 then
      //Read internal parameter from written index from the parameter I-INTHWK
      rc2 := AddASyncEntry(AxisNo:=AxisNo, usParaNr:=SDD_I_INTHWK, usRdWr:=0, dValue:=0, pThisObj:=pThisObj, usEntry:=usEntry, udTimeout:=udTimeout);
      if rc1 = 0 & rc2 = 0 then
        retcode := 0;
      end_if;
    end_if;

    sigclib_atomic_setU32(pValue:=#udProtectIntHWCValueVar, value:=0); //unlock method
  else
    //method is currently locked
    retcode := -99;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL _DriveMngBase::AddASyncEntryDS402
	VAR_INPUT
		AxisNo 	: USINT;
		uiParaID 	: UINT;
		usParaSubID 	: USINT;
		usRdWr 	: USINT;
		pValue 	: ^USINT;
		bsDataInfo 	: BSINT;
		pThisObj 	: ^void;
		usEntry 	: USINT;
		udTimeout 	: UDINT;(* := 0 *)
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR
  	pWrite    : ^_SDDBFENTRY;
    pRead     : ^_SDDBFENTRY;
  END_VAR
  
  retcode := -1;
  
  // check if the reading of the ringbuffer is already active (different tasks!!!!!)
  if bdSettings.bRingBufferRead = TRUE then
    retcode := -10;
    Trace("Reading of the ringbuffer is active! new Entry is not allowed!");
    return;
  end_if;
  
  // check if the writing of the ringbuffer is already active (different tasks!!!!!)
  if bdSettings.bRingBufferWrite = TRUE then
    retcode := -10;
    Trace("Writing of the ringbuffer is active! new Entry is not allowed!");
    return;
  end_if;
  
  bdSettings.bRingBufferWrite := TRUE;
  
  // check the Axisnumber
  if AxisNo >= 0 & AxisNo < SDDMAXENTRIES then //HasHan
    
    if (AxBuffer[AxisNo].pThis <> NIL) & (AxBuffer[AxisNo].AxAsyncPara^.pStart <> NIL) & 
      (AxBuffer[AxisNo].AxAsyncPara^.ActEntries < SDDBUFFERENTRY) then
      pWrite := AxBuffer[AxisNo].AxAsyncPara^.pWrite;
      pRead := AxBuffer[AxisNo].AxAsyncPara^.pRead;
      pWrite^.bFinished       := FALSE;
      pWrite^.uiParaIndex     := uiParaID;
      pWrite^.usParaSubIndex  := usParaSubID;
      pWrite^.usRDWR          := usRdWr;
      pWrite^.bsDataInfo      := bsDataInfo;      
      
      if usRdWr then
        _memcpy(ptr1:=#pWrite^.dValue, ptr2:=pValue, cntr:=4*((bsDataInfo and 0x0F) + 1));
      end_if;
      
      pWrite^.pThisObj  := pThisObj;
      pWrite^.usEntry   := usEntry;
      
      if udTimeout = 0 then
        pWrite^.udTimeoutCycles := ud_TimeoutCycles;
      else
        pWrite^.udTimeoutCycles := udTimeout * 1000 /  udCycleTimems;  
      end_if;
      
      
      // Changed by Rauand 
      pWrite^.bSent       := FALSE;
      
      // Timestamp for timeout
      
      pWrite^.udTimeStamp := ud_CycleCounter;
      
      AxBuffer[AxisNo].AxAsyncPara^.ActEntries += 1;
        
      if (pRead = pWrite) & ((cOnline = 1) & (bdSettings.DriveIsInitialized = TRUE)) then
        retcode := GetParameterState(usAxis:=AxisNo);
            
        if (retcode <> -1) & (retcode <> -3) then
        
          IF SetParameterDS402(usAxis     := AxBuffer[AxisNo].AxisIndex
                            , uiParaID    := pWrite^.uiParaIndex
                            , usParaSubID := pWrite^.usParaSubIndex
                            , usRdWr      := pWrite^.usRdWR
                            , pparavalue  := #pWrite^.dValue[0]
                            , bsDataInfo  := pWrite^.bsDataInfo
                            ) = 0 THEN
            pWrite^.bSent := TRUE;
            retcode := 0;
          END_IF;
   
        end_if;
      else
        retcode := 0;
      end_if;
          
      AxBuffer[AxisNo].AxAsyncPara^.pWrite += sizeof(_SDDBFENTRY);
      if AxBuffer[AxisNo].AxASyncPara^.pWrite >= AxBuffer[AxisNo].AxASyncPara^.pEnd then
        AxBuffer[AxisNo].AxASyncPara^.pWrite := AxBuffer[AxisNo].AxASyncPara^.pStart;
      end_if;
    end_if;
  end_if;
  
  bdSettings.bRingBufferWrite := FALSE;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL _DriveMngBase::UpdateASync
VAR
  pThisNewInst	: ^void;
	ret_code		: IPRSTATES;
	UserPara		: CmdStruct;
	UserResult  : Results;
	ActState    : DINT;
  pRead         : ^_SDDBFENTRY;
  x             : USINT;
  pThisNewInst1	: ^void;
  bNothingToDo  : BOOL;
  retcode       : DINT;
  usCounter     : USINT;
  pAxBuff         : ^_AXDEF;
END_VAR

  bdSettings.bRingBufferRead := TRUE;

  // check all axis objects
  for x := 0 to (SDDMAXENTRIES - 1) do 
    
    pAxBuff := #AxBuffer[x];
    
    // axis object available
    if pAxBuff^.pThis <> NIL then
      bNothingToDo := FALSE;
      if pAxBuff^.AxAsyncPara^.ActEntries > 0 then
        pRead := pAxBuff^.AxAsyncPara^.pRead;

        ActState := GetParameterState(usAxis:=x);
        if ActState = 0 then
          if pRead^.bSent = FALSE then
            if pRead^.uiParaIndex = 0xFFFF then
              // set the next command to the drive
              retcode := SetParameter( usAxis         := pAxBuff^.AxisIndex,
                                       paranr         := pRead^.usParaSubIndex, 
                                       rdwr           := pRead^.usRDWR,
                                       paravalue      := pRead^.dValue[0]$DINT);
                                       
            else                    
              retcode := SetParameterDS402(usAxis     := pAxBuff^.AxisIndex
                                        , uiParaID    := pRead^.uiParaIndex
                                        , usParaSubID := pRead^.usParaSubIndex
                                        , usRdWr      := pRead^.usRdWR
                                        , pparavalue  := #pRead^.dValue[0]
                                        , bsDataInfo  := pRead^.bsDataInfo
                                        );
            end_if; 
            
            if retcode = 0 then
              pRead^.udTimestamp := ud_CycleCounter;
              pRead^.bFinished := FALSE;
              pRead^.bSent := TRUE;
              bNothingToDo := TRUE;
            end_if;
            
          // now finish the command
          elsif pRead^.bFinished = FALSE then
          
            pRead^.bFinished := TRUE;
            pRead^.bSent := FALSE;
            pThisNewInst := pRead^.pThisObj;
            if pThisNewInst <> NIL then
              if pRead^.usRDWR = 0 then
                // it was a reading parameter command
                if pRead^.uiParaIndex = 0xFFFF then
                  pRead^.dValue[0]$DINT := GetParameter(usAxis:= pAxBuff^.AxisIndex);
                else
                  _memcpy(ptr1:=#pRead^.dValue[0], ptr2:=GetParameterDS402(usAxis:=pAxBuff^.AxisIndex), cntr:=12);
                end_if;
              end_if;
              
              // Asynchronous access is finished
              UserPara.uiCmd := SDD_ASYNC_READY;
              UserPara.aPara[0] := to_dint(pRead^.usParaSubIndex);
              UserPara.aPara[1] := to_dint(pRead^.usRDWR);
              if pRead^.uiParaIndex = 0xFFFF then
                UserPara.aPara[2] := pRead^.dValue[0]$DINT;
                UserPara.aPara[4] := 0;
              else  
                UserPara.aPara[2] := 0;
                UserPara.aPara[4] := (#pRead^.dValue[0])$DINT;
              end_if;              
              UserPara.aPara[3] := to_dint(x); // Achsennummer
              
// Bedeutung usEntry ..
// 0... default
// 1... Refresh der Driveparameter wenn Parameterklassen vorhanden sind
// 2... Ist der erste Part vom Refresh der Parameterklassen abgeschlossen (wird als letztes gesendet)
// 3... Eintrag kommt von Lasal2 Tool zum Lesen/Schreiben asynchroner Parameter

              // internal command of Lasal2
              if (pRead^.usEntry = 3) then  
                if (HWVersion and DRIVEMNG_DRIVESCOPE_SCOPE_BIT) = DRIVEMNG_DRIVESCOPE_SCOPE_BIT
                & pRead^.uiParaIndex = DRIVEMNG_DRIVESCOPE_GETALL_PARAM then
                  _memcpy(ptr1:=#aDriveScopeData[0] , ptr2:= #pRead^.dValue[0], cntr:=12);
                  
                  for usCounter :=0 to 2 do  
                    // Asynchronous access is finished
                    UserPara.uiCmd    := SDD_ASYNC_READY;
                    UserPara.aPara[0] := 251 + usCounter; //index number
                    UserPara.aPara[1] := 0; //read/write
                    UserPara.aPara[2] := aDriveScopeData[usCounter];
                    UserPara.aPara[3] := to_dint(pAxBuff^.AxisIndex); // Achsennummer für Lasal2
                    UserPara.aPara[4] := 0; //error state
                    
                    ret_code := L2CmdFinished(#UserPara, #UserResult);   
                    
                    // when lasal2 reads a parameter, we use the value also for eventually placed parameter-objects
                    UserPara.uiCmd := SDD_REFRESHPARAOBJECTS;
                    pThisNewInst := pAxBuff^.pThis;
                    pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
                  end_for;
                  
                else                  
                  UserPara.aPara[3] := to_dint(pAxBuff^.AxisIndex); // Achsennummer für Lasal2
                  ret_code := L2CmdFinished(#UserPara, #UserResult);
                  
                  // when lasal2 reads a parameter, we use the value also for eventually placed parameter-objects
                  UserPara.uiCmd := SDD_REFRESHPARAOBJECTS;
                  pThisNewInst := pAxBuff^.pThis;
                  pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
                end_if;
              else
                ret_code := pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
              end_if;
            
              // check if parameter has to be saved
              if (pRead^.usRDWR = 1) & ((pRead^.usEntry = 0) | (pRead^.usEntry = 3)) then
                pThisNewInst1 := pAxBuff^.pThis;
                UserPara.uiCmd := SDD_SAVPARAVALUE;
                UserPara.aPara[4] := 1;
                ret_code := pThisNewInst1$^VirtualBase^.NewInst(#UserPara, #UserResult);
                
                // if it's a change from the classes, refresh the values in lasal
                if (pRead^.usEntry = 0) then
                
                  // if buffer hasn't been allocated yet => do it
                  if ChangesRingBuffer.pStart = NIL then
                    // allocate the memory for the ringbuffer
                    ChangesRingBuffer.pStart$^void := coStdLib.Malloc(SDDBUFFERENTRY * sizeof(_ParaRefreshBufEntry));
                  
                    // initialize ringbuffer
                    if ChangesRingBuffer.pStart then
                      ChangesRingBuffer.pEnd := ChangesRingBuffer.pStart + SDDBUFFERENTRY * sizeof(_ParaRefreshBufEntry);
                      ChangesRingBuffer.pRead := ChangesRingBuffer.pStart;
                      ChangesRingBuffer.pWrite := ChangesRingBuffer.pStart;
                      ChangesRingBuffer.ActEntries := 0;
                      
                      _memset(ChangesRingBuffer.pStart, 16#00, SDDBUFFERENTRY*sizeof(_ParaRefreshBufEntry));
                    end_if;
                  end_if;

                  // save the new changes into the ringbuffer
                  if ChangesRingBuffer.pStart then
                    ChangesRingBuffer.pWrite^.AxisNo   := pAxBuff^.AxisIndex;
                    ChangesRingBuffer.pWrite^.Reserved := 0;
                    ChangesRingBuffer.pWrite^.ParaNo   := pRead^.usParaSubIndex;
                    ChangesRingBuffer.pWrite^.NewValue := pRead^.dValue[0]$DINT;
                    
                    ChangesRingBuffer.pWrite += sizeof(_ParaRefreshBufEntry);
                    if ChangesRingBuffer.pWrite >= ChangesRingBuffer.pEnd then
                      ChangesRingBuffer.pWrite := ChangesRingBuffer.pStart;
                    end_if;
                    
                    if ChangesRingBuffer.ActEntries < SDDBUFFERENTRY then
                      ChangesRingBuffer.ActEntries += 1;
                    end_if;
                  end_if;
                end_if;
              end_if;

              // Überprüfung ob der Parameter abgespeichert werden muss
              if (pRead^.usEntry = 1) then
                pThisNewInst1 := pAxBuff^.pThis;
                UserPara.uiCmd := SDD_SAVPARAVALUE;
                UserPara.aPara[4] := 0;
                ret_code := pThisNewInst1$^VirtualBase^.NewInst(#UserPara, #UserResult);
              end_if;

            end_if;
            
            // Ist der Parameter refresh abgeschlossen ?
            if pRead^.usEntry = 2 then
              // Refresh all parameter is now successfully finished
              pThisNewInst1 := pAxBuff^.pThis;
              UserPara.uiCmd := SDD_REFRESHPARA;
              ret_code := pThisNewInst1$^VirtualBase^.NewInst(#UserPara, #UserResult);
            end_if;
            
          end_if;
          if bNothingToDo = FALSE then
            // check if we have a next command
            pAxBuff^.AxAsyncPara^.ActEntries -= 1;
            pAxBuff^.AxAsyncPara^.pRead += sizeof(_SDDBFENTRY);
            pRead := pAxBuff^.AxAsyncPara^.pRead;
        
            if pAxBuff^.AxAsyncPara^.pRead >= pAxBuff^.AxAsyncPara^.pEnd then
              pAxBuff^.AxAsyncPara^.pRead := pAxBuff^.AxAsyncPara^.pStart;
              pRead := pAxBuff^.AxAsyncPara^.pRead;
            end_if;
        
            if pRead <> pAxBuff^.AxAsyncPara^.pWrite then
              if pRead^.uiParaIndex = 0xFFFF then
                // set the next command to the drive
                retcode := SetParameter( usAxis         := pAxBuff^.AxisIndex,
                                         paranr         := pRead^.usParaSubIndex, 
                                         rdwr           := pRead^.usRDWR,
                                         paravalue      := pRead^.dValue[0]$DINT); 
                                         
              else                    
                retcode := SetParameterDS402(usAxis     := pAxBuff^.AxisIndex
                                          , uiParaID    := pRead^.uiParaIndex
                                          , usParaSubID := pRead^.usParaSubIndex
                                          , usRdWr      := pRead^.usRdWR
                                          , pparavalue  := #pRead^.dValue[0]
                                          , bsDataInfo  := pRead^.bsDataInfo
                                          );
              end_if; 
                
              IF retcode = 0 THEN
                pRead^.udTimestamp := ud_CycleCounter;
                pRead^.bFinished := FALSE;
                pRead^.bSent := TRUE;
              END_IF;
            end_if;
          end_if;
        
        // class not ready or maximum time for asynchronous access exceeded
        elsif (ActState <> -1) | ((ud_CycleCounter - pAxBuff^.AxAsyncPara^.pRead^.udTimeStamp) > pAxBuff^.AxAsyncPara^.pRead^.udTimeoutCycles) then                
          pRead^.bFinished := TRUE;
          pRead^.bSent := FALSE;
          pThisNewInst := pAxBuff^.AxASyncPara^.pRead^.pThisObj;
          if pThisNewInst <> NIL then
            
            // now we have an error
            UserPara.uiCmd := SDD_ASYNC_ERROR;
            UserPara.aPara[0] := to_dint(pRead^.usParaSubIndex);
            UserPara.aPara[2] := pRead^.dValue[0]$DINT;
            
            if ((ud_CycleCounter - pAxBuff^.AxAsyncPara^.pRead^.udTimeStamp) > pAxBuff^.AxAsyncPara^.pRead^.udTimeoutCycles) then
              ActState := ERR_OBJ_HANDLING_TIMEOUT;
            end_if;
            
            // internal command of Lasal2
            if (pAxBuff^.AxASyncPara^.pRead^.usEntry = 3) then
              UserPara.aPara[1] := to_dint(pRead^.usRDWR);
              UserPara.aPara[4] := ActState;
              UserPara.aPara[3] := pAxBuff^.AxisIndex;
              
              ret_code := L2CmdFinished(#UserPara, #UserResult);
              
            // asynchronous command from applikation
            else
            
              // check if it was a timeout
              UserPara.aPara[1] := ActState;
              UserPara.aPara[3] := x; // Achsenummer
            
              ret_code := pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
              
            end_if; 

            // check if we have a next command
            pAxBuff^.AxAsyncPara^.ActEntries -= 1;
            pAxBuff^.AxAsyncPara^.pRead += sizeof(_SDDBFENTRY);
            pRead := pAxBuff^.AxAsyncPara^.pRead;

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

              pRead^.bFinished := FALSE;
              pRead^.bSent := TRUE;
            end_if;
          end_if;
          // Ist der erste Part vom Refresh abgeschlossen ?
          if pRead^.usEntry = 2 then
            // Refresh all parameter is now successfully finished
            pThisNewInst1 := pAxBuff^.pThis;
            UserPara.uiCmd := SDD_REFRESHPARA;
            ret_code := pThisNewInst1$^VirtualBase^.NewInst(#UserPara, #UserResult);
          end_if;
        end_if;
      end_if;
    else
      exit;
    end_if;
  end_for;
	
  bdSettings.bRingBufferRead := FALSE;

END_FUNCTION


FUNCTION GLOBAL _DriveMngBase::DriveInitState
	VAR_OUTPUT
		retcode 	: BOOL;
	END_VAR

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


FUNCTION GLOBAL _DriveMngBase::AxisInitFinished
	VAR_INPUT
		AxisNo 	: USINT;
	END_VAR
  VAR
  	x       : USINT;
    MyPara   : CmdStruct;
    MyResult : results;  
  END_VAR

    if AxisNo >= 0 & AxisNo < SDDMAXENTRIES then
      AxBuffer[AxisNo].InitFinished := TRUE;
    end_if;
    
    
    for x := 0 to SDDMAXENTRIES -1 do
      if (AxBuffer[x].pThis <> NIL) then
        if(AxBuffer[x].InitFinished = FALSE) & (AxBuffer[x].AxisOk = 1) then
          return;
        end_if;
      else
        exit;
      end_if;
    end_for;
    
    bdSettings.AxisInit := TRUE;
    
    if bVaranConnected then
      toVaran.ExternInitFinished();
    else
      MyPara.uiCmd := BUSIF_DRIVEMNGBASE_EXTERN_INIT_FINISH;
      ToBusIF.NewInst(#MyPara, #MyResult);
    end_if;
    
    
END_FUNCTION


FUNCTION _DriveMngBase::ResetAxisInit
  VAR
  	x       : USINT;
  END_VAR

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

END_FUNCTION


FUNCTION GLOBAL _DriveMngBase::CommunicationState
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  
  retcode := cOnline;
  
END_FUNCTION

FUNCTION _DriveMngBase::L2CmdFinished
	VAR_INPUT
		pPara 	: ^CmdStruct;
		pResult 	: ^results;
	END_VAR
	VAR_OUTPUT
		ret_code 	: iprStates;
	END_VAR
  
  ret_code := READY;
  
  L2Buffer[L2WrIndex].AxisNo := to_usint(pPara^.aPara[3]);
  L2Buffer[L2WrIndex].ParRW := to_usint(pPara^.aPara[1]);
  L2Buffer[L2WrIndex].ParNo := to_usint(pPara^.aPara[0]);
  L2Buffer[L2WrIndex].ParValue := pPara^.aPara[2];
  L2Buffer[L2WrIndex].bActive := TRUE;

  if pPara^.uiCmd = SDD_ASYNC_READY then
    L2Buffer[L2WrIndex].ParState := 0;
  else
    L2Buffer[L2WrIndex].ParState := 1;
    L2Buffer[L2WrIndex].ParError := to_sint(pPara^.aPara[4]);
  end_if;
  
  L2WrIndex += 1;
  L2NewEntry += 1;
  if L2WrIndex > (L2MAXINDEX - 1) then
    L2WrIndex := 0;
  end_if;
    

END_FUNCTION


FUNCTION VIRTUAL GLOBAL _DriveMngBase::CmdState::NewInst
	VAR_INPUT
		pPara 	: ^CmdStruct;
		pResult 	: ^results;
	END_VAR
	VAR_OUTPUT
		ret_code 	: iprStates;
	END_VAR
  VAR
    AxisNo          : USINT;
    ParRW           : USINT;
    ParNo           : USINT;
    retcode         : DINT;
    AxIndex         : USINT;
    RetcodeSizeLeft : UDINT;
    pActRetEntry    : ^_ParaRefreshBufEntry;
    i               : USINT;
    pThisRes        : ^UDINT;
    FoundAxis       : USINT;
    
    // Variables for CMD_GET_HARDWARE_DIAGNOSIS and CMD_GET_HARDWARE_TREE_ENTRY
    pStr_HWTRequested         : ^CHAR;
    us_HWTRequestedCurrIndex  : USINT;
    us_RequestedPlace         : USINT;
    us_RequestedAxis          : USINT;
    us_NextAxis               : USINT;
    us_NextPlace              : USINT;
    ud_StrSize                : UDINT;
    ud_TempSerNo              : UDINT;
    
    MyPara   : CmdStruct;
    MyResult : results;  
  END_VAR

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

  ret_code := READY;

  CASE pPara^.uiCmd OF
  SDD_ASYNC_READY :
  
    // check the parameter number 
    case (pPara^.aPara[0]) of
    
    SDD_I_HW :
      
      HWVersion := pPara^.aPara[2];
      DriveType := GetDriveType(pPara^.aPara[2]);
      bdWait4HwInfoResponse.I_HW := FALSE;

    SDD_I_TYPE :
      
      Parameter_I_Type := pPara^.aPara[2];
      bdWait4HwInfoResponse.I_Type := FALSE;
    
    SDD_I_SER :
      
      SerialNo := pPara^.aPara[2]; 
      bdWait4HwInfoResponse.I_SER := FALSE;
    
    SDD_I_FW :
    
      FwVersionInt :=  pPara^.aPara[2];
      bdWait4HwInfoResponse.I_FW := FALSE;
      SetFWVersion();
      
    SDD_I_BUILD :
    
      FWDateInt :=  pPara^.aPara[2]$UDINT;
      bdWait4HwInfoResponse.I_BUILD := FALSE;
      SetFwDate();
    
    else
      
      // Parameter for log file are dependent on the drive, usParaLogIdx is set in GetLogFileCyclic
      if pPara^.aPara[0] = s_LogFileV.usParaLogIdx then
        s_LogFileV.dParaLogValRd     := pPara^.aPara[2];
        s_LogFileV.bWait4LogFilePara := FALSE;
      end_if;
    
    end_case;
    
  SDD_ASYNC_ERROR :
    case pPara^.aPara[0] of
    
    SDD_I_HW :
      
      HWVersion := 16#7FFFFFFF;
      DriveType := _NotFound;
      bdWait4HwInfoResponse.I_HW := FALSE;   
      
    SDD_I_TYPE :
      
      Parameter_I_Type := 16#7FFFFFFF; 
      bdWait4HwInfoResponse.I_Type := FALSE;
    
    SDD_I_SER :
      
      SerialNo := 16#7FFFFFFF; 
      bdWait4HwInfoResponse.I_SER := FALSE;

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

    SDD_I_BUILD :
    
      FWDateInt :=  16#7FFFFFFF;
      bdWait4HwInfoResponse.I_BUILD := FALSE;

    else
      
      // Parameter for log file are dependent on the drive, usParaLogIdx is set in GetLogFileCyclic
      if pPara^.aPara[0] = s_LogFileV.usParaLogIdx then
        s_LogFileV.dParaLogValRd     := 16#7FFFFFFF;
        s_LogFileV.bWait4LogFilePara := FALSE;
      end_if;
      
    end_case;
  
  SDD_GETVERSION :
    ret_code := READY;
    pResult^.uiLng := sizeof(UINT);
    pResult^.aData[0] := SDD_L2VERSION;
    pResult^.aData[1] := 0;
  
  SDD_ONLINEOK :
    
    ret_code := READY;
    pResult^.uiLng := sizeof(USINT);
    pResult^.aData[0] := to_usint(Online.read());
    
    // if the ringbuffer is allocated
    if ChangesRingBuffer.pStart then
      // we reset the ringbuffer which contains the changes
      ChangesRingBuffer.ActEntries := 0;
      ChangesRingBuffer.pWrite := ChangesRingBuffer.pRead := ChangesRingBuffer.pStart;
      _memset(ChangesRingBuffer.pStart, 16#00, SDDBUFFERENTRY*sizeof(_ParaRefreshBufEntry));
    end_if;
  
  SDD_RWPARLASAL2 :
    
    if Online.read() = 1 then
      ret_code := BUSY;
      
      // get Axisnumber
      AxisNo := to_usint(pPara^.aPara[0] AND 16#FF);
      
      // on SDD210 or SDD215 we fake the axis number of the 2nd axis for external use, so we have to correct it here
      if b_IsSDD21x & (AxisNo = 2) then // RamAnd 22.09.2010 16:12
        AxisNo := 3;
      end_if;
      
      AxIndex := GetAxIndex(AxisNo-1);
      
      if AxIndex = 16#FF then
        ret_code := ERROR;
        return;
      end_if;
      
      // read or write
      ParRw   := to_usint((pPara^.aPara[0] AND 16#FF00) SHR 8);
      // parameter number 
      ParNo   := to_usint((pPara^.aPara[0] AND 16#FF0000) SHR 16);

      case ParRw of
      0 : // Read the parameter
        //if right I-HC code and scope buffer request then read 12 byte drive scope data over ID 0x2080 and SubID 0x09 is allowed 
        if ((HWVersion and DRIVEMNG_DRIVESCOPE_SCOPE_BIT) = DRIVEMNG_DRIVESCOPE_SCOPE_BIT) 
        & bLasalErrorBufferRequest = FALSE then
          
          case ParNo of
            251:
              AddASyncEntryDS402(AxisNo:=AxIndex, uiParaID:=DRIVEMNG_DRIVESCOPE_GETALL_PARAM, usParaSubID:=9, usRdWr:=0, pValue:=Nil, bsDataInfo:=2, pThisObj:= this, usEntry:=3);
              ret_code := Busy;
              
            252:
              //use always zero for SDD1X00 scope data
              pPara^.aPara[0] := (pPara^.aPara[0] AND (16#FFFFFF00)$DINT);
              ret_code := CmdState.GetState(pPara:=pPara, pResult:=pResult);
            
            253:
              //use always zero for SDD1X00 scope data
              pPara^.aPara[0] := (pPara^.aPara[0] AND (16#FFFFFF00)$DINT);
              ret_code := CmdState.GetState(pPara:=pPara, pResult:=pResult);
            
          else
            retcode := AddASyncEntry(AxisNo:= AxIndex, usParaNr:= ParNo , usRdWr:= ParRw, dValue:=0, pThisObj:= this, usEntry:=3);
          end_case;          
        else
          retcode := AddASyncEntry(AxisNo:= AxIndex, usParaNr:= ParNo , usRdWr:= ParRw, dValue:=0, pThisObj:= this, usEntry:=3);
        end_if;
        
      1 : // Write the parameter    
        //if right I-HC code then read 12 byte drive scope data over ID 0x2080 and SubID 0x09 is allowed   
        if ((HWVersion and DRIVEMNG_DRIVESCOPE_SCOPE_BIT) = DRIVEMNG_DRIVESCOPE_SCOPE_BIT) then         
          if ParNo = 249 then
            //remember which request come from Lasal2 (Drive Scope or Errorbuffer)
            if pPara^.aPara[1] > DRIVEMNG_DRIVESCOPE_SINDEX_RANGE then
              bLasalErrorBufferRequest := TRUE;
            else
              bLasalErrorBufferRequest := FALSE;
            end_if;   
          end_if;
        end_if;  
      
        retcode := AddASyncEntry(AxisNo:= AxIndex, usParaNr:= ParNo , usRdWr:= ParRw, dValue:=pPara^.aPara[1], pThisObj:= this, usEntry:=3);
      else
        ret_code := ERROR;
      end_case;
      
      if retcode < 0 then
        // internal failure
        Ret_code := ERROR;
      end_if;
    else
      ret_code := ERROR;
    end_if;
  
  SDD_GETAXISINUSE :
    ret_code := READY;
    pResult^.uiLng := sizeof(BDINT);
    pResult^.aData[0]$BDINT :=  AxIndizesL2;
  
  SDD_GETSERIE :
    retcode := READY;
    pResult^.uiLng := sizeof(USINT);
    if bVaranConnected then
      pResult^.aData[0] := toVaran.GetSeries();
    else   
      //sdias drive connected
      MyPara.uiCmd  := BUSIF_DRIVEMNGBASE_SDD_GETSERIES;
      ToBusIF.NewInst(#MyPara, #MyResult);    
      pResult^.aData[0] := MyResult.aData[0];
    end_if;

  // new commands in lasal communication version 4 (SDD_GET_CHANGE_CNT, SDD_GET_PARAMS)
  SDD_GET_CHANGE_CNT :
    retcode := READY;
    pResult^.uiLng := sizeof(UDINT);
    pResult^.aData[0]$^DINT := #ChangesRingBuffer.ActEntries;
  
  SDD_GET_PARAMS :
    retcode := READY;
    if ChangesRingBuffer.ActEntries then

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

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

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

        // increase pointer in retcode
        pActRetEntry += sizeof(_ParaRefreshBufEntry);

        // increase read pointer in ring buffer
        ChangesRingBuffer.pRead += sizeof(_ParaRefreshBufEntry);
        if ChangesRingBuffer.pRead >= ChangesRingBuffer.pEnd then
          ChangesRingBuffer.pRead := ChangesRingBuffer.pStart;
        end_if;
        
        // decrease available changes
        ChangesRingBuffer.ActEntries -= 1;
      end_while;
      
      // save number of entries in the first 2 byte of the array
      pResult^.aData[0]$UINT := pResult^.uiLng / sizeof(_ParaRefreshBufEntry);
      
      LastRetcode := pResult^;
    else
      // no changes to fetch
      pResult^.uiLng := 0;
    end_if;

  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  SDD_GET_AXIS_PTR_LIST:
  
    ret_code := READY;
    
    //                    NoAxis    +  Thisptr per axis
    pResult^.uiLng := (sizeof(DINT) + AxCount * sizeof(UDINT))$UINT;
    
    // get no of axis
    pResult^.aData[0]$DINT := AxCount;
    
    // get this pointer of axis to resultbuffer (with increasing AxNumber)
    pThisRes := #pResult^.aData[4]$UDINT;
    FoundAxis := 0;
    for i := 0 to SDDMAXENTRIES-1 do
      AxIndex := GetAxIndexByAxisBit(1 SHL i);
      if AxIndex <> 16#FF then
        FoundAxis += 1;
        pThisRes^ := AxBuffer[AxIndex].pThis$UDINT;
        pThisRes += sizeof(UDINT);
      end_if;
      if FoundAxis = AxCount then
        // all avaliable found, exit loop
        exit;
      end_if;
    end_for;
    // fill space with NIL if a axis is not found
    while FoundAxis < AxCount do
      pThisRes^ := NIL;
      pThisRes += sizeof(UDINT);
      FoundAxis += 1;
    end_while;

  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  CMD_GET_HARDWARE_DIAGNOSIS : 

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

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

                ud_StrSize := FwNumStr.GetLength() ;
                pResult^.aData[0]$t_HWCGetHardwareDiagnosisOut.pStr_FWVersion     := NIL;
                
                if ud_StrSize then

                  if (ud_StrSize < sizeof(a_FWVersion)) then // < to account for 0 termination
                    // Copy complete string
                    FwNumStr.GetDataAt(pData:=#a_FWVersion[0], udSize:=ud_StrSize, udAt:=0);
                    a_FWVersion[ud_StrSize] := 0; // 0 termination
                  else
                    // Copy part string
                    FwNumStr.GetDataAt(pData:=#a_FWVersion[0], udSize:=sizeof(a_FWVersion)-1, udAt:=0);
                    a_FWVersion[sizeof(a_FWVersion)-1] := 0; // 0 termination
                  end_if;

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

    end_if;
    
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  CMD_GET_HARDWARE_TREE_ENTRY:

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

            us_NextAxis := to_usint(AxBuffer[i].AxisNo);
          end_if;
          
        end_for;
        
        if (us_NextAxis < 16#FF) then
          // Copy string and add axis no 
          // Copy passed string 
          _memcpy(ptr1 := #a_HWTEntryStr[0]
                , ptr2 := pStr_HWTRequested
                , cntr := pStr_HWTRequested^$UINT+2); // +2 for 2 byte length
                
          // Add Escape Sequence axis
          a_HWTEntryStr[0]$UINT += 1;   
          a_HWTEntryStr[a_HWTEntryStr[0]$UINT+1] := HWT_ESCAPE_AXIS;
          
          // Add axis no
          a_HWTEntryStr[0]$UINT += 1;   
          a_HWTEntryStr[a_HWTEntryStr[0]$UINT+1] := us_NextAxis - 1; // -1 AxisNo in HWT String run from 0 to 2
          
          // Set return pointer
          pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.pStr_NextHardewareTreeEntry := #a_HWTEntryStr[0];
          
          ret_code := READY;
          pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_OK_HWTSTR_RETURNED;
          
          return;
        else
          
          // Find min next place
          us_NextPlace := 16#FF;
          
          // No Axis found at this place, return next place
          for i := 0 to SDDMAXENTRIES - 1 do
            
            if (AxBuffer[i].Place > us_RequestedPlace) &  // Next Place must be the minmum place that is greater then the passed palce
               (AxBuffer[i].Place < us_NextPlace) then
              
              us_NextPlace := to_usint(AxBuffer[i].Place);
            end_if;

          end_for;
          
          if (us_NextPlace < 16#FF) then
            // Copy string and replace place
            // Copy passed string 
            _memcpy(ptr1 := #a_HWTEntryStr[0]
                  , ptr2 := pStr_HWTRequested
                  , cntr := pStr_HWTRequested^$UINT+2); // +2 for 2 byte length   
                  
            // replace place
            a_HWTEntryStr[a_HWTEntryStr[0]$UINT+1] := us_NextPlace;
            
            // Set return pointer
            pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.pStr_NextHardewareTreeEntry := #a_HWTEntryStr[0];
            
            ret_code := READY;
            pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_OK_HWTSTR_RETURNED;
            return;
            
          else
          
            ret_code := READY;
            pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_OK_END_OF_LIST;
            return;
          end_if;

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

 
  //*******************************************************************************************************************
  SDD_GET_DEVICESERIALNO:
    ret_code := READY;
    //Get Serial No. of Head of MDD100
    //Here: Get Serial No of all devices (also of VAC)
    if bVaranConnected then
      pResult^.uiLng := 1 + (toVaran.SerialNoStr.GetLength())$UINT;
      toVaran.SerialNoStr.GetDataAt(#pResult^.aData[0], pResult^.uiLng, 0);
    end_if;

  //*******************************************************************************************************************
  SDD_GET_MNG_TRANSPARENT:
    ret_code := READY;
   //Get transparent information from VaranCommunication object. used to not show transparent objects in DiasDriveOnline Window
    pResult^.uiLng := sizeof(DINT);
    if bVaranConnected then
      pResult^.aData[0]$DINT := toVaran.Transparent.Read();
    else
      pResult^.aData[0]$DINT := 0$DINT;
    end_if;
    
  //*******************************************************************************************************************
  SDD_GETFILE: //command will be called from application

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

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

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

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

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

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

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

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


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

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

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

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

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

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

  end_case;

END_FUNCTION


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

  ret_code := READY;
  
  case pPara^.uiCmd of
  
  SDD_RWPARLASAL2 :
    
    ret_code := BUSY;
    
    // get Axisnumber
    AxisNo := to_usint(pPara^.aPara[0] AND 16#FF) - 1;

    // on SDD210 or SDD215 we fake the axis number of the 2nd axis for external use, so we have to correct it here
    if b_IsSDD21x & (AxisNo = 1) then // RamAnd 22.09.2010 16:12
      AxisNo := 2;
    end_if;

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

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


END_FUNCTION


FUNCTION GLOBAL _DriveMngBase::GetAxisWrPtr
	VAR_INPUT
		usAxis 	: USINT;
	END_VAR
	VAR_OUTPUT
		ptr 	: ^_VaranDriveBase::t_WriteValuePtr;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;   
  END_VAR  
  
  if usAxis >= 0 & usAxis < SDDMAXENTRIES then //HasHan
    if bVaranConnected then
      ptr := toVaran.GetAxisWrPtr(AxisNr:=AxBuffer[usAxis].AxisIndex);
    else      
      MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_AXIS_WR_PTR;
      MyPara.aPara[0] := to_dint(AxBuffer[usAxis].AxisIndex);
      ToBusIF.NewInst(#MyPara, #MyResult);
      ptr := MyResult.aData[0]$^_VaranDriveBase::t_WriteValuePtr;
    end_if;
  end_if;
  
  
END_FUNCTION


FUNCTION GLOBAL _DriveMngBase::GetAxisRdPtr
	VAR_INPUT
		usAxis 	: USINT;
	END_VAR
	VAR_OUTPUT
		ptr 	: ^_VaranDriveBase::t_ReadValuePtr;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;   
  END_VAR  
  
  if usAxis >= 0 & usAxis < SDDMAXENTRIES then //HasHan
    if bVaranConnected then
      ptr := toVaran.GetAxisRdPtr(AxisNr:=AxBuffer[usAxis].AxisIndex);
    else      
      MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_AXIS_RD_PTR;
      MyPara.aPara[0] := to_dint(AxBuffer[usAxis].AxisIndex);
      ToBusIF.NewInst(#MyPara, #MyResult);
      ptr := MyResult.aData[0]$^_VaranDriveBase::t_ReadValuePtr;
    end_if;
  end_if;
  
  
END_FUNCTION


FUNCTION GLOBAL _DriveMngBase::InitDrive
	VAR_INPUT
		Mode 	: USINT;
	END_VAR
  VAR
    UserPara     : CmdStruct;
    UserResult   : Results;
    x            : USINT;
    pThisNewInst : ^void;
  END_VAR
  
  if bVaranConnected then
    toVaran.InitDrive();
  else
    UserPara.uiCmd := BUSIF_DRIVEMNGBASE_INIT_DRIVE;
    ToBusIF.NewInst(#UserPara, #UserResult);
  end_if;

  
  
  for x := 0 to (SDDMAXENTRIES - 1) do
    if (AxBuffer[x].pThis <> NIL) then
      if (AxBuffer[x].AxisOk = 1) then
        if Mode = 0 then
          UserPara.uiCmd := SDD_INITAXLE;
        else
          UserPara.uiCmd := SDD_URINITAXLE;
        end_if;

        pThisNewInst := AxBuffer[x].pThis;
        pThisNewInst$^VirtualBase^.NewInst(#UserPara, #UserResult);
      end_if;
    end_if;
  end_for;
  
END_FUNCTION


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

END_FUNCTION

FUNCTION _DriveMngBase::GetAxIndexByAxisBit
	VAR_INPUT
		AxisBit 	: BDINT;
	END_VAR
	VAR_OUTPUT
		AxIndex 	: USINT;
	END_VAR
  VAR
  	x     : USINT;
  END_VAR
  
  AxIndex := 16#FF;
  
  for x := 0 to (SDDMAXENTRIES - 1) do
    if (AxBuffer[x].pThis <> NIL) then
      if (AxBuffer[x].AxisBit = AxisBit) then
        AxIndex := x;
        exit;
      end_if;
    else
      exit;
    end_if;
  end_for;

END_FUNCTION


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

END_FUNCTION


FUNCTION _DriveMngBase::SetFwVersion
VAR
  szValue     : ARRAY[0..19] of CHAR;
  StrLen      : UDINT;
END_VAR

  Bin2Ascii(pt:=#szValue[0], value:=FwVersionInt, format:=16#820);
  StrLen := _strlen(#szValue[0]);
  FwNumStr.WriteDataOff(udLen:= Strlen, udOff:=0, pData:= #szValue[0]);
  
END_FUNCTION


FUNCTION _DriveMngBase::SetFwDate
VAR
	szValue     : ARRAY[0..19] of CHAR;
  szFwDate    : ARRAY[0..99] of CHAR;
  StrLen      : UDINT;
  Value       : UDINT;
  tmpYear     : UDINT;
END_VAR

  // Ermitteln des Tages
  Value := FWDateInt AND 16#003F0000;
  Value := Value SHR 16;
  Bin2Ascii(pt:=#szValue[0], value:=Value$DINT, format:=16#102);
  _strcpy(#szFwDate[0], #szValue[0]);
  _strcat(#szFwDate[0], ".");
  
  // ermitteln des Monats
  Value := FWDateInt AND 16#0F000000;
  Value := Value SHR 24;
  Bin2Ascii(pt:=#szValue[0], value:=Value$DINT, format:=16#102);
  _strcat(#szFwDate[0], #szValue[0]);
  _strcat(#szFwDate[0], ".");

  // ermitteln des Jahres
  Value := FWDateInt AND 16#F0000000;  
  Value := Value SHR 28;
  
  //Newer firmwares >= 2016 are using 2 Bits more, which where originally reserved for day, to have more bits to display year dates.
  //With this change we can display year dates until 2063 instead of 2015, 
  tmpYear := FWDateInt AND 16#00C00000;
  tmpYear := tmpYear SHR 18; //Shift Right 18 instead of 22 because these two bits are bit 4 and 5 for the year
  Value := Value OR tmpYear;
    
  Value += 2000;
  Bin2Ascii(pt:=#szValue[0], value:=Value$DINT, format:=16#800);
  _strcat(#szFwDate[0], #szValue[0]);
  _strcat(#szFwDate[0], " ");
  
  // ermitteln der Stunde
  Value := FWDateInt AND 16#0000FF00;
  Value := Value SHR 8;
  Bin2Ascii(pt:=#szValue[0], value:=Value$DINT, format:=16#102);
  _strcat(#szFwDate[0], #szValue[0]);
  _strcat(#szFwDate[0], ":");
  
  // ermitteln der Minuten
  Value := FWDateInt AND 16#000000FF;
  Bin2Ascii(pt:=#szValue[0], value:=Value$DINT, format:=16#102);
  _strcat(#szFwDate[0], #szValue[0]);
    
  StrLen := _strlen(#szFwDate[0]);
  FwDatetr.WriteDataOff(udLen:= Strlen, udOff:=0, pData:= #szFwDate[0]);

END_FUNCTION

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

*)


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

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

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

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

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


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

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

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

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

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

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

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

END_FUNCTION



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

  if bVaranConnected then 
    RetryCounter := toVaran.RetryCounter.Read();
  else  
    MyPara.uiCmd  := BUSIF_DRIVEMNGBASE_READ_RETRY_COUNTER;
    ToBusIF.NewInst(#MyPara, #MyResult);    
    RetryCounter := MyResult.aData[0]$UDINT; 
  end_if;

  output := RetryCounter;	

END_FUNCTION


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


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


FUNCTION GLOBAL _DriveMngBase::GetDriveType
	VAR_INPUT
		HWCode 	: DINT;
	END_VAR
	VAR_OUTPUT
		DriveType 	: _DRIVETYPE;
	END_VAR
  VAR
  	buffer   : DINT;
    MyPara   : CmdStruct;
    MyResult : results;
    dRetCode : iprStates;
  END_VAR
  
  //LanSte 27.07.2021 When adding new drivetypes GetDriveTypeStr must also be updated!
  
  if bVaranConnected then
    buffer := HWCode SHR 16;
    case buffer of
    // 3 Achsen
      0: DriveType:=_SDD_310;
      1: DriveType:=_SDD_315;
      2: DriveType:=_S_340;  
      3: DriveType:=_SDD_310;
      4: DriveType:=_S_340;  
      6: DriveType:=_SDD_315;
     12: DriveType:=_SDD_335;
     16: DriveType:=_SDD_305;
     20: DriveType:=_SDD_305;
     26: DriveType:=_SDD_310;
     
     // 2 Achsen
      5: DriveType:=_SDD_215;
      9: DriveType:=_SDD_210;
     22: DriveType:=_SDD_205;
     
     // 1 Achse
      7: DriveType:=_SDD_120;
     21: DriveType:=_SDD_105;
     10: DriveType:=_SDD_115;
    
    else
      if DeviceID = DIASDRIVE_MINI_DEVICE_ID then
        DriveType := _MDD_100;
      else
        DriveType:=_NotFound;
      end_if;
    end_case;
    
  else
    //if businterface is connected
    MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_BUSTYPE;
    //first parameter is the length of followed data
    MyPara.aPara[0] := 0;
    
    dRetCode := ToBusIF.NewInst(#MyPara, #MyResult);
    
    if dRetCode = Ready 
    & MyResult.uiLng = 1 then
      if MyResult.aData[0] = HWT_ESCAPE_SDIAS then
        case DeviceID of
          DRIVEMNG_BUSDEVICEID_DC061:
            DriveType := _DC061;
          
          DRIVEMNG_BUSDEVICEID_DC062:
            DriveType := _DC062;
            
          DRIVEMNG_BUSDEVICEID_SR011:
            DriveType := _SR011;
            
          DRIVEMNG_BUSDEVICEID_SR012:
            DriveType := _SR012;
          
          DRIVEMNG_BUSDEVICEID_DC101:
            DriveType := _DC101;
            
          DRIVEMNG_BUSDEVICEID_DC102:
            DriveType := _DC102;
            
          DRIVEMNG_BUSDEVICEID_SR011_1:
            DriveType := _SR011_1;
            
        else
          DriveType:=_NotFound;
        end_case;
      
      elsif MyResult.aData[0] = HWT_ESCAPE_VARAN then
        case DeviceID of
          DRIVEMNG_BUSDEVICEID_SDD1300:
            DriveType := _SDD_1300;
            
          DRIVEMNG_BUSDEVICEID_SDD1400:
            DriveType := _SDD_1400;
            
          DRIVEMNG_BUSDEVICEID_SDD1500:
            DriveType := _SDD_1500;
            
          DRIVEMNG_BUSDEVICEID_SDD1600:
            DriveType := _SDD_1600;
            
          DRIVEMNG_BUSDEVICEID_VSDC151:
          
            //Check I-Type to display correct Drive type (both VSDC151 and VSDC152 have the same Varan device ID but different I-TYPE parameter values)
            if Parameter_I_Type = DRIVEMNG_I_TYPE_VSDC151 then
              DriveType := _VSDC_151;
            elsif Parameter_I_Type = DRIVEMNG_I_TYPE_VSDC152 then
              DriveType := _VSDC_152;
            else
              DriveType:=_NotFound;
            end_if;
            
          DRIVEMNG_BUSDEVICEID_MDD2000:
            DriveType := _MDD_2000;
            
        else
          DriveType:=_NotFound;
          
        end_case;
        
      elsif MyResult.aData[0] = HWT_ESCAPE_VARAN_S2 then
        case DeviceID of 
        
          DRIVEMNG_BUSDEVICEID_WA011:
            DriveType := _WA011;
            
          DRIVEMNG_BUSDEVICEID_WA012:
            DriveType := _WA012;
        
        else
          DriveType:=_NotFound;
          
        end_case;
        
      else
        DriveType:=_NotFound;
      end_if;
      
    else
      DriveType:=_NotFound;
    end_if;  
  end_if;
  
END_FUNCTION


FUNCTION GLOBAL _DriveMngBase::GetVaranDriveState
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  VAR  	
    MyPara   : CmdStruct;
    MyResult : results;
  END_VAR
    
  if bVaranConnected then  
    retcode := toVaran.GetDriveIntState();
  else      
    MyPara.uiCmd := BUSIF_DRIVEMNGBASE_GET_DRIVE_INT_STATE;
    ToBusIF.NewInst(#MyPara, #MyResult);
    retcode := MyResult.aData[0]$DINT;
  end_if;
  
END_FUNCTION


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

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

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

END_FUNCTION


FUNCTION _DriveMngBase::_DriveMngBase
	VAR_OUTPUT
		ret_code 	: ConfStates;
	END_VAR

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

END_FUNCTION


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

END_FUNCTION


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

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


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

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

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

END_FUNCTION


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

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


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

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

FUNCTION VIRTUAL GLOBAL _DriveMngBase::GetDriveTypeStr
	VAR_INPUT
		eDriveType 	: _DRIVETYPE;
		pDriveTypeStr 	: ^CHAR;
    DriveTypeStrSize : UDINT;
	END_VAR
  VAR
  	tmpstr : array [0..20] of char;
  END_VAR
  
  if pDriveTypeStr then
  
    case eDriveType of
      _DRIVETYPE::_NotFound:
        _strcpy(dest:=#tmpstr[0], src:="DiasDrive");
      _DRIVETYPE::_SDD_310:
        _strcpy(dest:=#tmpstr[0], src:="SDD310");
      _DRIVETYPE::_SDD_315:
        _strcpy(dest:=#tmpstr[0], src:="SDD315");
      _DRIVETYPE::_SDD_105:
        _strcpy(dest:=#tmpstr[0], src:="SDD105");
      _DRIVETYPE::_SDD_120:
        _strcpy(dest:=#tmpstr[0], src:="SDD120");
      _DRIVETYPE::_SDD_305:
        _strcpy(dest:=#tmpstr[0], src:="SDD305");
      _DRIVETYPE::_SDD_335:
        _strcpy(dest:=#tmpstr[0], src:="SDD335");
      _DRIVETYPE::_SDD_215:
        _strcpy(dest:=#tmpstr[0], src:="SDD215");
      _DRIVETYPE::_SDD_205:
        _strcpy(dest:=#tmpstr[0], src:="SDD205");
      _DRIVETYPE::_SDD_210:
        _strcpy(dest:=#tmpstr[0], src:="SDD210");
      _DRIVETYPE::_MDD_100:
        _strcpy(dest:=#tmpstr[0], src:="MDD100");
      _DRIVETYPE::_S_340: // ?
        _strcpy(dest:=#tmpstr[0], src:="DiasDrive"); 
      _DRIVETYPE::_SDD_115:
        _strcpy(dest:=#tmpstr[0], src:="SDD115");
      _DRIVETYPE::_SDD_1300:
        _strcpy(dest:=#tmpstr[0], src:="SDD1300");
      _DRIVETYPE::_SDD_1400:
        _strcpy(dest:=#tmpstr[0], src:="SDD1400");
      _DRIVETYPE::_SDD_1500:
        _strcpy(dest:=#tmpstr[0], src:="SDD1500");
      _DRIVETYPE::_SDD_1600:
        _strcpy(dest:=#tmpstr[0], src:="SDD1600");
      _DRIVETYPE::_MDD_2000:
        _strcpy(dest:=#tmpstr[0], src:="MDD2000");
  	  _DRIVETYPE::_VSDC_151:
        _strcpy(dest:=#tmpstr[0], src:="VSDC151");
  	  _DRIVETYPE::_VSDC_152:
        _strcpy(dest:=#tmpstr[0], src:="VSDC152");
      _DRIVETYPE::_DC061:
        _strcpy(dest:=#tmpstr[0], src:="DC061");
      _DRIVETYPE::_DC062:
        _strcpy(dest:=#tmpstr[0], src:="DC062");
      _DRIVETYPE::_SR011:
        _strcpy(dest:=#tmpstr[0], src:="SR011");
      _DRIVETYPE::_SR012:
        _strcpy(dest:=#tmpstr[0], src:="SR012");
      _DRIVETYPE::_DC101:
        _strcpy(dest:=#tmpstr[0], src:="DC101");
      _DRIVETYPE::_DC102:
        _strcpy(dest:=#tmpstr[0], src:="DC102");
      _DRIVETYPE::_WA011:
        _strcpy(dest:=#tmpstr[0], src:="WA011");
      _DRIVETYPE::_WA012:
        _strcpy(dest:=#tmpstr[0], src:="WA012");
      else
        _strcpy(dest:=#tmpstr[0], src:="DiasDrive");
    end_case;
    
    if (_strlen(src:=#tmpstr[0]) + 1) <= DriveTypeStrSize then  // +1 for 0 termination
      _strcpy(dest:=pDriveTypeStr, src:=#tmpstr[0] );
    end_if;
    
  end_if;
  
END_FUNCTION  


FUNCTION VIRTUAL _DriveMngBase::GetSystemTime

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

END_FUNCTION


FUNCTION VIRTUAL _DriveMngBase::SetSystemTimeAtDrive
	VAR_INPUT
		AxisNo 	: USINT;
	END_VAR

  //Method is called only in derivations when it is needed to set the sysdate/time to the drive firmware (e.g MDD2000 or VSDC151)  

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

END_FUNCTION


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

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

END_FUNCTION


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

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

  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL _DriveMngBase::GetFileState
	VAR_INPUT
		pdError 	: ^DINT;(* := nil *)
		pdProgress 	: ^DINT;(* := nil *)
		pudBytesRead 	: ^UDINT;(* := nil *)
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR
  VAR
    MyPara   : CmdStruct;
    MyResult : results;
  END_VAR  

  if bVaranConnected then
    retcode := ERROR; //Not supported with _VaranDriveBase class
    if pdError then
      pdError^:= DRIVEMNG_FILE_HANDLING_RETCODE_NOT_SUPPORTED;
    end_if;
  else
  
    if Online.read() = 0 then
      retcode := ERROR; //Drive is not online
      if pdError then
        pdError^ := DRIVEMNG_FILE_HANDLING_RETCODE_NOT_ONLINE;
      end_if;
      return;
    end_if;
    
    // Check if filehandling is active only in busif 
    if (sigclib_atomic_getU32(pValue:=#ud_FileHandlingReserved) = DRIVEMNG_FILE_RESERVE_IDDEFAULT) then
    
      // Pass on command to Busif
      MyPara.uiCmd    := BUSIF_DRIVEMNGBASE_GET_FILE_STATE;
      MyPara.aPara[0] := BUSIF_DRIVEMNGBASE_GET_FILE_STATE_CB_VER1$DINT;  //Version
      MyPara.aPara[1] := pdError$DINT;  
      MyPara.aPara[2] := pdProgress$DINT;
      MyPara.aPara[3] := pudBytesRead$DINT;
      
      retcode := ToBusIF.NewInst(#MyPara, #MyResult);
      
      if (retcode = READY) | (retcode = ERROR) then
        // File handling has completed => unlock
        ReleaseFileHandling();
      end_if;

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

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

END_FUNCTION

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

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

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

END_FUNCTION


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

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

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

END_FUNCTION


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

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

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

END_FUNCTION

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

//*****************************************************************************    
    t_e_GetLogFileSSW::IdleGetLogFile: 
      // Do Nothing
      
//*****************************************************************************
    t_e_GetLogFileSSW::StartGetLogFileSSW,
    t_e_GetLogFileSSW::WriteLOGFileParam:
    
      s_LogFileV.ErrorCodeLogFile := DRIVEMNG_FILE_HANDLING_RETCODE_NOERROR;  // Fehlercode zurücksetzen
      
      //Only allow to get logfile if no axis is enabled
      if IsAnyAxisEnabled() = FALSE then
      
        // get the standard information of the drive
        usAxisNo := GetFirstAxIndex();
                
        if usAxisNo <> 16#FF then
          //We have to tell the firmware that the logfile should be written
          
          //Writing to K-LOG leads to that the firmware is going to write their logbuffer into the logfile on the drive 
          //This will block the other asynchronous communication and can take some seconds
          //Give this access a high timeout so we won't get an error with the default timeout
          
          // Get usParaLogIdx and dParaLogVal from derived class
          GetLogFileWrParam(pParaIDX:=#s_LogFileV.usParaLogIdx, pParaVal:=#s_LogFileV.dParaLogVal, pParaTimeout:=#s_LogFileV.udParaLogTimeout,s_LogFileV.udFileSelectId);
          
          if s_LogFileV.usParaLogIdx then
            if AddASyncEntry(AxisNo    :=  usAxisNo
                           , usParaNr  :=  s_LogFileV.usParaLogIdx
                           , usRdWr    :=  1
                           , dValue    :=  s_LogFileV.dParaLogVal  //Start to write logfile
                           , pThisObj  :=  this
                           , usEntry   :=  0
                           , udTimeout :=  s_LogFileV.udParaLogTimeout) = 0 then
                   
              s_LogFileV.bWait4LogFilePara := TRUE;
              s_LogFileV.udTimeStampLogPara := ops.tAbsolute;
              s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::Wait4WrLOGFileResponse;
            end_if;
          else
            // usParaLogIdx not used to write parameter, skip step.
            s_LogFileV.eGetLogFileSSW := t_e_GetLogFileSSW::ReadLOGFileParam;
          end_if;

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

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

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

END_FUNCTION

FUNCTION VIRTUAL _DriveMngBase::GetLogFileWrParam
	VAR_INPUT
		pParaIDX 	: ^USINT;
		pParaVal 	: ^DINT;
		pParaTimeout 	: ^UDINT;
		FileSelect 	: UDINT;
	END_VAR
  
  // Default Implementation, not supported. Override in derived Classes for support
  if pParaIDX then
    pParaIDX^ := 0;
  end_if;
  
  if pParaVal then
    pParaVal^ := 0;
  end_if;
  
  if pParaTimeout then
    pParaTimeout^ := DRIVEMNG_FILE_HANDLING_TIMEOUT_LOG_PARAM;
  end_if;

END_FUNCTION

FUNCTION VIRTUAL _DriveMngBase::GetLogFileRdParam
	VAR_INPUT
		pParaIDX 	: ^USINT;
		pParaVal 	: ^DINT;
		pParaTimeout 	: ^UDINT;
		FileSelect 	: UDINT;
	END_VAR
  
  // Default Implementation, not supported. Override in derived Classes for support
  if pParaIDX then
    pParaIDX^ := 0;
  end_if;
  
  if pParaVal then
    pParaVal^ := 0;
  end_if;
  
  if pParaTimeout then
    pParaTimeout^ := DRIVEMNG_FILE_HANDLING_TIMEOUT_LOG_PARAM;
  end_if;

END_FUNCTION

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

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

END_FUNCTION


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

END_FUNCTION


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

END_FUNCTION

FUNCTION VIRTUAL _DriveMngBase::CheckFileHandlingAvailable
	VAR_INPUT
		pdError 	: ^DINT;(* := nil *)
		ReserveID 	: UDINT;(* := DRIVEMNG_FILE_RESERVE_IDDEFAULT *)
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR
  
  // Default 
  retcode := ERROR;
  
  if bVaranConnected then
     //Not supported with _VaranDriveBase class
    if pdError then
      pdError^:= DRIVEMNG_FILE_HANDLING_RETCODE_NOT_SUPPORTED;
    end_if;
  else   
      
    if Online.read() = 0 then
      //Drive is not online
      if pdError then
        pdError^ := DRIVEMNG_FILE_HANDLING_RETCODE_NOT_ONLINE;
      end_if;
      return;
    end_if;
    
    if ReserveFileHandling(ReserveID) = TRUE then

      retcode := READY;
      
      // Reset ErrorCode
      if pdError then
        pdError^ := DRIVEMNG_FILE_HANDLING_RETCODE_NOERROR;
      end_if;
    
    elsif pdError then
      pdError^ := DRIVEMNG_FILE_HANDLING_RETCODE_FILEHANDLING_BUSY;
    end_if;
    
  end_if;
  
END_FUNCTION

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

END_FUNCTION

FUNCTION VIRTUAL _DriveMngBase::ReleaseFileHandling

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

END_FUNCTION