#ifndef JAXIS_H
#define JAXIS_H

#define WIN32_LEAN_AND_MEAN

#include <string>
#include <map>
#include "AxisPara.h"
#include <Windows.h>
//使用类型擦除方式
#include <any>
/*
 * 接口设计原则
 * 1、只定义外部接口,Axis内部使用接口不计入
 * 2、底层的、单一完整的功能接口
 * 3、都为用户单位User Units
 * 4、函数均为非模态,若实现方式不是下到运动控制卡中执行,则需要开线程执行
 * 5、尽量与特定品牌特性分离
 * 7、轴配置参数、回零参数、限位参数等保存在数据库中
 * 8、构造时赋予的轴编号或轴名称为外部对轴的唯一标识
 * 9、单一基础功能,组合功能在上层AxisManager中做
 */

//返回值定义
#define AXIS_CMD_SUCCESS  0
//轴错误指令
#define AXIS_CMD_ERROR_INSTRUCTION  1
//轴参数错误
#define AXIS_CMD_ERROR_PARAMETER  2
//处于错误的运动模式
#define AXIS_CMD_ERROR_MOTION_MODE  3
//轴处于禁止的状态
#define AXIS_CMD_ERROR_FORBID_STATE  4
//硬件错误
#define AXIS_CMD_ERROR_DRIVE_FAULT  5
//硬件禁止
#define AXIS_CMD_ERROR_DRIVE_INHIBIT  6
//轴伺服未使能
#define AXIS_CMD_ERROR_DRIVE_DISABLE  7
//轴伺服未软使能
#define AXIS_CMD_ERROR_SOFT_DISABLE  8
//轴未回过零
#define AXIS_CMD_ERROR_NOT_HOMED  9
//轴触发负硬限位
#define AXIS_CMD_ERROR_HARD_NEG_LIMIT  10
//轴触发正硬限位
#define AXIS_CMD_ERROR_HARD_POS_LIMIT  11
//轴触发负软限位
#define AXIS_CMD_ERROR_SOFT_NEG_LIMIT  12
//轴触发正软限位
#define AXIS_CMD_ERROR_SOFT_POS_LIMIT  13
//错误的轴类型
#define AXIS_CMD_ERROR_AXISTYPE        14
//超过轴运动的允许时间
#define AXIS_CMD_ERROR_TIME_OVER       15
//轴正在运动无法设置
#define AXIS_CMD_ERROR_MOVING       16
//轴中没有此运动模式
#define AXIS_CMD_ERROR_NO_MOTION_MODE 17
//轴中跟随误差超限
#define AXIS_CMD_ERROR_TRACE_LIMIT 18
//轴获取回零时位置误差超限(10次大循环,没有连续两次编码器位置在误差内的)
#define AXIS_CMD_ERROR_ENC_DIFF 19
//轴回零方式不存在
#define AXIS_CMD_ERROR_WRONG_HOME_METHOD 20

//坐标系中轴数量不足
#define AXIS_CMD_ERROR_LACK_AXIS 21
//坐标系中包含的轴错误
#define AXIS_CMD_ERROR_WRONG_AXIS 22
//输入参数类型错误
#define AXIS_CMD_ERROR_WRONG_VAR_TYPE 23

//发送消息失败
#define AXIS_CMD_ERROR_MSG_FAULT 24



#define AXIS_HOME_ERROR_NO_HOME  1001
#define AXIS_HOME_ERROR_NO_INDEX  1002
//.....




#define ELMO_COMPARE_POS1 "ui[1]"
#define ELMO_FEEDBACK_POS "px"
#define ELMO_COMPARE_ENABLE "ui[2]"
#define ELMO_STOP_SIGNAL "ob[2]"
enum AxisStopMode
{
    AXIS_SMOOTH_STOP = 0,//平滑停止
    AXIS_ABRUPT_STOP = 1,//急停
};

