using System;
using System.Runtime.InteropServices;

namespace pci
{

class zecm
{

public enum ECAT_RESULT
{
    ECAT_S_OK = 0,
    ECAT_S_SIZE_LIMIT = 1,
    ECAT_S_NOITEMS = 2,
    ECAT_S_PI_ALREADY_SYNC = 3,
    ECAT_S_NOITEMS_MAILBOX_WAIT = 4,
    ECAT_S_TIMEOUT = 5,
    ECAT_S_THREAD_EXIT = 6,
    ECAT_S_SYNC_CALL = 7,
    ECAT_S_REDUNDANCY = 8,
    ECAT_S_AGAIN = 9,
    ECAT_S_OBJECT = 10,
    ECAT_S_INVALID_LICENSE = 256,
    ECAT_S_DEMO_TIME_EXPIRED = 257,
    ECAT_S_PI_SYNC_LATE = 528,
    ECAT_S_PI_SYNC_FAST = 544,
    ECAT_E_OUTOFMEMORY = 32769,
    ECAT_E_INVALIDARG = 32770,
    ECAT_E_FAIL = 32771,
    ECAT_E_NOTIMPL = 32772,
    ECAT_E_XML_OPEN = 32773,
    ECAT_E_XML_PARSE = 32774,
    ECAT_E_MASTER_NOT_CONFIGURED = 32775,
    ECAT_E_MASTER_NOT_CONNECTED = 32776,
    ECAT_E_MASTER_ALREADY_CONNECTED = 32777,
    ECAT_E_INVALID_SLAVE_INDEX = 32778,
    ECAT_E_INVALID_TRANSITION = 32779,
    ECAT_E_DRIVER_LOAD = 32780,
    ECAT_E_DRIVER_INIT = 32781,
    ECAT_E_DRIVER_NOT_SUPPORTED = 32782,
    ECAT_E_DRIVER_NOT_LOADED = 32783,
    ECAT_E_SEND_FRAME_FAILED = 32784,
    ECAT_E_RECV_FRAME_FAILED = 32785,
    ECAT_E_TRACE_BUFFER_OVERFLOW = 32786,
    ECAT_E_NOTAVIABLE_TRANSITION = 32787,
    ECAT_E_TRANSITION_ERROR = 32788,
    ECAT_E_INVALID_POINTER = 32789,
    ECAT_E_INVALID_COMMAND_TYPE = 32790,
    ECAT_E_TRANSITION_FORBIDDEN = 32791,
    ECAT_E_SYNC_CALL_TIMEOUT = 32792,
    ECAT_E_MB_COE_TRANSITION_ABORTED = 32793,
    ECAT_E_INVALID_WC = 32794,
    ECAT_E_INVALID_SLAVE_STATE = 32795,
    ECAT_E_SNAPSHOT_DATA_LOSE = 32796,
    ECAT_E_XML_LICENSE_OPEN = 32797,
    ECAT_E_XML_LICENSE_PARSE = 32798,
    ECAT_E_XML_LICENSE_PRODUCT_NAME = 32799,
    ECAT_E_XML_LICENSE_LICENSED_TO = 32800,
    ECAT_E_XML_LICENSE_EXP_DATE = 32801,
    ECAT_E_XML_LICENSE_DEMO_MODE = 32802,
    ECAT_E_XML_LICENSE_HW_BINDING = 32803,
    ECAT_E_XML_LICENSE_PRODUCT_KEY = 32804,
    ECAT_E_CMD_ACYCLIC_SET_DATA = 32805,
    ECAT_E_CMD_CONTAINER_ADD_RES_CMD = 32806,
    ECAT_E_BUFFER_SIZE_LIMIT = 32807,
    ECAT_E_TELEGRAM_BUILD = 32808,
    ECAT_E_FRAME_BUILD = 32809,
    ECAT_E_LOAD_FORBIDDEN = 32810,
    ECAT_E_INVALID_CONFIGURATION = 32811,
    ECAT_E_READ_SLAVE_STATES = 32812,
    ECAT_E_TRANSIT_SLAVES = 32813,
    ECAT_E_SEND_MASTER_CMDS = 32814,
    ECAT_E_MASTER_ALREADY_STARTED = 32815,
    ECAT_E_THREAD_INITIALISE = 32816,
    ECAT_E_READ_EEPROM = 32817,
    ECAT_E_MB_NOT_SUPPORTED = 32818,
    ECAT_E_MB_COE_NOT_SUPPORTED = 32819,
    ECAT_E_PI_ALREADY_UNLOCKED = 32820,
    ECAT_E_INVALID_FRAME_SIZE = 32821,
    ECAT_E_INVALID_FRAME_TYPE = 32822,
    ECAT_E_INVALID_COMMAND_SIZE = 32823,
    ECAT_E_INVALID_COMMAND_DATA = 32824,
    ECAT_E_WRITE_EEPROM = 32825,
    ECAT_E_MASTER_NOT_STARTED = 32826,
    ECAT_E_ARRAY_BOUNDS_EXCEEDED = 32827,
    ECAT_E_INVALID_LICENSE = 32828,
    ECAT_E_RECV_FRAME_TIMEOUT = 32829,
    ECAT_E_EEPROM_ACCESS_DENIED = 32830,
    ECAT_E_EEPROM_ACCESS_DENIDED = 32830,
    ECAT_E_BUSY = 32831,
    ECAT_E_TIME = 32832,
    ECAT_E_ABORTED = 32833,
    ECAT_E_SLAVE_PI_NOT_EXIST = 32834,
    ECAT_E_DC_SYNC = 32835,
    ECAT_E_BAD_CONTEXT = 32836,
    ECAT_E_NOT_PERMITTED = 32837,
    ECAT_E_INI_BAD_CONTENT = 32838,
    ECAT_E_OBJECT = 32839,
    ECAT_E_CHANNEL_TRANSFER = 32840,
    ECAT_E_OPEN_FILE = 32848,
    ECAT_E_WRITE_FILE = 32849,
    ECAT_E_READ_FILE = 32850,
    ECAT_E_CANT_GET_HW_KEY = 32851,
    ECAT_E_CANT_ENCODE_DATA = 32852,
    ECAT_E_CANT_DECODE_DATA = 32853,
    ECAT_E_DRIVER_INVALID_NIC = 32864,
    ECAT_E_QUEUE_RESOURCE_LACK = 32880,
    ECAT_E_QUEUE_NO_ITEMS = 32881,
    ECAT_E_MB_COE_UNSUPPORTED_DATA_TYPE = 33024,
    ECAT_E_MB_COE_OBJECT_IS_READ_ONLY = 33025,
    ECAT_E_MB_COE_OBJECT_IS_WRITE_ONLY = 33026,
    ECAT_E_MB_COE_INCOMPLETE_ENTRY_DESC = 33027,
    ECAT_E_MB_COE_SDOINFO_ERROR = 33028,
    ECAT_E_MB_VOE_NOT_SUPPORTED = 33104,
    ECAT_E_MASTER_IS_LOCKED = 33280,
    ECAT_E_MASTER_NO_RIGHTS = 33281,
    ECAT_E_MASTER_USER_NOT_FOUND = 33282,
    ECAT_E_MASTER_NAME_CANNOT_BE_FOUND = 33283,
    ECAT_E_TASK_CANNOT_BE_FOUND = 33284,
    ECAT_E_AOE_ERROR_CODE = 33536,
    ECAT_E_AOE_CMD_ERROR = 33537,
    ECAT_E_AOE_INVALID_HEADER = 33538,
    ECAT_E_MB_AOE_NOT_SUPPORTED = 33539,
    ECAT_E_AOE_INVALID_ROUTE = 33540,
    ECAT_E_MB_SOE_NOT_SUPPORTED = 33552,
    ECAT_E_SOE_ERROR_CODE = 33553,
    ECAT_E_SOE_INVALID_HEADER = 33554,
    ECAT_E_SOE_FRAGMENT_LEFT = 33555,
    ECAT_E_MB_EOE_NOT_SUPPORTED = 33568,
    ECAT_E_MB_FOE_NOT_SUPPORTED = 33584,
    ECAT_E_OD_OBJECT_NOTFOUND = 33792,
    ECAT_E_OD_OBJECT_ALREADY_EXISTS = 33793,
    ECAT_E_OD_ENTRY_DESCRIPTION_ALREADY_EXISTS = 33794,
    ECAT_E_OD_ENTRY_DESCRIPTION_FAILED = 33795,
    ECAT_E_OD_INVALID_OBJECT_TYPE = 33796,
    ECAT_E_OD_INVALID_ACCESS_TYPE = 33797,
    ECAT_E_OD_INVALID_DATA_TYPE = 33798,
    ECAT_E_OD_ACCESS_DENIED = 33799,
    ECAT_E_OD_NOT_CREATED = 33800,
    ECAT_E_OD_SDO_SERVICE_NOT_SUPORTED = 33801,
    ECAT_E_OD_SDO_SIZE_INVALID_HEADER = 33802,
    ECAT_E_OD_SDO_SIZE_TOO_SHORT = 33803,
    ECAT_E_OD_SDO_INVALID_SIZE = 33804,
    ECAT_E_OD_SUB_OBJ_NOTFOUND = 33805,
    ECAT_E_OD_MORE_MAXIMUM_VALUE = 33806,
    ECAT_E_OD_LESS_MINIMUM_VALUE = 33807,
    ECAT_E_LICENSE_INIT = 34050,
    ECAT_E_LICENSE_LOAD = 34051,
    ECAT_E_LICENSE_INVALID_TARGET = 34052,
    ECAT_E_LICENSE_EXPIRED = 34053,
    ECAT_E_LICENSE_INVALID_HW = 34054,
    ECAT_E_NO_CONFIG = 34055,
    ECAT_E_INVALID_MASTER_CONFIGURATION = 34056,
    ECAT_E_ALREADY_INITIALIZED = 34057,
    ECAT_E_PI_MAP_OUT_OF_IMAGE = 34058,
    ECAT_E_PI_MAP_REJECTED = 34059,
    ECAT_E_NOT_INITIALIZED = 34060,
    ECAT_E_FRAME_GENERAL = 34305,
    ECAT_E_FRAME_QUEUE = 34306,
    ECAT_E_FRAME_TRANSFER = 34307,
    ECAT_E_FRAME_SEND = 34308,
    ECAT_E_FRAME_WAIT_TIMEOUT = 34309,
    ECAT_E_FRAME_SEND_TIMEOUT = 34310,
    ECAT_E_FRAME_SCHEDULER_DESTROY = 34311,
    ECAT_E_FRAME_CANCEL = 34312,
    ECAT_E_FRAME_TOO_LONG = 34313,
    ECAT_E_MBXREQ_NOT_STARTED = 34336,
    ECAT_E_MBXREQ_RESPONSE = 34337,
    ECAT_E_MBXREQ_NO_RESPONSE_DATA = 34338,
    ECAT_E_MBXREQ_FINISHED = 34339,
    ECAT_E_MB_FAIL = 34352,
    ECAT_E_MB_INVALID_SYNTAX = 34353,
    ECAT_E_MB_INVALID_CHANNEL = 34355,
    ECAT_E_MB_SERVICE_NOT_SUPPORTED = 34356,
    ECAT_E_MB_INVALID_PROTOCOL_HEADER = 34357,
    ECAT_E_MB_SIZE_TOO_SHORT = 34358,
    ECAT_E_MB_NO_MORE_MEMORY = 34359,
    ECAT_E_MB_INVALID_SIZE = 34360,
    ECAT_E_INIT_MODULE = 34560,
    ECAT_E_CONNECTION = 34817,
    ECAT_E_RPC_RESPOND = 34818,
    ECAT_E_RPC_INIT = 34819,
    ECAT_E_LIBRARY = 34820,
    ECAT_E_NOITEMS = 34821,
    ECAT_E_SYS = 34822,

