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

//{{LSL_DEFINES
#define MDD2000VVBASE_OFFSET_TYPELABEL        0x1100

#define MDD2000VVBASE_PARALIST_INDEX_SET      0x2210
#define MDD2000VVBASE_PARALIST_INDEX_INFO     0x2211
#define MDD2000VVBASE_PARALIST_INDEX_SETNR    174

#define MDD2000VVBASE_MAX_SERVICEBOX          8
#define MDD2000VVBASE_SDO_RESPONSE_TIMEOUT    (5000)  
#define MDD2000VVBASE_SDO_RESPONSE_TIMEOUT_FILEHANDLING    (10000)  // don't reduce this timeout, the firmware of the WA013 uses this time to erase the flash (it only emulates a file system)
#define MDD2000VVBASE_SDO_TYPELABEL_TIMEOUT   (10000*2)  //20 sec timeout to read typelabel because drive need time for bootup


#define MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_STANDARD_MIN    0x2200
#define MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_STANDARD_MAX    0x23FF
#define MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_STANDARD_OFFSET 0x200
#define MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_SAFETY_MIN      0x4200
#define MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_SAFETY_MAX      0x43FF
#define MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_SAFETY_OFFSET   0x200
#define MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_DS402_MIN       0x6000
#define MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_DS402_MAX       0x67FF
#define MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_DS402_OFFSET    0x800
#define MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_MAX_AXIS        8

#define MDD2000VVBASE_SERVICE_APP_INVALID    0xFF

#define MDD2000VVBASE_FULL_PARADATA_SIZE     12
#define MDD2000VVBASE_CANOPEN_FOOTER_SIZE    4
#define MDD2000VVBASE_LASAL_PARADATA_SIZE    4

#define MDD2000VVBASE_VANDAL_MAILBOX_COMMAND_FILE_READ                      25
#define MDD2000VVBASE_VANDAL_MAILBOX_COMMAND_FILE_WRITE                     26
#define MDD2000VVBASE_VANDAL_MAILBOX_COMMAND_FILE_DELETE                    27
#define MDD2000VVBASE_VANDAL_MAILBOX_COMMAND_FILE_SET_WORKING_DIRECTORY     30
#define MDD2000VVBASE_VANDAL_MAILBOX_COMMAND_FILE_GET_DIRECTORY_LIST        31
#define MDD2000VVBASE_VANDAL_FILEHANDLING_MAX_FILES       255

// *** The actual limits might be smaller depending on the drive ***
// limit to size of command MDD2000VVBASE_VANDAL_MAILBOX_COMMAND_FILE_GET_DIRECTORY_LIST struct t_s_VandalGetDirectoryEntry
// Use 94 instead of 95 because array[0..CONSTANT] is CONSTANT+1 charīs and then there is space for a closing zero.
#define MDD2000VVBASE_VANDAL_FILEHANDLING_MAX_FILENAME    94
// limited by the size of the mailbox data[0..123] + footer
#define MDD2000VVBASE_VANDAL_FILEHANDLING_MAX_DIRECTORYNAME    123


#define MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_NO_ERROR                   0
#define MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_MAILBOX_NOT_AVAILABLE     -1
#define MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_BUSY                      -2
#define MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_INVALID_POINTER           -3
#define MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_FILENAME_DRIVE_TOO_LONG   -4
#define MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_FILEPATH_DRIVE_TOO_LONG   -5
#define MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_FILEDPNE_TOO_LONG         -6
#define MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_VANDAL_COMMUNICATION      -7
#define MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_VANDAL_TIMEOUT            -8
#define MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_DRIVE_FILE_NOT_FOUND      -9
#define MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_OPEN_LOCAL_FILE           -10
#define MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_WRITE_LOCAL_FILE          -11
#define MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_INVALID_LENGTH            -12
#define MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_BUFFER_TOO_SMALL          -13
#define MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_FILE_TOO_SMALL            -14
#define MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_CREATETHREAD_FAILED       -15


#define MDD2000VVBASE_VANDAL_MAILBOX_MSG_CNT_MASK 2#111


#define MDD2000VVBASE_PDO_GENERAL_DATA            4 //4 byte read and write general PDO data
#define MDD2000VVBASE_PDO_AXIS_OFFSET         16#14 //4*5 = 20 Byte
#define MDD2000VVBASE_PDO_AXIS_SIZE              20 //4*5 = 20 Byte
#define MDD2000VVBASE_PDO_AXIS_OFFSET2        16#08 //4*2 = 8 Byte
#define MDD2000VVBASE_PDO_AXIS_SIZE2              8 //4*2 = 8 Byte

#define MDD2000VVBASE_TYPELBL_EXTPDOSUPPORT       2 // Extended PDO are suported with Type Label Major Version 2 or higher
#define MDD2000VVBASE_MAX_AXIS_IDX                6 // 0 .. 6 = 7 entries
// #define MDD2000VVBASE_PDO_AXIS_OFFSET_EXTEND  ((MDD2000VVBASE_MAX_AXIS_IDX + 1) * 4) //4*7 = 28 Byte
#define MDD2000VVBASE_PDO_AXIS_SIZE_EXTEND    ((MDD2000VVBASE_MAX_AXIS_IDX + 1) * 4) //4*7 = 28 Byte


#define MDD2000VVBASE_SDO_MAILBOX_OFFSET    16#10

#define MDD2000VVBASE_ONE_DO_SIZE            128

#define MDD2000VVBASE_MDD2000_MAX            3 //3 axis

#define MDD2000VVBASE_MAX_AXIS              MDD2000VVBASE_MDD2000_MAX
#define MDD2000VVBASE_SDO_TIMOUT            1000
#define MDD2000VVBASE_WRITE_PLCTIME         (1000*60*30)    //cyclic time to write PLC time stamp to drive


// time to wait (in ms) until other tasks in the same or lower priority than post init have done their stuff
#define MDD2000VVBASE_WAIT_TIME_IN_POST_INIT    1
//}}LSL_DEFINES

//{{LSL_DECLARATION
#include "..\..\Source\interfaces\lsl_st_hardwaretree.h"
#include "..\..\Class\HwControl\HwControl.h"
#include "..\..\Source\BusInterface.h"
#include "..\..\class\_drivemngbase\drivemngbase.h"
#include "..\..\Source\BusIFVVDrive.h"
#include "..\..\Class\SafetyManager\SafetyManager.h"
#include "..\..\Class\MDD2000MngBase\MDD2000MngBase.h"

(*!
<Class
	Name               = "MDD2000VVBase"
	Revision           = "1.1"
	GUID               = "{89E9F863-F1DA-48FF-8939-CFA6A16D814C}"
	RealtimeTask       = "false"
	CyclicTask         = "false"
	BackgroundTask     = "false"
	DefBackground      = "100 ms"
	Sigmatek           = "true"
	OSInterface        = "false"
	HighPriority       = "false"
	Automatic          = "false"
	UpdateMode         = "Prescan"
	IconPath           = ".\Class\Varan_16x16.ico"
	SharedCommandTable = "true"
	Objectsize         = "(720,960)">
	<Channels>
		<Server Name="CallCommandFSoE" GUID="{E028E719-6DDC-4C78-B050-C178A8BCAF4D}" Visualized="false" Initialize="false" WriteProtected="true" Retentive="false"/>
		<Server Name="ClassState" GUID="{8C7FB97D-1092-4B41-9059-D3BD96AFA0F7}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false"/>
		<Server Name="DriveBusIF" GUID="{D854B97A-0A4C-4443-B8A9-562971CF1431}" Visualized="false" Initialize="false" WriteProtected="true" Retentive="false"/>
		<Server Name="Input1" GUID="{FEBA4463-9A78-4295-BFE0-86769212CDC2}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="State of digital input 1 of drive.&#13;&#10; 0 .. off&#13;&#10; 1 .. on&#13;&#10;-1 .. deactivated"/>
		<Server Name="Input2" GUID="{4EA518E7-275E-4C05-9F4B-83E443323C68}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="State of digital input 2 of drive.&#13;&#10; 0 .. off&#13;&#10; 1 .. on&#13;&#10;-1 .. deactivated"/>
		<Server Name="Input3" GUID="{936E1726-745F-45E9-8F62-4678EB70943C}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="State of digital input 3 of drive.&#13;&#10; 0 .. off&#13;&#10; 1 .. on&#13;&#10;-1 .. deactivated"/>
		<Server Name="Input4" GUID="{4DCACE87-8562-4BED-AC70-C73275B95B54}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="State of digital input 4 of drive.&#13;&#10; 0 .. off&#13;&#10; 1 .. on&#13;&#10;-1 .. deactivated"/>
		<Server Name="Input5" GUID="{EF8F809A-ACC1-4AF1-B281-4E8A02E56054}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="State of digital input 5 of drive.&#13;&#10; 0 .. off&#13;&#10; 1 .. on&#13;&#10;-1 .. deactivated"/>
		<Server Name="Input6" GUID="{BF138DAB-C7C4-40E8-AE39-5E840C44E6B7}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="State of digital input 6 of drive.&#13;&#10; 0 .. off&#13;&#10; 1 .. on&#13;&#10;-1 .. deactivated"/>
		<Server Name="SafetyRunState" GUID="{2579C0CA-0AF8-48A2-BCF0-363942BCEE33}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false"/>
		<Client Name="DeviceID" Required="true" Internal="false"/>
		<Client Name="TimeMultiplier" Required="true" Internal="false" DefValue="1"/>
		<Client Name="ToBusInterface" Required="true" Internal="false"/>
		<Client Name="ToMultiTask" Required="false" Internal="false"/>
		<Client Name="toStdLib" Required="false" Internal="false"/>
		<Client Name="toVaranIn" Required="true" Internal="false"/>
	</Channels>
	<Dependencies>
		<Files>
			<File Path=".\Source\interfaces\lsl_st_hardwaretree.h" Include="true"/>
			<File Path=".\Class\HwControl\HwControl.h" Include="true"/>
			<File Path=".\Source\BusInterface.h" Include="true"/>
			<File Path=".\class\_drivemngbase\drivemngbase.h" Include="true"/>
			<File Path=".\Source\BusIFVVDrive.h" Include="true"/>
			<File Path=".\Class\SafetyManager\SafetyManager.h" Include="true"/>
			<File Path=".\Class\MDD2000MngBase\MDD2000MngBase.h" Include="true"/>
		</Files>
	</Dependencies>
	<RevDoku>
		<Owner Company="Sigmatek" Author="LanSte"/>
		<Dokumentation Revision="1.1" Date="16.12.2024" Author="LanSte" Company="Sigmatek" Description="Fixed function of commands _ MDD2000INIT and _ MDD2000URINIT"/>
		<Dokumentation Revision="1.0" Date="28.08.2023" Author="LanSte" Company="Sigmatek" Description="First library version."/>
	</RevDoku>
</Class>
*)
MDD2000VVBase : CLASS
	TYPE
	  aBuffer : ARRAY [0..15] OF USINT;
	  bdAxisPlace : BDINT
	  [
	    1 Axis1,
	    2 Axis2,
	    3 Axis3,
	    4 Axis4,
	    5 Axis5,
	    6 Axis6,
	    7 Axis7,
	    8 Axis8,
	    9 Bit9,
	    10 Bit10,
	    11 Bit11,
	    12 Bit12,
	    13 Bit13,
	    14 Bit14,
	    15 Bit15,
	    16 Bit16,
	    17 Bit17,
	    18 Bit18,
	    19 Bit19,
	    20 Bit20,
	    21 Bit21,
	    22 Bit22,
	    23 Bit23,
	    24 Bit24,
	    25 Bit25,
	    26 Bit26,
	    27 Bit27,
	    28 Bit28,
	    29 Bit29,
	    30 Bit30,
	    31 Bit31,
	    32 Bit32,
	  ];
	  bdFlags : BDINT
	  [
	    1 bOnline,
	    2 bMailBoxInitOk,
	    3 bAlreadyAxisInit,
	    4 bPostInitFinished,
	    5 bDeactivated,
	    6 bUpdateThisTime,
	    7 bDeviceIDOk,
	    8 bAddDOListAvailable,
	    9 bIsoDOCreated,
	    10 bAsyDOCreated,
	    11 Bit11,
	    12 Bit12,
	    13 Bit13,
	    14 Bit14,
	    15 Bit15,
	    16 Bit16,
	    17 Bit17,
	    18 Bit18,
	    19 Bit19,
	    20 Bit20,
	    21 Bit21,
	    22 Bit22,
	    23 Bit23,
	    24 Bit24,
	    25 Bit25,
	    26 Bit26,
	    27 Bit27,
	    28 Bit28,
	    29 Bit29,
	    30 Bit30,
	    31 Bit31,
	    32 Bit32,
	  ];
	  bs_DigIn : BSINT
	  [
	    1 Bit1,
	    2 Bit2,
	    3 Bit3,
	    4 Bit4,
	    5 Bit5,
	    6 Bit6,
	    7 Bit7,
	    8 Bit8,
	  ];
	  e_ParaSSW :
	  (
	    _IdlePara,
	    _RequReadPara,
	    _RespReadPara,
	    _Wait4ReadPara,
	    _WritePara,
	    _Wait4WritePara,
	    _FinishedPara,
	    _ControlPara
	  )$UDINT;
#pragma pack(push, 1)
	  t_DataReadOneAxis : STRUCT
	    Value6 : DINT;
	    Value7 : DINT;
	    Value8 : DINT;
	    Value9 : DINT;
	    Value10 : DINT;
	  END_STRUCT;
#pragma pack(pop)
	  t_DataReadOneAxis2 : ARRAY [0..1] OF DINT;
#pragma pack(push, 1)
	  ts_DriveInputs : STRUCT
	    bsDigIn : bs_DigIn;
	    bsDriveInfo : BSINT
	    [
	      1 Bit1,
	      2 Bit2,
	      3 Bit3,
	      4 Bit4,
	      5 Bit5,
	      6 Bit6,
	      7 Bit7,
	      8 Bit8,
	    ];
	    SafetyRunState : UINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_DataWriteOneAxis : STRUCT
	    Value1 : DINT;
	    Value2 : DINT;
	    Value3 : DINT;
	    Value4 : DINT;
	    Value5 : DINT;
	  END_STRUCT;
#pragma pack(pop)
	  t_DataWriteOneAxis2 : ARRAY [0..1] OF DINT;
#pragma pack(push, 1)
	  t_s_MailboxData : STRUCT
	    Data : ARRAY [0..123] OF USINT;
	    Footer : tsMailboxFooter;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_DOInfo : STRUCT
	    pData : pVoid;
	    Handle : UDINT;
	    Length : USINT;
	    udOffset : UDINT;
	    hdDOAddress : HDINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_DOInfoDyn : STRUCT
	    pData : ^void;
	    Handle : UDINT;
	    Length : USINT;
	    Offset : HDINT;
	    OldLength : USINT;
	    OldOffset : HDINT;
	    MailboxOffset : HINT;
	    AxisPlaceNr : USINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_Accesses : STRUCT
	    pReadIso : ARRAY [0..MDD2000VVBASE_MAX_AXIS-1] OF ^t_DataReadOneAxis;
	    LenReadIso : UDINT;
	    pReadIso2 : ARRAY [0..MDD2000VVBASE_MAX_AXIS-1] OF ^t_DataReadOneAxis2;
	    LenReadIso2 : UDINT;
	    pReadDigIn : ^ts_DriveInputs;
	    pWriteIso : ARRAY [0..MDD2000VVBASE_MAX_AXIS-1] OF ^t_DataWriteOneAxis;
	    LenWriteIso : UDINT;
	    pWriteIso2 : ARRAY [0..MDD2000VVBASE_MAX_AXIS-1] OF ^t_DataWriteOneAxis2;
	    LenWriteIso2 : UDINT;
	    pWriteIsoErrorInfo : ^HDINT;
	    pReadAsy : ARRAY [0..MDD2000VVBASE_MAX_AXIS-1] OF ^aBuffer;
	    pReadFileHandlingAsy : ^t_s_MailboxData;
	    pWriteAsy : ARRAY [0..MDD2000VVBASE_MAX_AXIS-1] OF ^aBuffer;
	    pWriteFileHandlingAsy : ^t_s_MailboxData;
	    ReadAccessIso : t_DOInfo;
	    WriteAccessIso : t_DOInfo;
	    ReadAccessAsy : ARRAY [0..MDD2000VVBASE_MAX_AXIS-1] OF t_DOInfoDyn;
	    ReadFileAccessAsy : t_DOInfoDyn;
	    WriteAccessAsy : ARRAY [0..MDD2000VVBASE_MAX_AXIS-1] OF t_DOInfoDyn;
	    WriteFileAccessAsy : t_DOInfoDyn;
	    ServiceIDNr : USINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_AccessInfo : STRUCT
	    AccessHandle : UDINT;
	    pControlByte : ^t_SDIAS_ControlByte;
	    pStateByte : ^t_SDIAS_StateByte;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_AccessInfoDyn : STRUCT
	    AccessHandle : UDINT;
	    pControlByte : ^BOOL;
	    pStateByte : ^t_SDIAS_StateByte;
	    ActDoLength : USINT;
	    LastDoLength : DINT;
	    ActDoOffset : USINT;
	  END_STRUCT;
#pragma pack(pop)
	  t_AxisState :
	  (
	    _NotUsed,
	    _NoInit,
	    _InitOk,
	    _NoParaList,
	    _NotSynchron,
	    _AxisOk
	  )$USINT;
	  t_ParaState :
	  (
	    _SendExecution,
	    _EnableRead,
	    _Wait4Response,
	    _IdleState,
	    _GotValueForExecution
	  )$UDINT;
#pragma pack(push, 1)
	  t_ParaList : STRUCT
	    us_number : USINT;
	    sd_value : DINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_ReadValuePtr : STRUCT  //! <Type Public="true" Name="t_ReadValuePtr"/>
	    a_SyncValues : ARRAY [0..MDD2000VVBASE_MAX_AXIS_IDX] OF DINT;
	    bs_InputStates : BSINT
	    [
	      1 OptionBoardInputState,
	    ];
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_WriteValuePtr : STRUCT  //! <Type Public="true" Name="t_WriteValuePtr"/>
	    a_SyncValues : ARRAY [0..MDD2000VVBASE_MAX_AXIS_IDX] OF DINT;
	  END_STRUCT;
#pragma pack(pop)
	  t_AxisData : STRUCT
	    usAxisPlaceNr : USINT;
	    usPDOArrayNrb : USINT;
	    e_AxisState : t_AxisState;
	    us_ParaReady : t_ParaState;
	    p_AsyPipeHandle : pVoid;
	    a_AsyncData : aBuffer;
	    sd_ObjectError : DINT;
	    b_ListActive : BOOL;
	    p_ParaList : ^t_ParaList;
	    ui_ParaListCnt : UINT;
	    ud_CRCError : UDINT;
	    ud_DOLength : UDINT;
	    b_OldToggleState : DINT;
	    s_ReadValues : t_ReadValuePtr;
	    s_WriteValues : t_WriteValuePtr;
	  END_STRUCT;
#pragma pack(push, 1)
	  t_AxisInfo : STRUCT
	    usTmpAxisNbr : USINT;
	    usAxisActiveNo : USINT;
	    usMaxAxisAvailable : USINT;
	    usHighestAxisNrb : USINT;
	    aActAxisNrb : ARRAY [0..MDD2000VVBASE_MAX_AXIS-1] OF USINT;
	    AxisAvailableHW : bdAxisPlace;
	    AxisAvailableSW : bdAxisPlace;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_DriveTypeVars : STRUCT
	    hsDriveITYPE : HSINT;
	    eDriveType :  //! <Type Comment="0 .. drive type is not read&#13;&#10;1 .. drive type is not known&#13;&#10;2 .. mdp2000&#13;&#10;3 .. mdd2000&#13;&#10;" Name="t_DriveTypeVars.eDriveType"/>
	    (
	      _TypeNotRead,
	      _UnknownType,
	      _MDPType,
	      _MDDType
	    )$UDINT;
	    uiHwPathLen : UINT;
	    pHwPath : ^USINT;
	    psDriveMDPErrorInfo : ^ts_DriveInputs;
	    uiHwPathLenMDP : UINT;
	    pHwPathMDP : ^USINT;
	  END_STRUCT;
#pragma pack(pop)
	  t_e_FileAccessType :
	  (
	    _ReadFile,
	    _WriteFile,
	    _GetFileSize,
	    _ReadFileInBuffer
	  )$UDINT;
	  t_e_MailboxHandling :
	  (
	    _MailBox_SetRequest,
	    _MailBox_SetResponse,
	    _MailBox_Wait4Response
	  )$UDINT;
	  t_e_VandalWriteAccessMode :
	  (
	    CreateNew,
	    OverwriteExisting,
	    Append,
	    CloseFile
	  )$USINT;
	  t_FileHandlingSSW :
	  (
	    _IdleFileHandling,
	    _GetActMsgCounter_Req,
	    _GetActMsgCounter_Resp,
	    _SetWorkingDirectory,
	    _GetWorkingDirectory,
	    _SendFileToDrive,
	    _CreateLocalFile,
	    _ReadFileFromDrive,
	    _WriteDataInLocalFile,
	    _ErrorDuringFileHandling,
	    _FinishFileHandling
	  )$UDINT;
	  t_InitAccesses :
	  (
	    _IdleAccesses,
	    _ReadoutTypeLabel,
	    _AddAccesses,
	    _FinishInitAccesses,
	    _ErrorInitAccesses
	  )$UDINT;
	  t_InitDriveSSW :
	  (
	    _SetDataObjectOn,
	    _Wait4Read:=1,
	    _SetInitAxis:=2,
	    _SetEnableRead:=3,
	    _WaitInit:=4,
	    _SetFinishInit:=5,
	    _SetDisableWrite:=6,
	    _SetExecuteBack:=7,
	    _GetFinishInit:=8,
	    _CyIdle:=9,
	    _Finish:=10,
	    _InitError:=11
	  )$UDINT;
	  t_InitModul :
	  (
	    _ReadTypeLabel,
	    _AddLocalAsyDO,
	    _AddLocalIsoDO,
	    _ChangeDriveDO,
	    _InitAxisMailBox,
	    _GetSafetyInfos,
	    _AddSafetyIsoDO,
	    _ChangeSafetyDO,
	    _ConnectEvent,
	    _StopPostInit,
	    _AddSafetyRtIsoDO,
	    _AddLocalRtIsoDO,
	    _ChangeSafetyRtDO,
	    _ChangeDriveRtDO,
	    _StartSafetyRtIsoDO,
	    _StartDriveRtIsoDO,
	    _DefaultWork,
	    _ErrorInit
	  )$UDINT;
	  t_p_SigClib : ^SigCLib;
#pragma pack(push, 1)
	  t_ParaSkipOneAxis : STRUCT
	    us_No : USINT;
	    p_Values : ^USINT;
	  END_STRUCT;
#pragma pack(pop)
	  t_RequiredReferenceSigCLib : ^SigCLib;
	  t_ResponseState :
	  (
	    _idle,
	    _wait,
	    _valid
	  )$UDINT;
	  t_RtSSW :
	  (
	    _InitAxis,
	    _GetSendParaList,
	    _WaitForSynchrony,
	    _Operational
	  )$UDINT;
#pragma pack(push, 1)
	  t_s_VandalWriteFile : STRUCT
	    udFileOffset : UDINT;
	    eMode : t_e_VandalWriteAccessMode;
	    aData : ARRAY [0..118] OF USINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_s_VandalReadFile : STRUCT
	    FileOffset : HDINT;
	    usLength_Cmd : USINT;
	    aData : ARRAY [0..118] OF USINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_s_FileHandling : STRUCT
	    eFileHandlingSSW : t_FileHandlingSSW;
	    eFileHandlingSSWErrorStep : t_FileHandlingSSW;
	    aFileNameDrive : ARRAY [0..MDD2000VVBASE_VANDAL_FILEHANDLING_MAX_FILENAME] OF CHAR;
	    aFilePathDrive : ARRAY [0..MDD2000VVBASE_VANDAL_FILEHANDLING_MAX_DIRECTORYNAME] OF CHAR;
	    aDestinationDPNE : ARRAY [0..199] OF CHAR;
	    sMailBoxSendData : t_s_MailboxData;
	    sMailboxReceiveData : t_s_MailboxData;
	    dAccessType : t_e_FileAccessType;
	    hdRequestOffset : HDINT;
	    hdResponseOffset : HDINT;
	    udTimeStamp : UDINT;
	    sWriteFileData : t_s_VandalWriteFile;
	    pWriteData : ^void;
	    udWriteDataLen : UDINT;
	    udWriteDataHeaderOffset : UDINT;
	    udMaxDataSizePerWriteAccess : UDINT;
	    udWriteActSendSize : UDINT;
	    udSentDataSize : UDINT;
	    bFinishFileTransfer : BOOL;
	    sReadFileData : t_s_VandalReadFile;
	    pFileHandle : ^void;
	    udDataLenToRead : UDINT;
	    udReadedDataLen : UDINT;
	    udActReadSize : UDINT;
	    udCurrentGetWorkingDirectoryCount : UDINT;
	    pReadBufferUser : ^void;
	    ReadOrWriteFileSuccessful : DINT;
	    dProgress : DINT;
	    dError : DINT;
	    dGetFileSizeStarted : DINT;
	    pudGetFileSizeReturn : ^UDINT;
	    udUserBufferLength : UDINT;
	    udDataLenToReadUserBuffer : UDINT;
	    mtTaskHandle : MT_TASKHANDLE;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_s_VandalGetDirectoryEntry : STRUCT
	    hdCRC32 : HDINT;
	    udSize : UDINT;
	    uidate : UINT;
	    uitime : UINT;
	    usattrib : USINT;
	    aFileName : ARRAY [0..94] OF CHAR;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_SafetyFSoEClass : STRUCT
	    pThisSafety : pVirtualBase;
	    pCallback : pVirtualBase;
	    usCallOption : BSINT
	    [
	      1 RtPre,
	      2 RtPost,
	      3 Cyclic,
	      4 Bit4,
	      5 Bit5,
	      6 Bit6,
	      7 Bit7,
	      8 Bit8,
	    ];
	    bdSafetyFlags : BDINT
	    [
	      1 bSafetyDeactivated,
	      2 bSafetyOK,
	      3 bIsoDOCreated,
	      4 Bit4,
	      5 Bit5,
	      6 Bit6,
	      7 Bit7,
	      8 Bit8,
	      9 Bit9,
	      10 Bit10,
	      11 Bit11,
	      12 Bit12,
	      13 Bit13,
	      14 Bit14,
	      15 Bit15,
	      16 Bit16,
	      17 Bit17,
	      18 Bit18,
	      19 Bit19,
	      20 Bit20,
	      21 Bit21,
	      22 Bit22,
	      23 Bit23,
	      24 Bit24,
	      25 Bit25,
	      26 Bit26,
	      27 Bit27,
	      28 Bit28,
	      29 Bit29,
	      30 Bit30,
	      31 Bit31,
	      32 Bit32,
	    ];
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_SDORequest : STRUCT
	    sd_ObjectValue : ARRAY [0..11] OF USINT;
	    ParaIndex : HINT;
	    ParaSubIndex : USINT;
	    RequestControl : BSINT
	    [
	      1 ToggleBit,
	      2 ReadWriteObject,
	      3 InitCommunication,
	      4 res1,
	      5 res2,
	      6 res3,
	      7 DataLength1,
	      8 DataLength2,
	    ];
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_SDOResponse : STRUCT
	    sd_ObjectValue : ARRAY [0..11] OF USINT;
	    ParaIndex : HINT;
	    ParaSubIndex : USINT;
	    ResponseControl : BSINT
	    [
	      1 ToggleBit,
	      2 ErrorInObjectHandling,
	      3 Warning,
	      4 res1,
	      5 res2,
	      6 res3,
	      7 DataLength1,
	      8 DataLength2,
	    ];
	  END_STRUCT;
#pragma pack(pop)
	  t_TypeLabelSSW :
	  (
	    _ReadFirstSector,
	    _ReadMailbox,
	    _CheckServiceID,
	    _ReadAxisAmount,
	    _GetDriveErrorInfoMDP,
	    _TypeLabelFinish,
	    _TypeLabelError,
	    _NoErrorReadTypeLabel
	  )$UDINT;
#pragma pack(push, 1)
	  t_SDOVars : STRUCT
	    sActWrData : ARRAY [0..MDD2000VVBASE_MAX_AXIS-1] OF t_SDORequest;
	    sActRdData : ARRAY [0..MDD2000VVBASE_MAX_AXIS-1] OF t_SDOResponse;
	    eReadTypeLabelSSW : t_TypeLabelSSW;
	    eErrorTypeLabelSSW : t_TypeLabelSSW;
	    eResponseState : t_ResponseState;
	    udSDOTimeOut : UDINT;
	    udSDOTimeMark : UDINT;
	    udTimeOutTypeLabel : UDINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_TimeVars : STRUCT
	    tSysTime : SYSTIME;
	    tSysDate : SYSDATE;
	    hdKDATEP241 : HDINT;
	    bTimeIsSet : BOOL;
	    udLastWrite : UDINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  t_VANDALMapping : STRUCT
	    VersionMinor : HSINT;
	    VersionMajor : HSINT;
	    DeviceName : ARRAY [0..23] OF CHAR;
	    DeviceInfoPointer : HINT;
	    DeviceID : DINT;
	    PDOs : STRUCT
	      MOCI : t_MapEntry;
	      MICO : t_MapEntry;
	    END_STRUCT;
	    WriteBeforeSync : USINT;
	    ReadAfterSync : USINT;
	    MailboxNumber : USINT;
	    aReserved : ARRAY [0..4] OF USINT;
	    aMailBoxes : ARRAY [0..MDD2000VVBASE_MAX_SERVICEBOX-1] OF t_MailBox;
	    AxisAvailable : bdAxisPlace;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  ts_AxPDOInfos : STRUCT
	    AxLenRd : UDINT;
	    AxLenWr : UDINT;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  ts_SdoMailbox : STRUCT
	    dMBAvailable : DINT;
	    sMailboxInfo : t_MailBox;
	    eParaState : e_ParaSSW;
	    tsRdPara : STRUCT
	      usCnt : USINT;
	      aRequ : ARRAY [0..15] OF tsDS402RdRequ;
	      aResp : ARRAY [0..15] OF DINT;
	      aRespCB : ARRAY [0..1] OF ^DINT;
	    END_STRUCT;
	    tsWrPara : STRUCT
	      usCnt : DINT;
	      aRequ : ARRAY [0..14] OF tsDS402WrRequ;
	    END_STRUCT;
	    tsReq : STRUCT
	      sMBFooter : tsMailboxFooter;
	    END_STRUCT;
	    tsResp : STRUCT
	      pMBFooter : ^tsMailboxFooter;
	    END_STRUCT;
	  END_STRUCT;