enum AxisMotionMode
{
    AXIS_MODE_TRAP = 0,//点位运动模式
    AXIS_MODE_JOG = 1,//Jog模式
    AXIS_MODE_PT = 2,//PT模式
    AXIS_MODE_GEAR = 3,//电子齿轮模式
    AXIS_MODE_FOLLOW = 4,//Follow模式(电子凸轮)
    AXIS_MODE_COORDINATE = 5,//插补模式//INTERPOLATION
    AXIS_MODE_PVT = 6,//PVT模式
    AXIS_MODE_FORCE = 7,//力轴模式
};




struct AxisStatus
{
    bool bInitOK = false; // 初始化成功
    bool bDriveFaulted = false; // 伺服报警
    bool bInhibitedFaulted = false; // 轴禁止故障
    bool bTrackError = false; // 跟随误差越限
    bool bPosHardLimitEnable = false;//正限位使能
    bool bNegHardLimitEnable = false;//负限位使能
    bool bPosHardLimit = false; // 正硬限位触发
    bool bNegHardLimit = false; // 负硬限位触发
    bool bNegSoftLimitEnable = false;// 负软限位使能
    bool bPosSoftLimitEnable = false;// 正软限位使能
    bool bPosSoftLimit = false; // 正软限位触发
    bool bNegSoftLimit = false; // 负软限位触发
    bool bSmoothStop = false;// 平滑停止标志
    bool bAbruptStop = false; // 急停标志
    bool bDriveEnabled = false; // 伺服使能
    bool bSoftEnabled = false; // 软使能
    bool bHomed = false; // 已寻过零标志
    bool bMoving = false; // 规划器运动标志
    bool bArrival = false; // 电机到位标志

    AxisMotionMode eMotionMode = AXIS_MODE_TRAP;//运动模式
    AxisStopMode eStopMode = AXIS_SMOOTH_STOP;//默认为平滑停止
};

struct MotionStatus
{
    /*所有单位都是 user units*/
    double m_dTargetPos = 0.0;//目标运动位置
    double m_dMoveDistance = 0.0;//最近一次运动距离
    double m_dTargetVel = 0.0;//目标预计速度
    double m_dTargetAcc = 0.0;//目标预计加速度
    double m_dTargetDec = 0.0;//目标预计减速度
    double m_dTargetJerk = 0.0;//目标预计Jerk
};

struct AxisIOStatus
{
    bool bHomeSensorInput = false;
    bool bPosLimitSensorInput = false;
    bool bNegLimitSensorInput = false;
    bool bAxisInhibitedInput = false;//急停输入,Safety Torque Off
    bool bDriveEnableOutput = false;
    bool bDriveFaultResetOutput = false;
};

struct AxisHomeStatus
{
    bool bHomeRunning = false; // false—已停止运动,true-正在回原点
    bool bHomeDone = false; // false—回零未完成,true-回零完成
    bool bHomeError = false; // false—回零未出错,true-回零出错
    int nHomeStage = 0; // 回原点运动的阶段
    int nErrorCode = 0; // 回原点过程的发生的错误码
    double dCapturePos = 0.0; // 捕获到Home或Index时刻的编码器位置,user units
    double dTargetPos = 0.0; // 需要运动到的目标位置(原点位置或者原点位置+偏移量),user units
};

class  JAxis
{
public:

    JAxis(){};

    virtual ~JAxis(){};

public:
    //获取轴ID
    virtual int GetAxisId() = 0;

    //获取轴名称
    virtual std::string GetAxisName() = 0;

public:
    /*-------------------------
     * 轴配置
    --------------------------*/
    //轴初始化
    virtual int Init(AxisData* Data/*,int nFormerAxis*/,HANDLE hCtrlComm) = 0;

    //轴硬件使能
    virtual int AxisOn() = 0;

    //轴断硬件使能
    virtual int AxisOff() = 0;

    //状态清除/故障
    virtual int ClearStatus() = 0;

    //电气硬限位使能
    virtual int EnableHardLimit(bool bEnableNeg, bool bEnablePos) = 0;