    ECAT_E_FILL_NAME_TOO_LONG = 80000,
    ECAT_E_QUEUE_FULL,
    ECAT_E_RECV_BUFF_TOO_SMALL,
    ECAT_E_RECV_TIMEOUT,
    ECAT_E_NOT_FIND_DEVICE,
    ECAT_E_INVALID_CHANNEL,
    ECAT_E_API_NOT_SUPPORT,
    ECAT_E_BOARD_FILE_SIZE,
    ECAT_E_ENI_FILE_SIZE,
    ECAT_E_FOE_FILE_SIZE,
    ECAT_E_UPDATE_FILE_SIZE,
    ECAT_E_SEND_TIMEOUT,
    ECAT_E_VERSION,
    ECAT_E_INVALID_HANDLE,
    ECAT_E_SLAVE_DISCONNECT,
    ECAT_E_SLAVE_NOT_READY,
    ECAT_E_LOGIC_ADDR_MAP_FORMAT_ERROR,
    ECAT_E_INVALID_PARAM,
    ECAT_E_ENI_FILE_MISMATCH,
    ECAT_E_BOARDCAST_NON_EXISTENT,
    
    ECAT_E_WATCHDOG_SIZE_ERR = 90000,
    ECAT_E_WATCHDOG_DATA_ERR,
    ECAT_E_WATCHDOG_CMD_ERR,
    ECAT_E_WATCHDOG_MALLOC_ERR,
    ECAT_E_WATCHDOG_FUNC_ERR,
    ECAT_E_WATCHDOG_OFFSET_ERR,
    ECAT_E_WATCHDOG_SLAVE_ID_ERR,
    ECAT_E_WATCHDOG_SLAVE_BUFF_SIZE_ERR,
};

/** @brief  DLL名称  */
public const string PCI_ZECM_DLL_NAME = "pci_zecm.dll";

/** @brief  驱动信息  */
[StructLayout(LayoutKind.Sequential)]
public struct DRIVER_INFO
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
    public char[]   caDriverVersion;                //!< 驱动版本信息
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
    public char[]   caApiVersion;                   //!< 动态库的API版本
    public UInt32     u32BoardCnt;                    //!< 板卡的数量
};

/** @brief  板卡信息  */
[StructLayout(LayoutKind.Sequential)]
public struct BOARD_INFO
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
    public char[]   cName;                          //!< 板卡的名称
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
    public char[]   cVersion;                       //!< 板卡的版本号
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
    public char[]   cSerialNo;                      //!< 板卡的序列号，可用于打开板卡或通道
    public UInt32     u32Alias;                       //!< 板卡的别名，可用于打开板卡或通道，如BOARD_ALIAS(name, 10)
    public UInt32     u32EcatChannelCnt;              //!< EtherCAT通道个数
    public UInt32     u32FpgaVersion;                 //!< FPGA版本
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public UInt32[]   u32Res;                         //!< 保留
};

/** @brief  ECAT信息  */
[StructLayout(LayoutKind.Sequential)]
public struct ECAT_INFO
{
    public UInt32     u32PiQueueNum;                  //!< PI镜像队列的深度
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public UInt32[]   u32Res;                         //!< 保留
};

/** @brief  ENI信息  */
[StructLayout(LayoutKind.Sequential)]
public struct ECAT_ENI_INFO
{
    public UInt32     u32MainCycle;                   //!< 主循环周期，PDO周期
    public UInt32     u32MailboxCycle;                //!< 邮箱周期
    public UInt32     u32PIOutputByteSize;            //!< 镜像输出有效字节大小
    public UInt32     u32PIInputByteSize;             //!< 镜像输入有效字节大小
};

/** @brief  ENI扩展信息  */
[StructLayout(LayoutKind.Sequential)]
public struct ECAT_ENI_EX_INFO
{
    public ECAT_ENI_INFO  tBase;                      //!< 基础信息
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public byte[]         u8Crc;                      //!< CRC校验和
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public byte[]         u8Res;                      //!< 保留
};

/** @brief  PI镜像索引定义  */
public const UInt32 PI_AREA_LOCAL_OUTPUT = 0;           //!< 镜像本地输出缓存，可读写，非线程安全，同步控制
public const UInt32 PI_AREA_LOCAL_INPUT = 1;            //!< 镜像本地输入缓存，可读写，非线程安全，同步控制
public const UInt32 PI_AREA_FAST_OUTPUT = 2;            //!< 快速输出缓存，可读写，进程安全，异步控制
public const UInt32 PI_AREA_SHADOW_OUTPUT = 3;          //!< 镜像影子输出缓存，只读，进程安全，异步控制
public const UInt32 PI_AREA_SHADOW_INPUT = 4;           //!< 镜像影子输入缓存，只读，进程安全，异步控制

/** @brief  PI异步控制模式 */
public enum ECAT_PI_ASYNC_MODE : UInt32
{
    ECAT_PI_ASYNC_MODE_DIRECT_ACCESS = 0,           //!< 调用PIRead/PIWrite时，数据直接同步到板卡
    ECAT_PI_ASYNC_MODE_CYCLE_ACCESS,                //!< 调用PIRead/PIWrite时，数据写到缓存，再周期同步到板卡
    ECAT_PI_ASYNC_MODE_MANUAL_ACCESS,               //!< 调用PIRead/PIWrite时，数据写到缓存，
                                                    //!<   直到用户调用EcatPIASyncUpdateData数据才同步到板卡
};

/** @brief  PI异步控制模式 */
public enum ECAT_PI_REINIT_MODE : UInt32
{
    ECAT_PI_REINIT_AUTO = 0,                        //!< 自动模式，先根据本地模式与全局模式（本地>全局），
                                                    //!< 最后确定复位行为，如果还是AUTO则等价于ECAT_PI_REINIT_ALL。
    ECAT_PI_REINIT_ALL,                             //!< 清空全部缓存
    ECAT_PI_REINIT_EXCEPT_ASYNC_AREA,               //!< 仅保留异步缓存（PI_AREA_FAST_OUTPUT、PI_AREA_SHADOW_INPUT）的数据
    ECAT_PI_REINIT_EXCEPT_SYNC_AREA,                //!< 仅保留同步缓存（PI_AREA_LOCAL_OUTPUT、PI_AREA_LOCAL_INPUT）的数据
};

/** @brief  主从站状态标志  */
public const byte EcatStateNotSet = 0;
public const byte EcatStateI = 1;
public const byte EcatStateP = 2;
public const byte EcatStateB = 3;
public const byte EcatStateS = 4;
public const byte EcatStateO = 8;
public const byte EcatStateMask = 15;
public const byte EcatStateErrorFlag = 16;
public const byte EcatStateII = 129;
public const byte EcatStatePP = 130;
public const byte EcatStateSS = 132;
public const byte InternalEcatStateMask = 128;

