// mtn_lib20_ecat.java

///******************************************************************
//
// Moudle Name  :   mtn_lib20_ecat.java
// Abstract     :   GaoChuan Motion 2.0 ethercat user header (Java version)
// Note :       1.结构体定义中所有的'reservedxxx'的成员都是保留参数,为保持兼容性,请设置为0
//              2.无特别说明,所有API返回RTN_CMD_SUCCESS（即0值）表示执行成功,其他则表示错误代码
//              3.所有的API参数中,无特别说明,axisHandle表示操作轴的句柄,devHandle表示目标控制器的句柄,crdHandle表示目标坐标系组句柄
//              4.此Java版本使用JNA(Java Native Access)实现本地方法调用
///******************************************************************
package com.gaochuan.motion.ecat;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.ShortByReference;

import java.util.Arrays;
import java.util.List;

public interface MtnLib20Ecat extends Library {
    MtnLib20Ecat INSTANCE = Native.load("mtn_lib20", MtnLib20Ecat.class);

    // 启动Ethercat主站
    short NMC_EcatStart(Pointer devHandle);

    // 停止Ethercat主站
    short NMC_EcatStop(Pointer devHandle);

    // 获取当前在线的从站数量
    // pSlaveCnt:从站的总数
    // pDriverCnt:驱动器数量
    // pIoCnt:IO类型从站数量
    short NMC_EcatGetResource(Pointer devHandle, ShortByReference pSlaveCnt,
                              ShortByReference pDriverCnt, ShortByReference pIoCnt);

    // 从站信息结构体
    @Structure.FieldOrder({"vendor_id", "product_id", "devType", "dcCode",
            "txPdoCnt", "rxPdoCnt", "reserved"})
    public static class TEcatSlvInfo extends Structure {
        public int vendor_id;        //厂商ID
        public int product_id;       //设备ID
        public short devType;        //设备类型：1：驱动器，2：IO，3：其他
        public short dcCode;         // dc码
        public short txPdoCnt;       // txPdo数量
        public short rxPdoCnt;       // rxPdo数量
        public short[] reserved = new short[4]; // 保留