    //软件限位使能
    virtual int EnableSoftLimit(bool bEnableNeg, bool bEnablePos) = 0;

    //到位检查使能
    //确认
    virtual int EnableArrivalCheck(bool bEnable) = 0;

    //设置当前规划位置值
    virtual int SetCurrentProfilePos(double dPos) = 0;

    //设置当前实际位置值
    virtual int SetCurrentActualPos(double dPos) = 0;

    //设置当前规划和实际位置值
    virtual int SetCurrentPos(double dPos) = 0;

    //设置当前规划和实际位置值为0(即被动回零)
    virtual int ZeroCurrentPos() = 0;

    /*-------------------------
     * 轴参数设置
    --------------------------*/
    // //设置轴单个参数(TODO-通用参数读写接口需要优化)
    // virtual int SetParameter(std::string strPrmName, double dValue) = 0;

    // //获取轴单个参数(TODO-通用参数读写接口需要优化)
    // virtual int GetParameter(std::string strPrmName, double& dValue) = 0;

    // //获取轴所有参数副本(TODO-通用参数读写接口需要优化)
    // virtual int GetAllParameters(std::map<std::string, double>& prmsMap) = 0;

    //获取轴数据结构体指针
    virtual const AxisData* GetAxisData() const /*{return m_stData;}*/ = 0;

    //设置轴数据结构体中的数据(新增)
    virtual int SetAxisData(AxisData* data) = 0;


    //获取轴当前的轴类型,如Servo,Forcer,Step;其实没有意义,需要删除2024/11/25
    virtual AxisType GetAxisType() = 0;



    //设置到位误差及整定时间
    virtual int  SetArrivalBand(double dErrorBand, double dSettingTime) = 0;

    //设置软限位
    virtual int  SetSoftLimit(double dNegLimit, double dPosLimit) = 0;

    //获取轴硬件编号
    virtual int  GetAxisNo() = 0;

    //获取到位误差及整定时间
    virtual int  GetArrivalBand(double& dErrorBand, double& dSettingTime) = 0;

    //获取软限位及软行程
    virtual int  GetSoftLimit(double& dSoftLimitNeg, double& dSoftLimitPos, double& dSoftTravelRange) = 0;

    //获取最大速度设置
    virtual int  GetMaxVelocity(double& dMaxVel) = 0;

    //获取最大加/减速度设置
    virtual int  GetMaxAcceleration(double& dMaxAcc, double& dMaxDec) = 0;

    //获取最大Jerk设置
    virtual int  GetMaxJerk(double& dMaxJerk) = 0;

    /*-------------------------
     * 运动Buffer参数获取与设置
    --------------------------*/

    virtual int SetBufferParamF(int nBufferNo,std::string sParamFName,double dDoubleParam)=0;
    virtual int SetBufferParam(int nBufferNo,std::string sParamName,int nIntParam)=0;


    virtual int GetBufferParamF(int nBufferNo,std::string sParamFName,double& dDoubleParam)=0;
    virtual int GetBufferParam(int nBufferNo,std::string sParamName,int& nIntParam )=0;

    //运行驱动器中的脚本
    virtual int RunBuffer(int nBufferNo)=0;

    /*-------------------------
     * 轴运动
    --------------------------*/
    //串口通讯写入参数值(USB),默认为GBK编解码
    //默认数据位8,校验位None,停止位1
    //模板类型

    // template <typename T>
    virtual int WriteSerialValue(std::string sSerial,std::any tValue)=0;

    //virtual int WriteSerialValue(std::string sSerial)=0;
    virtual int WriteSockValue(std::string sSerial,std::any tValue)=0;

    //设置软使能状态
    virtual int SetAxisSoftEnable(bool bEnable) = 0;

    //设置停止减速度
    virtual int SetStopDec(double dSmoothStopDec, double dAbruptStopDec) = 0;
    virtual int SetStopDecR(double dSmoothStopRatio,double dAbruptStopRatio) = 0;