/** @brief ECAT总线状态状态   */
public enum EcatBusStatusFlag : UInt32
{
    //! 主站状态正常
    EcatMasterBusStatusOK                         = 0x00000000,
 
    //! 检测到不可热插拔的从站状态错误
    EcatMasterBusStatusWrongSlaveState            = 0x00000001,
    //! 检测到不可热插拔的从站掉线
    EcatMasterBusStatusSlaveIsOffline             = 0x00000002,
    //! 检测到网络掉线
    EcatMasterBusStatusNetLinkDown                = 0x00000004,   
 
    //! 检测到可热插拔的从站状态错误
    EcatMasterBusStatusWrongHotConnectSlaveState  = 0x00010000,
    //! 检测到可热插拔的从站掉线
    EcatMasterBusStatusHotConnectSlaveIsOffline   = 0x00020000,
 
    //! 错误掩码
    EcatMasterBusStatusErrorMask                  = 0x0000FFFF,
    //! 警告掩码
    EcatMasterBusStatusWarningMask                = 0xFFFF0000,
};

/** @brief ECAT看门狗类型   */
public enum ECAT_WATCHDOG_TYPE : UInt32{
    ECAT_WATCHDOG_IO_DATA = 0,
    ECAT_WATCHDOG_NUM,
};

/** @brief 从站信息   */
[StructLayout(LayoutKind.Sequential)]
public struct ECAT_SLAVE_INFO
{
    public UInt32        u32Vendor;                     //!< 厂商ID
    public UInt32        u32ProductCode;                //!< 产品代码
    public UInt32        u32SN;                         //!< 序列号
    public UInt32        u32Revision;                   //!< 版本
    public UInt32        u32DevType;                    //!< 设备类型，未使用，固定为0
    public UInt32        u32Alias;                      //!< 别名
    public UInt32        u32PIOutputsBitSize;           //!< 从站过程镜像的输出位大小，主站生产，从站消费
    public UInt32        u32PIInputsBitSize;            //!< 从站过程镜像的输入位大小，主站消费，从站生产
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    public UInt32[]     u32Res;                         //!< 保留
};

/** @brief  void *值  */
public class VOIDP_VALUE
{
    public VOIDP_VALUE(object v)
    {
        _hl = GCHandle.Alloc(v);
    }
    public IntPtr ToIntPtr()
    {
        return GCHandle.ToIntPtr(_hl);
    }
    public static object FromPtr(IntPtr pv)
    {
        return GCHandle.FromIntPtr(pv).Target;
    }
    ~VOIDP_VALUE()
    {
        _hl.Free();
    }
    private GCHandle _hl;
};

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool PFN_PROGRESS_CALLBACK(IntPtr pvUser, float fRatio);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void PFN_PI_ASYNC_MODE_CYCLE_CALLBACK(IntPtr context, IntPtr hHandle);

/*******************************************************************************
    驱动接口
*******************************************************************************/
/**
    @brief  获取驱动信息
  
    @param[out]  ptDriverInfo     输出驱动信息
    @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "DriverGetInfo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 DriverGetInfo(ref DRIVER_INFO ptDriverInfo);

/**
  @brief  枚举板卡的信息
  
  @param       u32BoardIdx      板卡的索引，范围：0~DRIVER_INFO::u32BoardCnt-1
  @param[out]  ptBoardInfo      输出板卡信息
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "DriverEnumBoard", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 DriverEnumBoard(Int32 u32BoardIdx, ref BOARD_INFO ptBoardInfo);

/**
  @brief  枚举板卡ECAT通道的信息
  
  @param       u32BoardIdx      板卡的索引，有效范围：0~DRIVER_INFO::u32BoardCnt-1
  @param       u32EcatChannel   板卡EtherCAT的通道号，有效范围：0~BOARD_INFO::u32EcatChannelCnt-1
  @param[out]  ptEcatInfo       输出EtherCAT通道的信息
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "DriverEnumEcat", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 DriverEnumEcat(Int32 u32BoardIdx, Int32 u32EcatChannel, ref ECAT_INFO ptEcatInfo);

/**
  @brief  获取错误码对应的错误信息
  
  @param  err_code              错误码
  @return  返回对应的字符串
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "DriverGetErrStr", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr _DriverGetErrStr(Int32 err_code);
public static string DriverGetErrStr(Int32 err_code)
{
    return Marshal.PtrToStringAnsi(_DriverGetErrStr(err_code));
}

/*******************************************************************************
  板卡接口
*******************************************************************************/
public static string BOARD_IDX(UInt32 index)
{
    return string.Format("ID{0}", index);
}
public static string BOARD_ALIAS(UInt32 alias)
{
    return string.Format("AL{0}", alias);
}

/**
  @brief  打开指定的板卡
  
  @param[out]  phHandle         返回板卡的控制句柄
  @param       sBoardIf         板卡接口字符串，可以是
                                    ID<Board Index>     索引，BOARD_IDX(0)
                                    AL<Board Alias>     别名，BOARD_ALIAS(0)
                                    NOxxxxxx            序列号
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardOpen", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardOpen(ref IntPtr phHandle, string sBoardIf);

/**
  @brief  返回当前板卡的信息
  
  @param  hHandle               板卡的控制句柄
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardClose", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardClose(IntPtr hHandle);

/**
  @brief  设置通信超时间时间，默认为20000
  
  @param  hHandle               板卡的控制句柄
  @param  timeout_ms            超时时间，毫秒为单位
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardSetTimeout", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardSetTimeout(IntPtr hHandle, UInt32 timeout_ms);

/**
  @brief  返回当前板卡是否活着
  
  @param       hHandle          板卡的控制句柄
  @return  返回true表示活着，false表示死亡
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardIsAlive", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern bool BoardIsAlive(IntPtr hHandle);

/**
 * @brief 返回当前板卡连接的心跳计数
 * @param hHandle              板卡的控制句柄
 * @param coreIndex            通道号
 * @param result               读取的结果
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
 */
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardHeardCnt", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern UInt32 BoardHeardCnt(IntPtr hHandle, UInt32 coreIndex, ref UInt32 result);