        public TEcatSlvInfo() {
            Arrays.fill(reserved, (short)0);
        }

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("vendor_id", "product_id", "devType", "dcCode",
                    "txPdoCnt", "rxPdoCnt", "reserved");
        }
    }

    // 获取从站信息
    short NMC_EcatGetSaveInfoEx(Pointer devHandle, short masterIdx,
                                short slvIdx, TEcatSlvInfo pInfo);

    // 获取主站状态
    // pSts:返回状态码
    //        bit0-bit7:主站状态（取值：0x01,0x02,0x03,0x04,0x08）
    //                  0x01: INIT
    //                  0x02: PREOP
    //                  0x03: BOOT
    //                  0x04: SAFEOP
    //                  0x0: OP
    //        bit8-bit11:状态机步骤
    short NMC_EcatGetSts(Pointer devHandle, ShortByReference pSts);

    // 设置从站驱动器的工作模式，用户一般不需要调用
    // mode: Control Mode : CSP:8 CSV:9  CST:10
    // axisHandle:轴句柄，通过NMC_MtOpen获取，ethercat从站轴的编号从16开始
    short NMC_EcatAxisSetMode(Pointer axisHandle, byte mode);

    // 获取从站驱动器的工作模式
    // axisHandle:轴句柄，通过NMC_MtOpen获取，ethercat从站轴的编号从16开始
    short NMC_EcatAxisGetMode(Pointer axisHandle, ByteByReference pMode);

    // 获取从站驱动器的错误代码
    // axisHandle:轴句柄，通过NMC_MtOpen获取，ethercat从站轴的编号从16开始
    short NMC_EcatAxisGetErrorCode(Pointer axisHandle, ShortByReference pError);

    // 获取从站驱动器的数字量输入状态
    // axisHandle:轴句柄，通过NMC_MtOpen获取，ethercat从站轴的编号从16开始
    short NMC_EcatAxisGetDi(Pointer axisHandle, IntByReference pDiVal);

    // 获取从站驱动器的编码器
    short NMC_EcatAxisGetEncPos(Pointer axisHandle, IntByReference pEncPos);

    // 启动回零，回零状态可以通过NMC_MtGetHomeSts查询
    // method:回零方式，根据标准，只支持402要求必须实现的，具体请参考驱动器相关的说明
    // velSwitch:找原点速度command/s
    // velZero:找index脉冲速度command/s
    // acc:加速度command/s^2
    // prmEx:保留
    // axisHandle:轴句柄，通过NMC_MtOpen获取，ethercat从站轴的编号从16开始
    short NMC_EcatStartHome(Pointer axisHandle, int method, double velSwitch,
                            double velZero, double acc, double prmEx);

    // 获取驱动器的回零状态
    short NMC_EcatGetHomeSts(Pointer axisHandle, ByteByReference pStatus);

    // 终止回零
    // axisHandle:轴句柄，通过NMC_MtOpen获取，ethercat从站轴的编号从16开始
    short NMC_EcatStopHome(Pointer axisHandle);

    // Ethercat SDO 读
    // devId:从站号
    // idx:SDO的Index
    // sub_idx:SDO的SubIndex
    // len:数据长度
    // val:数据内容
    // abort_code:错误码
    short NMC_EcatSdoRead(Pointer devHandle, short devId, short idx, byte sub_idx,
                          int len, byte[] val, IntByReference abort_code);

    // Ethercat SDO 写
    // devId:从站号
    // idx:SDO的Index
    // sub_idx:SDO的SubIndex
    // len:数据长度
    // val:数据内容
    // abort_code:错误码
    short NMC_EcatSdoWrite(Pointer devHandle, short devId, short idx, byte sub_idx,
                           int len, byte[] val, IntByReference abort_code);

    // 下载Ethercat配置文件（配置文件通过配置工具生成）
    // gmlFileName:配置工具路径
    // masterIdx:主站序号，保留，写0
    short NMC_EcatLoadConfigFromFile(Pointer devHandle, String gmlFileName, short masterIdx);

    // Ehercat:设置目标转矩，对应PDO序号0x6071
    // slv:从轴号，取值范围[0,n)
    // tgtTorque:目标转矩，参数范围及单位请参考对应的伺服驱动器手册
    short NMC_EcatAxisTorqSetTgt(Pointer devHandle, short slv, int tgtTorque);
    short NMC_EcatAxisTorqGetTgt(Pointer devHandle, short slv, IntByReference pTgtTorque);

    // Ehercat:设置最大转矩，对应PDO序号0x6072
    // slv:从轴号，取值范围[0,n)
    // maxTorque:最大转矩，参数范围及单位请参考对应的伺服驱动器手册
    short NMC_EcatAxisTorqSetMax(Pointer devHandle, short slv, int maxTorque);
    short NMC_EcatAxisTorqGetMax(Pointer devHandle, short slv, IntByReference pMaxTorque);

    // Ehercat:设置转矩斜坡值，对应PDO序号0x6087
    // slv:从轴号，取值范围[0,n)
    // torqueSlope:转矩斜坡值，参数范围及单位请参考对应的伺服驱动器手册
    short NMC_EcatAxisTorqSetSlope(Pointer devHandle, short slv, int torqueSlope);
    short NMC_EcatAxisTorqGetSlope(Pointer devHandle, short slv, IntByReference pTorqueSlope);

    // Ehercat:设置转矩偏移值，对应PDO序号0x60B2
    // slv:从轴号，取值范围[0,n)
    // torqueOffset:转矩偏移值，参数范围及单位请参考对应的伺服驱动器手册
    short NMC_EcatAxisTorqSetOffset(Pointer devHandle, short slv, int torqueOffset);
    short NMC_EcatAxisTorqGetOffset(Pointer devHandle, short slv, IntByReference pTorqueOffset);

    // Ehercat:设置转矩正向的限定值，对应PDO序号0x60E0
    // slv:从轴号，取值范围[0,n)
    // torquePosLmt:转矩正向的限定值，参数范围及单位请参考对应的伺服驱动器手册
    short NMC_EcatAxisTorqSetPosLmt(Pointer devHandle, short slv, int torquePosLmt);
    short NMC_EcatAxisTorqGetPosLmt(Pointer devHandle, short slv, IntByReference pTorquePosLmt);

    // Ehercat:设置转矩负向的限定值，对应PDO序号0x60E1
    // slv:从轴号，取值范围[0,n)
    // torquePosLmt:转矩负向的限定值，参数范围及单位请参考对应的伺服驱动器手册
    short NMC_EcatAxisTorqSetNegLmt(Pointer devHandle, short slv, int torqueNegLmt);
    short NMC_EcatAxisTorqGetNegLmt(Pointer devHandle, short slv, IntByReference pTorqueNegLmt);

    // Ehercat:设置伺服的最大电机速度，对应PDO序号0x6080
    // slv:从轴号，取值范围[0,n)
    // maxMotorVel:最大电机速度，参数范围及单位请参考对应的伺服驱动器手册
    short NMC_EcatAxisSetMaxMotorVel(Pointer devHandle, short slv, int maxMotorVel);
    short NMC_EcatAxisGetMaxMotorVel(Pointer devHandle, short slv, IntByReference pMaxMotorVel);

    // Ehercat:设置伺服的最大规划速度，对应PDO序号0x607F
    // slv:从轴号，取值范围[0,n)
    // maxPrfVel:最大规划速度，参数范围及单位请参考对应的伺服驱动器手册
    short NMC_EcatAxisSetMaxPrfVel(Pointer devHandle, short slv, int maxPrfVel);
    short NMC_EcatAxisGetMaxPrfVel(Pointer devHandle, short slv, IntByReference pMaxPrfVel);

    // 自定义引用类型用于处理byte指针参数
    public static class ByteByReference extends com.sun.jna.ptr.ByReference {
        public ByteByReference() {
            this((byte) 0);
        }

        public ByteByReference(byte value) {
            super(1);
            setValue(value);
        }

        public void setValue(byte value) {
            getPointer().setByte(0, value);
        }

        public byte getValue() {
            return getPointer().getByte(0);
        }
    }
}