    //运动停止(同时停止寻零)
    virtual int Stop(AxisStopMode eStopMode = AXIS_SMOOTH_STOP) = 0;

    //设置轴运动模式
    virtual int SetMotionMode(AxisMotionMode eMode) = 0;

    //ACS所有运动参数相关设置,单位均为um/s->um/s而非um/s->cnt/ms
    //设置目标Acc/Dec参数,user units
    virtual int SetTargetAccDec(double dAcc, double dDec) = 0;
    virtual int SetTargetAccDecR(double dAccRatio,double dDecRatio) = 0;


    //设置目标Jerk参数,user units
    virtual int SetTargetJerk(double dJerk) = 0;
    virtual int SetTargetJerkR(double dJerkRatio) = 0;

    //设置目标速度(直接速度),user units
    virtual int SetTargetVel(double dVel) = 0;
    virtual int SetTargetVelR(double dVelRatio) = 0;


    //超时会返回错误码,直接停止并退出
    //启动绝对位移运动,user units
    virtual int MoveAbs(double dPos,double dTime = 0) = 0;
    virtual int MoveAbs(double dPos,double dTime,double dPassPos) = 0;
    virtual int MoveAbsR(double dPos,double dVelRatio,double dTime = 0) = 0;
    virtual int MoveAbsR(double dPos,double dVelRatio,double dTime,double dPassPos) = 0;

    //启动相对位移运动,user units
    virtual int MoveRel(double dDist,double dTime = 0) = 0;
    virtual int MoveRel(double dDist,double dTime,double dPassDist) = 0;
    virtual int MoveRelR(double dDist,double dVelRatio,double dTime = 0) = 0;
    virtual int MoveRelR(double dDist,double dVelRatio,double dTime,double dPassDist) = 0;

    //启动Jog运动,user units
    virtual int Jog(double dVel) = 0;
    virtual int JogR(double dVelRatio) = 0;

    //启动力轴力矩模式运动
    //千分之最大电流;Slope/上升时间 ms;停止时间 ms
    virtual int MoveForce(int nTorqueRatio,int nReachTime = 50,int nStopTime = 10) = 0;



    //启动本轴作为从轴的齿轮运动
    virtual int MoveGear() = 0;
    //设置从轴的齿轮比(只有齿轮运动模式才有)
    //主轴齿数,从轴齿数,离合区;单位均为pulse
    virtual int SetGearRatio(long nMEven,long nSEven,long nMasterSlope = 0 ) = 0;
    //设置本从轴的主轴
    virtual int SetGearMaster(const JAxis* pMaster) = 0;

    //运动过程中改变运动速度,user units
    virtual int ChangeVel(double dVel) = 0;
    virtual int ChangeVelR(double dRatio) = 0;

    //启动寻零运动(时间大于0则在时间内等待)
    virtual int GoHome(double dTime = 0) = 0;


    /*-------------------------
     * 轴状态
    --------------------------*/
    //获取轴运动模式
    virtual int GetMotionMode(AxisMotionMode& axisMotionMode) = 0;

    //获取轴状态
    virtual int GetAxisStatus(AxisStatus& axisStatus) = 0;

    //轴是否已经初始化过
    virtual bool IsInitOK() = 0;

    //硬件故障
    virtual bool IsHardwareFaulted() = 0;

    //sto输出极切断
    virtual bool IsInhibitedFaulted() = 0;

    //是否轴已使能
    virtual bool IsDriveEnabled() = 0;

    //是否轴已软使能
    virtual bool IsSoftEnabled() = 0;

    //轴是否回过零
    virtual bool IsHomed() = 0;

    //是否轴正在运动
    virtual bool IsMoving() = 0;

    //是否轴已到达预设位置
    virtual bool IsArrival() = 0;

    //
    //virtual bool WaitArrival() = 0;

    //获取IO状态
    virtual int GetIOStatus(AxisIOStatus& axisIOStatus) = 0;