/**
  @brief  返回当前板卡的信息
  
  @param       hHandle          板卡的控制句柄
  @param[out]  ptBoardInfo      输出板卡信息
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardGetInfo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardGetInfo(IntPtr hHandle, ref BOARD_INFO ptBoardInfo);

/**
  @brief  返回当前板卡的alias
  
  @param       hHandle          板卡的控制句柄
  @param[out]  ptBoardInfo      输出alias
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardGetInfo_Alias", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardGetInfo_Alias(IntPtr hHandle, ref UInt32 pu32Alias);

/**
  @brief  复位板卡
  
  @param  hHandle               板卡的控制句柄
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardReset", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardReset(IntPtr hHandle);

/**
  @brief  写板卡文件
  
  @param  hHandle               板卡的控制句柄
  @param  psLocalFileName       本地文件系统的文件名
  @param  psDeviceFileName      设备文件系统的文件名
  @param  pfnPropfnCallback     进度回调，可为空
  @param  pvUser                进度回调的第一个参数，可为空
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardFileDownload", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private static extern Int32 BoardFileDownload(
    IntPtr                      hHandle,
    string                      psLocalFileName,
    string                      psDeviceFileName,
    PFN_PROGRESS_CALLBACK       pfnPropfnCallback,
    IntPtr                      pvUser);

public static Int32 BoardFileDownload(
    IntPtr                      hHandle,
    string                      psLocalFileName,
    string                      psDeviceFileName,
    PFN_PROGRESS_CALLBACK       pfnPropfnCallback,
    VOIDP_VALUE                 pvUser)
{
    return BoardFileDownload(hHandle, psLocalFileName, psDeviceFileName, pfnPropfnCallback, pvUser.ToIntPtr());
}
/**
  @brief  读板卡文件
  
  @param  hHandle               板卡的控制句柄
  @param  psLocalFileName       本地文件系统的文件名
  @param  psDeviceFileName      设备文件系统的文件名
  @param  pfnPropfnCallback     进度回调，可为空
  @param  pvUser                进度回调的第一个参数，可为空
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardFileUpload", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private static extern Int32 BoardFileUpload(
    IntPtr                      hHandle,
    string                      psLocalFileName,
    string                      psDeviceFileName,
    PFN_PROGRESS_CALLBACK       pfnPropfnCallback,
    IntPtr                      pvUser);

public static Int32 BoardFileUpload(
    IntPtr                      hHandle,
    string                      psLocalFileName,
    string                      psDeviceFileName,
    PFN_PROGRESS_CALLBACK       pfnPropfnCallback,
    VOIDP_VALUE                 pvUser)
{
    return BoardFileUpload(hHandle, psLocalFileName, psDeviceFileName, pfnPropfnCallback, pvUser.ToIntPtr());
}


/**
  @brief  更新板卡文件
  
  @param  hHandle               板卡的控制句柄
  @param  psLocalFileName       本地文件系统的文件名
  @return  返回0表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardUpdate", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardUpdate(
    IntPtr              hHandle,
    string              psLocalFileName);

/**
  @brief  更新板卡文件
  
  @param  hHandle               板卡的控制句柄
  @param  psLocalFileName       本地文件系统的文件名
  @param  prop_callback         进度回调函数
  @param  user                  回调函数的用户句柄
  @return  返回0表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardUpdateEx", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private static extern Int32 BoardUpdateEx(
    IntPtr              hHandle,
    string              psLocalFileName,
    PFN_PROGRESS_CALLBACK prop_callback, 
    IntPtr              user);

public static Int32 BoardUpdateEx(
	IntPtr                hHandle,
    string              psLocalFileName,
    PFN_PROGRESS_CALLBACK prop_callback, 
    VOIDP_VALUE			    pvUser)
{
	return BoardUpdateEx(hHandle, psLocalFileName, prop_callback, pvUser.ToIntPtr());
}


/*************** IO Module ******************/
/**
 * @brief 读DO输出
 * @param       hHandle   板卡的控制句柄
 * @param[out]  u32DO     当前DO输出值，[15:0]：DO15~0，[31:16]：保留
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardDORead", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardDORead(IntPtr hHandle, ref UInt32 u32DO);
/**
 * @brief 写DO输出
 * @param hHandle         板卡的控制句柄
 * @param u32DO           配置DO输出值，[15:0]：DO15~0，[31:16]：保留
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardDOWrite", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardDOWrite(IntPtr hHandle, UInt32 u32DO);
/**
 * @brief 读DI输入
 * @param hHandle         板卡的控制句柄
 * @param[out] u32DI      当前DI输出值，[15:0]：DI15~0，[31:16]：保留
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardDIRead", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardDIRead(IntPtr hHandle, ref UInt32 u32DI);

/**
 *  @brief 锁存模式 
*/
// 单次锁存模式
public const UInt32 IO_LATCH_Z_RAISING_TO_POS_A = 1;
public const UInt32 IO_LATCH_Z_FALLING_TO_POS_A = 2;
public const UInt32 IO_LATCH_R0_RAISING_TO_POS_A = 3;
public const UInt32 IO_LATCH_R0_FALLING_TO_POS_A = 4;
public const UInt32 IO_LATCH_R0_RAISING_TO_POS_A_AND_Z_RAISING_TO_POS_B = 6;
public const UInt32 IO_LATCH_R0_RAISING_TO_POS_A_AND_Z_FALLING_TO_POS_B = 7;
public const UInt32 IO_LATCH_R0_FALLING_TO_POS_A_AND_Z_RAISING_TO_POS_B = 8;
public const UInt32 IO_LATCH_R0_FALLING_TO_POS_A_AND_Z_FALLING_TO_POS_B = 9;
public const UInt32 IO_LATCH_R0_RAISING_TO_POS_A_AND_R1_RAISING_TO_POS_B = 10;
public const UInt32 IO_LATCH_R0_RAISING_TO_POS_A_AND_R1_FALLING_TO_POS_B = 11;
public const UInt32 IO_LATCH_R0_FALLING_TO_POS_A_AND_R1_RAISING_TO_POS_B = 12;
public const UInt32 IO_LATCH_R0_FALLING_TO_POS_A_AND_R1_FALLING_TO_POS_B = 13;
public const UInt32 IO_LATCH_R1_RAISING_TO_POS_B = 14;
public const UInt32 IO_LATCH_R1_FALLING_TO_POS_B = 15;
public const UInt32 IO_LATCH_Z_RAISING_TO_POS_B = 16;
public const UInt32 IO_LATCH_Z_FALLING_TO_POS_B = 17;
public const UInt32 IO_LATCH_R2_RAISING_TO_POS_C = 18;
public const UInt32 IO_LATCH_R2_FALLING_TO_POS_C = 19;
public const UInt32 IO_LATCH_R3_RAISING_TO_POS_D = 20;
public const UInt32 IO_LATCH_R3_FALLING_TO_POS_D = 21;
public const UInt32 IO_LATCH_MAX = 22;

// 连续锁存模式
public const UInt32 IO_SEQ_LATCH_Z_RAISING_TO_POS_A = 101;
public const UInt32 IO_SEQ_LATCH_Z_FALLING_TO_POS_A = 102;
public const UInt32 IO_SEQ_LATCH_R0_RAISING_TO_POS_A = 103;
public const UInt32 IO_SEQ_LATCH_R0_FALLING_TO_POS_A = 104;
public const UInt32 IO_SEQ_LATCH_R1_RAISING_TO_POS_B = 114;
public const UInt32 IO_SEQ_LATCH_R1_FALLING_TO_POS_B = 115;
public const UInt32 IO_SEQ_LATCH_Z_RAISING_TO_POS_B = 116;
public const UInt32 IO_SEQ_LATCH_Z_FALLING_TO_POS_B = 117;
public const UInt32 IO_SEQ_LATCH_R2_RAISING_TO_POS_C = 118;
public const UInt32 IO_SEQ_LATCH_R2_FALLING_TO_POS_C = 119;
public const UInt32 IO_SEQ_LATCH_R3_RAISING_TO_POS_D = 120;
public const UInt32 IO_SEQ_LATCH_R3_FALLING_TO_POS_D = 121;
public const UInt32 IO_SEQ_LATCH_R0_RAISING_TO_POS_B = 123;
public const UInt32 IO_SEQ_LATCH_R0_FALLING_TO_POS_B = 124;
public const UInt32 IO_SEQ_LATCH_R0_RAISING_THEN_FALLING_TO_POS_A = 133;
public const UInt32 IO_SEQ_LATCH_R0_FALLING_THEN_RAISING_TO_POS_A = 134;
public const UInt32 IO_SEQ_LATCH_R1_RAISING_THEN_FALLING_TO_POS_B = 135;
public const UInt32 IO_SEQ_LATCH_R1_FALLING_THEN_RAISING_TO_POS_B = 136;
public const UInt32 IO_SEQ_LATCH_MAX = 137;