#pragma pack(pop)
	END_TYPE
  //Servers:
	ClassState 	: SvrChCmd_t_e_VaranErrors;
	DriveBusIF 	: SvrChCmd_DINT;
	Input1 	: SvrCh_DINT;
	Input2 	: SvrCh_DINT;
	Input3 	: SvrCh_DINT;
	Input4 	: SvrCh_DINT;
	Input5 	: SvrCh_DINT;
	Input6 	: SvrCh_DINT;
	SafetyRunState 	: SvrCh_t_e_MDD2000SafetyRunState_PTofCls_MDD2000MngBase;
	CallCommandFSoE 	: SvrChCmd_DINT;
  //Clients:
	ToBusInterface 	: CltChCmd_DINT;
	toVaranIn 	: CltChCmd_Hub_Base;
	DeviceID 	: CltCh_UDINT;
	TimeMultiplier 	: CltCh_UDINT;
	ToMultiTask 	: CltChCmd__MultiTask;
	toStdLib 	: CltChCmd__StdLib;
  //Variables:
		us_FirstScan 	: USINT;
		sAccesses 	: t_Accesses;
		sTypeLabel 	: t_VANDALMapping;
		sAxisData : ARRAY [0..MDD2000VVBASE_MAX_AXIS-1] OF t_AxisData;

		sAxisInfo 	: t_AxisInfo;
		sSDOVars 	: t_SDOVars;
		sSkipParameter : ARRAY [0..MDD2000VVBASE_MAX_AXIS-1] OF t_ParaSkipOneAxis;

		bdGeneralFlags 	: bdFlags;
		pDriveMngBase 	: ^void;
		pCallBackServer 	: ^DINT;
		eRtSSW 	: t_RtSSW;
		eInitModulSSW 	: t_InitModul;
		eInitDriveSSW 	: t_InitDriveSSW;
		udTimemarkInit 	: UDINT;
		udTimeCounter 	: UDINT;
		hdDeviceAddress 	: HDINT;
		sConnSafety 	: t_SafetyFSoEClass;
		sDriveType 	: t_DriveTypeVars;
		bdErrorSL : BDINT
		[
		  1 GetNextMDP,
		];

		sCmdIntMB 	: ts_SdoMailbox;
		sTimeVars 	: t_TimeVars;
		AsyErrorRetValBuffer 	: aBuffer;
		sFileHandling 	: t_s_FileHandling;
		eMailboxHandling 	: t_e_MailboxHandling;
		udMailboxTimestamp 	: UDINT;
		bExtendedPDOSupport 	: BOOL;
		sAxPDOInfos 	: ts_AxPDOInfos;
  //Functions:
	
	FUNCTION VIRTUAL GLOBAL Init;
	
	FUNCTION VIRTUAL GLOBAL CyWork
		VAR_INPUT
			EAX 	: UDINT;
		END_VAR
		VAR_OUTPUT
			state (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL RtWork
		VAR_INPUT
			EAX 	: UDINT;
		END_VAR
		VAR_OUTPUT
			state (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL ConnectEvent;
	
	FUNCTION VIRTUAL GLOBAL DisconnectEvent;
	
	FUNCTION VIRTUAL GLOBAL InterruptEvent;
	
	FUNCTION GLOBAL StartCommunication
		VAR_INPUT
			pServer4CallBack 	: ^BDINT;
		END_VAR;
	
	FUNCTION GLOBAL ExternInitFinished;
	
	FUNCTION GLOBAL SetParaList
		VAR_INPUT
			usAxis 	: USINT;
			p_list 	: ^void;
			ui_counter 	: UINT;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
	
	FUNCTION GLOBAL SetParameter
		VAR_INPUT
			usAxis 	: USINT;
			uiParaID 	: UINT;
			usParaSubID 	: USINT;
			usRdWr 	: USINT;
			pvalue 	: ^DINT;
			bsDataInfo 	: BSINT;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
	
	FUNCTION GLOBAL SetSyncParameter
		VAR_INPUT
			usAxis 	: USINT;
			us_value 	: USINT;
			sd_data 	: DINT;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
	
	FUNCTION GLOBAL GetSyncParameter
		VAR_INPUT
			usAxis 	: USINT;
			us_value 	: USINT;
			p_data 	: ^DINT;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL AddDefaultAsyAccess;
	
	FUNCTION SkipEntries
		VAR_INPUT
			usAxisArray 	: USINT;
			pAxis 	: ^t_AxisData;
		END_VAR;
	
	FUNCTION GLOBAL GetParameterState
		VAR_INPUT
			usAxis 	: USINT;
		END_VAR
		VAR_OUTPUT
			sd_para_state 	: DINT;
		END_VAR;
	
	FUNCTION GLOBAL GetParameter
		VAR_INPUT
			usAxis 	: USINT;
			pRetcode 	: ^iprStates;
		END_VAR
		VAR_OUTPUT
			p_para_data 	: ^aBuffer;
		END_VAR;
	
	FUNCTION GLOBAL GetDriveIntState
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION VIRTUAL InitAxis
		VAR_INPUT
			usAxisArray 	: USINT;
		END_VAR
		VAR_OUTPUT
			sd_retval 	: DINT;
		END_VAR;
	
	FUNCTION GLOBAL GetAxisRdPtr
		VAR_INPUT
			usAxis 	: USINT;
		END_VAR
		VAR_OUTPUT
			pReadPara 	: ^t_ReadValuePtr;
		END_VAR;
	
	FUNCTION GLOBAL GetAxisWrPtr
		VAR_INPUT
			usAxis 	: USINT;
		END_VAR
		VAR_OUTPUT
			pWritePara 	: ^t_WriteValuePtr;
		END_VAR;
	
	FUNCTION GLOBAL InitDrive;
	
	FUNCTION ReadTypeLabel
		VAR_OUTPUT
			eModuleInitState 	: iprStates;
		END_VAR;
	
	FUNCTION GetObjectValue
		VAR_INPUT
			usAxisArray 	: USINT;
		END_VAR;
	
	FUNCTION SetWriteData
		VAR_INPUT
			usAxisArray 	: USINT;
		END_VAR;
	
	FUNCTION GetReadData
		VAR_INPUT
			usAxisArray 	: USINT;
		END_VAR;
	
	FUNCTION DisableDO
		VAR_INPUT
			AccessHandle 	: UDINT;
		END_VAR
		VAR_OUTPUT
			Success 	: BOOL;
		END_VAR;
	
	FUNCTION EnableDO
		VAR_INPUT
			AccessHandle 	: UDINT;
		END_VAR
		VAR_OUTPUT
			Success 	: BOOL;
		END_VAR;
	
	FUNCTION ChangeRdDO
		VAR_INPUT
			AccessHandle 	: UDINT;
			NewOffset 	: HDINT;
			NewLength 	: UDINT;
		END_VAR
		VAR_OUTPUT
			Success 	: BOOL;
		END_VAR;
	
	FUNCTION ChangeWrDO
		VAR_INPUT
			AccessHandle 	: UDINT;
			NewOffset 	: HDINT;
			NewLength 	: UDINT;
		END_VAR
		VAR_OUTPUT
			Success 	: BOOL;
		END_VAR;
	
	FUNCTION VIRTUAL AddAsyAccesses;
	
	FUNCTION VIRTUAL AddIsoAccesses
		VAR_INPUT
			bAddDoLater 	: BOOL := FALSE;
		END_VAR
		VAR_OUTPUT
			retcode 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL LogValue
		VAR_INPUT
			pString 	: ^CHAR;
			Value 	: UDINT;
			Value2 	: UDINT := 16#;
			Value3 	: UDINT := 16#;
		END_VAR;
	
	FUNCTION VIRTUAL LogError
		VAR_INPUT
			e_msg 	: ^CHAR;
		END_VAR;
	
	FUNCTION GLOBAL AddSafetyTask
		VAR_INPUT
			pCmd 	: ^CmdStruct;
			presult 	: ^results;
		END_VAR;
	
	FUNCTION GetMailboxInfo
		VAR_INPUT
			hiID 	: t_MailboxTypes;
			pMailboxData 	: ^t_MailBox;
			pMailboxID 	: ^USINT;
		END_VAR
		VAR_OUTPUT
			dRetCode 	: DINT;
		END_VAR;
	
	FUNCTION SetClassState
		VAR_INPUT
			tClassState 	: t_e_VaranErrors;
		END_VAR;
	
	FUNCTION GetAxisNoHW
		VAR_INPUT
			bdAxisPlaces 	: BDINT;
		END_VAR
		VAR_OUTPUT
			usAxisNo 	: USINT;
		END_VAR;
	
	FUNCTION GetIsoObjectLength
		VAR_INPUT
			bdHwAxis 	: BDINT;
			bdSwAxis 	: BDINT;
			DeviceID 	: UDINT;
			usMaxAxis 	: USINT;
			pusHighestAxisNrb 	: ^USINT;
			pudDataOffset 	: ^UDINT;
			puiLength 	: ^UINT;
			bRd 	: BOOL;
		END_VAR
		VAR_OUTPUT
			dRetCode 	: iprStates;
		END_VAR;
	
	FUNCTION GetObjectValueNew;
	
	FUNCTION GLOBAL GetNReadPara
		VAR_INPUT
			hiIndex 	: HINT;
			hsSubIndex 	: HSINT;
			pDataCB 	: ^DINT;
			usParaType 	: USINT := _BUSIF_VVDRIVE_INTEGER32;
			usAxisNbr 	: USINT := 0;
		END_VAR
		VAR_OUTPUT
			dRetCode 	: DINT;
		END_VAR;
				//! <Function Comment="Method to upload a specific file from the drive and save it on the SPS" Name="GetFile"/>
	FUNCTION 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;			//! <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 open logfile&#13;&#10;-11 ... Failed to write data to logfile&#13;&#10;-12 ... Invalid length&#13;&#10;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="GetFile.pdError"/>
		END_VAR
		VAR_OUTPUT
			dRetCode 	: 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.dRetCode"/>
		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 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 open logfile&#13;&#10;-11 ... Failed to write data to logfile&#13;&#10;-12 ... Invalid length&#13;&#10;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="GetFileState.pdError"/>
			pdProgress 	: ^DINT := nil;			//! <Variable Comment="Pointer to a 4 Byte variable where the progress of the fileupload will be written in percentage (0-1000) (optional, can be nil)" Name="GetFileState.pdProgress"/>
			pudBytesRead 	: ^UDINT := nil;			//! <Variable Comment="Pointer to where the amount of read bytes will be copied (optional, can be NIL)" Name="GetFileState.pudBytesRead"/>
		END_VAR
		VAR_OUTPUT
			dState 	: 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.dState"/>
		END_VAR;
				//! <Function Comment="Method to get the size of a specific file from the drive" Name="GetFileSize"/>
	FUNCTION 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 when the retcode is 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;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="GetFileSize.pdError"/>
		END_VAR
		VAR_OUTPUT
			dRetCode 	: iprStates;			//! <Variable Comment="READY ... filesize was read succesfully&#13;&#10;BUSY ... filesize is being fetched (method has to be called again, until retcode is READY or ERROR)&#13;&#10;ERROR ... get filesize failed (see parameter pdError for more information)" Name="GetFileSize.dRetCode"/>
		END_VAR;
				//! <Function Comment="Method to read data from a specific file from the drive and write data into an user buffer." Name="GetFileBuffer"/>
	FUNCTION 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;			//! <Variable Comment="Pointer to buffer where read data will be copied." 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 ... Given buffer size is smaller than filesize&#13;&#10;-14 ... Filesize of file is smaller than amount of bytes to read from file.&#13;&#10;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="GetFileBuffer.pdError"/>
		END_VAR
		VAR_OUTPUT
			dRetCode 	: 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.dRetCode"/>
		END_VAR;
				//! <Function Comment="Method to write a specific file on the drive." Name="SetFile"/>
	FUNCTION 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 open logfile&#13;&#10;-11 ... Failed to write data to logfile&#13;&#10;-12 ... Invalid length&#13;&#10;-98 ... Drive is not online&#13;&#10;-99 ... Function not supported&#13;&#10;" Name="SetFile.pdError"/>
		END_VAR
		VAR_OUTPUT
			dRetcode 	: 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.dRetcode"/>
		END_VAR;
	
	FUNCTION ProcessFileHandling;
	
	FUNCTION SetMailboxRequest
		VAR_INPUT
			pSendMailBox 	: ^t_s_MailboxData;
			pSDOWriteDataPtr 	: ^void;
			pData 	: ^void;
			usLen 	: USINT;
			usCommand 	: USINT;
		END_VAR;
	
	FUNCTION CheckMailBoxResponse
		VAR_INPUT
			pRecvMailBox 	: ^t_s_MailboxData;
			pSendMailBox 	: ^t_s_MailboxData;
			pReadData 	: ^void;
			udRequestTimeStamp 	: UDINT;
			udTimeout 	: UDINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
	
	FUNCTION FileHandlingMailBoxAccess
		VAR_INPUT
			pSendRequestData 	: ^void;
			usRequestLen 	: USINT;
			usCommand 	: USINT;
			hdRequestOffset 	: HDINT;
			hdResponseOffset 	: HDINT;
			udWriteDOLen 	: UDINT;
			udReadDOLen 	: UDINT;
			pdErrorCode 	: ^DINT;
		END_VAR
		VAR_OUTPUT
			dRetcode 	: iprStates;
		END_VAR;
	
	FUNCTION FilehandlingTask;
	
	FUNCTION SetFileHandlingError
		VAR_INPUT
			dError 	: DINT;			//! <Variable Comment="error code to set" Name="SetFileHandlingError.dError"/>
			pdError 	: ^DINT;			//! <Variable Comment="can be use to get back the error that getīs set.&#13;&#10;Used to give back error code in calling function, so GetFileState() must not be called." Name="SetFileHandlingError.pdError"/>
		END_VAR;
				//! <Function Name="ClassState.NewInst" UseBaseCmd="true"/>
	FUNCTION VIRTUAL GLOBAL ClassState::NewInst
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL DriveBusIF::NewInst
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL CallCommandFSoE::NewInst
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
  //Tables:
	FUNCTION @STD
		VAR_OUTPUT
			ret_code	: CONFSTATES;
		END_VAR;
	FUNCTION GLOBAL TAB @CT_;
END_CLASS;

#pragma usingLtd _MultiTask
#pragma usingLtd _StdLib
#pragma usingLtd Hub_Base


//}}LSL_DECLARATION


FUNCTION GLOBAL TAB MDD2000VVBase::@CT_
0$UINT,
2#0100000000000000$UINT, //TY_MDD2000VVBASE
1$UINT, 1$UINT, (SIZEOF(::MDD2000VVBase))$UINT, 
10$UINT, 6$UINT, 0$UINT, 
TO_UDINT(1968777221), "MDD2000VVBase", //Class
TO_UDINT(0), 0, 0$UINT, 0$UINT, //Baseclass
//Servers:
(::MDD2000VVBase.ClassState.pMeth)$UINT, _CH_CMD$UINT, 2#0000000000000000$UINT, TO_UDINT(1096059024), "ClassState", 
(::MDD2000VVBase.DriveBusIF.pMeth)$UINT, _CH_CMD$UINT, 2#0000000000000000$UINT, TO_UDINT(253971569), "DriveBusIF", 
(::MDD2000VVBase.Input1.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1344628668), "Input1", 
(::MDD2000VVBase.Input2.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(3375117830), "Input2", 
(::MDD2000VVBase.Input3.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(3190490768), "Input3", 
(::MDD2000VVBase.Input4.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(542085939), "Input4", 
(::MDD2000VVBase.Input5.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1464378277), "Input5", 
(::MDD2000VVBase.Input6.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(3460428319), "Input6", 
(::MDD2000VVBase.SafetyRunState.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1037834220), "SafetyRunState", 
(::MDD2000VVBase.CallCommandFSoE.pMeth)$UINT, _CH_CMD$UINT, 2#0000000000000000$UINT, TO_UDINT(2758564975), "CallCommandFSoE", 
//Clients:
(::MDD2000VVBase.ToBusInterface.pCh)$UINT, _CH_CLT_CMD$UINT, 2#0000000000000010$UINT, TO_UDINT(1682766337), "ToBusInterface", 
(::MDD2000VVBase.toVaranIn.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000010$UINT, TO_UDINT(380324403), "toVaranIn", TO_UDINT(3238133653), "Hub_Base", 1$UINT, 21$UINT, 
(::MDD2000VVBase.DeviceID.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000010$UINT, TO_UDINT(4261957967), "DeviceID", 
(::MDD2000VVBase.TimeMultiplier.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000010$UINT, TO_UDINT(2421717411), "TimeMultiplier", 
(::MDD2000VVBase.ToMultiTask.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000000$UINT, TO_UDINT(4206025932), "ToMultiTask", TO_UDINT(2641766936), "_MultiTask", 1$UINT, 1$UINT, 
(::MDD2000VVBase.toStdLib.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000000$UINT, TO_UDINT(2501598121), "toStdLib", TO_UDINT(3689364044), "_StdLib", 2$UINT, 0$UINT, 
END_FUNCTION


#define USER_CNT_MDD2000VVBase 9

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	IF CallCommandFSoE.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;

END_FUNCTION

#pragma usingLtd SigCLib

//{{LSL_IMPLEMENTATION
FUNCTION VIRTUAL GLOBAL MDD2000VVBase::Init
  VAR
    dataADDTASK : t_TaskCfg;
  	MyPara     : CmdStruct;
    MyResult     : results;
    dataSyncDataMyPara : t_SyncData;
    dataADDCallback : t_BusIFAddCallback;
    udBusCycleTime      : UDINT;
    udIsoStartPoint     : UDINT;
    sdSyncOffset        : DINT;
  END_VAR

  //no init if module is deactivated
  if bdGeneralFlags.bDeactivated then
    return;
  end_if;

  case us_FirstScan of
    0:
      
      //read client
      DeviceID := DeviceID.Read();

      // first check if the module may be deactivated
      MyPara.uiCmd     := _BUS_IF_GET_DEACTIVATED_STATE;

      ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
      if MyResult.aData[0]$t_BusIFRetvalErrorcode = _BUS_IF_RETVAL_OK then
        bdGeneralFlags.bDeactivated := MyResult.aData[4]$BOOL;
        if bdGeneralFlags.bDeactivated then
          return;
        end_if;
      else
        LogError("@01D6 (MDD2000VVBase::Init) Failed to get deactivation state via BusInterface.");
      end_if;
      
      // intialize return code for asy buffer
      AsyErrorRetValBuffer$DINT := -1;

    4:
      // login as operator
      dataADDCallback.pthis := this$pVirtualBase;

      MyPara.uiCmd     := _BUS_IF_ADD_CALLBACK;
      MyPara.aPara[0]  := (#dataADDCallback)$DINT;
      ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
      if MyResult.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
        LogError("@01C2 (MDD2000VVBase::Init) Failed to install callback at bus interface.");
      end_if;

      //add realtime task
      dataADDTASK.Priority    := _BUS_IF_ISO;
      dataADDTASK.callOptions := (CALL_OPTION_RT_PRESCAN or CALL_OPTION_RT_POSTSCAN);
      dataADDTASK.pthis       := this$UDINT;

      MyPara.uiCmd     := _BUS_IF_ADD_TASK;
      MyPara.aPara[0]  := (#dataADDTASK)$DINT;
      ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);

      if MyResult.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
        LogError("@0742 (MDD2000VVBase::Init) Failed to install realtime tasks");
        SetClassState(tClassState:=_InvalidConfguration);
        return;
      end_if;

      //add cyclic task
      dataADDTASK.Priority    := _BUS_IF_ASY;
      dataADDTASK.callOptions := CALL_OPTION_CYCLIC;
      dataADDTASK.pthis       := this$UDINT;

      MyPara.uiCmd     := _BUS_IF_ADD_TASK;
      MyPara.aPara[0]  := (#dataADDTASK)$DINT;
      ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);

      if MyResult.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
        LogError("@0743 (MDD2000VVBase::Init) Failed to install a cyclic task");
        SetClassState(tClassState:=_InvalidConfguration);
        return;
      end_if;

    5:
      //read time multiplier
      //************************************************************************************
      TimeMultiplier := TimeMultiplier.Read();
      if ( TimeMultiplier = 0 ) then
        TimeMultiplier := 1;
      end_if;

      //get bus cycle time
      //************************************************************************************
      MyPara.uiCmd     := _BUS_IF_GET_BUSCYCLE_TIME;
      ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);

      if MyResult.aData[0]$t_GetBusCycleTime.retcode  <> _BUS_IF_RETVAL_OK then
        LogError("@0134 (MDD2000VVBase::Init) Failed to get bus cycle time");
        SetClassState(tClassState:=_InvalidConfguration);
        return;
      else
        udBusCycleTime  := MyResult.aData[0]$t_GetBusCycleTime.udBusCycleTime ;
        udIsoStartPoint := MyResult.aData[0]$t_GetBusCycleTime.udIsoStartPoint;
        sdSyncOffset    := ( udBusCycleTime - udIsoStartPoint )$DINT / 10;
      end_if;

      //activate Sync Out 0
      //************************************************************************************
      MyPara.uiCmd                  := _BUS_IF_SET_SYNC;
      dataSyncDataMyPara.us_sync_nr := 0;
      dataSyncDataMyPara.sd_offset  := sdSyncOffset;
      dataSyncDataMyPara.us_period_multiplier     := to_usint(TimeMultiplier);
      dataSyncDataMyPara.us_frame_count_threshold := 0;
      dataSyncDataMyPara.us_enable_frame_count    := 0;
      MyPara.aPara[0] := (#dataSyncDataMyPara)$DINT;

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

      if MyResult.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
        LogError("@0745 (MDD2000VVBase::Init) Failed to activate Pll");
        SetClassState(tClassState:=_InvalidConfguration);
        return;
      end_if;

      //activate Sync Out 1
      //************************************************************************************
      MyPara.uiCmd                  := _BUS_IF_SET_SYNC_DIVIDER;
      dataSyncDataMyPara.us_sync_nr := 1;
      dataSyncDataMyPara.sd_offset  := sdSyncOffset MOD 6250;
      dataSyncDataMyPara.us_period_multiplier     := 0;
      dataSyncDataMyPara.us_frame_count_threshold := 0;
      dataSyncDataMyPara.us_enable_frame_count    := 0;
      dataSyncDataMyPara.b_use_divider_sync       := TRUE;
      MyPara.aPara[0] := (#dataSyncDataMyPara)$DINT;
      MyPara.aPara[1] := to_dint(udBusCycleTime/62500); //us_PLLDivider for PLL

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

      if MyResult.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
        LogError("@0745 (MDD2000VVBase::Init) Failed to activate Pll");
        SetClassState(tClassState:=_InvalidConfguration);
        return;
      end_if;

      //get support of adding do's to list
      MyPara.uiCmd    := _BUS_IF_GET_PARAM;
      MyPara.aPara[0] := _BUS_IF_DOLISTADD_AVAILABLE;
      ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);

      if MyResult.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
        LogError("@0750 (MDD2000VVBase::Init) Failed to get Parameter from BusIF");
        bdGeneralFlags.bAddDOListAvailable := FALSE;
      else
        bdGeneralFlags.bAddDOListAvailable := MyResult.aData[4]$BOOL;
      end_if;

      // add asy default access for drive
      AddDefaultAsyAccess();

  end_case;

  us_FirstScan += 1;

END_FUNCTION


FUNCTION VIRTUAL MDD2000VVBase::AddDefaultAsyAccess
  VAR
    dataADDDO   : t_AddDOCfg;
  	MyPara     : CmdStruct;
    MyResult     : results;
    usCounter   : USINT;
    aLogVal1 : DINT;
  END_VAR
  
  //reset local memory
  _memset(dest:=#dataADDDO, usByte:=0x00, cntr:=sizeof(dataADDDO));

  //Add Asynchrone Read DO
  //************************************************************************************
  //add all read accesses
  dataADDDO.Priority                := _BUS_IF_ASY;
  dataADDDO.RdWr                    := _BUS_IF_READ;
  dataADDDO.ud_WaitForAccessHandle  := 0;

  dataADDDO.ui_length_read     := MDD2000VVBASE_ONE_DO_SIZE;  //first do is used to read type label
  dataADDDO.b_UseLocalCopy     := FALSE;

  // if there are no axis object do to read type label is needed
  usCounter := 0;
  sAccesses.ReadAccessAsy[usCounter].Offset := 0;
  dataADDDO.ud_addressoff_read  := sAccesses.ReadAccessAsy[usCounter].Offset;

  MyPara.uiCmd     := _BUS_IF_ADD_DO;
  MyPara.aPara[0]  := (#dataADDDO)$DINT;

  ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
  if MyResult.aData[0]$t_BusIFRetvalErrorcode = _BUS_IF_RETVAL_OK then
    sAccesses.ReadAccessAsy[usCounter].Handle := MyResult.aData$t_AddDORet.Handle;
    sAccesses.ReadAccessAsy[usCounter].pData  := MyResult.aData$t_AddDORet.pDataRead;
    sAccesses.pReadAsy[usCounter]$pVoid       := sAccesses.ReadAccessAsy[usCounter].pData;
    sAccesses.ReadAccessAsy[usCounter].Length := dataADDDO.ui_length_read$USINT;

    //change retry timeout for varan do
    MyPara.uiCmd     := _BUS_IF_RESET_DO;
    MyPara.aPara[0]  := (#sAccesses.ReadAccessAsy[usCounter].Handle)$DINT;
    ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
  else
    aLogVal1 := MyResult.aData[0]$DINT;
    HWC_LogPrintf(pThis:=this, format:= "@0747 (MDD2000VVBase::AddDefaultAsyAccess) Failed to add a DO for SDO read data with error %d",#aLogVal1);          
    SetClassState(tClassState:=_DOHandleInvalid);
    return;
  end_if;

END_FUNCTION


FUNCTION VIRTUAL MDD2000VVBase::AddIsoAccesses
	VAR_INPUT
		bAddDoLater 	: BOOL;(* := FALSE *)
	END_VAR
	VAR_OUTPUT
		retcode 	: iprStates;
	END_VAR
  VAR
    dataADDDO   : t_AddDOCfg;
  	MyPara     : CmdStruct;
    MyResult     : results;
    usCounter   : USINT;
    tPriority   : t_BusIFPriority;
    dTmpRetCode : iprStates;
    udTempOffset: UDINT;
    udTmpAxisOffset : UDINT;
  END_VAR
  
  retcode := READY; //Default retcode

  if bAddDoLater = FALSE then
    tPriority := _BUS_IF_ISO;
  else
    tPriority := _BUS_IF_ISO_ADDLATER;
  end_if;

  //reset local memory
  _memset(dest:=#dataADDDO, usByte:=0x00, cntr:=sizeof(dataADDDO));

  if sAxisInfo.usAxisActiveNo then
    //Add Isochrone Read DO
    //************************************************************************************    
    MyPara.uiCmd     := _BUS_IF_ADD_DO;
    MyPara.aPara[0]  := (#dataADDDO)$DINT;

    //add read accesses
    dataADDDO.Priority                := tPriority;
    dataADDDO.RdWr                    := _BUS_IF_READ;
    dataADDDO.ud_WaitForAccessHandle  := 0;
    dataADDDO.b_UseLocalCopy          := TRUE;
    
    //get length of nedded dataobject
    dTmpRetCode := GetIsoObjectLength(bdHwAxis            := sAxisInfo.AxisAvailableHW
                                    , bdSwAxis            := sAxisInfo.AxisAvailableSW
                                    , DeviceID            := DeviceID
                                    , usMaxAxis           := sAxisInfo.usMaxAxisAvailable
                                    , pusHighestAxisNrb   := #sAxisInfo.usHighestAxisNrb
                                    , pudDataOffset       := #udTempOffset
                                    , puiLength           := #dataADDDO.ui_length_read
                                    , bRd                 := TRUE
                                    );

    dataADDDO.ud_addressoff_read := sTypeLabel.PDOs.MICO.hiAddress + udTempOffset;
    
    MyPara.uiCmd     := _BUS_IF_ADD_DO;
    MyPara.aPara[0]  := (#dataADDDO)$DINT;
    
    ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
        
    if MyResult.aData[0]$t_BusIFRetvalErrorcode = _BUS_IF_RETVAL_OK then
      sAccesses.ReadAccessIso.Handle := MyResult.aData$t_AddDORet.Handle;
      sAccesses.ReadAccessIso.pData  := MyResult.aData$t_AddDORet.pDataRead;
      sAccesses.ReadAccessIso.Length := dataADDDO.ui_length_read$USINT;
      sAccesses.ReadAccessIso.udOffset    := udTempOffset;
      sAccesses.ReadAccessIso.hdDOAddress := dataADDDO.ud_addressoff_read;

      //change retry timeout for varan do
      MyPara.uiCmd     := _BUS_IF_RESET_DO;
      MyPara.aPara[0]  := (#sAccesses.ReadAccessIso.Handle)$DINT;
      ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
      
    else
      //if add later is active the call is from cyclic task
      if bAddDoLater = TRUE then
        LogError("@0749 (MDD2000VVBase::AddIsoAccesses) Failed to add a DO for PDO read data");
      end_if;
      SetClassState(tClassState:=_DOHandleInvalid);
      retcode := ERROR;
      return;
    end_if;
    
    //set digin pointer if offset starts from 0
    if sAccesses.ReadAccessIso.udOffset = 0 then
      sAccesses.pReadDigIn$pVoid := sAccesses.ReadAccessIso.pData;
      //add 4 because general data is not used
      udTmpAxisOffset := sizeof(ts_DriveInputs);
    else
      udTmpAxisOffset := 0;
      // the input information is not available
      Input1 :=
      Input2 :=
      Input3 :=
      Input4 :=
      Input5 :=
      Input6 := -1;
    end_if;
    
    // Memory Mapping ISO Read DO
    // 4 Byte General Data (ts_DriveInputs)
    // 5*4 Byte Axis 1 PDO Data 
    // 5*4 Byte Axis 2 PDO Data (Only if there are 2 or more axis)
    // 5*4 Byte Axis 3 PDO Data (Only if there are 3 or more axis)    
    // 2*4 Byte Axis 1 PDO 2 Data (only if bExtendedPDOSupport) 
    // 2*4 Byte Axis 2 PDO 2 Data (Only if there are 2 or more axis and bExtendedPDOSupport)
    // 2*4 Byte Axis 3 PDO 2 Data (Only if there are 3 or more axis and bExtendedPDOSupport) 
    // There are no gaps in the mapping, if 1 or more axis are missing then the offset shift accordingly
    if sAxisInfo.usHighestAxisNrb then
    
      sAccesses.LenReadIso := MDD2000VVBASE_PDO_AXIS_SIZE;
      
      if bExtendedPDOSupport then
        sAccesses.LenReadIso2 := MDD2000VVBASE_PDO_AXIS_SIZE2;
      end_if;
      
      for usCounter := 0 to sAxisInfo.usHighestAxisNrb-1 do
        
        sAccesses.pReadIso[usCounter]$pVoid  := sAccesses.ReadAccessIso.pData + udTmpAxisOffset + (MDD2000VVBASE_PDO_AXIS_OFFSET*usCounter);
        
        if bExtendedPDOSupport then
          sAccesses.pReadIso2[usCounter]$pVoid  := sAccesses.ReadAccessIso.pData + udTmpAxisOffset + (MDD2000VVBASE_PDO_AXIS_OFFSET*sAxisInfo.usHighestAxisNrb) + (MDD2000VVBASE_PDO_AXIS_OFFSET2 * usCounter);
        end_if;

      end_for;
    end_if;

    //Add Isochrone Write DO
    //************************************************************************************
    //add write accesses
    dataADDDO.Priority                := tPriority;
    dataADDDO.RdWr                    := _BUS_IF_WRITE;
    dataADDDO.ud_WaitForAccessHandle  := 0;
    dataADDDO.b_UseLocalCopy          := TRUE;

    //get length of nedded dataobject
    dTmpRetCode := GetIsoObjectLength(bdHwAxis          := sAxisInfo.AxisAvailableHW
                                    , bdSwAxis          := sAxisInfo.AxisAvailableSW
                                    , DeviceID          := DeviceID
                                    , usMaxAxis         := sAxisInfo.usMaxAxisAvailable
                                    , pusHighestAxisNrb := #sAxisInfo.usHighestAxisNrb
                                    , pudDataOffset     := #udTempOffset
                                    , puiLength         := #dataADDDO.ui_length_write
                                    , bRd               := FALSE
                                    );
                                    
    //write of error info from mdp is only needed for MDD Drive
    if sDriveType.eDriveType = _MDPType then
      //dont write general data payload to mdp drive
      udTempOffset += MDD2000VVBASE_PDO_GENERAL_DATA;
      dataADDDO.ui_length_write -= MDD2000VVBASE_PDO_GENERAL_DATA;
    end_if;
    
    dataADDDO.ud_addressoff_write := sTypeLabel.PDOs.MOCI.hiAddress  + udTempOffset;
    
    MyPara.uiCmd     := _BUS_IF_ADD_DO;
    MyPara.aPara[0]  := (#dataADDDO)$DINT;

    ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
    if MyResult.aData[0]$t_BusIFRetvalErrorcode = _BUS_IF_RETVAL_OK then
      sAccesses.WriteAccessIso.Handle := MyResult.aData$t_AddDORet.Handle;
      sAccesses.WriteAccessIso.pData  := MyResult.aData$t_AddDORet.pDataWrite;
      sAccesses.WriteAccessIso.Length := dataADDDO.ui_length_write$USINT;
      sAccesses.WriteAccessIso.udOffset    := udTempOffset; 
      sAccesses.WriteAccessIso.hdDOAddress := dataADDDO.ud_addressoff_write;

      //change retry timeout for varan do
      MyPara.uiCmd     := _BUS_IF_RESET_DO;
      MyPara.aPara[0]  := (#sAccesses.WriteAccessIso.Handle)$DINT;
      ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
    else
      //if add later is active the call is from cyclic task
      if bAddDoLater = TRUE then
        LogError("@074A (MDD2000VVBase::AddIsoAccesses) Failed to add a DO for PDO write data");
      end_if;
      SetClassState(tClassState:=_DOHandleInvalid);
      retcode := ERROR;      
      return;
    end_if;

    //set general write pointer if offset starts from 0
    if sAccesses.WriteAccessIso.udOffset = 0 then
      sAccesses.pWriteIsoErrorInfo$pVoid := sAccesses.WriteAccessIso.pData;
      udTmpAxisOffset := sizeof(sAccesses.pWriteIsoErrorInfo^);
      
    else
      udTmpAxisOffset := 0;
    end_if;    

    // Memory Mapping ISO Write DO
    // 4 Byte General Data (pWriteIsoErrorInfo)
    // 5*4 Byte Axis 1 PDO Data 
    // 5*4 Byte Axis 2 PDO Data (Only if there are 2 or more axis)
    // 5*4 Byte Axis 3 PDO Data (Only if there are 3 or more axis)    
    // 2*4 Byte Axis 1 PDO 2 Data (only if bExtendedPDOSupport) 
    // 2*4 Byte Axis 2 PDO 2 Data (Only if there are 2 or more axis and bExtendedPDOSupport)
    // 2*4 Byte Axis 3 PDO 2 Data (Only if there are 3 or more axis and bExtendedPDOSupport) 
    // There are no gaps in the mapping, if 1 or more axis are missing then the offset shift accordingly
    if sAxisInfo.usHighestAxisNrb then
      
      sAccesses.LenWriteIso := MDD2000VVBASE_PDO_AXIS_SIZE;
      
      if bExtendedPDOSupport then
        sAccesses.LenWriteIso2 := MDD2000VVBASE_PDO_AXIS_SIZE2;
      end_if;
      
      for usCounter := 0 to sAxisInfo.usHighestAxisNrb-1 do
      
        sAccesses.pWriteIso[usCounter]$pVoid := sAccesses.WriteAccessIso.pData + udTmpAxisOffset + (MDD2000VVBASE_PDO_AXIS_OFFSET*usCounter);
        
        if bExtendedPDOSupport then
          sAccesses.pWriteIso2[usCounter]$pVoid  := sAccesses.WriteAccessIso.pData + udTmpAxisOffset + (MDD2000VVBASE_PDO_AXIS_OFFSET*sAxisInfo.usHighestAxisNrb) + (MDD2000VVBASE_PDO_AXIS_OFFSET2 * usCounter) ;
        end_if;
        
      end_for;
    end_if;
  else
  
    //if add later is active the call is from cyclic task
    if bAddDoLater = TRUE then
        LogError("@078B (MDD2000VVBase::AddIsoAccesses) There is no axis object placed, due to this the drive is not initialzed!");    
    end_if;
    
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL MDD2000VVBase::AddAsyAccesses
  VAR
    dataADDDO   : t_AddDOCfg;
  	MyPara     : CmdStruct;
    MyResult     : results;
    usCounter   : USINT;
    aLogVal1 : DINT;
  END_VAR
  
  //set axis available from hardware
  sAxisInfo.AxisAvailableHW := sTypeLabel.AxisAvailable;
  
  //set amount of axis available read out from drive
  sAxisInfo.usMaxAxisAvailable := GetAxisNoHW(sTypeLabel.AxisAvailable);
    
  //check for active axis objects
  if sAxisInfo.usMaxAxisAvailable then
    for usCounter := 0 to sAxisInfo.usMaxAxisAvailable-1 do
      if (sAxisInfo.AxisAvailableSW shr usCounter) AND 1 = TRUE then
        //store number of active axis at array
        sAxisData[sAxisInfo.usAxisActiveNo].usPDOArrayNrb              := usCounter;
        sAxisData[sAxisInfo.usAxisActiveNo].usAxisPlaceNr              := usCounter+1;
        sAccesses.WriteAccessAsy[sAxisInfo.usAxisActiveNo].AxisPlaceNr := usCounter+1;
        sAccesses.ReadAccessAsy[sAxisInfo.usAxisActiveNo].AxisPlaceNr  := usCounter+1;
        //add Pipe for receive data
        sAxisData[sAxisInfo.usAxisActiveNo].p_AsyPipeHandle$^void := cPipe_CTor(sizeof(aBuffer), 1);
        sAxisInfo.usAxisActiveNo += 1;
      end_if;
    end_for;
  else
    //exit init if there is no axis object
    LogError("@075E (MDD2000VVBase::AddAsyAccesses) There is no axis object available!");
    return;
  end_if;

  //reset local memory
  _memset(dest:=#dataADDDO, usByte:=0x00, cntr:=sizeof(dataADDDO));

  //Add Asynchrone Read DO
  //************************************************************************************
  //add all read accesses
  dataADDDO.Priority                := _BUS_IF_ASY;
  dataADDDO.RdWr                    := _BUS_IF_READ;
  dataADDDO.ud_WaitForAccessHandle  := 0;

  dataADDDO.ui_length_read     := sizeof(aBuffer);
  dataADDDO.b_UseLocalCopy     := FALSE;

  if sAxisInfo.usAxisActiveNo > 1 then  // 1st Asy DO is always added in AddDefaultAsyAccess
    for usCounter := 1 to sAxisInfo.usAxisActiveNo-1 do

      sAccesses.ReadAccessAsy[usCounter].Offset := 0;
      dataADDDO.ud_addressoff_read  := sAccesses.ReadAccessAsy[usCounter].Offset;

      MyPara.uiCmd     := _BUS_IF_ADD_DO;
      MyPara.aPara[0]  := (#dataADDDO)$DINT;

      ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
      if MyResult.aData[0]$t_BusIFRetvalErrorcode = _BUS_IF_RETVAL_OK then
        sAccesses.ReadAccessAsy[usCounter].Handle := MyResult.aData$t_AddDORet.Handle;
        sAccesses.ReadAccessAsy[usCounter].pData  := MyResult.aData$t_AddDORet.pDataRead;
        sAccesses.pReadAsy[usCounter]$pVoid       := sAccesses.ReadAccessAsy[usCounter].pData;
        sAccesses.ReadAccessAsy[usCounter].Length := dataADDDO.ui_length_read$USINT;

        //change retry timeout for varan do
        MyPara.uiCmd     := _BUS_IF_RESET_DO;
        MyPara.aPara[0]  := (#sAccesses.ReadAccessAsy[usCounter].Handle)$DINT;
        ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
      else
        aLogVal1 := MyResult.aData[0]$DINT;
        HWC_LogPrintf(pThis:=this, format:= "@0747 (MDD2000VVBase::AddAsyAccesses) Failed to add a DO for SDO read data with error %d",#aLogVal1);          
        SetClassState(tClassState:=_DOHandleInvalid);
        return;
      end_if;
    end_for;
  end_if;
  
  
  //Asynchronous DO for filehandling  
  dataADDDO.Priority                := _BUS_IF_ASY;
  dataADDDO.RdWr                    := _BUS_IF_READ;
  dataADDDO.ud_WaitForAccessHandle  := 0;

  dataADDDO.ui_length_read     := sizeof(t_s_MailboxData);
  dataADDDO.b_UseLocalCopy     := FALSE;

  sAccesses.ReadFileAccessAsy.Offset := 0;
  dataADDDO.ud_addressoff_read  := sAccesses.ReadFileAccessAsy.Offset;

  MyPara.uiCmd     := _BUS_IF_ADD_DO;
  MyPara.aPara[0]  := (#dataADDDO)$DINT;

  ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
  if MyResult.aData[0]$t_BusIFRetvalErrorcode = _BUS_IF_RETVAL_OK then
    sAccesses.ReadFileAccessAsy.Handle    := MyResult.aData$t_AddDORet.Handle;
    sAccesses.ReadFileAccessAsy.pData     := MyResult.aData$t_AddDORet.pDataRead;
    sAccesses.pReadFileHandlingAsy$pVoid  := sAccesses.ReadFileAccessAsy.pData;
    sAccesses.ReadFileAccessAsy.Length    := dataADDDO.ui_length_read$USINT;

    //change retry timeout for varan do
    MyPara.uiCmd     := _BUS_IF_RESET_DO;
    MyPara.aPara[0]  := (#sAccesses.ReadFileAccessAsy.Handle)$DINT;
    ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
  else
    aLogVal1 := MyResult.aData[0]$DINT;
    HWC_LogPrintf(pThis:=this, format:= "@0747 (MDD2000VVBase::AddAsyAccesses) Failed to add a DO for SDO read data with error %d",#aLogVal1);          
    SetClassState(tClassState:=_DOHandleInvalid);
    return;
  end_if;
  

  //Add Asynchrone Write DO
  //************************************************************************************
  if sAxisInfo.usAxisActiveNo then
    //add all write accesses
    dataADDDO.Priority                := _BUS_IF_ASY;
    dataADDDO.RdWr                    := _BUS_IF_WRITE;
    dataADDDO.ud_WaitForAccessHandle  := 0;

    dataADDDO.ui_length_write     := sizeof(aBuffer);
    dataADDDO.b_UseLocalCopy      := FALSE;

    for usCounter := 0 to sAxisInfo.usAxisActiveNo-1 do
      sAccesses.WriteAccessAsy[usCounter].Offset := 0;
      dataADDDO.ud_addressoff_write := sAccesses.WriteAccessAsy[usCounter].Offset;

      MyPara.uiCmd     := _BUS_IF_ADD_DO;
      MyPara.aPara[0]  := (#dataADDDO)$DINT;

      ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
      if MyResult.aData[0]$t_BusIFRetvalErrorcode = _BUS_IF_RETVAL_OK then
        sAccesses.WriteAccessAsy[usCounter].Handle  := MyResult.aData$t_AddDORet.Handle;
        sAccesses.WriteAccessAsy[usCounter].pData   := MyResult.aData$t_AddDORet.pDataWrite;
        sAccesses.pWriteAsy[usCounter]$pVoid        := sAccesses.WriteAccessAsy[usCounter].pData;
        sAccesses.WriteAccessAsy[usCounter].Length  := dataADDDO.ui_length_write$USINT;

        //change retry timeout for varan do
        MyPara.uiCmd     := _BUS_IF_RESET_DO;
        MyPara.aPara[0]  := (#sAccesses.WriteAccessAsy[usCounter].Handle)$DINT;
        ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
      else
        LogError("@0748 (MDD2000VVBase::AddAsyAccesses) Failed to add a DO for SDO write data");
        SetClassState(tClassState:=_DOHandleInvalid);
        return;
      end_if;
    end_for;
  end_if;
  
  //Asynchronous DO for filehandling 
  dataADDDO.Priority                := _BUS_IF_ASY;
  dataADDDO.RdWr                    := _BUS_IF_WRITE;
  dataADDDO.ud_WaitForAccessHandle  := 0;

  dataADDDO.ui_length_write     := sizeof(t_s_MailboxData);
  dataADDDO.b_UseLocalCopy      := FALSE;

  sAccesses.WriteFileAccessAsy.Offset := 0;
  dataADDDO.ud_addressoff_write := sAccesses.WriteFileAccessAsy.Offset;

  MyPara.uiCmd     := _BUS_IF_ADD_DO;
  MyPara.aPara[0]  := (#dataADDDO)$DINT;

  ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
  if MyResult.aData[0]$t_BusIFRetvalErrorcode = _BUS_IF_RETVAL_OK then
    sAccesses.WriteFileAccessAsy.Handle     := MyResult.aData$t_AddDORet.Handle;
    sAccesses.WriteFileAccessAsy.pData      := MyResult.aData$t_AddDORet.pDataWrite;
    sAccesses.pWriteFileHandlingAsy$pVoid   := sAccesses.WriteFileAccessAsy.pData;
    sAccesses.WriteFileAccessAsy.Length     := dataADDDO.ui_length_write$USINT;

    //change retry timeout for varan do
    MyPara.uiCmd     := _BUS_IF_RESET_DO;
    MyPara.aPara[0]  := (#sAccesses.WriteFileAccessAsy.Handle)$DINT;
    ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
  else
    LogError("@0748 (MDD2000VVBase::AddAsyAccesses) Failed to add a DO for SDO write data");
    SetClassState(tClassState:=_DOHandleInvalid);
    return;
  end_if;


END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000VVBase::RtWork
	VAR_INPUT
		EAX 	: UDINT;
	END_VAR
	VAR_OUTPUT
		state (EAX) 	: UDINT;
	END_VAR
  VAR
  	calloption  : UDINT;
    usCounter   : USINT;
		MyPara 	    : CmdStruct;
		MyResult	  : results;
    dRetCode    : iprStates;
    TempInputs  : ts_DriveInputs;
    pAxisData   : ^t_AxisData;
  END_VAR

  calloption := EAX;
  state      := READY;

  case eInitModulSSW of
    //******************************************************************************************************************************************
    _ReadTypeLabel:
    //is done in cyclic

    //******************************************************************************************************************************************
    _ChangeSafetyDO:
    //is done in cyclic

    //******************************************************************************************************************************************
    _ChangeDriveDO:
    //is done in cyclic

    //******************************************************************************************************************************************
    _ConnectEvent:
    //is done in cyclic

    //******************************************************************************************************************************************
    _StopPostInit:
    //is done in cyclic

    //******************************************************************************************************************************************
    _AddSafetyRtIsoDO:
      // add iso and asy accesses for safety
      if sConnSafety.bdSafetyFlags.bIsoDOCreated = FALSE then
        //call safety class if logged in and ok
        if sConnSafety.bdSafetyFlags.bSafetyOK then
          //init accesses of connected safety part
          //************************************************************************************
          MyPara.uiCmd    := _BUSIF_VVDRIVE_ADD_ISO_DATAOBJECT;
          MyPara.aPara[0] := bdGeneralFlags.bAddDOListAvailable;
          dRetCode        := sConnSafety.pCallback^.pSvrChCmd.NewInst(#MyPara,#MyResult);

          sConnSafety.bdSafetyFlags.bIsoDOCreated := TRUE;

          if dRetCode <> READY then
            sConnSafety.bdSafetyFlags.bSafetyOK := FALSE;
          end_if;
        end_if;
      end_if;
      eInitModulSSW := _AddLocalRtIsoDO;

    //******************************************************************************************************************************************
    _AddLocalRtIsoDO:
    
      eInitModulSSW := _ChangeSafetyRtDO;
      
      // add iso and asy accesses for drive
      if bdGeneralFlags.bIsoDOCreated = FALSE then
        dRetcode := AddIsoAccesses(bAddDoLater:=FALSE);
        if dRetCode = READY then
          bdGeneralFlags.bIsoDOCreated := TRUE;
        else 
          eInitModulSSW := _ErrorInit;  //Abort initialization
        end_if;
      end_if;

    //******************************************************************************************************************************************
    _ChangeSafetyRtDO:
      //Change address of safety DO
      if sConnSafety.pCallback & sConnSafety.bdSafetyFlags.bSafetyOK then
        MyPara.uiCmd := _BUSIF_VVDRIVE_CHANGE_DO_ADDRESSES;
        dRetCode := sConnSafety.pCallback^.pSvrChCmd.NewInst(#MyPara,#MyResult);
        if dRetCode <> READY then
          sConnSafety.bdSafetyFlags.bSafetyOK := FALSE;
        end_if;
      end_if;
      eInitModulSSW := _ChangeDriveRtDO;

    //******************************************************************************************************************************************
    _ChangeDriveRtDO:
    
      if sAccesses.WriteAccessIso.pData then
        //reset write memory
        _memset(dest:=sAccesses.WriteAccessIso.pData, usByte:=0x00, cntr:=sAccesses.WriteAccessIso.Length);      
      end_if;
      
      eInitModulSSW := _StartSafetyRtIsoDO;

    //******************************************************************************************************************************************
    _StartSafetyRtIsoDO:
      //Realtime PreScan
      //safety part
      //******************************************************************************************************************************************
      if calloption = CALL_OPTION_RT_PRESCAN then
        //enable safety DO
        //************************************************************************************
        if sConnSafety.pCallback & sConnSafety.bdSafetyFlags.bSafetyOK then
          MyPara.uiCmd := _BUSIF_VVDRIVE_START_ISO_DATAOBJECT;
          sConnSafety.pCallback^.pSvrChCmd.NewInst(#MyPara,#MyResult);
        end_if;

        eInitModulSSW := _StartDriveRtIsoDO;
        
      end_if;

    //******************************************************************************************************************************************
    _StartDriveRtIsoDO:
      //Realtime PreScan
      //drive part
      //******************************************************************************************************************************************
      if calloption = CALL_OPTION_RT_PRESCAN then
      
        //only start iso data objects if an axis is available
        if sAxisInfo.usAxisActiveNo then
          //Isochrone Read DO
          //************************************************************************************
          //start dataobjects
          if sAccesses.ReadAccessIso.Handle then
            EnableDO(AccessHandle:=sAccesses.ReadAccessIso.Handle);
            
          else
            SetClassState(tClassState:=_DOHandleInvalid);
            eInitModulSSW := _ErrorInit;
            return;
          end_if;

          //Isochrone Write DO
          //************************************************************************************
          if sAccesses.WriteAccessIso.Handle then
            EnableDO(AccessHandle:=sAccesses.WriteAccessIso.Handle);
          else
            SetClassState(tClassState:=_DOHandleInvalid);
            eInitModulSSW := _ErrorInit;
            return;
          end_if;        
        end_if;
            
        eInitModulSSW := _DefaultWork;
        ClassState    := _NotInitialized;
      end_if;

    //******************************************************************************************************************************************
    _DefaultWork:
      // safety part
      //******************************************************************************************************************************************
      //call safety class if logged in and safety class is ok
      if sConnSafety.pThisSafety <> NIL & sConnSafety.bdSafetyFlags.bSafetyOK = TRUE then
        //Realtime PreScan
        //********************************************************************************
        if sConnSafety.usCallOption.RtPre
        & calloption = CALL_OPTION_RT_PRESCAN then
          sConnSafety.pThisSafety^.RtWork(EAX:=calloption);

        //Realtime PostScan
        //********************************************************************************
        elsif sConnSafety.usCallOption.RtPost
        & calloption = CALL_OPTION_RT_POSTSCAN then
          sConnSafety.pThisSafety^.RtWork(EAX:=calloption);
        end_if;

      end_if;

      //only call rt if there is an active axis object
      if sAxisInfo.usAxisActiveNo then

        //Realtime PreScan
        //******************************************************************************************************************************************
        if calloption = CALL_OPTION_RT_PRESCAN then
           // drive part
          //******************************************************************************************************************************************
          if (ClassState = _ClassOk | ClassState = _NotInitialized) then

            //update in right intervall
            udTimeCounter -= 1;
            if ( udTimeCounter <> 0 ) then
              bdGeneralFlags.bUpdateThisTime := FALSE;
              return;
            else
              bdGeneralFlags.bUpdateThisTime := TRUE;
              udTimeCounter := TimeMultiplier;
            end_if;
            
            case eRtSSW of
              //******************************************************************************************************************************************
              _InitAxis:

              //******************************************************************************************************************************************
              _WaitForSynchrony:

                for usCounter := 0 to (sAxisInfo.usAxisActiveNo-1) do
                  pAxisData := #sAxisData[usCounter];
                
                  //only copy data if Axis is used
                  if ( pAxisData^.e_AxisState <> _NotUsed ) then
                    //set axis state to ok
                    pAxisData^.e_AxisState := _AxisOk;
                    
                    //copy synchron values
                    _memcpy(#pAxisData^.s_ReadValues.a_SyncValues[0], sAccesses.pReadIso[(pAxisData^.usPDOArrayNrb)], sAccesses.LenReadIso);
                    
                    if bExtendedPDOSupport then
                      _memcpy(#pAxisData^.s_ReadValues.a_SyncValues[sAccesses.LenReadIso/sizeof(DINT)], sAccesses.pReadIso2[(pAxisData^.usPDOArrayNrb)], sAccesses.LenReadIso2);
                    end_if;
                    
                  end_if;
                end_for;
                
                
                //hardware is ready for user application
                ClassState := _ClassOk;
                eRtSSW     := _Operational;

              //******************************************************************************************************************************************
              _Operational:               
                for usCounter := 0 to (sAxisInfo.usAxisActiveNo-1) do
                  pAxisData := #sAxisData[usCounter];
                
                  //only copy data if Axis is used
                  if ( pAxisData^.e_AxisState <> _NotUsed ) then
                    //set axis state to ok
                    pAxisData^.e_AxisState := _AxisOk;
                    
                    _memcpy(#pAxisData^.s_ReadValues.a_SyncValues[0], sAccesses.pReadIso[(pAxisData^.usPDOArrayNrb)], sAccesses.LenReadIso);
                    
                    if bExtendedPDOSupport then
                      _memcpy(#pAxisData^.s_ReadValues.a_SyncValues[sAccesses.LenReadIso/sizeof(DINT)], sAccesses.pReadIso2[(pAxisData^.usPDOArrayNrb)], sAccesses.LenReadIso2);
                    end_if;
                    
                  end_if;
                end_for;
            end_case;

            if sAccesses.pReadDigIn then
              TempInputs := sAccesses.pReadDigIn^;
              Input1 := TempInputs.bsDigIn.1;
              Input2 := TempInputs.bsDigIn.2;
              Input3 := TempInputs.bsDigIn.3;
              Input4 := TempInputs.bsDigIn.4;
              Input5 := TempInputs.bsDigIn.5;
              Input6 := TempInputs.bsDigIn.6;
            
              if bExtendedPDOSupport then
              
                SafetyRunState := (to_udint(TempInputs.SafetyRunState))$MDD2000MngBase::t_e_MDD2000SafetyRunState;
              
              end_if;

            end_if;
          end_if;

        //******************************************************************************************************************************************
        //Realtime PostScan
        elsif calloption = CALL_OPTION_RT_POSTSCAN then

          if bdGeneralFlags.bUpdateThisTime
          & ClassState = _ClassOk
          & eRtSSW = _Operational then
          
            for usCounter := 0 to (sAxisInfo.usAxisActiveNo-1) do
            
              pAxisData := #sAxisData[usCounter];
            
              //only copy data if Axis is used
              if ( pAxisData^.e_AxisState <> _NotUsed ) then
                
                _memcpy(sAccesses.pWriteIso[(pAxisData^.usPDOArrayNrb)], #pAxisData^.s_WriteValues.a_SyncValues[ 0 ], sAccesses.LenWriteIso);
                
                if bExtendedPDOSupport then
                  _memcpy(sAccesses.pWriteIso2[(pAxisData^.usPDOArrayNrb)], #pAxisData^.s_WriteValues.a_SyncValues[ sAccesses.LenWriteIso/sizeof(DINT) ], sAccesses.LenWriteIso2);
                end_if;
  
              end_if;
            end_for;
          end_if;
          
          if sDriveType.psDriveMDPErrorInfo <> NIL & sDriveType.eDriveType = _MDDType then
            sAccesses.pWriteIsoErrorInfo^ := sDriveType.psDriveMDPErrorInfo^$HDINT AND 0x0000FF00;
          end_if;
          
        end_if;  //if calloption = CALL_OPTION_RT_PRESCAN / CALL_OPTION_RT_POSTSCAN
      end_if; //if sAxisInfo.usAxisActiveNo

  end_case;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000VVBase::CyWork
	VAR_INPUT
		EAX 	: UDINT;
	END_VAR
	VAR_OUTPUT
		state (EAX) 	: UDINT;
	END_VAR
  VAR
  	dRetCode  : iprStates;
    usCounter : USINT;
		MyPara 	  : CmdStruct;
		MyResult	: results;
  END_VAR

  //call safety class if logged in and safety class is ok
  if (sConnSafety.pThisSafety <> NIL) &   // Do not check for sConnSafety.bdSafetyFlags.bSafetyOK = TRUE, otherwise a wrong configuration (PDO Len) can not be corrected by the SCP via SSDO
     (sConnSafety.usCallOption.Cyclic) then
    sConnSafety.pThisSafety^.CyWork(EAX:=0);
  end_if;

  state := READY;

  case eInitModulSSW of
    //******************************************************************************************************************************************
  	_ReadTypeLabel:
      //readout typelabel for iso and asy offsets
      dRetCode := ReadTypeLabel();
      if dRetCode = READY then
        eInitModulSSW := _AddLocalAsyDO;
      elsif dRetCode = ERROR then
        LogError("@04B4 (MDD2000VVBase::CyWork) Failed to read typelabel of module");
        SetClassState(tClassState:=_DeviceError);
        eInitModulSSW := _StopPostInit;
      else
        // check timeout
        if ((ops.tAbsolute - sSDOVars.udTimeOutTypeLabel) > (MDD2000VVBASE_SDO_TYPELABEL_TIMEOUT)) then
          DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[0].Handle);
          LogError("@074C (MDD2000VVBase::CyWork) Timeout while waiting for the type label");
          SetClassState(tClassState:=_TimeoutInInit);
          eInitModulSSW := _StopPostInit;
        end_if;
      end_if;

    //******************************************************************************************************************************************
    _AddLocalAsyDO:
      // add iso and asy accesses for drive
      if bdGeneralFlags.bAsyDOCreated = FALSE then
        AddAsyAccesses();
        bdGeneralFlags.bAsyDOCreated := TRUE;
      end_if;
      eInitModulSSW := _AddLocalIsoDO;      

    //******************************************************************************************************************************************
    _AddLocalIsoDO:
      // add iso and asy accesses for drive
      if bdGeneralFlags.bAddDOListAvailable = TRUE then
        eInitModulSSW := _ChangeDriveDO;
        if bdGeneralFlags.bIsoDOCreated = FALSE then
          dRetcode := AddIsoAccesses(bAddDoLater:=bdGeneralFlags.bAddDOListAvailable);
          if dRetCode = READY then
            bdGeneralFlags.bIsoDOCreated := TRUE;
          else
            eInitModulSSW := _ErrorInit;  //Abort initialization
          end_if;
        end_if;
      else
        //iso Dataobjects must be added at rt task
        eInitModulSSW := _ChangeDriveDO;
      end_if;

    //******************************************************************************************************************************************
    _ChangeDriveDO:
      // set sdo offsets for asynchrone parameter
      sAxisInfo.usTmpAxisNbr := 0;
      if sAxisInfo.usAxisActiveNo then
        for usCounter := 0 to sAxisInfo.usMaxAxisAvailable-1 do
          if (sAxisInfo.AxisAvailableSW shr usCounter) AND 1 = TRUE then
            sAccesses.ReadAccessAsy[sAxisInfo.usTmpAxisNbr].MailboxOffset  := (sTypeLabel.aMailBoxes[sAccesses.ServiceIDNr].Response.hiAddress + (MDD2000VVBASE_SDO_MAILBOX_OFFSET * usCounter));
            sAccesses.WriteAccessAsy[sAxisInfo.usTmpAxisNbr].MailboxOffset := (sTypeLabel.aMailBoxes[sAccesses.ServiceIDNr].Request.hiAddress  + (MDD2000VVBASE_SDO_MAILBOX_OFFSET * usCounter));
            sAxisInfo.aActAxisNrb[usCounter]  := sAxisInfo.usTmpAxisNbr;
            sAxisInfo.usTmpAxisNbr += 1;
          end_if;
        end_for;
        
        //reset variable
        sAxisInfo.usTmpAxisNbr := 0;
        
        // only change drive DO's if they are already added
        if bdGeneralFlags.bIsoDOCreated = TRUE then
          if sAccesses.WriteAccessIso.pData then
            //reset write memory
            _memset(dest:=sAccesses.WriteAccessIso.pData, usByte:=0x00, cntr:=sAccesses.WriteAccessIso.Length);      
          end_if;
        end_if;
      end_if;
      
      eInitModulSSW := _InitAxisMailBox;
      
    //******************************************************************************************************************************************
    _InitAxisMailBox:
      if bdGeneralFlags.bAlreadyAxisInit = FALSE then //Init all Axis
        for usCounter := 0 to (sAxisInfo.usAxisActiveNo-1) do
          //set right para state	
          sAxisData[usCounter].us_ParaReady  := _IdleState;
          sAxisData[usCounter].e_AxisState   := _NoInit;
        end_for;

        // initialize filetransfer (The Filetask will be closed if its still running, by setting the SSW to _IdleFileHandling)
        DisableDO(AccessHandle:=sAccesses.ReadFileAccessAsy.Handle);
        DisableDO(AccessHandle:=sAccesses.WriteFileAccessAsy.Handle);
        sFileHandling.ReadOrWriteFileSuccessful := 0;        
        sFileHandling.dProgress := 0;
        sFileHandling.dGetFileSizeStarted := 0;
        sFileHandling.bFinishFileTransfer := FALSE;
        sFileHandling.eFileHandlingSSW := t_FileHandlingSSW::_IdleFileHandling;
        sFileHandling.eFileHandlingSSWErrorStep := t_FileHandlingSSW::_IdleFileHandling;
        
        bdGeneralFlags.bAlreadyAxisInit := TRUE;
      end_if;
      
      //switch Axis
      case (sAxisInfo.usTmpAxisNbr) of

        0:	sAxisInfo.usTmpAxisNbr += 1;

        1..MDD2000VVBASE_MAX_AXIS: 	//wait until Axis are initialized
          if sAxisInfo.usTmpAxisNbr <= sAxisInfo.usAxisActiveNo then
            if InitAxis(usAxisArray := sAxisInfo.usTmpAxisNbr-1) = _CyIdle$DINT then
              sAxisInfo.usTmpAxisNbr 	+=1;
              eInitDriveSSW      := _SetDataObjectOn;
            end_if;
          else
            sAxisInfo.usTmpAxisNbr := MDD2000VVBASE_MAX_AXIS+1;
          end_if;

        else
          //class is ready
          bdGeneralFlags.bMailBoxInitOk  := TRUE;
          sAxisInfo.usTmpAxisNbr 	:= 0;
                            
          eInitModulSSW  := _GetSafetyInfos;

      end_case;
      
    //******************************************************************************************************************************************
    _GetSafetyInfos:
      if sConnSafety.pCallback & sConnSafety.bdSafetyFlags.bSafetyOK then
        
        MyPara.uiCmd := _BUSIF_VVDRIVE_GET_SAFETY_INFOS;
        dRetCode := sConnSafety.pCallback^.pSvrChCmd.NewInst(#MyPara,#MyResult);
        if dRetCode = READY then
          eInitModulSSW := _AddSafetyIsoDO;
        elsif dRetCode = BUSY then
          
          GetObjectValue(0);  // _GetSafetyInfos need DS402 access to drive
        elsif dRetCode = ERROR then
          LogError("@074D (MDD2000VVBase::CyWork) Error while get safety infos.");
          sConnSafety.bdSafetyFlags.bSafetyOK := FALSE;
          eInitModulSSW := _ConnectEvent;
        end_if;

      else
        eInitModulSSW := _ConnectEvent;
      end_if;

    //******************************************************************************************************************************************
    _AddSafetyIsoDO:
      // add iso and asy accesses for safety
      if sConnSafety.bdSafetyFlags.bIsoDOCreated = FALSE then
        //call safety class if logged in and ok
        if sConnSafety.bdSafetyFlags.bSafetyOK then
          //init accesses of connected safety part
          //************************************************************************************
          MyPara.uiCmd    := _BUSIF_VVDRIVE_ADD_ISO_DATAOBJECT;
          MyPara.aPara[0] := bdGeneralFlags.bAddDOListAvailable;
          dRetCode        := sConnSafety.pCallback^.pSvrChCmd.NewInst(#MyPara,#MyResult);

          sConnSafety.bdSafetyFlags.bIsoDOCreated := TRUE;

          if dRetCode <> READY then
            LogError("@0746 (MDD2000VVBase::CyWork) Failed to add safety Accesses.");
            sConnSafety.bdSafetyFlags.bSafetyOK := FALSE;
          end_if;
        end_if;
      end_if;
      eInitModulSSW := _ChangeSafetyDO;

    //******************************************************************************************************************************************
    _ChangeSafetyDO:
      //Add Safety DO
      if sConnSafety.pCallback & sConnSafety.bdSafetyFlags.bSafetyOK then
        MyPara.uiCmd := _BUSIF_VVDRIVE_CHANGE_DO_ADDRESSES;
        dRetCode := sConnSafety.pCallback^.pSvrChCmd.NewInst(#MyPara,#MyResult);
        if dRetCode <> READY then
          sConnSafety.bdSafetyFlags.bSafetyOK := FALSE;
        end_if;
      end_if;
      eInitModulSSW := _ConnectEvent;

    //******************************************************************************************************************************************
    _ConnectEvent:
      //call connect event
      ConnectEvent();
      eInitModulSSW := _StopPostInit;

    //******************************************************************************************************************************************
  	_StopPostInit:
      // stop blocking the init
      if bdGeneralFlags.bPostInitFinished = FALSE then
        bdGeneralFlags.bPostInitFinished := TRUE;
        MyPara.uiCmd := _BUS_IF_POST_INIT_FINISHED;
        ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);

        if MyResult.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
          LogError("@074B (MDD2000VVBase::CyWork) Failed to tell the manager to go on with initialisation");
        end_if;
      end_if;
      //check for error of class and stop initialisation if there is one
      if (ClassState = _ClassOk | ClassState = _NotInitialized) then
        if bdGeneralFlags.bIsoDOCreated = TRUE then
          eInitModulSSW := _StartSafetyRtIsoDO;
        else
          eInitModulSSW := _AddSafetyRtIsoDO;
        end_if;
      else
        eInitModulSSW := _ErrorInit;
      end_if;

    //******************************************************************************************************************************************
  	_StartSafetyRtIsoDO:
    //start Safety Do is done at RtWork task

    //******************************************************************************************************************************************
    _StartDriveRtIsoDO:
    //start Drive Do is done at RtWork task
      

    //******************************************************************************************************************************************
  	_DefaultWork:
      // safety part
      //******************************************************************************************************************************************

      // drive part
      //******************************************************************************************************************************************
      if (ClassState = _ClassOk | ClassState = _NotInitialized)
      & sAxisInfo.usAxisActiveNo > 0 then

        if eRtSSW = _InitAxis then
          eRtSSW := _GetSendParaList;
        end_if;
        
        if eRtSSW = _GetSendParaList | eRtSSW = _Operational then
          for usCounter := 0 to sAxisInfo.usAxisActiveNo-1 do
            // update asynchron parameters
            GetObjectValue(usCounter);
          end_for;
          
          #ifdef _BUSIF_VVDRIVE_READ_NPARA_MB
            //function for additional parameter handling
            GetObjectValueNew();            
          #endif
          
          //Call file handling SSW
          ProcessFileHandling();

        end_if;
        
        
        if sDriveType.psDriveMDPErrorInfo = NIL & sDriveType.eDriveType = _MDDType then        
          MyPara.uiCmd    := _BUSIF_VVDRIVE_ADD_MDD2000_MDP_ERROR;
          MyPara.aPara[0] := sDriveType.uiHwPathLen;
          MyPara.aPara[1] := sDriveType.pHwPath$DINT;
          MyPara.aPara[2]$UDINT := sDriveType.eDriveType;
          
          //if the next object is the varanmanager dont call the newinst (VaranIn is not connected at VM)
          if IsClientConnected(input:=#toVaranIn)
          & (sDriveType.pHwPath + (sDriveType.pHwPath^$UINT-1))^ <> HWT_ESCAPE_VARAN then
          
            dRetCode := toVaranIn.VaranIn.NewInst(pPara:=#MyPara, pResult:=#MyResult);

            if dRetCode = READY & MyResult.aData[0]$t_BusIFRetvalErrorcode = _BUS_IF_RETVAL_OK then
              sDriveType.psDriveMDPErrorInfo := MyResult.aData[4]$^ts_DriveInputs;
              sDriveType.uiHwPathLenMDP      := MyResult.aData[8]$UINT;
              sDriveType.pHwPathMDP          := MyResult.aData[10]$^USINT;              
            elsif dRetCode = ERROR then
              if bdErrorSL.GetNextMDP = FALSE then
                LogError("@0778 (MDD2000VVBase::CyWork) [SL] Error there is no MDP Hardware!");
                bdErrorSL.GetNextMDP := TRUE;
              end_if;
            end_if;
          else
            if bdErrorSL.GetNextMDP = FALSE then
              LogError("@0778 (MDD2000VVBase::CyWork) [SL] Error there is no MDP Hardware!");
              bdErrorSL.GetNextMDP := TRUE;
            end_if;
          end_if;
        end_if;  
      end_if;  

    //******************************************************************************************************************************************
  	_ErrorInit: //class is not correct initalized -> do nothing

  end_case;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000VVBase::ConnectEvent
  VAR
		MyPara 	  : CmdStruct;
		MyResult	: results;
  END_VAR

  //initial value to run SafetyBaseFSoE
  bdGeneralFlags.bOnline := TRUE;

  udTimeCounter  := TimeMultiplier;
  udTimemarkInit := ops.tAbsolute;

  if pCallBackServer then
    WR(pt:=pCallBackServer, dData:=sAxisInfo.AxisAvailableHW$DINT);
  end_if;

  // set online server first on 1 if data is valid
  MyPara.uiCmd    := _BUS_IF_SET_ONLINE;
  MyPara.aPara[0] := bdGeneralFlags.bOnline;

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

  if MyResult.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
    LogError("@0079 (MDD2000VVBase::ClassState::NewInst) Failed to set Online server.");
  end_if;

  //route data to connected safety class
  if sConnSafety.pCallback & sConnSafety.bdSafetyFlags.bSafetyOK then
    MyPara.uiCmd := _BUS_IF_HWCONNECT;
    sConnSafety.pCallback^.pSvrChCmd.NewInst(#MyPara,#MyResult);
  end_if;

  //---------------------------------------------------------------------------------------------------------
  //class is not initialized
  sTimeVars.bTimeIsSet  := FALSE;
  sTimeVars.udLastWrite -= MDD2000VVBASE_WRITE_PLCTIME;
  eInitDriveSSW     := _SetDataObjectOn;
  eRtSSW            := _InitAxis;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000VVBase::DisconnectEvent
VAR
	usCounter : USINT;
END_VAR

  // Reset axis data
  for usCounter := 0 to (MDD2000VVBASE_MAX_AXIS-1) do
    sAxisData[usCounter].e_AxisState := _NotUsed;
  end_for;

  bdGeneralFlags.bMailBoxInitOk := FALSE;
  bdGeneralFlags.bOnline := FALSE;
  bdGeneralFlags.bAlreadyAxisInit := FALSE;

  DisableDO(AccessHandle:=sAccesses.ReadAccessIso.Handle);
  DisableDO(AccessHandle:=sAccesses.WriteAccessIso.Handle);      
  
  //disable DO for filehandling
  DisableDO(AccessHandle:=sAccesses.ReadFileAccessAsy.Handle);
  DisableDO(AccessHandle:=sAccesses.WriteFileAccessAsy.Handle);

  //reset do length to get a change do if module is reconnected
  sAccesses.ReadFileAccessAsy.OldLength  := 0;
  sAccesses.WriteFileAccessAsy.OldLength  := 0;


  if sAxisInfo.usAxisActiveNo then
    for usCounter := 0 to sAxisInfo.usAxisActiveNo-1 do

      //disable asy do
      DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[usCounter].Handle);
      DisableDO(AccessHandle:=sAccesses.WriteAccessAsy[usCounter].Handle);

      //reset do length to get a change do if module is reconnected
      sAccesses.ReadAccessAsy[usCounter].OldLength  := 0;
      sAccesses.WriteAccessAsy[usCounter].OldLength  := 0;

      //look if Axis are in use
      sAxisData[usCounter].e_AxisState  := _NotUsed;
      sAxisData[usCounter].b_ListActive := FALSE;
      sAxisData[usCounter].us_ParaReady := _IdleState;
    end_for;
  else
   //disable asy do
    DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[0].Handle);
  end_if;
  
  // SSW Must be reset in connect because RtWork and CyWork may be called a few times after Disconnect (VARAN Task Priority is below Cyclic.)
  // => eInitModulSSW := _ReadTypeLabel; May cause are warning that Read TypeLabel Timeout
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000VVBase::InterruptEvent

  // set only the state (we're in the interrupt and have to be fast)
  bdGeneralFlags.bMailBoxInitOk := FALSE;
  bdGeneralFlags.bOnline := FALSE;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000VVBase::DriveBusIF::NewInst
	VAR_INPUT
		pPara 	: ^CmdStruct;
		pResult 	: ^results;
	END_VAR
	VAR_OUTPUT
		ret_code 	: iprStates;
	END_VAR
  VAR
  	BusIFType : t_BusIFType;
  END_VAR


  ret_code := READY;

  case pPara^.uiCmd of
   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_STARTCOMMUNICATION:
      StartCommunication(pServer4CallBack  :=(pPara^.aPara[2]$^BDINT) );
      sAxisInfo.AxisAvailableSW := pPara^.aPara[3]$BDINT;

  //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_SER_NO_LEN:
      pPara^.uiCmd    := _BUS_IF_GET_PARAM;
      pPara^.aPara[0] := _BUS_IF_SERIALNO_LENGTH;
      ToBusInterface.NewInst(pPara:=pPara, pResult:=pResult);

      if pResult^.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
        LogError("@0750 (MDD2000VVBase::DriveBusIF) Failed to get Parameter from BusIF");
        ret_code := ERROR;
      else
        pResult^.aData[0]$UDINT := pResult^.aData[4]$UDINT;
      end_if;

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_SER_NO_DATA:
      pPara^.uiCmd    := _BUS_IF_GET_PARAM;
      pPara^.aPara[3]$UDINT  := pPara^.aPara[2]$UDINT;
      pPara^.aPara[2]$UDINT  := pPara^.aPara[1]$UDINT;
      pPara^.aPara[1]$^USINT := pPara^.aPara[0]$^USINT;
      pPara^.aPara[0] := _BUS_IF_SERIALNO_DATA;

      ToBusInterface.NewInst(pPara:=pPara, pResult:=pResult);

      if pResult^.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
        LogError("@0750 (MDD2000VVBase::DriveBusIF) Failed to get Parameter from BusIF");
        ret_code := ERROR;
      end_if;

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_SET_PARALIST:
      SetParaList(usAxis      := (pPara^.aPara[0])$USINT
                , p_list      := (pPara^.aPara[1])$^void
                , ui_counter  := (pPara^.aPara[2])$UINT
                );

    //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_CREATE_DEF_PARALIST:
      if (pPara^.aPara[2] < MDD2000VVBASE_MAX_AXIS) & (sAxisData[pPara^.aPara[2]].e_AxisState <> _NotUsed) then
        sSkipParameter[pPara^.aPara[2]].us_No    := (pPara^.aPara[1])$USINT; // number of values in memory
        sSkipParameter[pPara^.aPara[2]].p_Values := (pPara^.aPara[0])$^USINT; // pointer on memory
      end_if;

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_GET_PARA_STATE:
      pResult^.aData[0]$DINT  := GetParameterState(usAxis := pPara^.aPara[0]$USINT);

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_SET_PARAMETER:
      pResult^.aData[0]$DINT := SetParameter( usAxis        := (pPara^.aPara[0])$USINT
                                            , uiParaID      := (pPara^.aPara[1])$UINT
                                            , usParaSubID   := (pPara^.aPara[2])$USINT
                                            , usRdWr        := (pPara^.aPara[3])$USINT
                                            , pvalue        := (pPara^.aPara[4])$^DINT
                                            , bsDataInfo    := (pPara^.aPara[5])$BSINT
                                            );

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_GET_PARAMETER:
      pResult^.aData[0]$DINT := ( GetParameter(usAxis := pPara^.aPara[0]$USINT
                                            , pRetcode:= #ret_code)
                                )$DINT;

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_GET_CMD_STATE:
      pPara^.uiCmd := _BUS_IF_GET_CLASS_STATE;
      ToBusInterface.NewInst(pPara:=pPara, pResult:=pResult);
      if pResult^.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
        LogError("@0751 (MDD2000VVBase::DriveBusIF) Failed to get class state.");
      else
        if pResult^.aData[4]$t_e_VaranErrors <> _ClassOk then
          ClassState := pResult^.aData[4]$t_e_VaranErrors;
        end_if;
      end_if;
      pResult^.aData[0]$DINT := ClassState$DINT;

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_EXTERN_INIT_FINISH:
      ExternInitFinished();

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_GET_AXIS_WR_PTR:
      pResult^.aData[0]$DINT := (GetAxisWrPtr(usAxis := pPara^.aPara[0]$USINT))$DINT;

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_GET_AXIS_RD_PTR:
      pResult^.aData[0]$DINT := (GetAxisRdPtr(usAxis := pPara^.aPara[0]$USINT))$DINT;

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_INIT_DRIVE:
      InitDrive();

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_GET_SYNC_PARA:
      pResult^.aData[0]$DINT := GetSyncParameter( usAxis   := (pPara^.aPara[0])$USINT
                                                , us_value := (pPara^.aPara[1])$USINT
                                                , p_data   := (pPara^.aPara[2])$^DINT
                                                );

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_SET_SYNC_PARA:
      pResult^.aData[0]$DINT := SetSyncParameter( usAxis   := (pPara^.aPara[0])$USINT
                                                , us_value := (pPara^.aPara[1])$USINT
                                                , sd_data  := (pPara^.aPara[2])
                                                );

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_GET_DRIVE_INT_State:
      pResult^.aData[0]$DINT  := GetDriveIntState();

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_SDD_GETSERIES:
      //GetSeries ID for MDD2000
      pResult^.aData[0] := 4;

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_READ_FPGA_VERSION:
      pPara^.uiCmd    := _BUS_IF_GET_PARAM;
      pPara^.aPara[0] := _BUS_IF_FPGA_VERSION;
      ToBusInterface.NewInst(pPara:=pPara, pResult:=pResult);

      if pResult^.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
        LogError("@0750 (MDD2000VVBase::DriveBusIF) Failed to get Parameter from BusIF");
        ret_code := ERROR;
      else
        pResult^.aData[0]$HDINT := pResult^.aData[4]$HDINT;
      end_if;

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_READ_RETRY_COUNTER:
      pPara^.uiCmd    := _BUS_IF_GET_PARAM;
      pPara^.aPara[0] := _BUS_IF_RETRYCOUNTER;
      ToBusInterface.NewInst(pPara:=pPara, pResult:=pResult);

      if pResult^.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
        LogError("@0750 (MDD2000VVBase::DriveBusIF) Failed to get Parameter from BusIF");
        ret_code := ERROR;
      else
        pResult^.aData[0]$UDINT := pResult^.aData[4]$UDINT;
      end_if;

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_READ_DEVICEID:
      pPara^.uiCmd    := _BUS_IF_GET_PARAM;
      pPara^.aPara[0] := _BUS_IF_DEVICEID;
      ToBusInterface.NewInst(pPara:=pPara, pResult:=pResult);

      if pResult^.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
        LogError("@0750 (MDD2000VVBase::DriveBusIF) Failed to get Parameter from BusIF");
        ret_code := ERROR;
      else
        pResult^.aData[0]$UDINT := pResult^.aData[4]$UDINT;
      end_if;

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_SET_OBJECT_CALLBACK:
      pDriveMngBase := pPara^.aPara[0]$pVoid;

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_READ_PARAMETER:
      case pPara^.aPara[0] of
        _BUS_IF_DRVMNG_DEVICEADDRESS:
          pPara^.uiCmd    := _BUS_IF_GET_PARAM;
          pPara^.aPara[0] := _BUS_IF_DEVICEADDRESS;
          ToBusInterface.NewInst(pPara:=pPara, pResult:=pResult);

          if pResult^.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
            LogError("@0750 (MDD2000VVBase::DriveBusIF) Failed to get Parameter from BusIF");
            ret_code := ERROR;
          else
            pResult^.aData[0]$HDINT := pResult^.aData[4]$HDINT;
            hdDeviceAddress         := pResult^.aData[4]$HDINT;
          end_if;

        _BUS_IF_DRVMNG_VENDORID:
          pPara^.uiCmd    := _BUS_IF_GET_PARAM;
          pPara^.aPara[0] := _BUS_IF_VENDORID;
          ToBusInterface.NewInst(pPara:=pPara, pResult:=pResult);

          if pResult^.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
            LogError("@0750 (MDD2000VVBase::DriveBusIF) Failed to get Parameter from BusIF");
            ret_code := ERROR;
          else
            pResult^.aData[0]$UDINT := pResult^.aData[4]$UDINT;
          end_if;
        else
          ret_code := ERROR;  //Unknown Parameter 
      end_case;

   //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_WRITE_PARAMETER:
      case pPara^.aPara[0] of
        _BUS_IF_DRVMNG_DISABLE_DEVICE:
          pPara^.uiCmd    := _BUS_IF_SET_PARAM;
          pPara^.aPara[0] := _BUS_IF_DISABLE_DEVICE;
          ret_code := ToBusInterface.NewInst(pPara:=pPara, pResult:=pResult);

        _BUS_IF_DRVMNG_ENABLE_DEVICE:
          pPara^.uiCmd    := _BUS_IF_SET_PARAM;
          pPara^.aPara[0] := _BUS_IF_ENABLE_DEVICE;
          ret_code := ToBusInterface.NewInst(pPara:=pPara, pResult:=pResult);
        else
          ret_code := ERROR;  //Unknown Parameter 
      end_case;

    //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_GET_BUSTYPE:
      // first paramater is datalength of followed data
      if pPara^.aPara[0] = 0 then
        // get connection type of bus interface
        pPara^.uiCmd := _BUS_IF_GET_INTERFACE_TYPE;
        ret_code := ToBusInterface.NewInst(pPara:=pPara, pResult:=pResult);

        if pResult^.aData[0]$t_GetBusCycleTime.retcode <> _BUS_IF_RETVAL_OK then
          ret_code := ERROR;
        else
          BusIFType := pResult^.aData[4]$t_BusIFType;
          if BusIFType = _BUS_IF_TYPE_SDIAS then
            pResult^.uiLng    := 1;
            pResult^.aData[0] := HWT_ESCAPE_SDIAS;
          elsif BusIFType = _BUS_IF_TYPE_VARAN then
            pResult^.uiLng    := 1;
            pResult^.aData[0] := HWT_ESCAPE_VARAN;
          else
            ret_code := ERROR;
          end_if;
        end_if;
      else
        ret_code := ERROR;
      end_if;
      
    //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_GET_FILE:
      
      ret_code := ERROR;
      
      if pPara^.aPara[0] = BUSIF_DRIVEMNGBASE_GET_FILE_CB_VER1 then
      
        ret_code := GetFile(pDestinationDPNE :=  pPara^.aPara[1]$^CHAR
                          , pFileNameDrive   :=  pPara^.aPara[2]$^CHAR
                          , pFilePathDrive   :=  pPara^.aPara[3]$^CHAR
                          , pdError          :=  pPara^.aPara[4]$^DINT
                           );
      
      else
        HWC_LogPrintf(pThis:=this, format:="@0822 (MDD2000VVBase::DriveBusIF) Unsupported version %d of commando BUSIF_DRIVEMNGBASE_GET_FILE detected", #pPara^.aPara[0]);
      end_if;

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

    //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_GET_FILE_STATE:
      
      ret_code := ERROR;      
      
      if pPara^.aPara[0] = BUSIF_DRIVEMNGBASE_GET_FILE_STATE_CB_VER1 then
      
        ret_code := GetFileState( pdError       :=  pPara^.aPara[1]$^DINT
                                , pdProgress    :=  pPara^.aPara[2]$^DINT
                                , pudBytesRead  :=  pPara^.aPara[3]$^UDINT
                                );
      else
        HWC_LogPrintf(pThis:=this, format:="@0823 (MDD2000VVBase::DriveBusIF) Unsupported version %d of commando BUSIF_DRIVEMNGBASE_GET_FILE_STATE detected", #pPara^.aPara[0]);      
      end_if;
      
      pResult^.uiLng := 4;
      pResult^.aData[0]$DINT := BUSIF_DRIVEMNGBASE_GET_FILE_STATE_CB_VERMAX;  //max supported version

    //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_SET_FILE:
      
      ret_code := ERROR;
      
      if pPara^.aPara[0] = BUSIF_DRIVEMNGBASE_SET_FILE_CB_VER1 then
      
        ret_code := SetFile(pWriteData      :=  pPara^.aPara[1]$^cHAR  
                          , udWriteDataLen  :=  pPara^.aPara[2]$UDINT
                          , pFilePathDrive  :=  pPara^.aPara[3]$^cHAR
                          , pFileNameDrive  :=  pPara^.aPara[4]$^cHAR
                          , pdError         :=  pPara^.aPara[5]$^DINT
                          );      
      else
        HWC_LogPrintf(pThis:=this, format:="@0822 (MDD2000VVBase::DriveBusIF) Unsupported version %d of commando BUSIF_DRIVEMNGBASE_SET_FILE detected", #pPara^.aPara[0]);
      end_if;

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

    //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_GET_FILE_SIZE:
      
      ret_code := ERROR;
      
      if pPara^.aPara[0] = BUSIF_DRIVEMNGBASE_GET_FILE_SIZE_CB_VER1 then

        ret_code := GetFileSize(pFileNameDrive  :=  pPara^.aPara[1]$^CHAR     
                              , pFilePathDrive  :=  pPara^.aPara[2]$^CHAR  
                              , pudSize         :=  pPara^.aPara[3]$^UDINT  
                              , pdError         :=  pPara^.aPara[4]$^DINT 
                                );
      else
        HWC_LogPrintf(pThis:=this, format:="@083C (MDD2000VVBase::DriveBusIF) Unsupported version %d of commando BUSIF_DRIVEMNGBASE_GET_FILE_SIZE detected", #pPara^.aPara[0]);
      end_if;

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

    //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_GET_FILE_BUFFER:
      
      ret_code := ERROR;
      
      if pPara^.aPara[0] = BUSIF_DRIVEMNGBASE_GET_FILE_BUFFER_CB_VER1 then
        
        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
                                );
      else
        HWC_LogPrintf(pThis:=this, format:="@083D (MDD2000VVBase::DriveBusIF) Unsupported version %d of commando BUSIF_DRIVEMNGBASE_GET_FILE_BUFFER detected", #pPara^.aPara[0]);
      end_if;

      pResult^.uiLng := 4;
      pResult^.aData[0]$DINT := BUSIF_DRIVEMNGBASE_GET_FILE_BUFFER_CB_VERMAX;  //max supported version
      
    //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_GET_TRANSPARENT_STATE:
          
      // get transparent info from bus interface itself
      pPara^.uiCmd := _BUS_IF_GET_TRANSPARENT_STATE;
      ret_code := ToBusInterface.NewInst(pPara:=pPara, pResult:=pResult);
      
    //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_GET_AXIS_WR_PTR_AND_LEN:
      
      ret_code := ERROR; //unsupported version
    
      pResult^.uiLng := 4;
      pResult^.aData[0]$DINT := BUSIF_DRIVEMNGBASE_GET_AXIS_WR_PTR_AND_LEN_VER_MAX;  //max supported version
      
      //Check version
      if pPara^.aPara[0] = BUSIF_DRIVEMNGBASE_GET_AXIS_WR_PTR_AND_LEN_VER_1 then
      
        pResult^.uiLng := 12;
        
        pResult^.aData[4]$DINT  := (GetAxisWrPtr(usAxis := pPara^.aPara[1]$USINT))$DINT;
        pResult^.aData[8]$UDINT := sAxPDOInfos.AxLenWr;
        
        ret_code := READY;
      
      end_if;
    
    //**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_GET_AXIS_RD_PTR_AND_LEN:
    
      ret_code := ERROR; //unsupported version
    
      pResult^.uiLng := 4;
      pResult^.aData[0]$DINT := BUSIF_DRIVEMNGBASE_GET_AXIS_RD_PTR_AND_LEN_VER_MAX;  //max supported version
      
      //Check version
      if pPara^.aPara[0] = BUSIF_DRIVEMNGBASE_GET_AXIS_RD_PTR_AND_LEN_VER_1 then
        
        pResult^.uiLng := 12;
        
        pResult^.aData[4]$DINT  := (GetAxisRdPtr(usAxis := pPara^.aPara[1]$USINT))$DINT;
        pResult^.aData[8]$UDINT := sAxPDOInfos.AxLenRd;
        
        ret_code := READY;
        
      end_if;
    
    //**********************************************************************************************************************************************************      
    MDD2000MNG_IF_SAFETYCONFIG_CHANGED:
      //forward command to MDD2000VVSafetyBase class
      if sConnSafety.pCallback then
        ret_code := sConnSafety.pCallback^.pSvrChCmd.NewInst(pPara:=pPara, pResult:=pResult);      
      else
        ret_code := ERROR;
      end_if;
    
    //**********************************************************************************************************************************************************      
  else
    //unknown command
    ret_code := ERROR;

  end_case;

END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::StartCommunication
	VAR_INPUT
		pServer4CallBack 	: ^BDINT;
	END_VAR

  pCallBackServer                := pServer4CallBack - sizeof(SvrCh.pMeth);

END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::SetParaList
	VAR_INPUT
		usAxis 	: USINT;
		p_list 	: ^void;
		ui_counter 	: UINT;
	END_VAR
	VAR_OUTPUT
		sd_retval 	: DINT;
	END_VAR
  VAR
    p_Axis			: ^t_AxisData;
  END_VAR

  sd_retval := -1;

  //look if class is ok

  if ( ClassState = _ClassOk ) | ( GetDriveIntState()$t_RtSSW = _GetSendParaList ) then

    p_Axis  := #sAxisData[sAxisInfo.aActAxisNrb[usAxis]];

  //-----------------------------------------------------------------------------------------------
  //look if Axis is in use
  if ( p_Axis^.e_AxisState = _NotUsed ) then
    sd_retval := -3;
    return;
  end_if;

  //mark function as ok
  sd_retval := 0;

  //look if parameter handling is ready and list processing is active
  if	( p_Axis^.us_ParaReady = _IdleState
    & p_Axis^.b_ListActive = FALSE
    )
  then
    p_Axis^.p_ParaList$^void	:= p_list;
    p_Axis^.ui_ParaListCnt		:= ui_counter;

    // skip all defined parameter entries
    SkipEntries(usAxis, p_Axis);

      //take over first parameter
      if ( p_Axis^.ui_ParaListCnt ) then
        if SetParameter(usAxis      := usAxis
                      , uiParaID    := 0xFFFF
                      , usParaSubID := p_Axis^.p_ParaList^.us_number
                      , usRdWr      := TRUE
                      , pvalue      := #p_Axis^.p_ParaList^.sd_value
                      , bsDataInfo  := 0
                      ) = 0 then
          p_Axis^.b_ListActive		:= TRUE;
          p_Axis^.ui_ParaListCnt 	-= 1;
          p_Axis^.p_ParaList 		+= sizeof( t_ParaList );
        end_if;
      end_if;
    else
      //not ready
      sd_retval := -1;
    end_if;
  else
    //not ready
    sd_retval := -1;
  end_if;

END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::SetParameter
	VAR_INPUT
		usAxis 	: USINT;
		uiParaID 	: UINT;
		usParaSubID 	: USINT;
		usRdWr 	: USINT;
		pvalue 	: ^DINT;
		bsDataInfo 	: BSINT;
	END_VAR
	VAR_OUTPUT
		sd_retval 	: DINT;
	END_VAR
  VAR
    p_Axis		: ^t_AxisData;
    usAxisArray : USINT;
  END_VAR

  sd_retval := -1;

  //look if class is ok
  if (ClassState <> _ClassOk ) & ( GetDriveIntState()$t_RtSSW <> _GetSendParaList ) & (eInitModulSSW <> _GetSafetyInfos) then
    return;
  end_if;

  //look if init was ok
  if ( bdGeneralFlags.bMailBoxInitOk ) then
     //set pointer to axis
     
     usAxisArray := sAxisInfo.aActAxisNrb[usAxis];
    if (sAxisData[usAxisArray].e_AxisState <> _NotUsed) then
      p_Axis	   := #sAxisData[usAxisArray];
    else
      sd_retval := -2;
      return;
    end_if;

    //----------------------------------------------------------------------------------------------
    //look if Axis is in use
    if ( p_Axis^.e_AxisState = _NotUsed ) then
      sd_retval := -3;
      return;
    end_if;

    //look if parameter handling is ready
    if	( p_Axis^.us_ParaReady = _IdleState
      & p_Axis^.b_ListActive = FALSE
      )
    then
      if uiParaID = 0xFFFF then
        if usParaSubID >= MDD2000VVBASE_PARALIST_INDEX_SETNR  then
          sSDOVars.sActWrData[usAxisArray].ParaIndex    := MDD2000VVBASE_PARALIST_INDEX_INFO$UINT;
          sSDOVars.sActWrData[usAxisArray].ParaSubIndex := usParaSubID - (MDD2000VVBASE_PARALIST_INDEX_SETNR - 1);
        else
          sSDOVars.sActWrData[usAxisArray].ParaIndex    := MDD2000VVBASE_PARALIST_INDEX_SET$UINT;
          sSDOVars.sActWrData[usAxisArray].ParaSubIndex := usParaSubID;
        end_if;
        
        //set value for parameter write
        sSDOVars.sActWrData[usAxisArray].sd_ObjectValue[8]$DINT := pvalue^; // lasal parameter have only 4Byte length
      else
        sSDOVars.sActWrData[usAxisArray].ParaIndex    := uiParaID;
        sSDOVars.sActWrData[usAxisArray].ParaSubIndex := usParaSubID;
      end_if;

      sSDOVars.sActWrData[usAxisArray].RequestControl.DataLength1 := bsDataInfo.1;
      sSDOVars.sActWrData[usAxisArray].RequestControl.DataLength2 := bsDataInfo.2;

      if ( usRdWr ) then
        sSDOVars.sActWrData[usAxisArray].RequestControl.ReadWriteObject := usRdWr$BOOL;

        sAccesses.WriteAccessAsy[usAxisArray].Length := MDD2000VVBASE_CANOPEN_FOOTER_SIZE + ((sSDOVars.sActWrData[usAxisArray].RequestControl shr 6) + 1) * MDD2000VVBASE_LASAL_PARADATA_SIZE;
        sAccesses.WriteAccessAsy[usAxisArray].Offset := (sizeof(t_SDORequest) - sAccesses.WriteAccessAsy[usAxisArray].Length);

        sAccesses.ReadAccessAsy[usAxisArray].Length := MDD2000VVBASE_CANOPEN_FOOTER_SIZE + MDD2000VVBASE_LASAL_PARADATA_SIZE; // besides the footer we need 4 bytes for a potential error code

        _memcpy(ptr1:=#sSDOVars.sActWrData[usAxisArray].sd_ObjectValue[0] + sAccesses.WriteAccessAsy[usAxisArray].Offset, ptr2:=pvalue, cntr:=sAccesses.WriteAccessAsy[usAxisArray].Length - MDD2000VVBASE_CANOPEN_FOOTER_SIZE);
      else
        sSDOVars.sActWrData[usAxisArray].RequestControl.ReadWriteObject := usRdWr$BOOL;
        sAccesses.WriteAccessAsy[usAxisArray].Length := MDD2000VVBASE_CANOPEN_FOOTER_SIZE;
        sAccesses.WriteAccessAsy[usAxisArray].Offset := (sizeof(t_SDORequest) - sAccesses.WriteAccessAsy[usAxisArray].Length);

        //set read length
        sAccesses.ReadAccessAsy[usAxisArray].Length := MDD2000VVBASE_CANOPEN_FOOTER_SIZE + ((sSDOVars.sActWrData[usAxisArray].RequestControl shr 6) + 1) * MDD2000VVBASE_LASAL_PARADATA_SIZE;
      end_if;

      //set data for object handling
      p_Axis^.us_ParaReady   := _GotValueForExecution;

      sd_retval := 0;
    end_if;
  end_if;

END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::SetSyncParameter
	VAR_INPUT
		usAxis 	: USINT;
		us_value 	: USINT;
		sd_data 	: DINT;
	END_VAR
	VAR_OUTPUT
		sd_retval 	: DINT;
	END_VAR
  VAR
    p_Axis_data		: ^t_AxisData;
  END_VAR	

  //only if class is ok
  if ( ClassState = _ClassOk ) then
    sd_retval := 0;

    //look for right value
    if ( us_value > ((sAxPDOInfos.AxLenWr / MDD2000VVBASE_LASAL_PARADATA_SIZE)-1) ) then
      sd_retval := -2;
      return;
    end_if;

    //look which Axis we have and set pointers
    if (sAxisData[sAxisInfo.aActAxisNrb[usAxis]].e_AxisState <> _NotUsed)
    & (usAxis < sAxisInfo.usMaxAxisAvailable) then
      p_Axis_data := #sAxisData[sAxisInfo.aActAxisNrb[usAxis]];
    else
      sd_retval   := -3;
      return;
    end_if;
    
    //only if Axis is ok
    if ( p_Axis_data^.e_AxisState = _AxisOk ) then

      p_Axis_data^.s_WriteValues.a_SyncValues[ us_value ] := sd_data;
    end_if;				
  else
    sd_retval := -1;
  end_if;

END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::GetSyncParameter
	VAR_INPUT
		usAxis 	: USINT;
		us_value 	: USINT;
		p_data 	: ^DINT;
	END_VAR
	VAR_OUTPUT
		sd_retval 	: DINT;
	END_VAR
  VAR
    p_Axis_data		: ^t_AxisData;
  END_VAR	

  //only if class is ok
  if ( ClassState = _ClassOk ) then
    sd_retval := 0;

    //look for right value
    if ( us_value > ((sAxPDOInfos.AxLenRd / MDD2000VVBASE_LASAL_PARADATA_SIZE)-1) ) then
      sd_retval := -2;
      return;
    end_if;

    //look which Axis we have and set pointers
    if  (sAxisData[sAxisInfo.aActAxisNrb[usAxis]].e_AxisState <> _NotUsed)
    & (usAxis < sAxisInfo.usMaxAxisAvailable) then
      p_Axis_data := #sAxisData[sAxisInfo.aActAxisNrb[usAxis]];
    else
      sd_retval   := -3;
      return;
    end_if;

    //only if Axis is ok
    if ( p_Axis_data^.e_AxisState = _AxisOk ) then
      
      p_data^ := p_Axis_data^.s_ReadValues.a_SyncValues[ us_value ];	
    end_if;				
  else
    sd_retval := -1;
  end_if;

END_FUNCTION


FUNCTION MDD2000VVBase::SkipEntries
	VAR_INPUT
		usAxisArray 	: USINT;
		pAxis 	: ^t_AxisData;
	END_VAR
  VAR
  	i         : UDINT;
    p_ActPara : ^USINT;
    b_ParaOK  : BOOL;
  END_VAR

  // if there are parameters to skip
  if sSkipParameter[usAxisArray].us_No > 0 then
    b_ParaOK := FALSE;

    // as long as the parameter is skipped and we have have still parameters in the list
    while (b_ParaOK = FALSE) & (pAxis^.ui_ParaListCnt) do
      // set pointer on first value to skip
      p_ActPara := sSkipParameter[usAxisArray].p_Values;

      b_ParaOK := TRUE;

      // for all skip parameters
      for i := 0 to (sSkipParameter[usAxisArray].us_No - 1) do
        // if the actual parameter number is found in the skip parameter list
        if p_ActPara^ = pAxis^.p_ParaList^.us_number then
          pAxis^.ui_ParaListCnt 	-= 1;
          pAxis^.p_ParaList 		  += sizeof( t_ParaList );

          b_ParaOK := FALSE;
          exit;
        end_if;

        p_ActPara += sizeof(USINT);
      end_for;
    end_while;
  end_if;

END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::GetParameterState
	VAR_INPUT
		usAxis 	: USINT;
	END_VAR
	VAR_OUTPUT
		sd_para_state 	: DINT;
	END_VAR
  VAR
    p_Axis			: ^t_AxisData;
  END_VAR

  sd_para_State := -1;

  //look if class is ok
  if (ClassState <> _ClassOk ) & ( GetDriveIntState()$t_RtSSW <> _GetSendParaList ) & (eInitModulSSW <> _GetSafetyInfos) then
    return;
  end_if;

  //look if init was ok
  if ( bdGeneralFlags.bMailBoxInitOk ) then

    //------------------------------------------------------------------------------------------------
    //look which Axis we have and set pointers
    if (sAxisData[sAxisInfo.aActAxisNrb[usAxis]].e_AxisState <> _NotUsed)
    & (usAxis < sAxisInfo.usMaxAxisAvailable) then
      p_Axis := #sAxisData[sAxisInfo.aActAxisNrb[usAxis]];
    else
      sd_para_State := -2;
      return;
    end_if;

    //----------------------------------------------------------------------------------------------
    //look if Axis is in use
    if ( p_Axis^.e_AxisState = _NotUsed ) then
      sd_para_State := -3;
      return;
    end_if;

    //look if parameter handling is ready
    if	( p_Axis^.us_ParaReady	= _IdleState
      & p_Axis^.b_ListActive	= FALSE
      )
    then
      //look for an object handling error
      if (p_Axis^.sd_ObjectError = 0) then
        sd_para_State := 0;
      else
        sd_para_State := p_Axis^.sd_ObjectError;
      end_if;
    end_if;
  end_if;

END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::GetParameter
	VAR_INPUT
		usAxis 	: USINT;
    pRetcode : ^iprStates;
	END_VAR
	VAR_OUTPUT
		p_para_data 	: ^aBuffer;
	END_VAR
  
  if pRetcode then
    pRetcode^ := ERROR;
  end_if;

  //get last object value of right Axis
  if (sAxisData[sAxisInfo.aActAxisNrb[usAxis]].e_AxisState <> _NotUsed) then
    p_para_data := #sAxisData[sAxisInfo.aActAxisNrb[usAxis]].a_AsyncData;
    //Get data from pipe
    if cPipe_Get(pd:=p_para_data
                , p:=sAxisData[sAxisInfo.aActAxisNrb[usAxis]].p_AsyPipeHandle) = 1 then
                
      if pRetcode then
        pRetcode^ := READY;
      end_if;
    else
      p_para_data := #AsyErrorRetValBuffer;
    end_if;
  else
    p_para_data := #AsyErrorRetValBuffer;
  end_if;

END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::GetDriveIntState
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR

  // to get the actual State of the rtwork State machine
  // retcode = 3 means Operational (MOD 4 is for model SDD100/5000 to have the same returncodes)
  retcode := eRtSSW$DINT MOD 4;

END_FUNCTION


FUNCTION VIRTUAL MDD2000VVBase::InitAxis
	VAR_INPUT
		usAxisArray 	: USINT;
	END_VAR
	VAR_OUTPUT
		sd_retval 	: DINT;
	END_VAR
  VAR
    p_Axis			: ^t_AxisData;
  END_VAR
  
  if ( bdGeneralFlags.bMailBoxInitOk = TRUE ) then
    return;
  end_if;

  //------------------------------------------------------------------------------------------------
  if (sAxisData[usAxisArray].e_AxisState <> _NotUsed) then
    p_Axis			:= #sAxisData[usAxisArray];
  else
    sd_retval := -2;
    return;
  end_if;


  //look which case we have
  case ( eInitDriveSSW ) of
  //******************************************************************************************************************
    _SetDataObjectOn:
      //is Axis in use
      if ( p_Axis^.e_AxisState <> _NotUsed ) then
      
        //clear asynchrone write memory
        _memset(#sSDOVars.sActWrData[usAxisArray], 16#00, sizeof(sSDOVars.sActWrData[usAxisArray]));

        //next step
        eInitDriveSSW := _SetInitAxis;

        sAccesses.ReadAccessAsy[usAxisArray].Length := MDD2000VVBASE_CANOPEN_FOOTER_SIZE + MDD2000VVBASE_LASAL_PARADATA_SIZE;

        if sAccesses.ReadAccessAsy[usAxisArray].Length <> sAccesses.ReadAccessAsy[usAxisArray].OldLength then
          sAccesses.ReadAccessAsy[usAxisArray].Offset := (sizeof(t_SDOResponse) - sAccesses.ReadAccessAsy[usAxisArray].Length);
          ChangeRdDO(AccessHandle := sAccesses.ReadAccessAsy[usAxisArray].Handle
                    , NewOffset   := sAccesses.ReadAccessAsy[usAxisArray].MailboxOffset + sAccesses.ReadAccessAsy[usAxisArray].Offset
                    , NewLength   := sAccesses.ReadAccessAsy[usAxisArray].Length
                    );
          sAccesses.ReadAccessAsy[usAxisArray].OldLength := sAccesses.ReadAccessAsy[usAxisArray].Length;
          sAccesses.ReadAccessAsy[usAxisArray].OldOffset := sAccesses.ReadAccessAsy[usAxisArray].Offset;
        end_if;

        EnableDO(AccessHandle:=sAccesses.ReadAccessAsy[usAxisArray].Handle);
        

      else
        //go to idle state
        eInitDriveSSW := _CyIdle;
      end_if;


  //******************************************************************************************************************
    _Wait4Read: // we have to wait another cycle, because at VARAN we need 1 more cycle to get the data
       //next step
      eInitDriveSSW := _SetInitAxis;


  //******************************************************************************************************************
    _SetInitAxis:
      GetReadData(usAxisArray);

      if ( p_Axis^.e_AxisState = _NoInit ) then
        sSDOVars.sActWrData[usAxisArray].RequestControl.InitCommunication 	:= TRUE;
      end_if;

      p_Axis^.b_OldToggleState := sSDOVars.sActRdData[usAxisArray].ResponseControl.ToggleBit;

      DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[usAxisArray].Handle);
      

      // toggle toggle bit
      sSDOVars.sActWrData[usAxisArray].RequestControl.ToggleBit := NOT sSDOVars.sActRdData[usAxisArray].ResponseControl.ToggleBit;

      sAccesses.WriteAccessAsy[usAxisArray].Length := MDD2000VVBASE_CANOPEN_FOOTER_SIZE;

      if sAccesses.WriteAccessAsy[usAxisArray].Length <> sAccesses.WriteAccessAsy[usAxisArray].OldLength then
        sAccesses.WriteAccessAsy[usAxisArray].Offset := (sizeof(t_SDORequest) - sAccesses.WriteAccessAsy[usAxisArray].Length);
        ChangeWrDO(AccessHandle := sAccesses.WriteAccessAsy[usAxisArray].Handle
                , NewOffset     := sAccesses.WriteAccessAsy[usAxisArray].MailboxOffset + sAccesses.WriteAccessAsy[usAxisArray].Offset
                , NewLength     := sAccesses.WriteAccessAsy[usAxisArray].Length
                );
                
        sAccesses.WriteAccessAsy[usAxisArray].OldLength := sAccesses.WriteAccessAsy[usAxisArray].Length;
        sAccesses.WriteAccessAsy[usAxisArray].OldOffset := sAccesses.WriteAccessAsy[usAxisArray].Offset;
      end_if;

      SetWriteData(usAxisArray);

      EnableDO(AccessHandle:=sAccesses.WriteAccessAsy[usAxisArray].Handle);

       //next step and timestamp
      eInitDriveSSW  := _SetEnableRead;
      udTimemarkInit := ops.tAbsolute;

  //******************************************************************************************************************
    _SetEnableRead:
      EnableDO(AccessHandle:=sAccesses.ReadAccessAsy[usAxisArray].Handle);
      
      DisableDO(AccessHandle:=sAccesses.WriteAccessAsy[usAxisArray].Handle);
      //next step and timestamp
      eInitDriveSSW  :=  _WaitInit;

  //******************************************************************************************************************
    _WaitInit:	//reset startobjecttransfer bit
      GetReadData(usAxisArray);

      //look if Axis 1 must be init
      if ( p_Axis^.e_AxisState = _NoInit ) then
        //object must be executed, error in object handling must be set and error code must be 9
        if (( sSDOVars.sActRdData[usAxisArray].ResponseControl.ToggleBit <> p_Axis^.b_OldToggleState)
            & (sSDOVars.sActRdData[usAxisArray].ResponseControl.ErrorInObjectHandling	= TRUE)
            & (sSDOVars.sActRdData[usAxisArray].sd_ObjectValue[8]$DINT 			= 9) ) then
          //set Axis to next state	
          p_Axis^.e_AxisState := _NoParaList;
          //disable read access
          DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[usAxisArray].Handle);
          
          eInitDriveSSW := _SetFinishInit;
        end_if;
      end_if;

      //after timeout check again
      if ( ops.tAbsolute - udTimemarkInit > 1sec ) then
        eInitDriveSSW := _Wait4Read;
        DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[usAxisArray].Handle);
        
      end_if;

  //******************************************************************************************************************
    _SetFinishInit:
      //If Axis is in right state
      if ( p_Axis^.e_AxisState = _NoParaList ) then

        sSDOVars.sActWrData[usAxisArray].RequestControl.InitCommunication  := FALSE;
      end_if;

      p_Axis^.b_OldToggleState := sSDOVars.sActRdData[usAxisArray].ResponseControl.ToggleBit;

      // toggle toggle bit
      sSDOVars.sActWrData[usAxisArray].RequestControl.ToggleBit := NOT sSDOVars.sActRdData[usAxisArray].ResponseControl.ToggleBit;

      //next step and timestamp
      eInitDriveSSW 		:= _SetDisableWrite;

      SetWriteData(usAxisArray);

      EnableDO(AccessHandle:=sAccesses.WriteAccessAsy[usAxisArray].Handle);

      udTimemarkInit := ops.tAbsolute;

  //******************************************************************************************************************
    _SetDisableWrite:
      EnableDO(AccessHandle:=sAccesses.ReadAccessAsy[usAxisArray].Handle);
      DisableDO(AccessHandle:=sAccesses.WriteAccessAsy[usAxisArray].Handle);

      //next step and timestamp
      eInitDriveSSW 		:= _GetFinishInit;

  //******************************************************************************************************************
    _GetFinishInit:
      GetReadData(usAxisArray);
      //look if Axis is in use and error bit is reset
      if	( sSDOVars.sActRdData[usAxisArray].ResponseControl.ErrorInObjectHandling = TRUE) &
          ( sSDOVars.sActRdData[usAxisArray].ResponseControl.ToggleBit <> p_Axis^.b_OldToggleState) then
        //final step, init ok and class ok
        eInitDriveSSW := _CyIdle;
        DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[usAxisArray].Handle);
        
      else
        //try again if return value is 10 or 8 (see DiasDrive Doku)
        if	( ( sSDOVars.sActRdData[usAxisArray].sd_ObjectValue[0]$DINT = 10| sSDOVars.sActRdData[usAxisArray].sd_ObjectValue[0]$DINT = 8 )
          & (sSDOVars.sActRdData[usAxisArray].ResponseControl.ErrorInObjectHandling = TRUE) ) then
          eInitDriveSSW 			:= _SetInitAxis;
          p_Axis^.e_AxisState := _NoInit;
          DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[usAxisArray].Handle);
          
        end_if;

        //if timeout check again
        if ( ops.tAbsolute - udTimemarkInit > 2sec ) then
          eInitDriveSSW := _SetFinishInit;
          DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[usAxisArray].Handle);
          
        end_if;	
      end_if;

  //******************************************************************************************************************
    _CyIdle:	

  end_case;

  //return ssw
  sd_retval := eInitDriveSSW$DINT;

END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::GetAxisRdPtr
	VAR_INPUT
		usAxis 	: USINT;
	END_VAR
	VAR_OUTPUT
		pReadPara 	: ^t_ReadValuePtr;
	END_VAR

  pReadPara := NIL;

  if (usAxis < (sAxisInfo.usMaxAxisAvailable)) 
  & (sAxisData[sAxisInfo.aActAxisNrb[usAxis]].e_AxisState <> _NotUsed) then
    pReadPara := #sAxisData[sAxisInfo.aActAxisNrb[usAxis]].s_ReadValues;
  end_if;

END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::GetAxisWrPtr
	VAR_INPUT
		usAxis 	: USINT;
	END_VAR
	VAR_OUTPUT
		pWritePara 	: ^t_WriteValuePtr;
	END_VAR

  pWritePara := NIL;

  if (usAxis < (sAxisInfo.usMaxAxisAvailable)) 
  & (sAxisData[sAxisInfo.aActAxisNrb[usAxis]].e_AxisState <> _NotUsed) then
    pWritePara := #sAxisData[sAxisInfo.aActAxisNrb[usAxis]].s_WriteValues;
  end_if;

END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::ExternInitFinished

  // if all axis parameters have been sent
  eRtSSW := _WaitForSynchrony;

END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::InitDrive
  VAR
 	  usCounter : USINT;
  END_VAR

  if bdGeneralFlags.bMailBoxInitOk then
    if sAxisInfo.usAxisActiveNo then
      for usCounter := 0 to sAxisInfo.usAxisActiveNo-1 do
        if ( sAxisData[usCounter].e_AxisState <> _NotUsed ) then
          sAxisData[usCounter].e_AxisState := _NoInit;
        end_if;

        sAxisData[usCounter].us_ParaReady := _IdleState;
      end_for;
    end_if;

    //---------------------------------------------------------------------------------------------------------
    //class is not initialized
    bdGeneralFlags.bAlreadyAxisInit := FALSE;
    ClassState        := _NotInitialized;
    eInitDriveSSW     := _SetDataObjectOn;
    eRtSSW            := _InitAxis;
  end_if;

END_FUNCTION


FUNCTION MDD2000VVBase::GetObjectValue
	VAR_INPUT
		usAxisArray 	: USINT;
	END_VAR
  VAR
    pAxis	: ^t_AxisData;
  	usAxis : USINT;
    udRetCode : UDINT;
  END_VAR

  //get axis place (internal first axis is on 0 - on Axis Object first axis is on place 1)
   usAxis := sAxisData[usAxisArray].usAxisPlaceNr-1;

	//------------------------------------------------------------------------------------------------
	//look which Axis we have and set pointers
  if (usAxis < sAxisInfo.usMaxAxisAvailable) & (sAxisData[usAxisArray].e_AxisState <> _NotUsed) then
    pAxis	:= #sAxisData[usAxisArray];
  else
    //else do nothing (should not come her)
    return;
  end_if;

    //------------------------------------------------------------------------------------------------
    //get to right step
    case ( pAxis^.us_ParaReady ) of

    //******************************************************************************************************************
      _GotValueForExecution,
      _SendExecution:// now toggle the togglebit to start tell the drive, that the data are complete (no chance for byte errors in this way)
          // toggle toggle bit
          sSDOVars.sActWrData[usAxisArray].RequestControl.ToggleBit := NOT sSDOVars.sActRdData[usAxisArray].ResponseControl.ToggleBit;

          if sAccesses.WriteAccessAsy[usAxisArray].Length <> sAccesses.WriteAccessAsy[usAxisArray].OldLength then
            sAccesses.WriteAccessAsy[usAxisArray].Offset := (sizeof(t_SDORequest) - sAccesses.WriteAccessAsy[usAxisArray].Length);
            ChangeWrDO(AccessHandle := sAccesses.WriteAccessAsy[usAxisArray].Handle
                    , NewOffset     := sAccesses.WriteAccessAsy[usAxisArray].MailboxOffset + sAccesses.WriteAccessAsy[usAxisArray].Offset
                    , NewLength     := sAccesses.WriteAccessAsy[usAxisArray].Length
                    );
            sAccesses.WriteAccessAsy[usAxisArray].OldLength := sAccesses.WriteAccessAsy[usAxisArray].Length;
            sAccesses.WriteAccessAsy[usAxisArray].OldOffset := sAccesses.WriteAccessAsy[usAxisArray].Offset;
          end_if;

          //send transmit execution request for object handling
          pAxis^.b_OldToggleState := sSDOVars.sActRdData[usAxisArray].ResponseControl.ToggleBit;

          //reset error and go to next step
          pAxis^.sd_ObjectError := 0;
          pAxis^.us_ParaReady := _EnableRead;

          SetWriteData(usAxisArray);

          EnableDO(AccessHandle:=sAccesses.WriteAccessAsy[usAxisArray].Handle);

    //******************************************************************************************************************
      _EnableRead:
          if sAccesses.ReadAccessAsy[usAxisArray].Length <> sAccesses.ReadAccessAsy[usAxisArray].OldLength then
            sAccesses.ReadAccessAsy[usAxisArray].Offset := (sizeof(t_SDOResponse) - sAccesses.ReadAccessAsy[usAxisArray].Length);
            ChangeRdDO(AccessHandle := sAccesses.ReadAccessAsy[usAxisArray].Handle
                    , NewOffset     := sAccesses.ReadAccessAsy[usAxisArray].MailboxOffset + sAccesses.ReadAccessAsy[usAxisArray].Offset
                    , NewLength     := sAccesses.ReadAccessAsy[usAxisArray].Length
                    );
            sAccesses.ReadAccessAsy[usAxisArray].OldLength := sAccesses.ReadAccessAsy[usAxisArray].Length;
            sAccesses.ReadAccessAsy[usAxisArray].OldOffset := sAccesses.ReadAccessAsy[usAxisArray].Offset;
          end_if;

          DisableDO(AccessHandle:=sAccesses.WriteAccessAsy[usAxisArray].Handle);
          EnableDO(AccessHandle:=sAccesses.ReadAccessAsy[usAxisArray].Handle);
          

          //next step
          pAxis^.us_ParaReady   := _Wait4Response;
          sSDOVars.udSDOTimeOut := ops.tAbsolute;


    //******************************************************************************************************************
      _Wait4Response:		//wait until receive state is
          GetReadData(usAxisArray);

          if ( sSDOVars.sActRdData[usAxisArray].ResponseControl.ToggleBit <> pAxis^.b_OldToggleState) then

            if sSDOVars.sActWrData[usAxisArray].ParaIndex = sSDOVars.sActRdData[usAxisArray].ParaIndex
             & sSDOVars.sActWrData[usAxisArray].ParaSubIndex = sSDOVars.sActRdData[usAxisArray].ParaSubIndex  then

              //look if we have a parameter list
              if ( pAxis^.b_ListActive = TRUE ) then

                // skip all defined parameter entries
                SkipEntries(usAxisArray:=usAxisArray, pAxis:=pAxis);

                //have we set all parameter
                if ( pAxis^.ui_ParaListCnt ) then

                  //send transmit execution request for object handling
                  pAxis^.b_OldToggleState := sSDOVars.sActRdData[usAxisArray].ResponseControl.ToggleBit;

                  // toggle toggle bit
                  sSDOVars.sActWrData[usAxisArray].RequestControl.ToggleBit := NOT sSDOVars.sActRdData[usAxisArray].ResponseControl.ToggleBit;

                  //reset error and go to next step
                  pAxis^.sd_ObjectError := 0;
                  pAxis^.us_ParaReady := _EnableRead;

                  if pAxis^.p_ParaList^.us_number >= MDD2000VVBASE_PARALIST_INDEX_SETNR  then
                    sSDOVars.sActWrData[usAxisArray].ParaIndex     := MDD2000VVBASE_PARALIST_INDEX_INFO$UINT;
                    sSDOVars.sActWrData[usAxisArray].ParaSubIndex	:= pAxis^.p_ParaList^.us_number - (MDD2000VVBASE_PARALIST_INDEX_SETNR - 1);
                  else
                    sSDOVars.sActWrData[usAxisArray].ParaIndex    := MDD2000VVBASE_PARALIST_INDEX_SET$UINT;
                    sSDOVars.sActWrData[usAxisArray].ParaSubIndex	 := pAxis^.p_ParaList^.us_number;
                  end_if;
                  
                  //set value for parameter write
                  sSDOVars.sActWrData[usAxisArray].sd_ObjectValue[8]$DINT	:= pAxis^.p_ParaList^.sd_value;
                  sSDOVars.sActWrData[usAxisArray].RequestControl.ReadWriteObject := TRUE;

                  //4 Byte datalength for Lasal Parameter
                  sSDOVars.sActWrData[usAxisArray].RequestControl.DataLength1 := 0;
                  sSDOVars.sActWrData[usAxisArray].RequestControl.DataLength2 := 0;

                  sAccesses.WriteAccessAsy[usAxisArray].Length := MDD2000VVBASE_CANOPEN_FOOTER_SIZE + MDD2000VVBASE_LASAL_PARADATA_SIZE;

                  sAccesses.ReadAccessAsy[usAxisArray].Length := MDD2000VVBASE_CANOPEN_FOOTER_SIZE + MDD2000VVBASE_LASAL_PARADATA_SIZE; // besides the footer we need 4 bytes for a potential error code

                  if sAccesses.WriteAccessAsy[usAxisArray].Length <> sAccesses.WriteAccessAsy[usAxisArray].OldLength then
                    sAccesses.WriteAccessAsy[usAxisArray].Offset := (sizeof(t_SDORequest) - sAccesses.WriteAccessAsy[usAxisArray].Length);
                    ChangeWrDO(AccessHandle := sAccesses.WriteAccessAsy[usAxisArray].Handle
                            , NewOffset     := sAccesses.WriteAccessAsy[usAxisArray].MailboxOffset + sAccesses.WriteAccessAsy[usAxisArray].Offset
                            , NewLength     := sAccesses.WriteAccessAsy[usAxisArray].Length
                            );
                    sAccesses.WriteAccessAsy[usAxisArray].OldLength := sAccesses.WriteAccessAsy[usAxisArray].Length;
                    sAccesses.WriteAccessAsy[usAxisArray].OldOffset := sAccesses.WriteAccessAsy[usAxisArray].Offset;
                  end_if;

                  SetWriteData(usAxisArray);
                  //enable write access
                  EnableDO(AccessHandle:=sAccesses.WriteAccessAsy[usAxisArray].Handle);

                  //set next parameter step and set pointer to next parameter data
                  pAxis^.us_ParaReady 	:= _EnableRead;  // _SendExecution;

                  //disable read access
                  DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[usAxisArray].Handle);
                  
                  pAxis^.ui_ParaListCnt 	-= 1;
                  pAxis^.p_ParaList 		+= sizeof( t_ParaList );

                else
                  //set ssw to idle and deactivate parameter list
                  pAxis^.b_ListActive 	:= FALSE;

                  //look if we get a parameter list
                  if ( pAxis^.e_AxisState = _NoParaList ) then
                    pAxis^.e_AxisState		:= _NotSynchron;
                  end_if;

                  pAxis^.us_ParaReady 	:= _IdleState;
                  //disable read access
                  DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[usAxisArray].Handle);
                  
                end_if;

              else
                //disable read access
                DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[usAxisArray].Handle);
                
                //look for an object error
                if ( sSDOVars.sActRdData[usAxisArray].ResponseControl.ErrorInObjectHandling = TRUE ) then
                  pAxis^.sd_ObjectError := sSDOVars.sActRdData[usAxisArray].sd_ObjectValue[8]$DINT;
                end_if;
                      
                udRetCode :=  cPipe_GetUsed(p:=pAxis^.p_AsyPipeHandle);
                
                if udRetCode > 0 then
                  //Free pipe because new sdo data is received
                  cPipe_Get(pd:=#sAxisData[sAxisInfo.aActAxisNrb[usAxisArray]].a_AsyncData
                           , p:=pAxis^.p_AsyPipeHandle);
                end_if;

                      
                udRetCode := cPipe_Add(pAxis^.p_AsyPipeHandle
                          , #sSDOVars.sActRdData[usAxisArray].sd_ObjectValue[0] + sAccesses.ReadAccessAsy[usAxisArray].Offset
                          , sAccesses.ReadAccessAsy[usAxisArray].Length);
                
                
                //Add Data to pipe (1 = successful)
                //if udRetCode <> 1 then
                  //add data failed
                //end_if;

                //get to idle step
                pAxis^.us_ParaReady := _IdleState;
              end_if;
            end_if;
          end_if;

          if (ops.tAbsolute - sSDOVars.udSDOTimeOut) >= MDD2000VVBASE_SDO_RESPONSE_TIMEOUT then
            //disable read access
            DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[usAxisArray].Handle);
            
            //get to idle step
            pAxis^.us_ParaReady := _IdleState;
            LogError("@0752 (MDD2000VVBase::GetObjectValue) SDO Receive: Timeout read toggle bit or wrong index/subindex number");
            HWC_LogPrintf(pThis:=this, format:="@0752 (MDD2000VVBase::GetObjectValue) Write Data: %X, Read Data: %X", p0:=#sSDOVars.sActWrData[usAxisArray].ParaIndex, p1:= #sSDOVars.sActRdData[usAxisArray].ParaIndex);
          end_if;


    //******************************************************************************************************************
      _IdleState:				//do nothing in this step

    end_case;

END_FUNCTION


FUNCTION MDD2000VVBase::SetWriteData
	VAR_INPUT
		usAxisArray 	: USINT;
	END_VAR
  
  // copy the actual write data to the DPRAM
  if sAccesses.pWriteAsy[usAxisArray] & sAccesses.WriteAccessAsy[usAxisArray].AxisPlaceNr then
    if sSDOVars.sActWrData[usAxisArray].ParaIndex >= MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_STANDARD_MIN
    & sSDOVars.sActWrData[usAxisArray].ParaIndex <= MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_STANDARD_MAX then
      sSDOVars.sActWrData[usAxisArray].ParaIndex += ((sAccesses.WriteAccessAsy[usAxisArray].AxisPlaceNr-1)*MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_STANDARD_OFFSET);
    elsif sSDOVars.sActWrData[usAxisArray].ParaIndex >= MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_SAFETY_MIN
    & sSDOVars.sActWrData[usAxisArray].ParaIndex <= MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_SAFETY_MAX then
      sSDOVars.sActWrData[usAxisArray].ParaIndex += ((sAccesses.WriteAccessAsy[usAxisArray].AxisPlaceNr-1)*MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_SAFETY_OFFSET);
    elsif sSDOVars.sActWrData[usAxisArray].ParaIndex >= MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_DS402_MIN
    & sSDOVars.sActWrData[usAxisArray].ParaIndex <= MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_DS402_MAX then
      sSDOVars.sActWrData[usAxisArray].ParaIndex += ((sAccesses.WriteAccessAsy[usAxisArray].AxisPlaceNr-1)*MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_DS402_OFFSET);
    end_if;
    _memcpy(ptr1:=sAccesses.pWriteAsy[usAxisArray]
          , ptr2:=(#sSDOVars.sActWrData[usAxisArray]+sAccesses.WriteAccessAsy[usAxisArray].Offset)
          , cntr:=sAccesses.WriteAccessAsy[usAxisArray].Length);
  end_if;

END_FUNCTION


FUNCTION MDD2000VVBase::GetReadData
	VAR_INPUT
		usAxisArray 	: USINT;
	END_VAR
  
  // copy the actual read data from the DPRAM
  if sAccesses.pReadAsy[usAxisArray] & sAccesses.ReadAccessAsy[usAxisArray].AxisPlaceNr then
    if sSDOVars.sActRdData[usAxisArray].ParaIndex >= MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_STANDARD_MIN
    & sSDOVars.sActRdData[usAxisArray].ParaIndex <= (MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_STANDARD_MAX+(MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_STANDARD_OFFSET*MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_MAX_AXIS)) then
      sSDOVars.sActRdData[usAxisArray].ParaIndex -= ((sAccesses.ReadAccessAsy[usAxisArray].AxisPlaceNr-1)*MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_STANDARD_OFFSET);
    elsif sSDOVars.sActRdData[usAxisArray].ParaIndex >= MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_SAFETY_MIN
    & sSDOVars.sActRdData[usAxisArray].ParaIndex <= (MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_SAFETY_MAX+(MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_SAFETY_OFFSET*MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_MAX_AXIS)) then
      sSDOVars.sActRdData[usAxisArray].ParaIndex -= ((sAccesses.ReadAccessAsy[usAxisArray].AxisPlaceNr-1)*MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_SAFETY_OFFSET);
    elsif sSDOVars.sActRdData[usAxisArray].ParaIndex >=MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_DS402_MIN
    & sSDOVars.sActRdData[usAxisArray].ParaIndex <= (MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_DS402_MAX+(MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_DS402_OFFSET*MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_MAX_AXIS)) then
      sSDOVars.sActRdData[usAxisArray].ParaIndex -= ((sAccesses.ReadAccessAsy[usAxisArray].AxisPlaceNr-1)*MDD2000VVBASE_SDO_SERVICE_APP_CANOPEN_DS402_OFFSET);
    end_if;
    _memcpy(ptr1:=(#sSDOVars.sActRdData[usAxisArray] + sAccesses.ReadAccessAsy[usAxisArray].Offset)
          , ptr2:=sAccesses.pReadAsy[usAxisArray]
          , cntr:=sAccesses.ReadAccessAsy[usAxisArray].Length);
  end_if;

END_FUNCTION


FUNCTION MDD2000VVBase::ChangeRdDO
	VAR_INPUT
		AccessHandle 	: UDINT;
		NewOffset 	: HDINT;
		NewLength 	: UDINT;
	END_VAR
	VAR_OUTPUT
		Success 	: BOOL;
	END_VAR
  VAR
  	MyPara   : CmdStruct;
    MyResult : results;
    dataUPDATEDO    : t_UpdateDOCfg;
  END_VAR

  Success := TRUE;

  // if length = zero we may just want to stop the DO
  if NewLength then
    dataUPDATEDO.Handle               := AccessHandle;
    dataUPDATEDO.ud_addressoff_read   := NewOffset;
    dataUPDATEDO.ud_length_read       := NewLength$UINT;

    MyPara.uiCmd         := _BUS_IF_UPDATE_DO;
    MyPara.aPara[0]      := (#dataUPDATEDO)$DINT;

    ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
    if MyResult.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
      LogError("@0753 (MDD2000VVBase::ChangeRdDO) Failed to change asynchron read access");
      Success := FALSE;
    end_if;
  else
    Success := FALSE;
  end_if;

END_FUNCTION


FUNCTION MDD2000VVBase::ChangeWrDO
	VAR_INPUT
		AccessHandle 	: UDINT;
		NewOffset 	: HDINT;
		NewLength 	: UDINT;
	END_VAR
	VAR_OUTPUT
		Success 	: BOOL;
	END_VAR
  VAR
  	MyPara   : CmdStruct;
    MyResult : results;
    dataUPDATEDO    : t_UpdateDOCfg;
  END_VAR

  Success := TRUE;

  // if length = zero we may just want to stop the DO
  if NewLength then
    dataUPDATEDO.Handle               := AccessHandle;
    dataUPDATEDO.ud_addressoff_write  := NewOffset;
    dataUPDATEDO.ud_length_write      := NewLength$UINT;

    MyPara.uiCmd         := _BUS_IF_UPDATE_DO;
    MyPara.aPara[0]      := (#dataUPDATEDO)$DINT;

    ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
    if MyResult.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
      LogError("@0754 (MDD2000VVBase::ChangeWrDO) Failed to change asynchron write access");
      Success := FALSE;
    end_if;
  else
    Success := FALSE;
  end_if;

END_FUNCTION


FUNCTION MDD2000VVBase::EnableDO
	VAR_INPUT
		AccessHandle 	: UDINT;
	END_VAR
	VAR_OUTPUT
		Success 	: BOOL;
	END_VAR
  VAR  	
  	MyPara   : CmdStruct;
    MyResult : results;
    dataSETRUNSTATE : t_SetRunStateCfg;
  END_VAR

  //initialize returncode
  Success := TRUE;

  // set runstate
  dataSETRUNSTATE.Handle      := AccessHandle;
  dataSETRUNSTATE.newRunState := _BUS_IF_RUN_STATE_CONT_RUN;

  MyPara.uiCmd     := _BUS_IF_SET_RUN_STATE;
  MyPara.aPara[0]  := (#dataSETRUNSTATE)$DINT;

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

  if MyResult.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
    LogError("@0755 (MDD2000VVBase::EnableDO) Error changing the run state of dataobject!");
    Success := FALSE;
  end_if;

END_FUNCTION


FUNCTION MDD2000VVBase::DisableDO
	VAR_INPUT
		AccessHandle 	: UDINT;
	END_VAR
	VAR_OUTPUT
		Success 	: BOOL;
	END_VAR
  VAR  	
  	MyPara   : CmdStruct;
    MyResult : results;
    dataSETRUNSTATE : t_SetRunStateCfg;
  END_VAR

  //initialize returncode
  Success := TRUE;
   // set runstate
  dataSETRUNSTATE.Handle      := AccessHandle;
  dataSETRUNSTATE.newRunState := _BUS_IF_RUN_STATE_NO_RUN;

  MyPara.uiCmd      := _BUS_IF_SET_RUN_STATE;
  MyPara.aPara[0]   := (#dataSETRUNSTATE)$DINT;

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

  if MyResult.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
    LogError("@0755 (MDD2000VVBase::DisableDO) Error changing the run state of dataobject!");
    Success := FALSE;
  end_if;

END_FUNCTION


FUNCTION MDD2000VVBase::ReadTypeLabel
	VAR_OUTPUT
		eModuleInitState 	: iprStates;
	END_VAR
  VAR
  	TmpRetcode  : BOOL;
    TmpIPRRetCode : iprStates;
    usCounter   : USINT;
  	MyPara   : CmdStruct;
    MyResult : results;
    p_ObjectPath : ^USINT;
  END_VAR

  usCounter                   := 0;
  eModuleInitState            := BUSY;
  sSDOVars.eErrorTypeLabelSSW := _NoErrorReadTypeLabel;

  // post init blocks the tasks in cyclic priority => give it some time
  if (bdGeneralFlags.bPostInitFinished = FALSE) then
    ToMultiTask.TASKDELAY(timeout0:=MDD2000VVBASE_WAIT_TIME_IN_POST_INIT);
  end_if;

  case sSDOVars.eReadTypeLabelSSW of    
    //**********************************************************************************************************************************************************
    _ReadFirstSector:
      case sSDOVars.eResponseState of
        //*****************************************************
        _idle:
          sAccesses.ReadAccessAsy[usCounter].Offset := MDD2000VVBASE_OFFSET_TYPELABEL;
          sAccesses.ReadAccessAsy[usCounter].Length := t_VANDALMapping.aMailBoxes;
          TmpRetcode := ChangeRdDO( AccessHandle:= sAccesses.ReadAccessAsy[usCounter].Handle
                                  , NewOffset   := sAccesses.ReadAccessAsy[usCounter].Offset
                                  , NewLength   := sAccesses.ReadAccessAsy[usCounter].Length
                                  );
                                  
          //Enable dataobject to read type label info              
          EnableDO(AccessHandle:=sAccesses.ReadAccessAsy[usCounter].Handle);          

          sSDOVars.eResponseState   := _wait;
          sSDOVars.udSDOTimeMark    := ops.tAbsolute;

        //*****************************************************
        _wait: // wait for response
           _memcpy(ptr1:=#sTypeLabel, ptr2:=sAccesses.ReadAccessAsy[usCounter].pData, cntr:=t_VANDALMapping.aMailBoxes);
          if ((sTypeLabel.VersionMinor <> 0) | (sTypeLabel.VersionMajor <> 0)) &  // Minor + Major Version must be <> 0
             ((sTypeLabel.DeviceID shr 31) = FALSE) then                          // if this bit is set, the module is in bootloader mode. retry readout of typelabel.
            sSDOVars.eResponseState    := _valid;
          else
            sSDOVars.eResponseState    := _idle;
            sSDOVars.eReadTypeLabelSSW := _ReadFirstSector;
          end_if;

          // check timeout
          if ((ops.tAbsolute - sSDOVars.udSDOTimeMark) > MDD2000VVBASE_SDO_RESPONSE_TIMEOUT) then
            LogError("@0756 (MDD2000VVBase::ReadTypeLabel) SDO Response timeout while waiting for the type label");
            sSDOVars.eErrorTypeLabelSSW  := sSDOVars.eReadTypeLabelSSW;
            sSDOVars.eReadTypeLabelSSW   := _ReadFirstSector;
            sSDOVars.eResponseState      := _idle;
          end_if;

        //*****************************************************
        _valid:
          //get Hw Path of module          
          MyPara.uiCmd     := _BUS_IF_GET_HW_PATH;
          MyPara.aPara[0]  := this$DINT;
          ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);
          if MyResult.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
            LogError("@01C3 (MDD2000VVBase::ReadTypeLabel) Failed to get hardware path.");
          else
            p_ObjectPath := MyResult.aData[4]$^USINT;
            sDriveType.uiHwPathLen := p_ObjectPath^$USINT + 1; // size of path (length + 1 for the length information)
            sDriveType.pHwPath     := p_ObjectPath;
          end_if;
          
          //get mdd2000 type          
          if (sTypeLabel.DeviceID and 1)$BOOL = FALSE then
            sDriveType.eDriveType := _MDPType;
          else
            sDriveType.eDriveType := _MDDType;
          end_if;

          sSDOVars.eReadTypeLabelSSW := _ReadMailbox;
          sSDOVars.eResponseState    := _idle;

      end_case;

    //**********************************************************************************************************************************************************
    _ReadMailbox:
      case sSDOVars.eResponseState of
        //*****************************************************
        _idle:
          sAccesses.ReadAccessAsy[usCounter].Offset := MDD2000VVBASE_OFFSET_TYPELABEL + t_VANDALMapping.aMailBoxes;
          sAccesses.ReadAccessAsy[usCounter].Length := sizeof(t_MailBox) * sTypeLabel.MailboxNumber;

          if sAccesses.ReadAccessAsy[usCounter].Length > 0 then
            TmpRetcode := ChangeRdDO(AccessHandle:=sAccesses.ReadAccessAsy[usCounter].Handle
                                    , NewOffset  :=sAccesses.ReadAccessAsy[usCounter].Offset
                                    , NewLength  :=sAccesses.ReadAccessAsy[usCounter].Length
                                    );

            sSDOVars.eResponseState     := _wait;
            sSDOVars.udSDOTimeMark      := ops.tAbsolute;
          else
            sSDOVars.eReadTypeLabelSSW := _ReadFirstSector;
          end_if;

        //*****************************************************
        _wait: // wait for response
          _memcpy(ptr1:=#sTypeLabel.aMailBoxes[0], ptr2:=sAccesses.ReadAccessAsy[usCounter].pData, cntr:=sAccesses.ReadAccessAsy[usCounter].Length);

          if GetMailboxInfo(hiID:=_BUSIF_VVDRIVE_SERVICE_APP_DS402$t_MailboxTypes
                          , pMailboxData:=NIL
                          , pMailboxID:=#sAccesses.ServiceIDNr) = 1 then
             
             //check for new mailbox
             sCmdIntMB.dMBAvailable := GetMailboxInfo(hiID:=_BUSIF_VVDRIVE_SERVICE_APP_CMDIN$t_MailboxTypes
                                                    , pMailboxData:=#sCmdIntMB.sMailboxInfo
                                                    , pMailboxID:=NIL);
                                                    

            if (sTypeLabel.DeviceInfoPointer)$UINT <> 0 then
              sSDOVars.eReadTypeLabelSSW  := _ReadAxisAmount;
              sSDOVars.eResponseState     := _idle;
            else
              sSDOVars.eResponseState      := _idle;
              sSDOVars.eReadTypeLabelSSW   := _ReadFirstSector;
            end_if;
          else
            sSDOVars.eResponseState      := _idle;
            sSDOVars.eReadTypeLabelSSW   := _ReadFirstSector;
          end_if;

          // check timeout
          if ((ops.tAbsolute - sSDOVars.udSDOTimeMark) > MDD2000VVBASE_SDO_RESPONSE_TIMEOUT) & (sSDOVars.eResponseState <> _valid) then
            LogError("@0756 (MDD2000VVBase::ReadTypeLabel) SDO Response timeout while waiting for the type label");
            sSDOVars.eErrorTypeLabelSSW  := sSDOVars.eReadTypeLabelSSW;
            sSDOVars.eReadTypeLabelSSW   := _ReadFirstSector;
            sSDOVars.eResponseState      := _idle;
          end_if;

      //*****************************************************
        //_valid://

      end_case;

    //**********************************************************************************************************************************************************
    _ReadAxisAmount:
      case sSDOVars.eResponseState of
        //*****************************************************
        _idle:
          sAccesses.ReadAccessAsy[usCounter].Offset := sTypeLabel.DeviceInfoPointer;
          sAccesses.ReadAccessAsy[usCounter].Length := sizeof(t_VANDALMapping.AxisAvailable);
          TmpRetcode := ChangeRdDO(AccessHandle:=sAccesses.ReadAccessAsy[usCounter].Handle
                                  , NewOffset  :=sAccesses.ReadAccessAsy[usCounter].Offset
                                  , NewLength  :=sAccesses.ReadAccessAsy[usCounter].Length
                                  );

          sSDOVars.eResponseState := _wait;

        //*****************************************************
        _wait: // wait for response
          sTypeLabel.AxisAvailable := sAccesses.ReadAccessAsy[usCounter].pData^$BSINT;
          if (sTypeLabel.AxisAvailable)$USINT = 0 then
            LogError("@0779 (MDD2000VVBase::ReadTypeLabel)Failed to read amount of axis from drive.");
          end_if;
          DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[usCounter].Handle);
          
          sSDOVars.eResponseState     := _valid;

        //*****************************************************
        _valid: //
          sSDOVars.eResponseState     := _idle;
          sSDOVars.eReadTypeLabelSSW  := _GetDriveErrorInfoMDP;

      end_case;

    //**********************************************************************************************************************************************************
    _GetDriveErrorInfoMDP:
        
      if sDriveType.eDriveType = _MDDType then

        MyPara.uiCmd    := _BUSIF_VVDRIVE_ADD_MDD2000_MDP_ERROR;
        MyPara.aPara[0] := sDriveType.uiHwPathLen;
        MyPara.aPara[1] := sDriveType.pHwPath$DINT;
        MyPara.aPara[2]$UDINT := sDriveType.eDriveType;
        
        if IsClientConnected(input:=#toVaranIn)
        & (sDriveType.pHwPath + (sDriveType.pHwPath^$UINT-1))^ <> HWT_ESCAPE_VARAN then
          TmpIPRRetCode := toVaranIn.VaranIn.NewInst(pPara:=#MyPara, pResult:=#MyResult);

          if TmpIPRRetCode = READY & MyResult.aData[0]$t_BusIFRetvalErrorcode = _BUS_IF_RETVAL_OK then
            sDriveType.psDriveMDPErrorInfo := MyResult.aData[4]$^ts_DriveInputs;
            sDriveType.uiHwPathLenMDP      := MyResult.aData[8]$UINT;
            sDriveType.pHwPathMDP          := MyResult.aData[10]$^USINT;          
          elsif TmpIPRRetCode = ERROR then
            LogError("@0778 (MDD2000VVBase::ReadTypeLabel) [SL] Error there is no MDP Hardware!");
            bdErrorSL.GetNextMDP := TRUE;
          end_if;
        else
          LogError("@0778 (MDD2000VVBase::ReadTypeLabel) [SL] Error there is no MDP Hardware!");
          bdErrorSL.GetNextMDP := TRUE;
        end_if; 
      end_if;
    
      sSDOVars.eReadTypeLabelSSW  := _TypeLabelFinish;
        
    //**********************************************************************************************************************************************************
    _TypeLabelFinish:
      
      if sTypeLabel.VersionMajor >= MDD2000VVBASE_TYPELBL_EXTPDOSUPPORT then
      
        bExtendedPDOSupport := TRUE;
        
        SafetyRunState  := MDD2000MngBase::t_e_MDD2000SafetyRunState::_POST;
      
        sAxPDOInfos.AxLenRd     := MDD2000VVBASE_PDO_AXIS_SIZE_EXTEND;
        sAxPDOInfos.AxLenWr     := MDD2000VVBASE_PDO_AXIS_SIZE_EXTEND;
        
      else
      
        SafetyRunState  := MDD2000MngBase::t_e_MDD2000SafetyRunState::_INACTIVE;
      
        sAxPDOInfos.AxLenRd     := MDD2000VVBASE_PDO_AXIS_SIZE;
        sAxPDOInfos.AxLenWr     := MDD2000VVBASE_PDO_AXIS_SIZE;
      
      end_if;
      
      sSDOVars.eReadTypeLabelSSW := _ReadFirstSector;
      eModuleInitState  := READY;

    //**********************************************************************************************************************************************************
    _TypeLabelError:
      DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[usCounter].Handle);
      sSDOVars.eReadTypeLabelSSW := _ReadFirstSector;
      sSDOVars.eResponseState    := _idle;
      eModuleInitState  := ERROR;

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

END_FUNCTION


FUNCTION VIRTUAL MDD2000VVBase::LogError
	VAR_INPUT
		e_msg 	: ^CHAR;
	END_VAR

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

END_FUNCTION


FUNCTION VIRTUAL MDD2000VVBase::LogValue
	VAR_INPUT
		pString 	: ^CHAR;
		Value 	: UDINT;
		Value2 	: UDINT;(* := 16# *)
		Value3 	: UDINT;(* := 16# *)
	END_VAR

#ifdef HWC_LogValue3
  HWC_LogValue3(this, pString, Value, Value2, Value3);
#endif

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000VVBase::ClassState::NewInst
	VAR_INPUT
		pPara 	: ^CmdStruct;
		pResult 	: ^results;
	END_VAR
	VAR_OUTPUT
		ret_code 	: iprStates;
	END_VAR
  VAR
  	MyPara   : CmdStruct;
    MyResult   : results;
  END_VAR

  ret_code := READY;

  case pPara^.uiCmd of
    //*****************************************************************************
    //** COMMANDS FROM Safety Manager                                            **
    //*****************************************************************************
    CMD_SM_CMD_MIN_RANGE .. CMD_SM_CMD_MAX_RANGE:
      //route data to connected safety
      if sConnSafety.pCallback then
        sConnSafety.pCallback^.pSvrChCmd.NewInst(pPara,pResult);
      else
        pResult^.aData[0] := _BUS_IF_RETVAL_OK;
      end_if;

    //**********************************************************************************************************************************************************
    //*****************************************************************************
    //** COMMANDS FROM BUS INTERFACE                                             **
    //*****************************************************************************
    //**********************************************************************************************************************************************************
    _BUS_IF_HWCONNECT:
      // device has been connected
      // install post init call back only if we're still in init (if we install it in init(), we may get called even the module is not connected)
      if us_Firstscan < 12 then
        MyPara.uiCmd := _BUS_IF_WAIT_4_POST_INIT;
        MyPara.aPara[0] := 0;
        ToBusInterface.NewInst(pPara:=#MyPara, pResult:=#MyResult);

        if MyResult.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
          LogError("@014F (MDD2000VVBase::ClassState::NewInst) Failed to install post init callback");
          SetClassState(tClassState:=_InvalidConfguration);          
        end_if;
      else
        bdGeneralFlags.bPostInitFinished := TRUE;
      end_if;

      // set online server first on 1 if data is valid
      MyPara.uiCmd    := _BUS_IF_SET_ONLINE;
      MyPara.aPara[0] := bdGeneralFlags.bOnline;

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

      if MyResult.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
        LogError("@0079 (MDD2000VVBase::ClassState::NewInst) Failed to set Online server.");
      end_if;

      if sConnSafety.pCallback & sConnSafety.bdSafetyFlags.bSafetyDeactivated = FALSE then
        //initialize safety state
        sConnSafety.bdSafetyFlags.bSafetyOK := TRUE;
      else
        sConnSafety.bdSafetyFlags.bSafetyOK := FALSE;
      end_if;
      
      ClassState        := _NotInitialized;
      eInitModulSSW     := _ReadTypeLabel;
      
      sSDOVars.udTimeOutTypeLabel := ops.tAbsolute;
      pResult^.aData[0] := _BUS_IF_RETVAL_OK;

//**********************************************************************************************************************************************************
    _BUS_IF_HWDISCONNECT :
      // device has been disconnected
      DisconnectEvent();

      //route data to connected safety class
      if sConnSafety.pCallback then
        sConnSafety.pCallback^.pSvrChCmd.NewInst(pPara,pResult);
      end_if;

      pResult^.aData[0] := _BUS_IF_RETVAL_OK;

//**********************************************************************************************************************************************************
    _BUS_IF_HWINTERRUPT :
      // error at device which may lead to a disconnect or replace the disconnect callback
      InterruptEvent();

      //route data to connected safety class
      if sConnSafety.pCallback then
        sConnSafety.pCallback^.pSvrChCmd.NewInst(pPara,pResult);
      end_if;

      pResult^.aData[0] := _BUS_IF_RETVAL_OK;

//**********************************************************************************************************************************************************
    _BUS_IF_POST_INIT_RT_READY:
      if eInitModulSSW = _DefaultWork | eInitModulSSW = _ErrorInit then
        ret_code := READY;
      else
        ret_code := BUSY;
      end_if;

//**********************************************************************************************************************************************************
    CMD_GET_HARDWARE_DIAGNOSIS:
      //route data to connected safety class for safety infos
      if sConnSafety.pCallback then
        sConnSafety.pCallback^.pSvrChCmd.NewInst(pPara,pResult);
      end_if;

      if pDriveMngBase then
        ret_code := pDriveMngBase$pVirtualBase^.pSvrChCmd.NewInst(pPara,pResult); //Pass on command to extension module
      else
        ret_code := READY;
        pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_OK_END_OF_LIST;
      end_if;

//**********************************************************************************************************************************************************
    CMD_GET_HARDWARE_TREE_ENTRY:
      if pDriveMngBase then
        ret_code := pDriveMngBase$pVirtualBase^.pSvrChCmd.NewInst(pPara,pResult); //Pass on command to extension module
      else
        ret_code := READY;
        pResult^.aData[0]$t_HWCGetHardwareTreeEntryOut.retcode := _HWC_RETVAL_OK_END_OF_LIST;
      end_if;

//**********************************************************************************************************************************************************
    _BUS_IF_CHECK_DEVICE_ID :
      // check for correct device id
      pResult^.aData[0] := (DeviceID = pPara^.aPara[0]$UDINT);

      bdGeneralFlags.bDeviceIDOk := pResult^.aData[0]$BOOL;

//**********************************************************************************************************************************************************
    _BUSIF_VVDRIVE_ADD_MDD2000_MDP_ERROR:
      if sDriveType.eDriveType = _MDPType then
        //give mdd class the read data pointer from mdp class        
        ret_code := READY;
        pResult^.aData[0]$UDINT := _BUS_IF_RETVAL_OK;
        pResult^.aData[4]$DINT  := (sAccesses.pReadDigIn)$DINT;
        //return mdp hw path        
        pResult^.aData[8]$UINT  := sDriveType.uiHwPathLen;
        pResult^.aData[10]$DINT := sDriveType.pHwPath$DINT;
      // its a mdd drive
      elsif sDriveType.eDriveType = _MDDType       
        & (sDriveType.pHwPath + (sDriveType.pHwPath^$UINT-1))^ <> HWT_ESCAPE_VARAN then
        //route data to businterface Varan
        ret_code := toVaranIn.VaranIn.NewInst(pPara, pResult);
      elsif sDriveType.eDriveType = _TypeNotRead then
        ret_code := BUSY;
      else
        ret_code := ERROR;
      end_if;
    
  //**********************************************************************************************************************************************************
  else
    //route data to businterface Varan
    ret_code := ToBusInterface.NewInst(#MyPara,#MyResult);

  end_case;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MDD2000VVBase::CallCommandFSoE::NewInst
	VAR_INPUT
		pPara 	: ^CmdStruct;
		pResult 	: ^results;
	END_VAR
	VAR_OUTPUT
		ret_code 	: iprStates;
	END_VAR
  VAR  	
    dTempRetCode : DINT;
  END_VAR

  ret_code := READY;

  case pPara^.uiCmd of
//**********************************************************************************************************************************************************
    _BUS_IF_ADD_CALLBACK :         // Set Callbackpointer
      pResult^.uiLng    := 4;

      if pPara^.aPara[0]$^t_BusIFAddCallback^.pthis = NIL then
        pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_ERROR_INVALID_POINTER;
        ret_code := ERROR;
      else
        sConnSafety.pCallback := pPara^.aPara[0]$^t_BusIFAddCallback^.pthis;
        pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;
      end_if;

//**********************************************************************************************************************************************************
    _BUS_IF_ADD_TASK :             // Add Task for connected safety class
      AddSafetyTask(pPara, pResult);
      if pResult^.aData[0]$t_BusIFRetvalErrorcode <> _BUS_IF_RETVAL_OK then
        ret_code := ERROR;
      end_if;

//**********************************************************************************************************************************************************
    _BUS_IF_ADD_DO :               // Add Data Object from safety class
      //route data from safety to businterface class
      ToBusInterface.NewInst(pPara, pResult);

//**********************************************************************************************************************************************************
    _BUS_IF_GET_PARAM:
      if pPara^.aPara[0] = _BUS_IF_DEVICEID then
        pResult^.aData[0]$t_BusIFRetvalErrorcode := _BUS_IF_RETVAL_OK;
        pResult^.aData[4]$UDINT := DeviceID;
      else
        ret_code := ToBusInterface.NewInst(pPara:=pPara, pResult:=pResult);
      end_if;

//**********************************************************************************************************************************************************
    _BUS_IF_CHECK_DEVICE_ID :
      // check for correct device id
      pResult^.aData[0] := (DeviceID = pPara^.aPara[0]$UDINT);

      bdGeneralFlags.bDeviceIDOk := pResult^.aData[0]$BOOL;

//**********************************************************************************************************************************************************
    _BUSIF_VVDRIVE_GET_MAILBOX :
      // get infos from vandal mailbox
      dTempRetCode := GetMailboxInfo(hiID:=pPara^.aPara[0]$t_MailboxTypes
                                   , pMailboxData:=#pResult^.aData[0]$t_Mailbox
                                   , pMailboxID := NIL);
      if dTempRetCode <> 1 then
        ret_code := ERROR;
        pResult^.aData[0]$DINT := dTempRetCode;
      end_if;

//**********************************************************************************************************************************************************
    _BUSIF_VVDRIVE_SET_SAFETY_STATE :
      // if state is 0 safety class is not ok - deactivate
      if pPara^.aPara[0] = 1 then
        sConnSafety.bdSafetyFlags.bSafetyDeactivated := FALSE;
      else
        sConnSafety.bdSafetyFlags.bSafetyDeactivated := TRUE;
      end_if;
      
//**********************************************************************************************************************************************************
    BUSIF_DRIVEMNGBASE_GET_PARA_STATE,
    BUSIF_DRIVEMNGBASE_SET_PARAMETER,
    BUSIF_DRIVEMNGBASE_GET_PARAMETER:
      ret_code := DriveBusIF.NewInst(pPara:=pPara, pResult:=pResult);

  //**********************************************************************************************************************************************************
  
    MDD2000MNG_IF_SAFETYCONFIG_CHANGEDRESULT:
      ret_code := pDriveMngBase$pVirtualBase^.pSvrChCmd.NewInst(pPara,pResult); //Pass on command to extension module
    
  else
    //route data to businterface class
    ret_code := ToBusInterface.NewInst(pPara, pResult);
  end_case;

END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::AddSafetyTask
	VAR_INPUT
		pCmd 	: ^CmdStruct;
		presult 	: ^results;
	END_VAR
  VAR
  	pTASKCfg      : ^t_TaskCfg;
  END_VAR

  presult^.uiLng    := 4;

  pTASKCfg := ((pCmd^.aPara[0])$^t_TaskCfg);

  // Check for null pointer
  if pTASKCfg^.pthis
  & (sConnSafety.pThisSafety = NIL | sConnSafety.pThisSafety$UDINT = pTASKCfg^.pthis) then

    sConnSafety.pThisSafety := (pTASKCfg^.pthis)$pVirtualBase;
    sConnSafety.usCallOption := sConnSafety.usCallOption or pTASKCfg^.callOptions;

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

END_FUNCTION


FUNCTION MDD2000VVBase::GetMailboxInfo
	VAR_INPUT
		hiID 	: t_MailboxTypes;
		pMailboxData 	: ^t_MailBox;
		pMailboxID 	: ^USINT;
	END_VAR
	VAR_OUTPUT
		dRetCode 	: DINT;
	END_VAR
  VAR
  	usTmpCnt : USINT;
  END_VAR

  //initialize Retcode with ID not found
  dRetCode := -1;

  if pMailboxID then
    pMailboxID^ := MDD2000VVBASE_SERVICE_APP_INVALID;
  end_if;

  //search for Mailbox ID
  for usTmpCnt := 0 to MDD2000VVBASE_MAX_SERVICEBOX-1 do
    if hiID = sTypeLabel.aMailBoxes[usTmpCnt].ID then
      //ID is found -> copy data to pointer
      if pMailboxData then
        pMailboxData^ := sTypeLabel.aMailBoxes[usTmpCnt];
      end_if;
      if pMailboxID then
        pMailboxID^ := usTmpCnt;
      end_if;
      dRetCode := 1;
      exit;
    end_if;
  end_for;

END_FUNCTION


FUNCTION MDD2000VVBase::SetClassState
	VAR_INPUT
		tClassState 	: t_e_VaranErrors;
	END_VAR
  VAR
  	MyPara   : CmdStruct;
    MyResult   : results;  	
  END_VAR

  ClassState      := tClassState;
  MyPara.uiCmd    := _BUS_IF_SET_CLASS_STATE;
  MyPara.aPara[0] := tClassState$DINT;
  ToBusInterface.NewInst(#MyPara, #MyResult);

END_FUNCTION


FUNCTION MDD2000VVBase::GetAxisNoHW
	VAR_INPUT
		bdAxisPlaces 	: BDINT;
	END_VAR
	VAR_OUTPUT
		usAxisNo 	: USINT;
	END_VAR
  VAR
  	usCnt : USINT;
  END_VAR
  
  usAxisNo := 0;
  
  for usCnt := 0 to 7 do
    if (bdAxisPlaces shr usCnt) and 1 = 1 then
      usAxisNo += 1;
    end_if;
  end_for;

END_FUNCTION


FUNCTION MDD2000VVBase::GetIsoObjectLength
	VAR_INPUT
		bdHwAxis 	: BDINT;
		bdSwAxis 	: BDINT;
		DeviceID 	: UDINT;
		usMaxAxis 	: USINT;
		pusHighestAxisNrb 	: ^USINT;
		pudDataOffset 	: ^UDINT;
		puiLength 	: ^UINT;
		bRd 	: BOOL;
	END_VAR
	VAR_OUTPUT
		dRetCode 	: iprStates;
	END_VAR
  VAR
  	siTmpCnt : SINT;
    bTmpFlagHW : BOOL;
    bTmpFlagSW : BOOL;
  END_VAR
  
  dRetCode := ERROR;
  
  //check pointer
  if puiLength & pusHighestAxisNrb & pudDataOffset then
    puiLength^ := 0;
    pusHighestAxisNrb^ := 0;
    pudDataOffset^     := 0;
  else
    return;
  end_if;
  
  for siTmpCnt := usMaxAxis$sint to 1 by -1 do
    bTmpFlagHW := ((bdHwAxis shr siTmpCnt-1)and 1)$BOOL;  
    bTmpFlagSW := ((bdSwAxis shr siTmpCnt-1)and 1)$BOOL;  
    if bTmpFlagHW & bTmpFlagSW then
      exit;
    end_if;
  end_for;
  
  // check amount of axis
  if siTmpCnt > 0 then    
    pusHighestAxisNrb^ := siTmpCnt$USINT;    
    puiLength^ := 4;
    
    if bRd then
      puiLength^ += (to_udint(siTmpCnt) * sAxPDOInfos.AxLenRd);
    else
      puiLength^ += (to_udint(siTmpCnt) * sAxPDOInfos.AxLenWr);
    end_if;    

  end_if;

END_FUNCTION


FUNCTION MDD2000VVBase::GetObjectValueNew
  VAR
    uiTmpDataLen  : UINT;
    hdTempOffset  : HDINT;
    usTmpMsgCnt   : USINT;
  END_VAR  

  if sCmdIntMB.dMBAvailable <> 1 then
    return;
  end_if;  

  //------------------------------------------------------------------------------------------------
  //get to right step
  case sCmdIntMB.eParaState of          
  //******************************************************************************************************************
    _IdlePara:				//do nothing in this step
      //check for new Read request
      if sCmdIntMB.tsRdPara.usCnt then
        sCmdIntMB.eParaState  := _RequReadPara;
      elsif sCmdIntMB.tsWrPara.usCnt then
      end_if;  

  //******************************************************************************************************************
    _RequReadPara://
      //check for new Read request
      uiTmpDataLen := sizeof(sCmdIntMB.tsRdPara.usCnt) + (sizeof(tsDS402RdRequ)*sCmdIntMB.tsRdPara.usCnt) + sizeof(tsMailboxFooter);
      hdTempOffset := sCmdIntMB.sMailboxInfo.Request.hiAddress + sCmdIntMB.sMailboxInfo.Request.uiLength - uiTmpDataLen;
      
      //set data length for mailbox footer
      sCmdIntMB.tsReq.sMBFooter.uiDatalength := uiTmpDataLen - sizeof(tsMailboxFooter);
      sCmdIntMB.tsReq.sMBFooter.usCmd        := _BUSIF_VVDRIVE_READ_PARA_CMD;
      
      //increment msg counter
      usTmpMsgCnt := (sCmdIntMB.tsReq.sMBFooter.bsControl and 0x07) + 1;
      
      //check for msg counter overflow
      if usTmpMsgCnt > 0x07 then
        usTmpMsgCnt := 0;
      end_if;
      
      sCmdIntMB.tsReq.sMBFooter.bsControl := usTmpMsgCnt$BSINT;
      
      ChangeWrDO(AccessHandle := sAccesses.WriteAccessAsy[0].Handle
              , NewOffset     := hdTempOffset
              , NewLength     := uiTmpDataLen
              );                
              
      //write data to pointer
      sAccesses.WriteAccessAsy[0].pData^$USINT := sCmdIntMB.tsRdPara.usCnt;
      _memcpy(ptr1:=sAccesses.WriteAccessAsy[0].pData + sizeof(sCmdIntMB.tsRdPara.usCnt)
            , ptr2:=#sCmdIntMB.tsRdPara.aRequ
            , cntr:=(sizeof(tsDS402RdRequ)*sCmdIntMB.tsRdPara.usCnt));
              
      //copy mailbox footer into request data
      _memcpy(ptr1:=sAccesses.WriteAccessAsy[0].pData + sCmdIntMB.tsReq.sMBFooter.uiDatalength
            , ptr2:=#sCmdIntMB.tsReq.sMBFooter
            , cntr:=sizeof(tsMailboxFooter));
      
      EnableDO(AccessHandle:=sAccesses.WriteAccessAsy[0].Handle);
      
      sCmdIntMB.eParaState := _RespReadPara;
      

  //******************************************************************************************************************
    _RespReadPara:    
      uiTmpDataLen := sizeof(sCmdIntMB.tsRdPara.usCnt) + (sizeof(DINT)*sCmdIntMB.tsRdPara.usCnt) + sizeof(tsMailboxFooter);
      hdTempOffset := sCmdIntMB.sMailboxInfo.Response.hiAddress + sCmdIntMB.sMailboxInfo.Response.uiLength - uiTmpDataLen;
    
      sAccesses.ReadAccessAsy[0].Offset := (sizeof(t_SDOResponse) - sAccesses.ReadAccessAsy[0].Length);
      ChangeRdDO(AccessHandle := sAccesses.ReadAccessAsy[0].Handle
              , NewOffset     := hdTempOffset
              , NewLength     := uiTmpDataLen
              );
              
      sAccesses.ReadAccessAsy[0].OldLength := sAccesses.ReadAccessAsy[0].Length;
      sAccesses.ReadAccessAsy[0].OldOffset := sAccesses.ReadAccessAsy[0].Offset;
      
      sCmdIntMB.tsResp.pMBFooter := sAccesses.ReadAccessAsy[0].pData + (uiTmpDataLen - sizeof(tsMailboxFooter));
      
      DisableDO(AccessHandle:=sAccesses.WriteAccessAsy[0].Handle);
      EnableDO(AccessHandle:=sAccesses.ReadAccessAsy[0].Handle);        

      //next step
      sCmdIntMB.eParaState   := _Wait4ReadPara;
      sSDOVars.udSDOTimeOut  := ops.tAbsolute;


  //******************************************************************************************************************
    _Wait4ReadPara:		//wait until receive state is    
      if (sCmdIntMB.tsResp.pMBFooter^.bsControl and 0x0F) = sCmdIntMB.tsReq.sMBFooter.bsControl 
      &  sAccesses.ReadAccessAsy[0].pData^$USINT = sCmdIntMB.tsRdPara.usCnt then
        _memcpy(ptr1:= #sCmdIntMB.tsRdPara.aResp
              , ptr2:= sAccesses.ReadAccessAsy[0].pData + sizeof(sCmdIntMB.tsRdPara.usCnt)
              , cntr:= sCmdIntMB.tsRdPara.usCnt * sizeof(DINT));
              
        //set read data to given data pointer 
        for usTmpMsgCnt := 0  to sCmdIntMB.tsRdPara.usCnt-1 do
          sCmdIntMB.tsRdPara.aRespCB[usTmpMsgCnt]^ := sCmdIntMB.tsRdPara.aResp[usTmpMsgCnt];
        end_for;
        
        //reset read para counter
        sCmdIntMB.tsRdPara.usCnt := 0;
        sCmdIntMB.eParaState  := _IdlePara;
        DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[0].Handle);
        
      elsif sCmdIntMB.tsResp.pMBFooter^.bsControl.ErrorFlag = TRUE then
        //error occurred
        //reset read para counter
        DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[0].Handle);
        sCmdIntMB.tsRdPara.usCnt := 0;
        sCmdIntMB.eParaState  := _IdlePara;
      end_if;      

      if (ops.tAbsolute - sSDOVars.udSDOTimeOut) >= MDD2000VVBASE_SDO_RESPONSE_TIMEOUT then
        DisableDO(AccessHandle:=sAccesses.ReadAccessAsy[0].Handle);
        //reset read para counter
        sCmdIntMB.tsRdPara.usCnt := 0;
        sCmdIntMB.eParaState  := _IdlePara;
      end_if;
      
  end_case;

END_FUNCTION

FUNCTION GLOBAL MDD2000VVBase::GetNReadPara
	VAR_INPUT
		hiIndex 	: HINT;
		hsSubIndex 	: HSINT;
		pDataCB 	: ^DINT;
		usParaType 	: USINT;(* := _BUSIF_VVDRIVE_INTEGER32 *)
		usAxisNbr 	: USINT;(* := 0 *)
	END_VAR
	VAR_OUTPUT
		dRetCode 	: DINT;
	END_VAR  
  
  #ifdef _BUSIF_VVDRIVE_READ_NPARA_MB
    //initialize retcode
    dRetCode := 0;
  #else
    dRetCode := -2;
    return;    
  #endif
  
  if sCmdIntMB.eParaState <> _IdlePara then
    dRetCode := -1;
    return;
  end_if;
  
  sCmdIntMB.tsRdPara.aRequ[sCmdIntMB.tsRdPara.usCnt].hiIndex    := hiIndex;
  sCmdIntMB.tsRdPara.aRequ[sCmdIntMB.tsRdPara.usCnt].hsSubIndex := hsSubIndex;
  sCmdIntMB.tsRdPara.aRequ[sCmdIntMB.tsRdPara.usCnt].usParaType := usParaType;
  sCmdIntMB.tsRdPara.aRespCB[sCmdIntMB.tsRdPara.usCnt]          := pDataCB;
  sCmdIntMB.tsRdPara.usCnt += 1;
  
END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::GetFile
	VAR_INPUT
		pDestinationDPNE 	: ^CHAR;
		pFileNameDrive 	: ^CHAR;
		pFilePathDrive 	: ^CHAR;
		pdError 	: ^DINT;
	END_VAR
	VAR_OUTPUT
		dRetCode 	: iprStates;
	END_VAR
  VAR
	  astr_threadname : ARRAY [0..30] OF CHAR;
  END_VAR
  
  dRetCode := ERROR;
  
  //Check if filehandling is busy, if it is busy we don't overwrite the error pointer
  if sFileHandling.eFileHandlingSSW <> t_FileHandlingSSW::_IdleFileHandling then
    if pdError then
      pdError^ := MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_BUSY;
    end_if;
    return;
  end_if;

  if sCmdIntMB.dMBAvailable = 0 then
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_MAILBOX_NOT_AVAILABLE, pdError);
    return;
  end_if;
    
  //Check for valid pointers  
  if pDestinationDPNE = NIL | pFileNameDrive = NIL | pFilePathDrive = NIL then
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_INVALID_POINTER, pdError);    
    return;
  end_if;
  
  //Use passed filename if it fits
  if sigclib_strlen(pFileNameDrive) < sizeof(sFileHandling.aFileNameDrive) then // < because space for closing zero
    sigclib_strcpy(#sFileHandling.aFileNameDrive[0], pFileNameDrive);
  else
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_FILENAME_DRIVE_TOO_LONG, pdError);    
    return;
  end_if;

  //Use passed filepath if it fits
  if sigclib_strlen(pFilePathDrive) < sizeof(sFileHandling.aFilePathDrive) then // < because space for closing zero
    sigclib_strcpy(#sFileHandling.aFilePathDrive[0], pFilePathDrive);
  else
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_FILEPATH_DRIVE_TOO_LONG, pdError);    
    return;
  end_if;
  
  //Use passed destination path if it fits
  if sigclib_strlen(pDestinationDPNE) < sizeof(sFileHandling.aDestinationDPNE) then // < because space for closing zero
    sigclib_strcpy(#sFileHandling.aDestinationDPNE[0], pDestinationDPNE);
  else
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_FILEDPNE_TOO_LONG, pdError);    
    return;
  end_if;
    
  //Reset error
  SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_NO_ERROR, pdError);
  
  //Set/Reset variables needed for filehandling
  sFileHandling.hdRequestOffset     := sCmdIntMB.sMailboxInfo.Request.hiAddress;
  sFileHandling.hdResponseOffset    := sCmdIntMB.sMailboxInfo.Response.hiAddress;
  sFileHandling.ReadOrWriteFileSuccessful := 0;  
  sFileHandling.dProgress           := 0; //reset progress
  
  sFileHandling.dAccessType        := t_e_FileAccessType::_ReadFile; //Read file
  
  //Start SSW
  sFileHandling.eFileHandlingSSW  :=  t_FileHandlingSSW::_GetActMsgCounter_Req;
  
  //Create a dynamic threadname
  sigclib_strcpy(#astr_threadname[0], "MDD2000VVBaseFileHndl");
  sigclib_htoa(#astr_threadname[sigclib_strlen(#astr_threadname[0])], this$udint);    
  
  //Start Task for file handling
  //************************************************************************************************
  sFileHandling.mtTaskHandle := toMultiTask.CREATETHREAD( taskfunction0  := #FilehandlingTask()
                                                        , priority0     := 10           // priority same as background
                                                        , stackSize0    := 0x4000
                                                        , flags0        := MT_TASK_SAVETHIS
                                                        , parameter0    := THIS
                                                        , name0         := #astr_threadname[0]);
  
  if sFileHandling.mtTaskHandle <> NIL then
    dRetCode := READY;  //get file was started.
  else
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_CREATETHREAD_FAILED, pdError);
  end_if;  

END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::GetFileState
	VAR_INPUT
		pdError 	: ^DINT;(* := nil *)
		pdProgress 	: ^DINT;(* := nil *)
		pudBytesRead 	: ^UDINT;(* := nil *)
	END_VAR
	VAR_OUTPUT
		dState 	: iprStates;
	END_VAR
    
  //Refresh error value if available
  if pdError then
    pdError ^:= sFileHandling.dError;
  end_if;
  
  //Refresh progress
  if pdProgress then
    pdProgress^ := sFileHandling.dProgress;
  end_if;
  
  //Refresh amount of bytes read
  if pudBytesRead then
    pudBytesRead^ := sFileHandling.udReadedDataLen;
  end_if;
  
  if sFileHandling.eFileHandlingSSW = t_FileHandlingSSW::_IdleFileHandling then
    
    case sFileHandling.dAccessType of
    
      _ReadFile,
      _WriteFile,
      _ReadFileInBuffer:
      
        //Not started yet or finished
        if sFileHandling.ReadOrWriteFileSuccessful = 0 | sFileHandling.ReadOrWriteFileSuccessful = 1 then
          dState := READY;
        else
          dState := ERROR;
        end_if;
      
      _GetFileSize:
      
        if sFileHandling.dGetFileSizeStarted = 0 then
          
          dState := READY;
          
        elsif sFileHandling.dGetFileSizeStarted = 1 then
    
          dState := BUSY;
         
        elsif sFileHandling.dGetFileSizeStarted = 2 then

          if sFileHandling.pudGetFileSizeReturn then
            sFileHandling.pudGetFileSizeReturn^ := sFileHandling.udDataLenToRead;  
          end_if;

          sFileHandling.dGetFileSizeStarted := 0; //Reset 
          
          dState := READY;
        
        elsif sFileHandling.dGetFileSizeStarted = -1 then
        
          sFileHandling.dGetFileSizeStarted := 0; //Reset 
          dState := ERROR;
        end_if;
    
    end_case;

  else
    dState := BUSY;
  end_if;

END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::SetFile
	VAR_INPUT
		pWriteData 	: ^void;
		udWriteDataLen 	: UDINT;
		pFilePathDrive 	: ^CHAR;
		pFileNameDrive 	: ^CHAR;
		pdError 	: ^DINT;(* := nil *)
	END_VAR
	VAR_OUTPUT
		dRetcode 	: iprStates;
	END_VAR  
  
  dRetCode := ERROR;
  
  //Check if filehandling is busy, if it is busy we don't overwrite the error pointer
  if sFileHandling.eFileHandlingSSW <> t_FileHandlingSSW::_IdleFileHandling then
    if pdError then
      pdError^ := MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_BUSY;
    end_if;
    return;
  end_if;
  
  if sCmdIntMB.dMBAvailable = 0 then
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_MAILBOX_NOT_AVAILABLE, pdError);
    return;
  end_if;
    
  //Check for valid pointers
  if pWriteData = NIL | pFileNameDrive = NIL | pFilePathDrive = NIL then
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_INVALID_POINTER, pdError);
    return;
  end_if;
  
  if (udWriteDataLen = 0) | (udWriteDataLen > 0x7FFFFFFF) then // Check if a negative returncode was passed as length.
    //Invalid length
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_INVALID_LENGTH, pdError);
    return;
  end_if;
  
  //Save pointer to write data and length
  sFileHandling.pWriteData     := pWriteData;
  sFileHandling.udWriteDataLen := udWriteDataLen;
  
  if sigclib_strlen(pFileNameDrive) < sizeof(sFileHandling.aFileNameDrive) then // < because space for closing zero
    sigclib_strcpy(#sFileHandling.aFileNameDrive[0], pFileNameDrive);
  else
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_FILENAME_DRIVE_TOO_LONG, pdError);
    return;
  end_if;

  //Use passed filepath if it fits
  if sigclib_strlen(pFilePathDrive) < sizeof(sFileHandling.aFilePathDrive) then // < because space for closing zero
    sigclib_strcpy(#sFileHandling.aFilePathDrive[0], pFilePathDrive);
  else
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_FILEPATH_DRIVE_TOO_LONG, pdError);    
    return;
  end_if;
    
  //Reset error
  SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_NO_ERROR, pdError);
  
  //Set/Reset variables needed for filehandling
  sFileHandling.hdRequestOffset     := sCmdIntMB.sMailboxInfo.Request.hiAddress;
  sFileHandling.hdResponseOffset    := sCmdIntMB.sMailboxInfo.Response.hiAddress;
  sFileHandling.ReadOrWriteFileSuccessful := 0;  
  sFileHandling.dProgress           := 0;
  sFileHandling.bFinishFileTransfer := FALSE;

  sFileHandling.dAccessType        := t_e_FileAccessType::_WriteFile; //write file
  
  //Start SSW
  sFileHandling.eFileHandlingSSW  :=  t_FileHandlingSSW::_GetActMsgCounter_Req;
    
  dRetCode := READY;  //get file was started.  

END_FUNCTION


FUNCTION MDD2000VVBase::ProcessFileHandling
VAR
  tmpRetCode : iprStates;
  TmpErrorCode : DINT;
  usRequestLen : USINT;
END_VAR

  case sFileHandling.eFileHandlingSSW of
  
    //********************************************************************************************************************************************************
    t_FileHandlingSSW::_IdleFileHandling: 
            
    //********************************************************************************************************************************************************
    t_FileHandlingSSW::_GetActMsgCounter_Req:
      
      //Read out the current message counter from the drive
      ChangeRdDO(AccessHandle := sAccesses.ReadFileAccessAsy.Handle
              , NewOffset     := (sFileHandling.hdResponseOffset + t_s_MailboxData.Footer.bsControl)
              , NewLength     := sizeof(t_s_MailboxData.Footer.bsControl)
              );
              
      EnableDO(AccessHandle:=sAccesses.ReadFileAccessAsy.Handle);                      
      sFileHandling.eFileHandlingSSW := t_FileHandlingSSW::_GetActMsgCounter_Resp;

    //********************************************************************************************************************************************************
    t_FileHandlingSSW::_GetActMsgCounter_Resp:
      
      //Save the current message counter of the mailbox
      sigclib_memcpy(#sFileHandling.sMailBoxSendData.Footer.bsControl, sAccesses.pReadFileHandlingAsy, sizeof(t_s_MailboxData.Footer.bsControl));
      DisableDO(AccessHandle:=sAccesses.ReadFileAccessAsy.Handle);
      
      //Go on with next step
      sFileHandling.eFileHandlingSSW := t_FileHandlingSSW::_SetWorkingDirectory;

    //********************************************************************************************************************************************************
    t_FileHandlingSSW::_SetWorkingDirectory:
    
      //Set the working directory where we want to read or write the wanted file   
      tmpRetCode := FileHandlingMailBoxAccess(pSendRequestData  :=  #sFileHandling.aFilePathDrive[0]
                                            , usRequestLen      :=  to_usint(sigclib_strlen(#sFileHandling.aFilePathDrive[0]) + 1) //+1 for termination
                                            , usCommand         :=  MDD2000VVBASE_VANDAL_MAILBOX_COMMAND_FILE_SET_WORKING_DIRECTORY
                                            , hdRequestOffset   :=  sFileHandling.hdRequestOffset
                                            , hdResponseOffset  :=  sFileHandling.hdResponseOffset
                                            , udWriteDOLen      :=  sizeof(t_s_MailboxData) 
                                            , udReadDOLen       :=  sizeof(t_s_MailboxData)
                                            , pdErrorCode       :=  #TmpErrorCode
                                            );
      
      if tmpRetCode = READY then
        
        //Check if we want to read or write file
        if sFileHandling.dAccessType = t_e_FileAccessType::_ReadFile | 
           sFileHandling.dAccessType = t_e_FileAccessType::_ReadFileInBuffer | 
           sFileHandling.dAccessType = t_e_FileAccessType::_GetFileSize   
        then
        
          //We want to read out file
          sFileHandling.udCurrentGetWorkingDirectoryCount := 0; //Reset value before going to next step
          sFileHandling.eFileHandlingSSW := _GetWorkingDirectory;
          
        elsif sFileHandling.dAccessType = t_e_FileAccessType::_WriteFile then
          //Write data active
          
          sFileHandling.udSentDataSize := 0;  //Reset sent data size
          
          //Copy filename in databuffer
          sigclib_strcpy(#sFileHandling.sWriteFileData.aData[0], #sFileHandling.aFileNameDrive[0]);
                                        
          //Get string length to know to which offset we have to copy the file data
          sFileHandling.udWriteDataHeaderOffset := sigclib_strlen(#sFileHandling.aFileNameDrive[0]) + 1;
          
          if sFileHandling.udWriteDataHeaderOffset < sizeof(sFileHandling.sWriteFileData.aData) then
            //Calculate maximum length we can transmit per access (depends on filename, because filename will be transmited with every access)
            sFileHandling.udMaxDataSizePerWriteAccess := sizeof(sFileHandling.sWriteFileData.aData) - sFileHandling.udWriteDataHeaderOffset;
            sFileHandling.eFileHandlingSSW := _SendFileToDrive;
          else
            //Filename is too long there would be no space left to send data via the file write command. Should be impossible, the filename should be limited to less already.
            HWC_LogPrintf(pThis:=this, format:= "@083B (MDD2000VVBase::ProcessFileHandling) The filename %s is too long. There is no space left for data", #sFileHandling.aFileNameDrive[0]);                      
            SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_FILENAME_DRIVE_TOO_LONG, NIL);      
          end_if;
        end_if;
      
      elsif tmpRetCode = ERROR then
        SetFileHandlingError(dError:=TmpErrorCode, NIL);      
      end_if;

    //********************************************************************************************************************************************************
    t_FileHandlingSSW::_GetWorkingDirectory:
      
      //Get the working directory data
      tmpRetCode := FileHandlingMailBoxAccess(pSendRequestData  :=  #sFileHandling.udCurrentGetWorkingDirectoryCount
                                            , usRequestLen      :=  sizeof(sFileHandling.udCurrentGetWorkingDirectoryCount)
                                            , usCommand         :=  MDD2000VVBASE_VANDAL_MAILBOX_COMMAND_FILE_GET_DIRECTORY_LIST
                                            , hdRequestOffset   :=  sFileHandling.hdRequestOffset
                                            , hdResponseOffset  :=  sFileHandling.hdResponseOffset
                                            , udWriteDOLen      :=  sizeof(t_s_MailboxData) 
                                            , udReadDOLen       :=  sizeof(t_s_MailboxData)
                                            , pdErrorCode       :=  #TmpErrorCode
                                            );
      
      if tmpRetCode = READY then
        
        //Check if we have found the needed filename
        if sigclib_strcmp(#sFileHandling.aFileNameDrive[0], #sFileHandling.sMailboxReceiveData.Data$t_s_VandalGetDirectoryEntry.aFileName[0]) = 0 then
          
          //Save the filesize of the needed file and calculate number of packets we have to read
          sFileHandling.udDataLenToRead := sFileHandling.sMailboxReceiveData.Data$t_s_VandalGetDirectoryEntry.udSize;
          
          if sFileHandling.udDataLenToRead <> 0 then
            
            sFileHandling.udReadedDataLen := 0;  //Reset read data size
            
            case sFileHandling.dAccessType of
              
              //---------------------------------------------------------------------------------------------------------------
              t_e_FileAccessType::_ReadFile: //read file and save it on file on PLC

                //go on with next step
                sFileHandling.eFileHandlingSSW := _CreateLocalFile;
              
              //---------------------------------------------------------------------------------------------------------------
              t_e_FileAccessType::_GetFileSize: //Only get file size, so we are finished here
              
                sFileHandling.dGetFileSizeStarted := 2; //We got the filesize
                sFileHandling.eFileHandlingSSW := _FinishFileHandling;
              
              //---------------------------------------------------------------------------------------------------------------
              t_e_FileAccessType::_ReadFileInBuffer: //read file in buffer, so we don't need to create a local file
                
                sFileHandling.eFileHandlingSSW := _ReadFileFromDrive;
                
                //Check if user wants to read the whole file (is the case when the variable is zero)
                if sFileHandling.udDataLenToReadUserBuffer = 0 then
                  
                  //Check if user buffer is big enough
                  if sFileHandling.udUserBufferLength < sFileHandling.udDataLenToRead then
                    HWC_LogPrintf(pThis:=this, format:= "@083E (MDD2000VVBase::ProcessFileHandling) Can't read file because user buffer length %d is smaller than file size %d", #sFileHandling.udUserBufferLength, #sFileHandling.udDataLenToRead);
                    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_BUFFER_TOO_SMALL, NIL);          
                  end_if;
                else
                
                  //Check if file is big enough to read so many data
                  if sFileHandling.udDataLenToReadUserBuffer > sFileHandling.udDataLenToRead then
                    HWC_LogPrintf(pThis:=this, format:= "@083F (MDD2000VVBase::ProcessFileHandling) Filesize %d to small, user wants to read %d bytes", #sFileHandling.udDataLenToRead, #sFileHandling.udDataLenToReadUserBuffer);
                    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_FILE_TOO_SMALL, NIL);          
                  else
                    //File is big enough
                    sFileHandling.udDataLenToRead := sFileHandling.udDataLenToReadUserBuffer; //Only read as much bytes as user wants to do
                  end_if;
                                   
                end_if;                
            end_case;
            
          else  
            //File was found on drive, but size is zero
            HWC_LogPrintf(pThis:=this, format:= "@082A (MDD2000VVBase::ProcessFileHandling) The file %s was found on drive but it is empty", #sFileHandling.aFileNameDrive[0]);          
            SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_INVALID_LENGTH, NIL);          
          end_if;          
          
        else
          //Wrong filename try next
          sFileHandling.eFileHandlingSSW := _GetWorkingDirectory;
          sFileHandling.udCurrentGetWorkingDirectoryCount += 1;
          
          //Check for last file
          if sFileHandling.udCurrentGetWorkingDirectoryCount = MDD2000VVBASE_VANDAL_FILEHANDLING_MAX_FILES then
            HWC_LogPrintf(pThis:=this, format:= "@0826 (MDD2000VVBase::ProcessFileHandling) The file %s was not found on drive", #sFileHandling.aFileNameDrive[0]);
            //File not found on drive
            SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_DRIVE_FILE_NOT_FOUND, NIL);
          end_if;

        end_if;
      
      elsif tmpRetCode = ERROR then
        SetFileHandlingError(dError:=TmpErrorCode, NIL);  
      end_if;
        
    //********************************************************************************************************************************************************
    t_FileHandlingSSW::_SendFileToDrive:
      
      //Only set write data in first step
      if eMailboxHandling = _MailBox_SetRequest then
        // update the offset in the file
        sFileHandling.sWriteFileData.udFileOffset := sFileHandling.udSentDataSize;
      
        // if it's the first package
        if sFileHandling.udSentDataSize = 0 then
          // we overwrite any existing file
          sFileHandling.sWriteFileData.eMode := t_e_VandalWriteAccessMode::CreateNew;
        else
          // otherwise we just append data in file
          sFileHandling.sWriteFileData.eMode := t_e_VandalWriteAccessMode::Append;
        end_if;   
            
        // check rest size
        if (sFileHandling.udWriteDataLen - sFileHandling.udSentDataSize) < sFileHandling.udMaxDataSizePerWriteAccess then
          // send the rest
          sFileHandling.udWriteActSendSize := sFileHandling.udWriteDataLen - sFileHandling.udSentDataSize;
        else
          // send a complete data package
          sFileHandling.udWriteActSendSize := sFileHandling.udMaxDataSizePerWriteAccess;
        end_if;
        
        //Set correct request length
        if sFileHandling.bFinishFileTransfer = FALSE then
          
          //Datalen = 4 Byte Offset + 1 Byte Mode + x Bytes for filename + x Bytes filedata
          usRequestLen := TO_USINT(sizeof(t_s_VandalWriteFile.udFileOffset)) + sizeof(t_s_VandalWriteFile.eMode) + TO_USINT(sFileHandling.udWriteDataHeaderOffset) + TO_USINT(sFileHandling.udWriteActSendSize) ;
          
          //Copy data into writebuffer
          sigclib_memcpy( #sFileHandling.sWriteFileData.aData[sFileHandling.udWriteDataHeaderOffset]
                        , sFileHandling.pWriteData + sFileHandling.sWriteFileData.udFileOffset
                        , sFileHandling.udWriteActSendSize);    
          
        else
          //Datalen = 4 Byte Offset + 1 Byte Mode + x Bytes for filename + 0 Bytes data (because it is the last access)
          usRequestLen := TO_USINT(sizeof(t_s_VandalWriteFile.udFileOffset)) + sizeof(t_s_VandalWriteFile.eMode) + TO_USINT(sFileHandling.udWriteDataHeaderOffset);
          
          sFileHandling.sWriteFileData.eMode := t_e_VandalWriteAccessMode::CloseFile;
          
          //Clear rest of write buffer
          sigclib_memset( #sFileHandling.sWriteFileData.aData[sFileHandling.udWriteDataHeaderOffset]
                        , 0
                        , sizeof(sFileHandling.sWriteFileData.aData) - sFileHandling.udWriteDataHeaderOffset);          
        end_if;
      
      end_if;
      
      //Write file data to drive   
      tmpRetCode := FileHandlingMailBoxAccess(pSendRequestData  :=  #sFileHandling.sWriteFileData
                                            , usRequestLen      :=  usRequestLen
                                            , usCommand         :=  MDD2000VVBASE_VANDAL_MAILBOX_COMMAND_FILE_WRITE
                                            , hdRequestOffset   :=  sFileHandling.hdRequestOffset
                                            , hdResponseOffset  :=  sFileHandling.hdResponseOffset
                                            , udWriteDOLen      :=  sizeof(t_s_MailboxData) 
                                            , udReadDOLen       :=  sizeof(t_s_MailboxData)
                                            , pdErrorCode       :=  #TmpErrorCode
                                            );
      
      if tmpRetCode = READY then
      
        // success => prepare sending more (if there is more)
        sFileHandling.udSentDataSize += sFileHandling.udWriteActSendSize;
        
        if sFileHandling.udSentDataSize = sFileHandling.udWriteDataLen  then
          
          if sFileHandling.bFinishFileTransfer = TRUE then
            //File transfer is finished now
            sFileHandling.eFileHandlingSSW := _FinishFileHandling;          
          else
            // we have transmitted all data, now send 0 byte data and closefile command to let the firmware know that we are finished
            sFileHandling.bFinishFileTransfer := TRUE;   
          end_if;           

        else
          // continue with sending the file (only count up to 99%, the last 1% is set in finished step)
          sFileHandling.dProgress := TO_DINT(sFileHandling.udSentDataSize * 999 / sFileHandling.udWriteDataLen);
          
          sFileHandling.eFileHandlingSSW := _SendFileToDrive;        
        end_if;            
            
      elsif tmpRetCode = ERROR then
        SetFileHandlingError(dError:=TmpErrorCode, NIL);  
      end_if;
    
    //********************************************************************************************************************************************************
    t_FileHandlingSSW::_CreateLocalFile:
      //nothing to do here (is done in filehandling task)
    
    //********************************************************************************************************************************************************
    t_FileHandlingSSW::_ReadFileFromDrive:
      
      if eMailboxHandling = _MailBox_SetRequest then
        //Set filename we want to read from
        sigclib_strcpy(#sFileHandling.sReadFileData.aData[0], #sFileHandling.aFileNameDrive[0]);
        
        //Set offset in file 
        sFileHandling.sReadFileData.FileOffset := sFileHandling.udReadedDataLen;  
        
        // check rest size
        if (sFileHandling.udDataLenToRead - sFileHandling.udReadedDataLen) < sizeof(t_s_VandalReadFile.aData) then
          // get the rest
          sFileHandling.udActReadSize := to_usint(sFileHandling.udDataLenToRead - sFileHandling.udReadedDataLen);
        else
          // get a complete data package
          sFileHandling.udActReadSize := sizeof(t_s_VandalReadFile.aData);
        end_if;
        
        sFileHandling.sReadFileData.usLength_Cmd := TO_USINT(sFileHandling.udActReadSize);
      end_if;
                        
      //Read file data from drive
      tmpRetCode := FileHandlingMailBoxAccess(pSendRequestData  :=  #sFileHandling.sReadFileData
                                            , usRequestLen      :=  TO_USINT(sizeof(t_s_VandalReadFile.FileOffset) + sizeof(t_s_VandalReadFile.usLength_Cmd) + sigclib_strlen(#sFileHandling.sReadFileData.aData[0]) + 1)
                                            , usCommand         :=  MDD2000VVBASE_VANDAL_MAILBOX_COMMAND_FILE_READ
                                            , hdRequestOffset   :=  sFileHandling.hdRequestOffset
                                            , hdResponseOffset  :=  sFileHandling.hdResponseOffset
                                            , udWriteDOLen      :=  sizeof(t_s_MailboxData) 
                                            , udReadDOLen       :=  sizeof(t_s_MailboxData)
                                            , pdErrorCode       :=  #TmpErrorCode
                                            );
                                            
      if tmpRetCode = READY then
        
        //---------------------------------------------------------------------------------------------------------------
        //Check if we want to read file and write data into a file on the PLC
        if sFileHandling.dAccessType = t_e_FileAccessType::_ReadFile then
        
          //We got data, write it into file
          sFileHandling.eFileHandlingSSW := t_FileHandlingSSW::_WriteDataInLocalFile;      
        
        //---------------------------------------------------------------------------------------------------------------
        //or if we want to read file and write the data into the user buffer
        elsif sFileHandling.dAccessType = t_e_FileAccessType::_ReadFileInBuffer then
          
          //Copy data to user buffer
          sigclib_memcpy(dst0 :=  sFileHandling.pReadBufferUser + sFileHandling.udReadedDataLen
                       , src0 :=  #sFileHandling.sMailboxReceiveData.Data[0]
                       , len0 :=  sFileHandling.sReadFileData.usLength_Cmd
                       );
          
          //Increase our read datalen with the amount of data we have read 
          sFileHandling.udReadedDataLen += sFileHandling.udActReadSize;
          
          //Check if we have read out all data
          if sFileHandling.udReadedDataLen = sFileHandling.udDataLenToRead then
            
            //We have read all data
            sFileHandling.eFileHandlingSSW := _FinishFileHandling;
            
          else
            sFileHandling.dProgress := TO_DINT((sFileHandling.udReadedDataLen * 999) / sFileHandling.udDataLenToRead);          
            //We need to read out more data
            sFileHandling.eFileHandlingSSW := t_FileHandlingSSW::_ReadFileFromDrive;
          end_if;        
        end_if;
        
      
      elsif tmpRetCode = ERROR then
        SetFileHandlingError(dError:=TmpErrorCode, NIL);  
      end_if;            

    //********************************************************************************************************************************************************
    t_FileHandlingSSW::_WriteDataInLocalFile:
      
      //is done in FilehandlingTask (can't be done in cyclic)
      
    //********************************************************************************************************************************************************
    t_FileHandlingSSW::_FinishFileHandling:
  
      //We have read or written all data, show state and set progress to 100 percent
      sFileHandling.ReadOrWriteFileSuccessful := 1;
      sFileHandling.dProgress := 1000; 
      sFileHandling.bFinishFileTransfer := FALSE;
      sFileHandling.eFileHandlingSSW := t_FileHandlingSSW::_IdleFileHandling;
      
    //********************************************************************************************************************************************************
    t_FileHandlingSSW::_ErrorDuringFileHandling:
      
      //Disable the DOs if they are still running
      DisableDO(AccessHandle:=sAccesses.ReadFileAccessAsy.Handle);
      DisableDO(AccessHandle:=sAccesses.WriteFileAccessAsy.Handle);
      
      sFileHandling.dGetFileSizeStarted := -1;
      sFileHandling.ReadOrWriteFileSuccessful := -1;        
      sFileHandling.dProgress := 0; //Reset progress at error
      sFileHandling.bFinishFileTransfer := FALSE;
      sFileHandling.eFileHandlingSSW := t_FileHandlingSSW::_IdleFileHandling;
        
  end_case;

END_FUNCTION


FUNCTION MDD2000VVBase::SetMailboxRequest
	VAR_INPUT
		pSendMailBox 	: ^t_s_MailboxData;
		pSDOWriteDataPtr 	: ^void;
		pData 	: ^void;
		usLen 	: USINT;
		usCommand 	: USINT;
	END_VAR
  
  //Set footer informations
  pSendMailBox^.Footer.uiDataLength := usLen;
  pSendMailBox^.Footer.usCmd        := usCommand;
  pSendMailBox^.Footer.bsControl    := ((pSendMailBox^.Footer.bsControl AND MDD2000VVBASE_VANDAL_MAILBOX_MSG_CNT_MASK) + 1) AND MDD2000VVBASE_VANDAL_MAILBOX_MSG_CNT_MASK;
  
  if pData then
    //Copy data into mailbox data
    sigclib_memcpy(#pSendMailBox^.Data[0], pData, usLen);
            
    //write data to sendbuffer
    sigclib_memcpy(pSDOWriteDataPtr, #pSendMailBox^.Data[0], usLen);
  end_if;

  //copy footer informations to sendbuffer
  sigclib_memcpy( pSDOWriteDataPtr + sizeof(t_s_MailboxData) - sizeof(tsMailboxFooter)
                , #pSendMailBox^.Footer
                , sizeof(tsMailboxFooter));
        
END_FUNCTION


FUNCTION MDD2000VVBase::CheckMailBoxResponse
	VAR_INPUT
		pRecvMailBox 	: ^t_s_MailboxData;
		pSendMailBox 	: ^t_s_MailboxData;
		pReadData 	: ^void;
		udRequestTimeStamp 	: UDINT;
		udTimeout 	: UDINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR
  
  retcode := 0; //BUSY
  
  //Copy footer data
  sigclib_memcpy( #pRecvMailBox^.Footer
                , pReadData + sizeof(t_s_MailboxData) - sizeof(tsMailboxFooter)
                , sizeof(tsMailboxFooter));
    
  // check if it's already the response to our request
  if ((pRecvMailBox^.Footer.bsControl AND MDD2000VVBASE_VANDAL_MAILBOX_MSG_CNT_MASK) = (pSendMailBox^.Footer.bsControl AND MDD2000VVBASE_VANDAL_MAILBOX_MSG_CNT_MASK)) &
     (pRecvMailBox^.Footer.usCmd = pSendMailBox^.Footer.usCmd) then

    // now check the answer
    if pRecvMailBox^.Footer.bsControl.ErrorFlag = 0 then      
    
      //Copy receive data
      sigclib_memcpy( #pRecvMailBox^.Data, pReadData, pRecvMailBox^.Footer.uiDatalength);
            
      retcode := 1;   //READY
    else
      //Copy receive data in every case (in case of error we want to get the errorcode)
      sigclib_memcpy( #pRecvMailBox^.Data
                    , pReadData + sizeof(t_s_MailboxData) - sizeof(tsMailboxFooter) - pRecvMailBox^.Footer.uiDatalength //Errorcode is stored at the last 4 byte
                    , pRecvMailBox^.Footer.uiDatalength);
    
      retcode := -1;  //ERROR errorflag
    end_if;
  
  elsif (ops.tAbsolute - udRequestTimeStamp) > udTimeout then
    retcode := -2;  //Error timeout
  end_if;

END_FUNCTION


FUNCTION MDD2000VVBase::FilehandlingTask
    
  //Run task as long as filehandling is active
  while sFileHandling.eFileHandlingSSW <> t_FileHandlingSSW::_IdleFileHandling do
    
    case sFileHandling.eFileHandlingSSW of
      
      //Empty cases are handled in method ProcessFileHandling
      
      //********************************************************************************************************************************************************
      t_FileHandlingSSW::_IdleFileHandling: 
      t_FileHandlingSSW::_GetActMsgCounter_Req:
      t_FileHandlingSSW::_GetActMsgCounter_Resp:
      t_FileHandlingSSW::_SetWorkingDirectory:
      t_FileHandlingSSW::_GetWorkingDirectory:
      
      //********************************************************************************************************************************************************
      t_FileHandlingSSW::_CreateLocalFile:
      
        // open file (create/overwrite always)
        sFileHandling.pFileHandle := sigclib_cfopen(dpne:=#sFileHandling.aDestinationDPNE[0], state:='W');
              
        if sFileHandling.pFileHandle then
        
          //go on with next step
          sFileHandling.eFileHandlingSSW := _ReadFileFromDrive;  //Start reading file data
        
        else
          // failed to open file
          HWC_LogPrintf(pThis:=this, format:= "@0827 (MDD2000VVBase::FilehandlingTask) Failed to create file %s",#sFileHandling.aDestinationDPNE[0]);
          sFileHandling.ReadOrWriteFileSuccessful := -1; 
          SetFileHandlingError(MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_OPEN_LOCAL_FILE, NIL);  //Failed to open file
        end_if;     
      
      //********************************************************************************************************************************************************
      t_FileHandlingSSW::_ReadFileFromDrive:
      
      //********************************************************************************************************************************************************
      t_FileHandlingSSW::_WriteDataInLocalFile:
                        
        // save content to file
        if sigclib_cfwrite(hdl        :=  sFileHandling.pFileHandle
                         , stc        :=  #sFileHandling.sMailboxReceiveData.Data[0]
                         , bytesize   :=  sFileHandling.sReadFileData.usLength_Cmd) = sFileHandling.sReadFileData.usLength_Cmd then
                               
          sFileHandling.udReadedDataLen += sFileHandling.udActReadSize;
          
          //Check if we have read out all data
          if sFileHandling.udReadedDataLen = sFileHandling.udDataLenToRead then
          
            //We have read all data, close file now
            sigclib_cfclose(hdl:=sFileHandling.pFileHandle);
            sFileHandling.pFileHandle := NIL;
            
            sFileHandling.eFileHandlingSSW := _FinishFileHandling;
            
          else
            sFileHandling.dProgress := TO_DINT((sFileHandling.udReadedDataLen * 999) / sFileHandling.udDataLenToRead);          
            //We need to read out more data
            sFileHandling.eFileHandlingSSW := t_FileHandlingSSW::_ReadFileFromDrive;
          end_if;
                                                            
        else
                                                            
          // failed to write to file
          HWC_LogPrintf(pThis:=this, format:= "@0828 (MDD2000VVBase::FilehandlingTask) Failed to write file %s",#sFileHandling.aDestinationDPNE[0]);

          // close file
          sigclib_cfclose(hdl:=sFileHandling.pFileHandle);          
          sFileHandling.pFileHandle := NIL;
         
          sFileHandling.ReadOrWriteFileSuccessful := -1;
          
          SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_WRITE_LOCAL_FILE, NIL);
        end_if;
        
      //********************************************************************************************************************************************************
      t_FileHandlingSSW::_ErrorDuringFileHandling:
                      
    end_case;
  
  end_while;

  //Close file if it is still open (can happen when there is a disconnect/connect or reinit while filetransfer is active)
  //this way we only need to set the sFileHandling.eFileHandlingSSW to "Idle" to stop the task. This is done in _InitAxis, so there is enough time to get to this code.
  if sFileHandling.pFileHandle <> NIL then
    sigclib_cfclose(hdl:=sFileHandling.pFileHandle);
    sFileHandling.pFileHandle := NIL;
  end_if;

  // the task will be terminated if we leave here. It will be started again if needed for a file upload.

END_FUNCTION


FUNCTION MDD2000VVBase::SetFileHandlingError
	VAR_INPUT
		dError 	: DINT;
		pdError 	: ^DINT;
	END_VAR
  
  //Set internal error
  sFileHandling.dError := dError;

  //Set error information for user if available
  if pdError then
    pdError^ := dError;
  end_if;
  
  if dError = MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_NO_ERROR then
    //clear error
    sFileHandling.eFileHandlingSSWErrorStep := _IdleFileHandling;
    //dont change SSW it self
    //sFileHandling.eFileHandlingSSW := _ErrorDuringFileHandling;
  else
    //Save last errorstep from SSW
    sFileHandling.eFileHandlingSSWErrorStep := sFileHandling.eFileHandlingSSW;
    sFileHandling.eFileHandlingSSW := _ErrorDuringFileHandling;
  end_if;

END_FUNCTION


FUNCTION MDD2000VVBase::FileHandlingMailBoxAccess
	VAR_INPUT
		pSendRequestData 	: ^void;
		usRequestLen 	: USINT;
		usCommand 	: USINT;
		hdRequestOffset 	: HDINT;
		hdResponseOffset 	: HDINT;
		udWriteDOLen 	: UDINT;
		udReadDOLen 	: UDINT;
		pdErrorCode 	: ^DINT;
	END_VAR
	VAR_OUTPUT
		dRetcode 	: iprStates;
	END_VAR
  VAR
    LogVal1 : DINT;  
  	sdRetVal : DINT;
  END_VAR
  
  dRetcode := BUSY;

  case eMailboxHandling of
  
//***********************************************************************************************************************
  	t_e_MailboxHandling::_MailBox_SetRequest:
      
      //Start mailbox request
      SetMailboxRequest(pSendMailBox      :=  #sFileHandling.sMailBoxSendData
                      , pSDOWriteDataPtr  :=  sAccesses.pWriteFileHandlingAsy
                      , pData             :=  pSendRequestData
                      , usLen             :=  usRequestLen
                      , usCommand         :=  usCommand
                      );
                                            
      //Change write DO to given offset
      ChangeWrDO(AccessHandle := sAccesses.WriteFileAccessAsy.Handle
              , NewOffset     := hdRequestOffset
              , NewLength     := udWriteDOLen
              );                
      
      //Enable the data object
      EnableDO(AccessHandle:=sAccesses.WriteFileAccessAsy.Handle);
                      
      //Save timestamp for timeout handling and go to next step                            
      udMailboxTimestamp := ops.tAbsolute;
      eMailboxHandling := _MailBox_SetResponse;
   
    
//***********************************************************************************************************************
  	t_e_MailboxHandling::_MailBox_SetResponse:

      //Disable our write data object              
      DisableDO(AccessHandle:=sAccesses.WriteFileAccessAsy.Handle);

      //Change offset of read data object and enable it
      ChangeRdDO(AccessHandle := sAccesses.ReadFileAccessAsy.Handle
              , NewOffset     := hdResponseOffset
              , NewLength     := udReadDOLen
              );
              
      EnableDO(AccessHandle:=sAccesses.ReadFileAccessAsy.Handle);        

      //go to next step
      eMailboxHandling   := _MailBox_Wait4Response;    
    
//***********************************************************************************************************************
  	t_e_MailboxHandling::_MailBox_Wait4Response:

      //Check if we already got the response to our request  
      sdRetVal := CheckMailBoxResponse( pRecvMailBox        :=  #sFileHandling.sMailboxReceiveData
                                      , pSendMailBox        :=  #sFileHandling.sMailBoxSendData
                                      , pReadData           :=  sAccesses.pReadFileHandlingAsy
                                      , udRequestTimeStamp  :=  udMailboxTimestamp
                                      , udTimeout           :=  MDD2000VVBASE_SDO_RESPONSE_TIMEOUT_FILEHANDLING
                                      );
      
      if sdRetVal = 1 then
        
        //we got the right response
        DisableDO(AccessHandle:=sAccesses.ReadFileAccessAsy.Handle);
        dRetcode := READY;
        eMailboxHandling := _MailBox_SetRequest;
      
      elsif sdRetVal < 0 then

        DisableDO(AccessHandle:=sAccesses.ReadFileAccessAsy.Handle);

        dRetcode := ERROR;
        eMailboxHandling := _MailBox_SetRequest;

        if sdRetVal = -1 then

          //Error at VANDAL communication
          LogVal1 := sFileHandling.sMailboxReceiveData.Data[0]$DINT;  //Save error code

          HWC_LogPrintf(pThis:=this, format:= "@0839 (MDD2000VVBase::FileHandlingMailBoxAccess) Error %d at VANDAL communication.",#LogVal1);              
          
          if pdErrorCode then
            pdErrorCode^ := MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_VANDAL_COMMUNICATION;
          end_if;
       
        elsif sdRetVal = -2 then

          HWC_LogPrintf(pThis:=this, format:= "@0825 (MDD2000VVBase::FileHandlingMailBoxAccess) Error while waiting for response to our request.");      
          if pdErrorCode then
            pdErrorCode^ := MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_VANDAL_TIMEOUT;
          end_if;
        end_if;
      end_if;
    
  end_case;
  
END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::GetFileSize
	VAR_INPUT
		pFileNameDrive 	: ^CHAR;
		pFilePathDrive 	: ^CHAR;
		pudSize 	: ^UDINT;
		pdError 	: ^DINT;(* := nil *)
	END_VAR
	VAR_OUTPUT
		dRetCode 	: iprStates;
	END_VAR  

  dRetCode := ERROR;
  
  //Check if filehandling is busy, if it is busy we don't overwrite the error pointer
  if sFileHandling.eFileHandlingSSW <> t_FileHandlingSSW::_IdleFileHandling then
    if pdError then
      pdError^ := MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_BUSY;
    end_if;
    return;
  end_if;

  if sCmdIntMB.dMBAvailable = 0 then
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_MAILBOX_NOT_AVAILABLE, pdError);
    return;
  end_if;
    
  //Check for valid pointers  
  if pudSize = NIL | pFileNameDrive = NIL | pFilePathDrive = NIL then
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_INVALID_POINTER, pdError);    
    return;
  end_if;
  
  //Use passed filename if it fits
  if sigclib_strlen(pFileNameDrive) < sizeof(sFileHandling.aFileNameDrive) then // < because space for closing zero
    sigclib_strcpy(#sFileHandling.aFileNameDrive[0], pFileNameDrive);
  else
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_FILENAME_DRIVE_TOO_LONG, pdError);    
    return;
  end_if;

  //Use passed filepath if it fits
  if sigclib_strlen(pFilePathDrive) < sizeof(sFileHandling.aFilePathDrive) then // < because space for closing zero
    sigclib_strcpy(#sFileHandling.aFilePathDrive[0], pFilePathDrive);
  else
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_FILEPATH_DRIVE_TOO_LONG, pdError);    
    return;
  end_if;
      
  //Reset error
  SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_NO_ERROR, pdError);
  
  //Set/Reset variables needed for filehandling
  sFileHandling.hdRequestOffset     := sCmdIntMB.sMailboxInfo.Request.hiAddress;
  sFileHandling.hdResponseOffset    := sCmdIntMB.sMailboxInfo.Response.hiAddress;
  sFileHandling.ReadOrWriteFileSuccessful := 0;  
  sFileHandling.dProgress           := 0; //reset progress
  
  sFileHandling.pudGetFileSizeReturn := pudSize;  // Safe pointer to return filesize
  
  sFileHandling.dAccessType        := t_e_FileAccessType::_GetFileSize; //only get filesize 
  
  sFileHandling.dGetFileSizeStarted := 1; //Remember that user has started to get filesize
  
  //Start SSW
  sFileHandling.eFileHandlingSSW  := t_FileHandlingSSW::_GetActMsgCounter_Req;
  
  dRetCode := READY;  //get filesize was started.
  
END_FUNCTION


FUNCTION GLOBAL MDD2000VVBase::GetFileBuffer
	VAR_INPUT
		pFileNameDrive 	: ^CHAR;
		pFilePathDrive 	: ^CHAR;
		udBufferSize 	: UDINT;
		pDataBuffer 	: ^void;
		udDataLenToRead 	: UDINT;(* := 0 *)
		pdError 	: ^DINT;(* := nil *)
	END_VAR
	VAR_OUTPUT
		dRetCode 	: iprStates;
	END_VAR  
  
  dRetCode := ERROR;
  
  //Check if filehandling is busy, if it is busy we don't overwrite the error pointer
  if sFileHandling.eFileHandlingSSW <> t_FileHandlingSSW::_IdleFileHandling then
    if pdError then
      pdError^ := MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_BUSY;
    end_if;
    return;
  end_if;

  if sCmdIntMB.dMBAvailable = 0 then
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_MAILBOX_NOT_AVAILABLE, pdError);
    return;
  end_if;
    
  //Check for valid pointers  
  if pDataBuffer = NIL | pFileNameDrive = NIL | pFilePathDrive = NIL then
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_INVALID_POINTER, pdError);    
    return;
  end_if;
  
  //Use passed filename if it fits
  if sigclib_strlen(pFileNameDrive) < sizeof(sFileHandling.aFileNameDrive) then // < because space for closing zero
    sigclib_strcpy(#sFileHandling.aFileNameDrive[0], pFileNameDrive);
  else
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_FILENAME_DRIVE_TOO_LONG, pdError);    
    return;
  end_if;

  //Use passed filepath if it fits
  if sigclib_strlen(pFilePathDrive) < sizeof(sFileHandling.aFilePathDrive) then // < because space for closing zero
    sigclib_strcpy(#sFileHandling.aFilePathDrive[0], pFilePathDrive);
  else
    SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_FILEPATH_DRIVE_TOO_LONG, pdError);    
    return;
  end_if;
      
  //Reset error
  SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_NO_ERROR, pdError);
  
  //Set/Reset variables needed for filehandling
  sFileHandling.hdRequestOffset     := sCmdIntMB.sMailboxInfo.Request.hiAddress;
  sFileHandling.hdResponseOffset    := sCmdIntMB.sMailboxInfo.Response.hiAddress;
  sFileHandling.ReadOrWriteFileSuccessful := 0;  
  sFileHandling.dProgress           := 0; //reset progress
  
  //Save information from user buffer
  sFileHandling.pReadBufferUser           := pDataBuffer;
  sFileHandling.udUserBufferLength        := udBufferSize;
  sFileHandling.udDataLenToReadUserBuffer := udDataLenToRead; //0 .. just use filesize, x .. amount of bytes user wants to read out
  
  if sFileHandling.udDataLenToReadUserBuffer > 0 then  
    //Check if the user wants to read more data than he has in his own buffer
    if sFileHandling.udDataLenToReadUserBuffer > sFileHandling.udUserBufferLength then
      SetFileHandlingError(dError:=MDD2000VVBASE_VANDAL_FILEHANDLING_ERROR_INVALID_LENGTH, pdError);
    end_if;
  end_if;
  
  sFileHandling.dAccessType        := t_e_FileAccessType::_ReadFileInBuffer; //Read file in buffer
  
  //Start SSW
  sFileHandling.eFileHandlingSSW  :=  t_FileHandlingSSW::_GetActMsgCounter_Req;
    
  dRetCode := READY;  //get file was started.
  

END_FUNCTION