    //获取寻零运动状态
    virtual int GetHomeStatus(AxisHomeStatus& axisHomeStatus) = 0;

    //获取硬限位使能配置状态
    virtual int GetHardLimitEnableStatus(bool& bEnabledNeg, bool& bEnabledPos) = 0;

    //获取软限位使能配置状态
    virtual int GetSoftLimitEnableStatus(bool& bEnabledNeg, bool& bEnabledPos) = 0;

    //获取到位检查使能配置状态
    virtual int GetArrivalCheckEnableStatus(bool& bEnabled) = 0;

    /*-------------------------
     * 轴过程数据
    --------------------------*/
    //获取目标位置数据,user units
    virtual int GetTargetPos(double& dTargetPos) = 0;

    //获取目标速度数据,user units
    virtual int GetTargetVel(double& dTargetVel) = 0;

    //获取目标Acc/Dec数据,user units
    virtual int GetTargetAccDec(double& dTargetAcc, double& dTargetDec) = 0;

    //获取目标Jerk数据,user units
    virtual int GetTargetJerk(double& dTargetJerk) = 0;

    //获取实时规划位置,user units
    virtual int GetProfilePos(double& dProfilePos) = 0;

    //获取实时规划速度,user units
    virtual int GetProfileVel(double& dProfileVel) = 0;

    //获取实时规划加速度,user units
    virtual int GetProfileAcc(double& dProfileAcc) = 0;

    //获取实时规划力矩(电流),user units
    virtual int GetProfileTorque(double& dProfileTorque) = 0;

    //获取实时实际位置,user units
    virtual int GetActualPos(double& dActualPos) = 0;

    //获取实时实际速度,user units
    virtual int GetActualVel(double& dActualVel) = 0;

    //获取实时实际加速度,user units
    virtual int GetActualAcc(double& dActualAcc) = 0;

    //获取实时位置误差,user units
    virtual int GetPosError(double& dPosError) = 0;

    //获取实时实际力矩(电流),user units
    virtual int GetActualTorque(double& dActualTorque) = 0;

    //! 切换到单轴运动模式
    virtual bool CrdMotion2PTPMotion(bool bCrd2Single)=0;

    //对于错误码返回值的解释
    virtual std::string ErrCodeTransfer(int nRtn){return "";};

// protected:
    //! 单位转换,用户单位(um)转换成轴单位(pulse),(无偏置适用速度相关转换)
    virtual long  User2Driver(double um,bool bWithHomeOffset = 0)=0;

    //! 单位转换,轴单位(pulse)转换成用户单位(um),(无偏置适用速度相关转换)
    virtual double Driver2User(double driverPulse,bool bWithHomeOffset = 0) = 0;

    //获取对应品牌的轴Index(不同品牌的逻辑不同,与m_stData中存储的轴Index不同)
    virtual int GetAxisIndex() const= 0;
protected:
    //!当前不同回零方式
    //!IO回零
    virtual int IO2HomeMethod() = 0;
    //!Home捕获回零
    virtual int Home2HomeMethod() = 0;
    //!Index捕获回零
    virtual int Index2HomeMethod() = 0;
    //!直接回零,绝对值编码器
    virtual int Direct2HomeMethod() = 0;
    //!负向 + INDEX捕获回零
    virtual int NegIndex2HomeMethod() = 0;
    //!正向 + INDEX捕获回零
    virtual int PosIndex2HomeMethod() = 0;

    //!判断Home开关是否正被触发
    virtual bool CheckHomeSensor() = 0;
protected:
    //轴类型:伺服,力,步进
    AxisType m_nAxisType;
    //定义的轴状态
    AxisIOStatus m_stIOStatus;
    AxisHomeStatus m_stHomeStatus;
    AxisStatus m_stAxisStatus;
    MotionStatus m_stMotionStatus;

    //当前轴的状态
    //需要为指针形式
    AxisData* m_stData;



};

#endif // JAXIS_H