/**
 * @brief 开启锁存功能
 * @param hHandle         板卡的控制句柄
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardLatchEnable", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardLatchEnable(IntPtr hHandle);
/**
 * @brief 关闭锁存功能
 * @param hHandle         板卡的控制句柄
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardLatchDisable", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardLatchDisable(IntPtr hHandle);
/**
 * @brief 锁存状态清零
 * @param hHandle           板卡的控制句柄
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardLatchClear", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardLatchClear(IntPtr hHandle);
/**
 * @brief 编码器计数器清零
 * @param hHandle           板卡的控制句柄
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardLatchCounterReset", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardLatchCounterReset(IntPtr hHandle);
/**
 * @brief 配置锁存引脚映射
 * @param hHandle         板卡的控制句柄
 * @param u32PortSel      配置锁存引脚映射，寄存器映射为：
 *                            [1:0]: R0映射
 *                            [3:2]: R1映射
 *                            [5:4]: R2映射
 *                            [7:6]: R3映射
 *                            [31:8]：保留
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardLatchPortSel", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardLatchPortSel(IntPtr hHandle, UInt32 u32PortSel);
/**
 * @brief 配置单次锁存功能
 * @param hHandle         板卡的控制句柄
 * @param u32LatchMode    配置单次锁存模式（1~21）
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardLatchCfg", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardLatchCfg(IntPtr hHandle, UInt32 u32LatchMode);
/**
 * @brief 切换单次锁存运行状态，开启一次锁存
 * @param hHandle         板卡的控制句柄
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardLatchRun", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardLatchRun(IntPtr hHandle);
/**
 * @brief 读取单次锁存编码器值
 * @param       hHandle     板卡的控制句柄
 * @param       u32Channel  锁存通道（0~3：A~D）
 * @param[out]  u32PosL     锁存编码器值低32位
 * @param[out]  u32PosH     锁存编码器值高32位
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardLatchOnRead", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardLatchOnRead(IntPtr hHandle, UInt32 u32Channel, ref UInt32 u32PosL, ref UInt32 u32PosH);
/**
 * @brief 配置连续锁存功能
 * @param hHandle             板卡的控制句柄
 * @param u32SeqLatchMode     配置连续锁存模式（101~136）
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardSeqLatchCfg", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardSeqLatchCfg(IntPtr hHandle, UInt32 u32SeqLatchMode);
/**
 * @brief 切换连续锁存运行状态，开启锁存
 * @param hHandle                 板卡的控制句柄
 * @param u32LatchSeqQueueLength  连续锁存次数（0~1023）(输入0时可触发但不会记录锁存值)
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardSeqLatchRun", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardSeqLatchRun(IntPtr hHandle, UInt32 u32LatchSeqQueueLength);
/**
 * @brief 读取连续锁存编码器值
 * @param       hHandle       板卡的控制句柄
 * @param       u32Channel    锁存通道（0~3：A~D）
 * @param       u32SeqIndex   读取的连续锁存值索引
 * @param[out]  u32PosL       锁存编码器值低32位
 * @param[out]  u32PosH       锁存编码器值高32位
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardSeqLatchOnRead", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardSeqLatchOnRead(IntPtr hHandle, UInt32 u32Channel, UInt32 u32SeqIndex, ref UInt32 u32PosL, ref UInt32 u32PosH);
/**
 * @brief 读取锁存状态
 * @param       hHandle         板卡的控制句柄
 * @param       u32Channel      锁存通道（0~3：A~D）
 * @param[out]  u32LatchState   指定通道锁存状态，1：已触发锁存，0：未触发
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardLatchState", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardLatchState(IntPtr hHandle, UInt32 u32Channel, ref UInt32 u32LatchState);
/**
 * @brief 切换锁存运行状态，进入空闲状态
 * @param hHandle         板卡的控制句柄
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardLatchStop", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardLatchStop(IntPtr hHandle);

/**
 * @brief 脉冲轴输出模块
*/
/**
 * @brief 配置脉冲控制输出（开启功能复用）
 * @param hHandle         板卡的控制句柄
 * @param u32Channel      通道号（0-3）
 * @param u32Mode         脉冲输出模式:
 *                        0 AB相
 *                        1 正/逆脉冲序列
 *                        2 脉冲+符号（servo_sign == !(u32Sign)）
 *                        3 脉冲+符号（servo_sign == u32Sign)
 * @param u32TriggerMode  0：连续输出脉冲模式（直接输出），1：指定脉冲数量输出模式（需要BoardPulseOutput触发才能输出）
 * @param u32Sign         脉冲方向
 * @param u32Period       脉冲周期（单位：Hz）
 * @param u32Duty         脉冲占空比（单位：%，整数，范围：0~100%）
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardPulseConfig", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardPulseConfig(
  IntPtr		hHandle,
  UInt32 		u32Channel,
  UInt32 		u32Mode,
  UInt32 		u32TriggerMode,
  UInt32 		u32Sign,
  UInt32 		u32Period, 
  UInt32 		u32Duty
);
/**
 * @brief 输出指定数量脉冲，仅当TriggerMode == 1指定脉冲数量输出模式时生效
 * @param hHandle         板卡的控制句柄
 * @param u32Channel      通道号（0-3）
 * @param u32PulseNum     脉冲数量
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardPulseOutput", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardPulseOutput(IntPtr hHandle, UInt32 u32Channel, UInt32 u32PulseNum);
/**
 * @brief 停止脉冲控制输出（关闭功能复用）
 * @param hHandle         板卡的控制句柄
 * @param u32Channel      通道号（0-3）
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardPulseStop", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardPulseStop(IntPtr hHandle, UInt32 u32Channel);
/**
 * @brief 读脉冲输出配置
 * @param hHandle             板卡的控制句柄
 * @param u32Channel          通道号（0-3）
 * @param[out] u32Mode        脉冲输出模式:
 *                            0 AB相
 *                            1 正/逆脉冲序列
 *                            2 脉冲+符号（servo_sign == !(u32Sign)）
 *                            3 脉冲+符号（servo_sign == u32Sign)
 * @param[out] u32TriggerMode 0：连续输出脉冲模式（直接输出），1：指定脉冲数量输出模式（需要BoardPulseOutput触发才能输出）
 * @param[out] u32Sign        脉冲方向
 * @param[out] u32Period      脉冲周期（单位：Hz）
 * @param[out] u32Duty        脉冲占空比（单位：%，整数，范围：0~100%）
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardPulseGetConfig", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardPulseGetConfig(
  IntPtr		hHandle,
  UInt32 		u32Channel,
  ref UInt32	u32Mode,
  ref UInt32	u32TriggerMode,
  ref UInt32	u32Sign,
  ref UInt32	u32Period, 
  ref UInt32	u32Duty
);

/**
 * @brief PWM输出模块
*/
/**
 * @brief 开启PWM输出
 * @param hHandle         板卡的控制句柄
 * @param u32Channel      通道号（0-3）
 * @param u32Period       脉冲周期（单位：Hz）
 * @param u32Duty         脉冲占空比（单位：%，整数，范围：0~100%）
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardPWMOutput", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardPWMOutput(
  IntPtr hHandle,
  UInt32 u32Channel,
  UInt32 u32Period,
  UInt32 u32Duty
);
/**
 * @brief 关闭PWM输出
 * @param hHandle         板卡的控制句柄
 * @param u32Channel      通道号（0-3）
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardPWMStop", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardPWMStop(IntPtr hHandle, UInt32 u32Channel);
/**
 * @brief 读PWM配置
 * @param hHandle         板卡的控制句柄
 * @param u32Channel      通道号（0-3）
 * @param[out] u32Period  脉冲周期（单位：Hz）
 * @param[out] u32Duty    脉冲占空比（单位：%，整数，范围：0~100%）
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "BoardPWMGetConfig", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 BoardPWMGetConfig(
  IntPtr 		hHandle,
  UInt32 		u32Channel,
  ref UInt32 	u32Period,
  ref UInt32	u32Duty
);

/*******************************************************************************
  ECAT接口
*******************************************************************************/
/**
  @brief  打开指定的ECAT
  
  @param[out]  phHandle         返回ECAT控制句柄
  @param       sBoardIf         板卡接口字符串，可以是
                                    ID<Board Index>     索引，BOARD_IDX(0)
                                    AL<Board Alias>     别名，BOARD_ALIAS(0)
                                    NOxxxxxx            序列号
  @param       u32EcatChannel   板卡EtherCAT的通道号，有效范围：0~BOARD_INFO::u32EcatChannelCnt-1
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatOpen", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatOpen(ref IntPtr phHandle, string sBoardIf, UInt32 u32EcatChannel);

/**
  @brief  关闭ECAT
  
  @param  hHandle               板卡的控制句柄
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatClose", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatClose(IntPtr hHandle);

/**
  @brief  设置邮箱通信超时间时间，默认为20000
  
  @param  hHandle               板卡的控制句柄
  @param  timeout_ms            超时时间，毫秒为单位
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatSetTimeout", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatSetTimeout(IntPtr hHandle, UInt32 timeout_ms);

/**
 * @brief  返回当前板卡的EtherCAT通道号
 * 
 * @param       hHandle          板卡的控制句柄
 * @param[out]  u32EcatChannel   输出EtherCAT通道号
 * @return  返回ECAT_S_OK(0)表示成功，非0表示失败
 */
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetCurrentChannel", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetCurrentChannel(IntPtr hHandle, ref UInt32 u32EcatChannel);

/**
  @brief  返回当前板卡的信息
  
  @param       hHandle          板卡的控制句柄
  @param[out]  ptBoardInfo      输出板卡信息
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetInfo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetInfo(IntPtr hHandle, ref BOARD_INFO ptBoardInfo);

/**
  @brief  返回当前板卡的BOARD_HANDLE
  
  @param       hHandle          板卡的控制句柄
  @param[out]  ptBoardInfo      输出板卡信息
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetBoardHandle", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetBoardHandle(IntPtr hHandle, ref IntPtr boardHandle);

/**
  @brief  复位ECAT
  
  @param  hHandle               ECAT控制句柄
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatReset", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatReset(IntPtr hHandle);

/**
  @brief  启动ECAT总线运行
  
  @param  hHandle               ECAT控制句柄
  @param  cEniFileName          ENI配置文件名
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatBusRun", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatBusRun(IntPtr hHandle, string cEniFileName);

/**
  @brief  启动ECAT总线运行
  
  @param  hHandle               ECAT控制句柄
  @param  cEniFileName          ENI配置文件名
  @param  PropfnCallback        进度回调，可为空
  @param  Context               进度回调的第一个参数，可为空
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatBusRunEx", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private static extern Int32 EcatBusRunEx(IntPtr hHandle, string cEniFileName, PFN_PROGRESS_CALLBACK PropfnCallback, IntPtr Context);

public static Int32 EcatBusRunEx(IntPtr hHandle, string cEniFileName, PFN_PROGRESS_CALLBACK PropfnCallback, VOIDP_VALUE Context)
{
	return EcatBusRunEx(hHandle, cEniFileName, PropfnCallback, Context.ToIntPtr());
}

/**
  @brief  停止ECAT总线运行
  
  @param  hHandle               ECAT控制句柄
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatBusStop", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatBusStop(IntPtr hHandle);

/**
  @brief  获得总线状态
  
  @param       hHandle          ECAT控制句柄
  @param[OUT]  pu32BusStatus    返回总线状态，@see EcatBusStatusFlag
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatBusStatus", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatBusStatus(IntPtr hHandle, ref UInt32 pu32BusStatus);

/**
  @brief  检查ECAT状态
  
  @param  hHandle               ECAT控制句柄
  @return  返回true表示在运行状态，返回false表示在停止状态，参数错误时亦返回false
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatBusIsRunning", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern bool EcatBusIsRunning(IntPtr hHandle);

/**
  @brief  设置PI复位本地模式，该模式会在调用EcatBusRun时触发行为
  
  @param  hHandle               ECAT控制句柄
  @param  u32ReinitMode         PI复位模式: 见ECAT_PI_REINIT_MODE，默认值为ECAT_PI_REINIT_AUTO
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIReinitModeSet", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIReinitModeSet(IntPtr hHandle, UInt32 u32ReinitMode);

/**
  @brief  获取PI复位本地模式
  
  @param  hHandle               ECAT控制句柄
  @param[out] pu32ReinitMode    PI复位模式: 见ECAT_PI_REINIT_MODE
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIReinitModeGet", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIReinitModeGet(IntPtr hHandle, ref UInt32 pu32ReinitMode);

/**
  @brief  设置PI复位全局模式，该模式会在调用EcatBusRun时触发行为
          本地模式优先级大于全局，当本地模式为AUTO时，将使全局模式作为复位的依据
          如果全局模式也为AUTO，则等价于ECAT_PI_REINIT_ALL
  
  @param  hHandle               ECAT控制句柄
  @param  u32ReinitMode         PI复位模式: 见ECAT_PI_REINIT_MODE，默认值为ECAT_PI_REINIT_AUTO
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIReinitModeSetGlobal", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIReinitModeSetGlobal(IntPtr hHandle, UInt32 u32ReinitMode);

/**
  @brief  获取PI复位全局模式
  
  @param  hHandle               ECAT控制句柄
  @param[out] pu32ReinitMode    PI复位模式: 见ECAT_PI_REINIT_MODE
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIReinitModeGetGlobal", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIReinitModeGetGlobal(IntPtr hHandle, ref UInt32 pu32ReinitMode);

/**
  @brief  获取总线EtherCAT主站OUT端口起的第一个出现网络连接断开的设备

  @param       hHandle                     ECAT控制句柄
  @param[out]  p32FirstLinkDownPortStatus  端口状态
                                             bit[31-16]: Slave id, 0~N-1
                                             bit[15] Link status on Port 3      1 : Link up   0: Link down
                                             bit[14] Loop Port 0                1 : Closed.   0: Open.
                                             bit[13] Link status on Port 2      1 : Link up   0: Link down
                                             bit[12] Loop Port 0                1 : Closed.   0: Open.
                                             bit[11] Link status on Port 1      1 : Link up   0: Link down
                                             bit[10] Loop Port 0                1 : Closed.   0: Open.
                                             bit[9]  Link status on Port 0      1 : Link up   0: Link down
                                             bit[8]  Loop Port 0                1 : Closed.   0: Open.
                                             bit[7-2]: reserved
                                             bit[1]: OUT Port Status            1 : Closed.   0: Open.
                                             bit[0]: IN  Port Status            1 : Closed.   0: Open.  

  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetFirstLinkDownPortStatus", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetFirstLinkDownPortStatus(IntPtr hHandle, ref UInt32 pdwFirstLinkDownPortStatus);

/**
  @brief  读ENI信息
  
  @param  hHandle               ECAT控制句柄
  @param[out] ptInfo            信息
  @return  返回true表示在运行状态，返回false表示在停止状态，参数错误时亦返回false
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetEniInfo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetEniInfo(IntPtr hHandle, ref ECAT_ENI_INFO ptInfo);

/**
  @brief  读ENI扩展信息
  
  @param  hHandle               ECAT控制句柄
  @param[out] ptInfo            信息
  @param  u32Length             ptInfo的字节长度信息
  @return  返回true表示在运行状态，返回false表示在停止状态，参数错误时亦返回false
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetEniInfoEx", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetEniInfoEx(IntPtr hHandle, ref byte ptInfo, UInt32 u32Length);

/**
  @brief  COE命令：写从站SDO
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param  u16Index              SDO索引
  @param  u8SubIndex            SDO子索引
  @param  u32DataLen            数据的字节长度，通常为：1,2,4
  @param  pvData                写入的数据，发送多字节时，须以小端排列
  @param  u32TimeOutMs          超时时间，以毫秒为单位
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatCoeSDODownload", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatCoeSDODownload(
    IntPtr              hHandle,
    UInt16              u16SlaveId,
    UInt16              u16Index,
    byte                u8SubIndex,
    UInt32              u32DataLen,
    ref byte            pvData,
    UInt32              u32TimeOutMs);

/**
  @brief  COE命令：读从站SDO
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param  u16Index              SDO索引
  @param  u8SubIndex            SDO子索引
  @param[INOUT]  pu32DataLen    IN：作为pu8Data的最大长度，ref：作为读取到的有效字节数，通常为：1,2,4
  @param[OUT]  pvData           存储读取到的数据，发送多字节时，须以小端排列
  @param  u32TimeOutMs          超时时间，以毫秒为单位
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatCoeSDOUpload", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatCoeSDOUpload(
    IntPtr              hHandle,
    UInt16              u16SlaveId,
    UInt16              u16Index,
    byte                u8SubIndex,
    ref UInt32          pu32DataLen,
    ref byte            pvData,
    UInt32              u32TimeOutMs);

/**
  @brief  COE命令扩展：写从站SDO
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param  u16Index              SDO索引
  @param  u8SubIndex            SDO子索引
  @param  bCompleteAccess       true: 完成访问，false: 非完全访问
  @param  u32DataLen            数据的字节长度，通常为：1,2,4
  @param  pvData                写入的数据，发送多字节时，须以小端排列
  @param  u32TimeOutMs          超时时间，以毫秒为单位
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatCoeSDODownloadEx", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatCoeSDODownloadEx(
    IntPtr              hHandle,
    UInt16              u16SlaveId,
    UInt16              u16Index,
    byte                u8SubIndex,
    bool                bCompleteAccess,
    UInt32              u32DataLen,
    ref byte            pvData,
    UInt32              u32TimeOutMs);

/**
  @brief  COE命令扩展：读从站SDO
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param  u16Index              SDO索引
  @param  u8SubIndex            SDO子索引
  @param  bCompleteAccess       true: 完成访问，false: 非完全访问
  @param[INOUT]  pu32DataLen    IN：作为pu8Data的最大长度，ref：作为读取到的有效字节数，通常为：1,2,4
  @param[OUT]  pvData           存储读取到的数据，发送多字节时，须以小端排列
  @param  u32TimeOutMs          超时时间，以毫秒为单位
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatCoeSDOUploadEx", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatCoeSDOUploadEx(
    IntPtr              hHandle,
    UInt16              u16SlaveId,
    UInt16              u16Index,
    byte                u8SubIndex,
    bool                bCompleteAccess,
    ref UInt32          pu32DataLen,
    ref byte            pvData,
    UInt32              u32TimeOutMs);

/**
  @brief  设置异步控制缓存的数据同步模式
  
  @param  hHandle               ECAT控制句柄
  @param  mode                  异步缓存工作模式，见ECAT_PI_ASYNC_MODE，
                                默认值为ECAT_PI_ASYNC_MODE_DIRECT_ACCESS
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIASyncModeSet", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIASyncModeSet(
    IntPtr				hHandle,
    UInt32              mode);

/**
  @brief  设置异步控制缓存的周期同步模式的回调函数
  
  @param  hHandle               ECAT控制句柄
  @param  pvContext             传输给回调函数的第一个参数
  @param  pfnCallback           回调函数
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIAsyncModeCycleCallbackHook", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private static extern Int32 EcatPIAsyncModeCycleCallbackHook(
    IntPtr				hHandle,
    IntPtr				pvContext,
    PFN_PI_ASYNC_MODE_CYCLE_CALLBACK pfnCallback);

public static Int32 EcatPIAsyncModeCycleCallbackHook(
    IntPtr				hHandle,
    VOIDP_VALUE			pvContext,
    PFN_PI_ASYNC_MODE_CYCLE_CALLBACK pfnCallback)
{
	return EcatPIAsyncModeCycleCallbackHook(hHandle, pvContext.ToIntPtr(), pfnCallback);
}

/**
  @brief  读取异步控制缓存的数据同步模式
  
  @param  hHandle               ECAT控制句柄
  @param  mode                  输出异步缓存工作模式，见ECAT_PI_ASYNC_MODE
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIASyncModeGet", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIASyncModeGet(
    IntPtr          hHandle,
    ref UInt32 		mode);

/**
  @brief  手动更新数据到板卡
  
  @param  hHandle               ECAT控制句柄
  @param  u32PiArea             镜像的区域索引，为以下值之一：PI_AREA_FAST_OUTPUT，PI_AREA_SHADOW_INPUT
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIASyncUpdateData", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIASyncUpdateData(
    IntPtr          hHandle,
    UInt32			u32PiArea);

/**
  @brief  写镜像输出数据到指定的缓存
  
  @param  hHandle               ECAT控制句柄
  @param  u32PiArea             镜像的区域索引，为以下值之一：PI_AREA_LOCAL_OUTPUT、PI_AREA_FAST_OUTPUT
  @param  u32Offset             区域的偏移地址
  @param  u32DataLen            写入的数据长度
  @param  pvData                写入的数据
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIWrite", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIWrite(
    IntPtr              hHandle,
    UInt32              u32PiArea,
    UInt32              u32Offset,
    UInt32              u32DataLen,
    ref byte            pvData);

/**
  @brief  通过掩码的方式写镜像输出数据到指定的缓存
  
  @param  hHandle               ECAT控制句柄
  @param  u32PiArea             镜像的区域索引，为以下值之一：PI_AREA_LOCAL_OUTPUT、PI_AREA_FAST_OUTPUT
  @param  u32Offset             区域的偏移地址
  @param  u32DataLen            写入的数据长度
  @param  pvMask                写入的数据掩码
  @param  pvData                写入的数据
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIMaskWrite", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIMaskWrite(
    IntPtr			hHandle,
    UInt32			u32PiArea,
    UInt32         	u32Offset,
    UInt32         	u32DataLen,
    ref byte       	pvMask,
    ref byte       	pvData);

/**
  @brief  从指定的缓存读取镜像输入数据

  @param  hHandle               ECAT控制句柄
  @param  u32PiArea             镜像的区域索引，为以下值之一：PI_AREA_LOCAL_INPUT、PI_AREA_SHADOW_INPUT
                                  PI_AREA_LOCAL_OUTPUT、PI_AREA_FAST_OUTPUT、PI_AREA_SHADOW_OUTPUT
  @param  u32Offset             区域的偏移地址
  @param  u32DataLen            读取的数据长度
  @param[OUT]  pvData           读取的数据
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIRead", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIRead(
    IntPtr hHandle,
    UInt32 u32PiArea,
    UInt32 u32Offset,
    UInt32 u32DataLen,
    ref byte pvData);

/**
  @brief  指定的缓存数据清零

  @param  hHandle               ECAT控制句柄
  @param  u32PiArea             镜像的区域索引，为以下值之一：PI_AREA_LOCAL_INPUT
                                  PI_AREA_LOCAL_OUTPUT、PI_AREA_FAST_OUTPUT
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIClear", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIClear(
    IntPtr      		hHandle,
    UInt32         		u32PiArea
);

/**
  @brief  获取指定从站的镜像缓存的内存映射偏移及大小

  @param  hHandle               ECAT控制句柄
  @param  u32PiArea             镜像的区域索引，为以下值之一：PI_AREA_LOCAL_INPUT、PI_AREA_SHADOW_INPUT
                                  PI_AREA_LOCAL_OUTPUT、PI_AREA_FAST_OUTPUT、PI_AREA_SHADOW_OUTPUT
  @param  [out]u32Offset        区域的偏移地址
  @param  [out]u32DataLen       读取的数据长度
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIGetRange", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIGetRange(
    IntPtr      		hHandle,
    UInt32         		u32PiArea,
    UInt32         		u32SlaveId,
    ref UInt32 			pu32Offset,
    ref UInt32        	pu32DataLen);

/**
  @brief  指定从站配置看门狗

  @param  hHandle               ECAT控制句柄
  @param  Slave                 从站编号
  @param  Type                  看门狗类型，@see ECAT_WATCHDOG_TYPE
  @param  Mask                  掩码，可为空，等价于全为0xFF
  @param  Data                  数据
  @param  Size                  长度
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIWatchDogConfig", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIWatchDogConfig(IntPtr hHandle, UInt32 Slave, UInt32 Type,
    ref byte Mask, ref byte Data, UInt32 Size);

/**
  @brief  查看从站配置看门狗

  @param  hHandle               ECAT控制句柄
  @param  Slave                 从站编号
  @param  [out]Type             看门狗类型，@see ECAT_WATCHDOG_TYPE
  @param  [out]Timeout          看门狗超时值，毫秒为单位
  @param  [out]Mask             掩码
  @param  [out]Data             数据
  @param  [in/out]Size          输入缓冲区长度，输出读取到的数据长度
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIWatchDogQuery", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIWatchDogQuery(IntPtr hHandle, UInt32 Slave, ref UInt32 Type,
    ref UInt32 Timeout, ref byte Mask, ref byte Data, ref UInt32 Size);

/**
  @brief  启动看门狗

  @param  hHandle               ECAT控制句柄
  @param  Timeout               看门狗超时值，0: 禁用，非0: 超时(ms)
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIWatchDogEnable", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIWatchDogEnable(IntPtr hHandle, UInt32 TimeoutMs);

/**
  @brief  手动喂狗，以避免PI超时。调用以下函数会自动触发喂狗：EcatPIWrite、EcatPIOutputQueuePush、EcatRequestMasterState

  @param  hHandle               ECAT控制句柄
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIWatchDogFeed", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIWatchDogFeed(IntPtr hHandle);

/**
  @brief  使能PI镜像缓存跟总线进行数据交换，等价于调用 EcatPIEnableSet(xx, 1)

  @param  hHandle               ECAT控制句柄
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIEnable", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIEnable(IntPtr hHandle);

/**
  @brief  禁能PI镜像缓存跟总线进行数据交换，等价于调用 EcatPIEnableSet(xx, 0)

  @param  hHandle               ECAT控制句柄
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIDisable", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIDisable(IntPtr hHandle);

/**
  @brief  设置PI镜像缓存跟总线进行数据交换是否使能，调用EcatBusRun后，复位并处于禁能状态

  @param  hHandle               ECAT控制句柄
  @param  bState                false(0)为禁能，true(1)为使能
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIEnableSet", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIEnableSet(IntPtr hHandle, UInt32 bState);

/**
  @brief  获取PI镜像缓存跟总线进行数据交换是否使能

  @param  hHandle               ECAT控制句柄
  @param[out]  bState           false(0)为禁能，true(1)为使能
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIEnableGet", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIEnableGet(IntPtr hHandle, ref UInt32 bState);

/**
  @brief  拷贝镜像输出缓存到输出队列的尾部，队列的有效个数加1，非线程安全
  
  @param  hHandle               ECAT控制句柄
  @param  bReqClearQueue        true: 请求清空之前的队列数据并快速输出当前帧，false：无特殊操作
  @param  u32TimeOutMs          超时时间，以毫秒为单位
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIOutputQueuePush", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIOutputQueuePush(
    IntPtr              hHandle,
    bool                bReqClearQueue,
    UInt32              u32TimeOutMs);

/**
  @brief  返回PI输出队列的有效数的个数
  
  @param  hHandle               ECAT控制句柄
  @param[OUT]  pu32Size         当前有效数据的个数
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIOutputQueueSize", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIOutputQueueSize(
    IntPtr              hHandle,
    ref UInt32          pu32Size);

/**
  @brief  拷贝输入队列的头部到镜像输入缓存，队列的有效个数减1，非线程安全
  
  @param  hHandle               ECAT控制句柄
  @param  bReqClearRemain       true: 请求清空残留的队列数据以获取最新的数据，false：无特殊操作
  @param  u32TimeOutMs          超时时间，以毫秒为单位
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIInputQueuePop", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIInputQueuePop(
    IntPtr              hHandle,
    bool                bReqClearRemain,
    UInt32              u32TimeOutMs);

/**
  @brief  返回输入队列的有效数的个数
  
  @param  hHandle               ECAT控制句柄
  @param  pu32Size              返回输入队列的有效数的个数
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIInputQueueSize", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIInputQueueSize(
    IntPtr              hHandle,
    ref UInt32          pu32Size);

/**
  @brief  等待总线更新输入数据，非线程安全
  
  @param  hHandle               ECAT控制句柄
  @param  u32TimeOutMs          超时时间，以毫秒为单位
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatPIInputWaitNotify", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatPIInputWaitNotify(
    IntPtr              hHandle,
    UInt32              u32TimeOutMs);

/**
  @brief  从从站中读文件到本地文件系统
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param  pszFileLocalName      本地文件系统的文件名
  @param  pszFileSlaveName      从站文件系统的文件名
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatFoERead", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatFoERead(
    IntPtr                      hHandle,
    UInt16                      u16SlaveId,
    string                      pszFileLocalName,
    string                      pszFileSlaveName);

/**
  @brief  从本地文件系统写文件到从站
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param  pszFileLocalName      本地文件系统的文件名
  @param  pszFileSlaveName      从站文件系统的文件名
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatFoEWrite", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatFoEWrite(
    IntPtr                      hHandle,
    UInt16                      u16SlaveId,
    string                      pszFileLocalName,
    string                      pszFileSlaveName);

/**
  @brief  请求切换主站状态
  
  @param  hHandle               ECAT控制句柄
  @param  u8State               切换到主站的状态，参考EcatStateP、EcatStateO等枚举值
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatRequestMasterState", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatRequestMasterState(IntPtr hHandle, byte u8State);

/**
  @brief  获取当前主站请求的状态
  
  @param  hHandle               ECAT控制句柄
  @param[OUT]  pu8State         主站当前的状态，参考EcatStateP、EcatStateO等枚举值
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetMasterReqState", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetMasterReqState(IntPtr hHandle, ref byte pu8State);

/**
  @brief  获取当前主站状态
  
  @param  hHandle               ECAT控制句柄
  @param[OUT]  pu8State         主站当前的状态，参考EcatStateP、EcatStateO等枚举值
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetMasterState", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetMasterState(IntPtr hHandle, ref byte pu8State);

/**
  @brief  获得当前ENI配置下从站的数量
  
  @param  hHandle               ECAT控制句柄
  @param[OUT]  pu16Count        从站的个数
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetSlaveCount", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetSlaveCount(IntPtr hHandle, ref UInt16 pu16Count);

/**
  @brief  获取当前网络中活跃的从站数量。当有从站进行热插拔时，这个数量可能会和EcatGetSlaveCount不同
  
  @param  hHandle               ECAT控制句柄
  @param[OUT]  pu16Count        从站的个数
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetActiveSlaveCount", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetActiveSlaveCount(IntPtr hHandle, ref UInt16 pu16Count);

/**
  @brief  判断当前主站和配置文件是否一致

  @param  hHandle               ECAT控制句柄
  @param  eniFile            eni
  @return  返回ECAT_S_OK(0)表示一致，非0表示不一致
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatCheckRunningEni", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatCheckRunningEni(
    IntPtr				hHandle,
    string				eniFile);

/**
  @brief  检索从站是否处于活跃状态

  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @return  返回true表示活跃，返回false表示离线
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatSlaveIsActive", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern bool EcatSlaveIsActive(IntPtr hHandle, UInt16 u16SlaveId);


/**
  @brief  获取从站的DL状态

  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param  [OUT]pu16LStatus      存储从站的DL状态
                                  bit     0: PDI Operational
                                  bit     1: PDI Watchdog Status
                                  bits 2..3: Reserved
                                  bit     4: Link on Port 0
                                  bit     5: Link on Port 1
                                  bit     6: Link on Port 2
                                  bit     7: Link on Port 3
                                  bit     8: Loop Port 0 (Channel A Loop Status)
                                  bit     9: Communication on Port 0 (Channel A Signal Detection)
                                  bit    10: Loop Port 1 (Channel B Loop Status)
                                  bit    11: Communication on Port 1 (Channel B Signal Detection)
                                  bit    12: Loop Port 2 (Channel C Loop Status)
                                  bit    13: Communication on Port 2 (Channel C Signal Detection)
                                  bit    14: Loop Port 3 (Channel D Loop Status)
                                  bit    15: Communication on Port 3 (Channel D Signal Detection)
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetSlaveDLStatus", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetSlaveDLStatus(IntPtr hHandle, UInt16 u16SlaveId, ref UInt16 pu16LStatus);

/**
  @brief  获取从站的AL状态码

  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param  [OUT]pu16ALStatusCode 存储从站的AL状态码 @see ECAT_AL_STATUS_CODE
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetSlaveALStatusCode", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetSlaveALStatusCode(IntPtr hHandle, UInt16 u16SlaveId, ref UInt16 pu16ALStatusCode);

/**
  @brief  获得当前的详细信息
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param[OUT]  pSlaveInfo       从站的信息
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetSlaveInfo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetSlaveInfo(IntPtr hHandle, UInt16 u16SlaveId, ref ECAT_SLAVE_INFO pSlaveInfo);

/**
  @brief  获取从站的状态
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param[OUT]  pu8State         主站当前的状态，参考EcatStateP、EcatStateO等枚举值
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetSlaveState", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetSlaveState(IntPtr hHandle, UInt16 u16SlaveId, ref byte pu8State);

/**
  @brief  获取前N个从站的状态
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveNum           从站数量
  @param[OUT]  pu8State         从站当前的状态数组，@see EcatState
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetSlaveStateEx", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetSlaveStateEx(IntPtr hHandle, UInt16 u16SlaveNum, ref byte pu8State);

/**
  @brief  获取从站的请求状态
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param[OUT]  pu8State         从站当前的状态，@see EcatState
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetSlaveReqState", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetSlaveReqState(IntPtr hHandle, UInt16 u16SlaveId, ref byte pu8State);

/**
  @brief  获取前N个从站的请求状态
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveNum           从站数量
  @param[OUT]  pu8State         从站当前的状态数组，@see EcatState
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetSlaveReqStateEx", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetSlaveReqStateEx(IntPtr hHandle,
    UInt16 u16SlaveNum,
    ref byte pu8State);

/**
  @brief  清除从站状态错误，如从站返回EcatStateErrorFlag错误码，则需要调用本API来清除错误
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1，0xFFFF表示清除所有从站的错误
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatClearSlaveStateError", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatClearSlaveStateError(IntPtr hHandle, UInt16 u16SlaveId);

/**
  @brief  设置自动清除状态错误是否使能，默认值，调用EcatBusRun后复位并处于使能状态

  @param  hHandle               ECAT控制句柄
  @param  State                 false(0)为禁能，true(1)为使能
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatAutoClearSlaveStateErrorEnableSet", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatAutoClearSlaveStateErrorEnableSet(IntPtr hHandle, UInt32 bState);

/**
  @brief  获取自动清除状态错误是否使能

  @param  hHandle               ECAT控制句柄
  @param[out]  State            false(0)为禁能，true(1)为使能
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatAutoClearSlaveStateErrorEnableGet", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatAutoClearSlaveStateErrorEnableGet(IntPtr hHandle, ref UInt32 bState);

/**
  @brief  获取从站的PI输入信息
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param[OUT]  pu16BitSize      存储从站镜像的位大小
  @param[OUT]  pu16BitOffset    存储从站镜像的位偏移
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetSlavePIInputsInfo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetSlavePIInputsInfo(
    IntPtr                  hHandle,
    UInt16                  u16SlaveId,
    ref UInt16              pu16BitSize,
    ref UInt16              pu16BitOffset);

/**
  @brief  获取从站的PI输出信息
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param[OUT]  pu16BitSize      存储从站镜像的位大小
  @param[OUT]  pu16BitOffset    存储从站镜像的位偏移
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetSlavePIOutputsInfo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetSlavePIOutputsInfo(
    IntPtr                  hHandle,
    UInt16                  u16SlaveId,
    ref UInt16              pu16BitSize,
    ref UInt16              pu16BitOffset);

/**
  @brief  获取从站制造商ID
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param[OUT]  pu32VendorID     存储从站的制造商ID
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetSlaveVendorID", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetSlaveVendorID(IntPtr hHandle, UInt16 u16SlaveId, ref UInt32 pu32VendorID);

/**
  @brief  获取从站的产品码
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param[OUT]  pu32ProductCode  存储从站的产品码
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetSlaveProductCode", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetSlaveProductCode(IntPtr hHandle, UInt16 u16SlaveId, ref UInt32 pu32ProductCode);

/**
  @brief  获取从站的修订号
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param[OUT]  pu32RevisionNo   存储从站的修订号
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetSlaveRevisionNo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetSlaveRevisionNo(IntPtr hHandle, UInt16 u16SlaveId, ref UInt32 pu32RevisionNo);

/**
  @brief  获取从站的序列号
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param[OUT]  pu32SerialNo     获取从站的序列号
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetSlaveSerialNo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetSlaveSerialNo(IntPtr hHandle, UInt16 u16SlaveId, ref UInt32 pu32SerialNo);

/**
  @brief  获取从站的别名
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param[OUT]  pu32Alias        获取从站的别名
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetSlaveAlias", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetSlaveAlias(IntPtr hHandle, UInt16 u16SlaveId, ref UInt32 pu32Alias);

/**
  @brief  获取从站的设备地址
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param[OUT]  pu32Alias        获取从站的设备地址
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetSlaveFixAddr", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetSlaveFixAddr(IntPtr hHandle, UInt16 u16SlaveId, ref UInt16 p16FixAddr);

/**
  @brief  写从站EEPROM
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param  u16StartAdr           EEPROM偏移地址
  @param  u16DataLen            数据的字节长度
  @param  pvData                写入的数据，发送多字节时，须以小端排列
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatSlaveEepromWrite", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatSlaveEepromWrite(IntPtr hHandle, UInt16 u16SlaveId, UInt16 u16StartAdr, UInt16 u16DataLen, ref byte pvData);

/**
  @brief  读从站EEPROM
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param  u16StartAdr           EEPROM偏移地址
  @param  u16DataLen            数据的字节长度
  @param[OUT]  pvData           存储读取到的数据，发送多字节时，须以小端排列
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatSlaveEepromRead", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatSlaveEepromRead(IntPtr hHandle, UInt16 u16SlaveId, UInt16 u16StartAdr, UInt16 u16DataLen, ref byte pvData);

/**
  @brief  写从站Memory
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param  u16StartAdr           Memory偏移地址
  @param  u16DataLen            数据的字节长度
  @param  pvData                写入的数据，发送多字节时，须以小端排列
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatSlaveMemoryWrite", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatSlaveMemoryWrite(IntPtr hHandle, UInt16 u16SlaveId, UInt16 u16StartAdr, UInt16 u16DataLen, ref byte pvData);

/**
  @brief  读从站Memory
  
  @param  hHandle               ECAT控制句柄
  @param  u16SlaveId            从站位置索引，范围：0~SlaveCount-1
  @param  u16StartAdr           Memory偏移地址
  @param  u16DataLen            数据的字节长度
  @param[OUT]  pvData           存储读取到的数据，发送多字节时，须以小端排列
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatSlaveMemoryRead", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatSlaveMemoryRead(IntPtr hHandle, UInt16 u16SlaveId, UInt16 u16StartAdr, UInt16 u16DataLen, ref byte pvData);

/**
  @brief  将从站的物理地址转换为从站索引
  
  @param  hHandle               ECAT控制句柄
  @param  fixAddr               从站物理地址
  @param[OUT]  slaveIndex           从站位置索引，范围：0~SlaveCount-1
  @return  返回ECAT_S_OK(0)表示成功，非0表示失败
*/
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatSlaveFixAddr2Index", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatSlaveFixAddr2Index(IntPtr hHandle, UInt16 fixAddr, ref UInt16 slaveIndex);

/**
 * @brief 获取固件编译信息
 * 
 * @param  hHandle              ECAT控制句柄
 * @param  outputStr            输出的字符串
 * @param  outputSize           存储空间的大小
 * @return 返回ECAT_S_OK(0)表示成功，非0表示失败
 */
[DllImport(PCI_ZECM_DLL_NAME, EntryPoint = "EcatGetFirmwareCompileMsg", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 EcatGetFirmwareCompileMsg(IntPtr hHandle, ref byte outputStr, ref UInt32 outputSize);

};


}
