using Advantech.Motion;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks; 
using System.Timers;
namespace AssistClient.Device
{
    public class AxisDev : IDisposable
    {
        public enum AxisStateType
        {
            [Description("轴状态")]
            AxisState = 0,
            [Description("轴运动状态")]
            AxisMotionState = 1,
            [Description("轴IO状态")]
            AxisIOState = 2, 
        }
       
        public Action<int, AxisStateType, uint> axisStateEvent;
        public enum AxisPosType
        {
            [Description("命令位置")]
            CmdPos = 0,
            [Description("反馈位置")]
            ActualPos = 1,
        }
        public Action<int, AxisPosType, double> axisPosEvent;
        /// <summary>                                                   使用
        /// 轴状态(AxisState 0-14) 单一值，无需按位取
        /// STA_AxDisable -- 轴被禁用，用户可打开并激活
        /// STA_AxReady ---- 轴已准备就绪，等待新的命令                  *
        /// STA_Stopping ---- 轴停止
        /// STA_AxErrorStop --- 出现错误，轴停止
        /// STA_AxHoming ---- 轴正在执行返回原点运动
        /// STA_AxPtpMotion ---- 轴正在执行PTP 运动
        /// STA_AxContiMotion ---- 轴正在执行连续运动
        /// STA_AxSyncMotion --- 轴在一个群组中，群组正在执行插补运动；或轴是一个从轴，正在执行Ecam/E-gear/Gantry 运动。
        /// STA_AX_EXT_JOG -- 轴由外部信号控制。当外部信号激活时，轴将执行JOG 模式运动。
        /// STA_AX_EXT_MPG --- 轴由外部信号控制。当外部信号激活时，轴将执行MPG 模式运动
        /// </summary>
        //public Action<int, int> axisStateEvent;

        /// <summary>
        /// 轴运动状态        使用
        /// 位 说明
        /// Stop ---- 停止 
        /// WaitERC---- 等待ERC 完成  
        /// InFA ---- 处于特定速度中 = FA
        /// InFL ---- 处于低速中 = FL
        /// InACC ---- 加速中
        /// InFH ---- 处于最大速度中 = FH
        /// InDEC ---- 减速中
        /// WaitINP---- 到位等待
        /// </summary>
        //public Action<int, int> axisMotionStateEvent;
        /// <summary>
        /// 轴IO状态 (Ax_Motion_IO)         使用
        /// RDY---- RDY 针脚输入    
        /// ALM ---- 报警信号输入         *
        /// LMT+ ---- 限位开关+         *
        /// LMT- ---- 限位开关-         *
        /// ORG---- 原始开关         *
        /// DIR ---- DIR 输出
        /// EMG ---- 紧急信号输入    
        /// EZ ---- 编码器 Z 信号
        /// INP ---- 到位信号输入
        /// SVON ---- 伺服开启（OUT6）         *
        /// ALRM ---- 报警复位输出状态
        /// SLMT+ ---- 软件限位+
        /// SLMT- ---- 软件限位-
        /// CMP----- 比较信号（OUT5）
        /// </summary>
        //public Action<int, bool, bool, bool, bool> axisIOStateEvent; 

        public Action<WarningEnum, string> WarningEvent;

        /// <summary>
        /// 设备列表（多张PCI板卡）
        /// </summary>
        public List<DEV_LIST> DevList { get; private set; }
        /// <summary>
        /// 设备数量
        /// </summary>
        //private uint deviceCount = 0;
        /// <summary>
        /// 设备号，用于打开设备（非索引）
        /// </summary>
        public uint DeviceNum { get; private set; } = 0;

        /// <summary>
        /// 设备句柄
        /// </summary>
        private IntPtr m_DeviceHandle = IntPtr.Zero;
        /// <summary>
        /// 轴数量
        /// </summary>
        private uint m_ulAxisCount = 0;
        private IntPtr[] m_Axishand = new IntPtr[0];
        public double[] CmdPos { get; private set; } = new double[32];//轴命令位置
        public double[] ActualPos { get; private set; } = new double[32];//轴实际(反馈)位置

        public UInt16[] AxState { get; private set; } = new UInt16[32];//轴状态
        public UInt32[] IOStatus { get; private set; } = new UInt32[32];//轴IO状态
        public uint[] AxMotionState { get; private set; } = new uint[32];//轴运动状态

        private uint[] AxEnableEvtArray = new uint[32];
        private uint[] GpEnableEvt = new uint[32];
        /// <summary>
        /// 组
        /// </summary>
        //private IntPtr m_GpHand = IntPtr.Zero;

        /// <summary>
        /// 断电后设备必需复位
        /// </summary>
        public bool IsReset { private set; get; }=false;
        public bool IsDebug = false;
        /// <summary>
        /// 是否打开设备成功
        /// </summary>
        public bool IsInit { get; private set; } = false;
        Thread checkEventThread;
        private System.Timers.Timer timer = new System.Timers.Timer();

        /// <summary>
        /// 获取设备列表
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        //public static List<DEV_LIST> getDevList()
        //{
        //    DEV_LIST[] curAvailableDevs = new DEV_LIST[Motion.MAX_DEVICES];
        //    uint deviceCount = 0;
        //    int Result = Motion.mAcm_GetAvailableDevs(curAvailableDevs, Motion.MAX_DEVICES, ref deviceCount);
        //    if (Result != (int)ErrorCode.SUCCESS || curAvailableDevs.Length < 1)
        //        throw new Exception("Get Device Numbers Failed With Error Code: [0x" + Convert.ToString(Result, 16) + "] DevCount=" + curAvailableDevs.Length);

        //    return curAvailableDevs.ToList().Take((int)deviceCount).ToList();
        //}
        public AxisDev()
        { 
            //初始化
            DEV_LIST[] curAvailableDevs = new DEV_LIST[Motion.MAX_DEVICES];
            uint deviceCount = 0;
            int Result = Motion.mAcm_GetAvailableDevs(curAvailableDevs, Motion.MAX_DEVICES, ref deviceCount);
            if (Result != (int)ErrorCode.SUCCESS || curAvailableDevs.Length < 1)
                throw new Exception("Get Device Numbers Failed With Error Code: [0x" + Convert.ToString(Result, 16) + "] DevCount=" + curAvailableDevs.Length);
            DevList = curAvailableDevs.ToList().Take((int)deviceCount).ToList();
        }
        public void Dispose()
        {
            stop(); 
        }

        /// <summary>
        /// 打开设备
        /// </summary>
        /// <exception cref="Exception"></exception>
        public bool start(int[] AxisPulseOutMode,bool debug=false)
        {
            if (DevList == null || DevList.Count < 1)
            {
                WarningEvent?.Invoke(WarningEnum.High, "Axis设备为空！");
                return false;
            }

            DeviceNum = DevList[0].DeviceNum;
            return start(DevList[0].DeviceNum, AxisPulseOutMode, debug);
        }
        int[] AxisPulseOutMode=new int[4];
        public bool start(uint DeviceNum,int[] AxisPulseOutMode, bool debug = false)
        {
            try
            {
                if (IsInit) return true;
                bALM = bEMG = bLMTP = bLMTN = false;

                //打开设备
                uint uResult = Motion.mAcm_DevOpen(DeviceNum, ref m_DeviceHandle);
                if (uResult != (int)ErrorCode.SUCCESS)
                    throw new Exception("Open Device Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");

                IsDebug = debug;
                IsReset = false;
                //读取轴数量
                uResult = Motion.mAcm_GetU32Property(m_DeviceHandle, (uint)PropertyID.FT_DevAxesCount, ref m_ulAxisCount);
                if (uResult != (uint)ErrorCode.SUCCESS)
                    throw new Exception("Get Axis Number Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");
                m_Axishand = new IntPtr[m_ulAxisCount];

                //打开轴
                for (int i = 0; i < m_ulAxisCount; i++)
                {
                    //打开每个轴并获得每个轴句柄  
                    uResult = Motion.mAcm_AxOpen(m_DeviceHandle, (UInt16)i, ref m_Axishand[i]);
                    if (uResult != (uint)ErrorCode.SUCCESS)
                        throw new Exception("Open Axis Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");

                    //先读取每个轴状态
                    this.refreshAxisState(i);

                    //判断与打开电源使能,1: On
                    if ((IOStatus[i] & (uint)Ax_Motion_IO.AX_MOTION_IO_SVON) == 0)
                    {
                        uResult = Motion.mAcm_AxSetSvOn(m_Axishand[i], 1);
                        if (uResult != (uint)ErrorCode.SUCCESS)
                            throw new Exception("Servo On Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");
                    }
                }
                //根据加载的文件设置设备的所有配置(需在打开每个轴 mAcm_AxSetSvOn 后设置)
                string cfgPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\DevCfg\\Axis_" + DeviceNum + ".cfg";
                if (File.Exists(cfgPath))
                {
                    uResult = Motion.mAcm_DevLoadConfig(m_DeviceHandle, cfgPath);
                    if (uResult != (uint)ErrorCode.SUCCESS)
                        throw new Exception("Load Config Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");
                }

                Thread.Sleep(500);
                for (int i = 0; i < m_ulAxisCount; i++)
                {
                    //先读取每个轴状态（进行报警）
                    this.refreshAxisState(i);
                    //每个轴的初始属性(reset 命令位置和实际(反馈)位置)
                    //double cmdPosition = new double();
                    //cmdPosition = 0;
                    //为指定的轴设置命令位置
                    //Motion.mAcm_AxSetCmdPosition(m_Axishand[i], cmdPosition);
                    //为指定的轴设置实际(反馈)位置
                    //Motion.mAcm_AxSetActualPosition(m_Axishand[i], cmdPosition);

                    //set Axis PulseOutMode
                    if (!setPulseOutMode(i, (AxisPulseOutMode)AxisPulseOutMode[i]))
                        throw new Exception($"Axis{i} 设置脉冲模式失败！");

                    this.AxisPulseOutMode = AxisPulseOutMode;
                    //Event
                    AxEnableEvtArray[i] |= (uint)EventType.EVT_AX_MOTION_DONE; //运动完成(减速直至停止)
                    //AxEnableEvtArray[i] |= (uint)EventType.EVT_AX_VH_START; //轴加速到运行速度时
                    //AxEnableEvtArray[i] |= (uint)EventType.EVT_AX_VH_END;//轴运行速度结束时，开始减速
                    AxEnableEvtArray[i] |= (uint)EventType.EVT_AX_HOME_DONE;
                    AxEnableEvtArray[i] |= (uint)EventType.EVT_AX_ERROR;

                    //初次获取轴的运动I/O状态。
                    this.refreshAxisState(i);
                }

            

                uResult = Motion.mAcm_EnableMotionEvent(m_DeviceHandle, AxEnableEvtArray, GpEnableEvt, m_ulAxisCount, 3);
                if (uResult != (uint)ErrorCode.SUCCESS)
                    throw new Exception("EnableMotionEvent Filed With Error Code[0x" + Convert.ToString(uResult, 16) + "]");

                IsInit = true;
                timer.Elapsed += Timer_Elapsed;
                timer.Interval = 100;
                timer.Start();

                //用户应该创建一个新的线程来检查事件状态，例如:CheckEvtThread()函数
                checkEventThread = new Thread(new ThreadStart(checkEvtThread));
                checkEventThread.Start();
                return true;
            }
            catch (Exception ex)
            {
                WarningEvent?.Invoke(WarningEnum.High, ex.Message);
                stop();
                return false;
            }
        }

        /// <summary>
        /// 关闭设备
        /// </summary>
        /// <exception cref="Exception"></exception>
        public bool stop()
        {
            try
            {
                if (!IsInit) return false;

                uint i;
                for (i = 0; i < m_ulAxisCount; i++)
                {
                    if (AxState[i] == (uint)AxisState.STA_AX_ERROR_STOP)
                    {
                        WarningEvent?.Invoke(WarningEnum.Low, i + "轴处于ErrorStop状态，已重置！");
                        //重置轴的状态。如果轴处于ErrorStop状态，则调用此函数后状态将更改为Ready
                        Motion.mAcm_AxResetError(m_Axishand[i]);
                    }
                    // 命令轴减速停止(缓停)
                    Motion.mAcm_AxStopDec(m_Axishand[i]);

                    //sleep? 关闭电源使能,1: On
                    uint uResult = Motion.mAcm_AxSetSvOn(m_Axishand[i], 0);
                    if (uResult != (uint)ErrorCode.SUCCESS)
                        throw new Exception("Servo On Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");
                }
                //删除组中的所有轴并关闭组句柄
                //Motion.mAcm_GpClose(ref m_GpHand);
                //m_GpHand = IntPtr.Zero;

                for (i = 0; i < m_ulAxisCount; i++)
                {
                    //Close Axes
                    Motion.mAcm_AxClose(ref m_Axishand[i]);
                }

                timer.Elapsed -= Timer_Elapsed;
                m_ulAxisCount = 0;
                //Close Device
                Motion.mAcm_DevClose(ref m_DeviceHandle);
                m_DeviceHandle = IntPtr.Zero;
                IsInit = false;
                timer.Stop();
                return true;
            }
            catch (Exception e)
            {
                return false;
            }
        }
        /// <summary>
        /// 轴事件
        /// </summary>
        private void checkEvtThread()
        {
            uint Result;
            UInt32[] AxEvtStatusArray = new UInt32[32];
            UInt32[] GpEvtStatusArray = new UInt32[32];
            UInt32 i;
            while (IsInit)
            {
                //如果你想获得轴或组的事件状态，你应该通过调用 Motion.mAcm_EnableMotionEvent 来启用这些事件  
                //AxEvtStatusArray[n]，返回每个轴的中断事件状态，n 表示运动设备的轴个数
                //GpEnableEvtArrayy[n]：返回每个群组的中断事件状态
                //AxArrayElements U32 IN AxEvtStatusArray 中元素个数
                //GpArrayElements U32 IN GpEvtStatusArray 中元素个数
                //Millisecond U32 IN 设定每次Check 事件时的等待时间
                Result = Motion.mAcm_CheckMotionEvent(m_DeviceHandle, AxEvtStatusArray, GpEvtStatusArray, m_ulAxisCount, 0, 1000);//3,10
                if (Result == (uint)ErrorCode.SUCCESS)
                {
                    for (i = 0; i < m_ulAxisCount; i++)
                    {
                        if ((AxEvtStatusArray[i] & (uint)EventType.EVT_AX_MOTION_DONE) > 0)
                        {
                            this.refreshAxisState((int)i);//更新AXIS状态
                        }
                        if ((AxEvtStatusArray[i] & (uint)EventType.EVT_AX_VH_START) > 0)
                        {
                            this.refreshAxisState((int)i);//更新AXIS状态
                        }
                        if ((AxEvtStatusArray[i] & (uint)EventType.EVT_AX_VH_END) > 0)
                        {
                            this.refreshAxisState((int)i);//更新AXIS状态
                        }
                        if ((AxEvtStatusArray[i] & (uint)EventType.EVT_AX_HOME_DONE) > 0)
                        {
                            this.refreshAxisState((int)i);//更新AXIS状态
                            WarningEvent?.Invoke(WarningEnum.Normal, $"轴{i}回原点完成；当前命令位置:{CmdPos[i]}，反馈位置:{ActualPos[i]}.");
                            //回原点后反馈位置未归0则置0 //重置后会自动重新更新状态
                            if (CmdPos[i] != 0) this.resetCmdPosition((int)i);
                            if (ActualPos[i] != 0)  this.resetActualPosition((int)i);
                        }
                        if ((AxEvtStatusArray[i] & (uint)EventType.EVT_AX_ERROR) > 0)
                        {
                            this.refreshAxisState((int)i);//更新AXIS状态
                        }

                    }
                    //if (m_GpHand != IntPtr.Zero)
                    //{
                    //    if (textBoxGpID.Text != "")
                    //    {
                    //        if ((GpEvtStatusArray[0] & ((uint)EventType.EVT_GP1_MOTION_DONE << Convert.ToByte(textBoxGpID.Text))) > 0)
                    //        {
                    //            m_GpDoneEvtCnt++;
                    //        }
                    //        if ((GpEvtStatusArray[1] & ((uint)EventType.EVT_GP1_VH_START << Convert.ToByte(textBoxGpID.Text))) > 0)
                    //        {
                    //            m_GpVHStartCnt++;
                    //        }
                    //        if ((GpEvtStatusArray[2] & ((uint)EventType.EVT_GP1_VH_END << Convert.ToByte(textBoxGpID.Text))) > 0)
                    //        {
                    //            m_GpVHEndCnt++;
                    //        }
                    //    }
                    //}
                }
            }
        }

        public bool isReady(int axisIndex = -1)
        { 
            for (int i = 0; i < m_ulAxisCount; i++)
            {
                if (isSkip(axisIndex)) continue;
                if (i == axisIndex || axisIndex == -1)
                {
                    Motion.mAcm_AxGetState(m_Axishand[i], ref AxState[i]);
                    if (AxState[i] != (uint)AxisState.STA_AX_READY)
                    {
                        if (AxState[i] == (uint)AxisState.STA_AX_ERROR_STOP)
                        {
                            var errCode = Motion.mAcm_GetLastError(m_Axishand[i]);
                            if (errCode != 0)
                            {
                                StringBuilder sb = new StringBuilder(512);
                                if (!Motion.mAcm_GetErrorMessage(errCode, sb, 511))
                                    sb = new StringBuilder("未知错误！");
                                string errStr = $"轴{i}运行错误,错误码({errCode}，错误信息:{sb.ToString().Trim()})";
                                WarningEvent?.Invoke(WarningEnum.High, errStr);
                                throw new Exception(errStr);
                            }
                            else
                            {
                                throw new Exception($"轴{i}运行错误,当前状态:{((AxisState)AxState[i]).ToString()}");
                            }
                        } 
                        return false;
                    }
                        
                }
            }

            return true;
        }
        public bool isError(int axisIndex = -1)
        {
            for (int i = 0; i < m_ulAxisCount; i++)
            {
                if (isSkip(axisIndex)) continue;
                if (i == axisIndex || axisIndex == -1)
                {
                    Motion.mAcm_AxGetState(m_Axishand[i], ref AxState[i]);
                    if (AxState[i] == (uint)AxisState.STA_AX_ERROR_STOP)
                        return true;

                    //
                    if ((IOStatus[i] & (uint)Ax_Motion_IO.AX_MOTION_IO_ALM) > 0 
                        || (IOStatus[i] & (uint)Ax_Motion_IO.AX_MOTION_IO_EMG) > 0
                        || (IOStatus[i] & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTP) > 0
                        || (IOStatus[i] & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTN) > 0) 
                        return true; 
                }
            }

            return false;
        }
        /// <summary>
        /// 缓停,jog时也可用
        /// </summary>
        public void stopDec(int axisIndex = -1)
        {
            for (int i = 0; i < m_ulAxisCount; i++)
            {
                if (i == axisIndex || axisIndex == -1)
                {
                    Motion.mAcm_AxStopDec(m_Axishand[i]);
                }
            }
        }
        /// <summary>
        /// 急停
        /// </summary>
        public void stopNow(int axisIndex = -1)
        {
            if (!IsInit) return;
            for (int i = 0; i < m_ulAxisCount; i++)
            {
                if (i == axisIndex || axisIndex == -1)
                { 
                    Motion.mAcm_AxStopEmg(m_Axishand[i]);
                }
            } 
        }
 
        public void resetAxisState(int axisIndex=-1)
        {
            if (!IsInit) return;

            for (int i = 0; i < m_ulAxisCount; i++)
            {
                if (isSkip(axisIndex)) continue;
                if (i == axisIndex || axisIndex == -1)
                {
                    if (AxState[i] == (uint)AxisState.STA_AX_ERROR_STOP)
                    {
                        //重置轴的状态。如果轴处于ErrorStop状态，则调用此函数后状态将更改为Ready
                        bALM = bEMG = bLMTP = bLMTN = false;
                        Motion.mAcm_AxResetError(m_Axishand[i]);
                        refreshAxisState(i);
                    }
                    // 命令轴减速停止(缓停)
                    Motion.mAcm_AxStopDec(m_Axishand[i]);
                }
            }
            
        }
        /// <summary>
        /// 指定的轴设置命令位置
        /// </summary>
        public void resetCmdPosition(int axisIndex = -1, double position = 0)
        {
            if (!IsInit) return;
            for (int i = 0; i < m_ulAxisCount; i++)
            {
                if (isSkip(axisIndex)) continue;
                if (i == axisIndex || axisIndex == -1)
                { 
                    Motion.mAcm_AxSetCmdPosition(m_Axishand[i], position);
                    this.refreshAxisState(i);
                }
            }
        }
        /// <summary>
        /// 指定的轴设置实际(反馈)位置
        /// </summary> 
        public void resetActualPosition(int axisIndex=-1, double position = 0)
        {
            if (!IsInit) return;
            for (int i = 0; i < m_ulAxisCount; i++)
            {
                if (isSkip(axisIndex)) continue;
                if (i == axisIndex || axisIndex == -1)
                {
                    Motion.mAcm_AxSetActualPosition(m_Axishand[i], position);
                    this.refreshAxisState(i);
                }
            }
        }
        /// <summary>
        /// 获取速度 [vellow,velhigh,acc,dec,Jerk]
        /// </summary>
        /// <param name="axisIndex"></param>
        /// <returns></returns>
        public double[] getAxisVelParam(int axisIndex)
        {
            double[] value=new double[5]; 
            Motion.mAcm_GetF64Property(m_Axishand[axisIndex], (uint)PropertyID.PAR_AxVelLow, ref value[0]);
            Motion.mAcm_GetF64Property(m_Axishand[axisIndex], (uint)PropertyID.PAR_AxVelHigh, ref value[1]);
            Motion.mAcm_GetF64Property(m_Axishand[axisIndex], (uint)PropertyID.PAR_AxAcc, ref value[2]);
            Motion.mAcm_GetF64Property(m_Axishand[axisIndex], (uint)PropertyID.PAR_AxDec, ref value[3]);
            Motion.mAcm_GetF64Property(m_Axishand[axisIndex], (uint)PropertyID.PAR_AxJerk, ref value[4]);//0-T/S 型曲线
            return value;
        }
        /// <summary>
        /// 速度设置 注：运动的过程中可变速度，加速度和减速度需使用AxChangeVelEx方法
        /// </summary>
        /// <param name="velLow">起始速度</param>
        /// <param name="high">运行速度</param>
        /// <param name="acc">加速度</param>
        /// <param name="dec">减速度</param>
        /// <param name="axisIndex"></param>
        /// <param name="isJogOrHome">true 不行，回HOME也是false</param>
        public void setAxisVelParam(double velLow, double high = 0, double acc = 0, double dec = 0, int axisIndex = -1,bool isJogOrHome=false)
        {
            uint result;
            for (int i = 0; i < m_ulAxisCount; i++)
            {
                if (i == axisIndex || axisIndex == -1)
                {
                    if (!isJogOrHome)
                    {
                        if ((AxisState)AxState[i] != AxisState.STA_AX_READY)
                            continue;
                        if (velLow > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.PAR_AxVelLow, toPulse(velLow, Config.Axis_MM2PulseNum[i]));
                        if (high > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.PAR_AxVelHigh, toPulse(high, Config.Axis_MM2PulseNum[i]));
                        if (acc > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.PAR_AxAcc, toPulse(acc, Config.Axis_MM2PulseNum[i]));
                        if (dec > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.PAR_AxDec, toPulse(dec, Config.Axis_MM2PulseNum[i]));
                        result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.PAR_AxJerk, 0);//0-T/S 型曲线 
                    }
                    else
                    {
                        if ((AxisState)AxState[i] != AxisState.STA_AX_EXT_JOG)
                            continue;
                        if (velLow > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.CFG_AxJogVelLow, toPulse(velLow, Config.Axis_MM2PulseNum[i]));
                        if (high > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.CFG_AxJogVelHigh, toPulse(high, Config.Axis_MM2PulseNum[i]));
                        if (acc > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.CFG_AxJogAcc, toPulse(acc, Config.Axis_MM2PulseNum[i]));
                        if (dec > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.CFG_AxJogDec, toPulse(dec, Config.Axis_MM2PulseNum[i]));
                        result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.CFG_AxJogJerk, 0);//0-T/S 型曲线 
                    }
                }
            }
        }
        
        /// <summary>
        /// 回HOME
        /// </summary>
        /// <param name="axisIndex"></param>
        /// <param name="homeMode">16种回HOME模式（0-15）</param>
        /// <param name="dir">0-正向 1-负向</param>
        /// <exception cref="Exception"></exception>
        public void home(int axisIndex = -1, uint homeMode = 11, uint dir = 1)
        {
            if (!IsInit) return; 

            //研华运动控制卡共提供两个函数执行回Home： Acm_AxHome 和Acm_AxMoveHome 
            //调用Acm_AxHome 执行回Home 时，通过PAR_AxVelLow、PAR_AxVelHigh、PAR_AxAcc、 PAR_AxDec、PAR_AxJerk 设置初速度，运行速度、加速度、减速度、速度曲线类型。
            //调用Acm_AxMoveHome 执行回Home 时，通过PAR_AxHomeVelLow、PAR_AxHomeVelHigh、 PAR_AxHomeAcc、PAR_AxHomeDec、PAR_AxHomeJerk 设置初速度，运行速度、加速度、 减速度、速度曲线类型。
            uint result;
            for (int i = 0; i < m_ulAxisCount; i++)
            {
                if (isSkip(axisIndex)) continue;
                if (i == axisIndex || axisIndex == -1)
                {
                    if ((AxisState)AxState[i] != AxisState.STA_AX_READY)
                        continue;

                    if (!setPulseOutMode(i, (AxisPulseOutMode)AxisPulseOutMode[i]))
                        throw new Exception($"Axis{i} 设置脉冲模式失败！");

                    //单独设置GO HOME 速度参数？？

                    // 
                    result = Motion.mAcm_AxHome(m_Axishand[i], homeMode, dir);
                    if (result != (uint)ErrorCode.SUCCESS)
                        throw new Exception("AxHome Failed With Error Code: [0x" + Convert.ToString(result, 16) + "]"); 
                }
            }

            //复位
            //if (axisIndex == -1 && !IsDebug && !IsReset)
            //    IsReset = true;
            if (!IsDebug && !IsReset)
                IsReset = true;
        }
        /// <summary>
        /// 点到点运动
        /// </summary>
        /// <param name="axisIndex"></param>
        /// <param name="pos">PPU位置，方向为正负值</param>
        /// <param name="moveMode"></param>
        public bool move_ptp(int axisIndex, double pos, AxMoveMode moveMode)
        {
            if (isSkip(axisIndex)) return true;
            if (!IsInit) return false;
            if (isError(axisIndex)) return false;

            pos = toPulse(pos, Config.Axis_MM2PulseNum[axisIndex]);

            uint result;
            if ((AxisState)AxState[axisIndex] != AxisState.STA_AX_READY)
                return false;

            if (!setPulseOutMode(axisIndex, (AxisPulseOutMode)AxisPulseOutMode[axisIndex])) 
            {
                WarningEvent?.Invoke(WarningEnum.High, $"Axis{axisIndex} 设置脉冲模式失败！");
                return false;
            }

            //--
            if (moveMode==AxMoveMode.MODE1_Abs) //Start single axis's absolute position motion.
                result = Motion.mAcm_AxMoveAbs(m_Axishand[axisIndex], pos);
            else //Start single axis's relative position motion
                result = Motion.mAcm_AxMoveRel(m_Axishand[axisIndex], pos);
            if (result != (uint)ErrorCode.SUCCESS)
            {
                WarningEvent?.Invoke(WarningEnum.High, "PTP Move Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");
                return false;
            }
            return true;
        }
        /// <summary>
        /// 判断是否正在动动
        /// </summary>
        /// <param name="axisIndex"></param>
        /// <returns></returns>
        public bool isMoveing(int axisIndex = -1)
        {
            if (!IsInit) return false;
            for (int i = 0; i < m_ulAxisCount; i++)
            { 
                if (i == axisIndex || axisIndex == -1)
                {
                    AxisState state = (AxisState)AxState[i];
                    if (state == AxisState.STA_AX_PTP_MOT || state == AxisState.STA_AX_HOMING || state == AxisState.STA_AX_CONTI_MOT)
                        return true;
                }
            }
            return false;
        }
        /// <summary>
        /// 设置脉冲模式 
        /// </summary>
        /// <param name="axisIndex"></param>
        /// <param name="outMode"></param>
        /// <returns></returns>
        private bool setPulseOutMode(int axisIndex, AxisPulseOutMode outMode)
        {
            uint refOutMode = 0;
            //先获取再判断
            uint result = Motion.mAcm_GetU32Property(m_Axishand[axisIndex], (uint)PropertyID.CFG_AxPulseOutMode, ref refOutMode);// 获取输出模式
            if (result != (uint)ErrorCode.SUCCESS)
            {
                WarningEvent?.Invoke(WarningEnum.High, $"Get Axis{axisIndex} Failed With Error Code: [0x" + Convert.ToString(result, 16) + "]");
                return false;
            }
            if ((uint)outMode != refOutMode)
            {
                //设置脉冲模式 
                result = Motion.mAcm_SetU32Property(m_Axishand[axisIndex], (uint)PropertyID.CFG_AxPulseOutMode, (uint)outMode);
                if (result != (uint)ErrorCode.SUCCESS && result != (uint)ErrorCode.PropertyIDNotSupport)//Added for Supporting PCI1245 and PCI1265 
                {
                    WarningEvent?.Invoke(WarningEnum.High, "Set Property-CFG_AxExtPulseNum Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");
                    return false;
                }
            }

            return true;
        }
        #region JOG
        public void openJogMode(int axisIndex)
        {
            if (!IsInit) return;
            if ((AxisState)AxState[axisIndex] != AxisState.STA_AX_READY)
                return;

            if (!setPulseOutMode(axisIndex, (AxisPulseOutMode)AxisPulseOutMode[axisIndex]))
                throw new Exception($"Axis{axisIndex} 设置脉冲模式失败！");

            uint result;
            //启用/禁用外置硬盘模式.0: Disabled (stop command) 1: JOG Mode  2: MPG Mode
            result = Motion.mAcm_AxSetExtDrive(m_Axishand[axisIndex], 0);
            result = Motion.mAcm_AxSetExtDrive(m_Axishand[axisIndex], 1);
            if (result != (uint)ErrorCode.SUCCESS)
                throw new Exception("Start external driver Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");

            //设置外部驱动器的输入引脚 
            //0 轴 0(默认值) 仅支持 0
            //1 轴 1(不支持)
            //2 轴 2(不支持)
            //3 轴 3(不支持) 
            result = Motion.mAcm_SetU32Property(m_Axishand[axisIndex], (uint)PropertyID.CFG_AxExtMasterSrc, 0);
            if (result != (uint)ErrorCode.SUCCESS)
                throw new Exception("Set Property-AxExtMasterSrc Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");

            //当启用外部驱动时。此属性允许通过数字输入通道选择驱动轴 
            result = Motion.mAcm_SetU32Property(m_Axishand[axisIndex], (uint)PropertyID.CFG_AxExtSelEnable, 1);
            if (result != (uint)ErrorCode.SUCCESS && result != (uint)ErrorCode.PropertyIDNotSupport)//Added for Supporting PCI1245 and PCI1265 
                throw new Exception("Set Property-AxExtSelEnable Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");

            //理论脉冲数 
            result = Motion.mAcm_SetU32Property(m_Axishand[axisIndex], (uint)PropertyID.CFG_AxExtPulseNum, 1000);
            if (result != (uint)ErrorCode.SUCCESS && result != (uint)ErrorCode.PropertyIDNotSupport)//Added for Supporting PCI1245 and PCI1265 
                throw new Exception("Set Property-CFG_AxExtPulseNum Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");

            //外部设置
            //setAxisVelParam(velLow, high, acc, dec, axisIndex, true);
            this.refreshAxisState(axisIndex);
        }
        public void closeJogMode(int axisIndex = -1)
        {
            if (!IsInit) return;

            uint result;
            for (int i = 0; i < m_ulAxisCount; i++)
            {
                if (i == axisIndex || axisIndex == -1)
                { 
                    if ((AxisState)AxState[i] == AxisState.STA_AX_EXT_JOG)
                    {
                        //启用/禁用外置硬盘模式.0: Disabled (stop command) 1: JOG Mode  2: MPG Mode
                        result = Motion.mAcm_AxSetExtDrive(m_Axishand[i], 0);
                        //命令轴减速停止
                        result = Motion.mAcm_AxStopDec(m_Axishand[i]);
                        this.refreshAxisState(i);
                    }
                }
            }
        }
        /// <summary>
        /// jog运行 0：正向，1：负向
        /// </summary>
        /// <param name="axisIndex"></param>
        /// <param name="dic">0：正向，1：负向</param>
        public void jog(int axisIndex, ushort dic)
        {
            if (isSkip(axisIndex)) return;
            if (isError(axisIndex)) return;
            if ((AxisState)AxState[axisIndex] != AxisState.STA_AX_EXT_JOG) return;
            //Jog 运动的方向，0：正向，1：负向
            Motion.mAcm_AxJog(m_Axishand[axisIndex], dic);
        }

        #endregion

        #region Private 
        private bool isSkip(int axisIndex)
        {
            if (axisIndex == 0 && Config.SkipAxis0) return true;
            if (axisIndex == 1 && Config.SkipAxis1) return true;
            if (axisIndex == 2 && Config.SkipAxis2) return true;
            if (axisIndex == 3 && Config.SkipAxis3) return true;
            return false;
        }
        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (!IsInit) return;
             
            for (int i = 0; i < m_ulAxisCount; i++)
                refreshAxisState(i);
        }
        private bool bALM, bEMG, bLMTP, bLMTN;
        private void refreshAxisState(int axisIndex)
        {
            //uint result;
            //获取指定轴的当前命令位置
            if ((uint)ErrorCode.SUCCESS == Motion.mAcm_AxGetCmdPosition(m_Axishand[axisIndex], ref CmdPos[axisIndex]))
                axisPosEvent?.Invoke(axisIndex, AxisPosType.CmdPos, tomm(CmdPos[axisIndex], Config.Axis_MM2PulseNum[axisIndex]));
            //获取指定轴的当前实际(反馈)位置
            if ((uint)ErrorCode.SUCCESS == Motion.mAcm_AxGetActualPosition(m_Axishand[axisIndex], ref ActualPos[axisIndex]))
                axisPosEvent?.Invoke(axisIndex, AxisPosType.ActualPos, tomm(ActualPos[axisIndex], Config.Axis_MM2PulseNum[axisIndex]) );
            
            //获取Axis的当前状态
            if ((uint)ErrorCode.SUCCESS == Motion.mAcm_AxGetState(m_Axishand[axisIndex], ref AxState[axisIndex]))
                axisStateEvent?.Invoke(axisIndex, AxisStateType.AxisState, AxState[axisIndex]);
            //log?.Invoke(WarningEnum.Normal, $"({AxisIndex}轴)AxisState = {((AxisState)AxState[AxisIndex]).ToString()}");

            //获取轴的运动I/O状态。
            if ((uint)ErrorCode.SUCCESS == Motion.mAcm_AxGetMotionIO(m_Axishand[axisIndex], ref IOStatus[axisIndex]))
            {
                bool isStopNow = false;
                if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_ALM) > 0) //ALM报警状态 需IO close (流程上必需在报警清除后先复位)
                {
                    if (!isStopNow)
                    {
                        isStopNow = true;
                        stopNow();//ALM报警需急停
                    }
                    if (!bALM)
                    {
                        bALM = true;
                        WarningEvent?.Invoke(WarningEnum.High, $"Axis{axisIndex} ALM报警!!!");
                    }
                }
                if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_EMG) > 0) //EMG急停状态 需重置 state (流程上必需在报警清除后先复位)
                {
                    if (!isStopNow)
                    {
                        isStopNow = true;
                        stopNow();//EMG状态需急停
                    }
                    if (!bEMG)
                    {
                        bEMG = true;
                        WarningEvent?.Invoke(WarningEnum.High, $"Axis{axisIndex} 触发EMG急停!!!");
                    }
                }
                //右极限  true->false (流程上必需在报警清除后先复位)
                if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTP) > 0 && ((AxisState)AxState[axisIndex]) != AxisState.STA_AX_HOMING) 
                {
                    if (!isStopNow)
                    {
                        isStopNow = true;
                        stopNow();//右极限状态需急停
                    }
                    if (!bLMTP)
                    {
                        bLMTP = true;
                        WarningEvent?.Invoke(WarningEnum.High, $"Axis{axisIndex} 触发右极限LMTP!!!");
                    }
                }
                //左极限  true->false (流程上必需在报警清除后先复位)
                if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTN) > 0 && ((AxisState)AxState[axisIndex]) != AxisState.STA_AX_HOMING) 
                {
                    if (!isStopNow)
                    {
                        isStopNow = true;
                        stopNow();//左极限状态需急停
                    }
                    if (!bLMTN)
                    {
                        bLMTN = true;
                        WarningEvent?.Invoke(WarningEnum.High, $"Axis{axisIndex} 触发左极限LMTN!!!");
                    }
                }
                ////ORG 回原点
                //if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_ORG) > 0)
                //{
                //    WarningEvent?.Invoke(WarningEnum.Normal, $"Axis{axisIndex} 触发ORG信号！");
                //}
                ////EZ 回原点
                //if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_EZ) > 0)
                //{
                //    WarningEvent?.Invoke(WarningEnum.Normal, $"Axis{axisIndex} 触发EZ信号！");
                //}

                axisStateEvent?.Invoke(axisIndex, AxisStateType.AxisIOState, IOStatus[axisIndex]);
                //log?.Invoke(WarningEnum.Normal, $"({AxisIndex}轴)AxisMotionIO = {((Ax_Motion_IO)IOStatus[AxisIndex]).ToString()}");
                //checkMotionIOStatus(AxisIndex, IOStatus[AxisIndex]);
            } 
             
            //获取Axis的当前运动状态
            if ((uint)ErrorCode.SUCCESS == Motion.mAcm_AxGetMotionStatus(m_Axishand[axisIndex], ref AxMotionState[axisIndex]))
                axisStateEvent?.Invoke(axisIndex,  AxisStateType.AxisMotionState, AxMotionState[axisIndex]);
            //log?.Invoke(WarningEnum.Normal, $"({AxisIndex}轴)AxisMotionStatus = {AxMotionState[AxisIndex].ToString()}");
        }
      
        //private void checkMotionIOStatus(int axisIndex, uint IOStatus)
        //{
        //    if ((IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_ALM) > 0)//报警信号输出 
        //        log?.Invoke(2, $"轴{axisIndex} 发出告警！！");
            
        //    bool ALM = (IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_ALM) > 0;
        //    bool ORG = (IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_ORG) > 0;//ORG  
        //    bool EL_R = (IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTP) > 0;//右极限  
        //    bool EL_L = (IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTN) > 0;//-EL 左  
        //    bool SVON = (IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_SVON) > 0; 
        //}
     
        private string getErrInfo(uint errorCode)
        {
            StringBuilder ErrorMsg = new StringBuilder("", 100);
            //Get the error message according to error code returned from API
            Boolean res = Motion.mAcm_GetErrorMessage(errorCode, ErrorMsg, 100); 
            if (res) return ErrorMsg.ToString();
            return "获取错误信息失败！";
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="pulseVal"></param>
        /// <param name="mmPulse"></param>
        /// <returns></returns>
        public double tomm(double pulseVal, double pulse)
        {
            return (pulseVal / pulse);
        }
        /// <summary>
        /// mm转脉冲
        /// </summary>
        /// <param name="mm"></param>
        /// <param name="mmPulse">1mm 对应 脉冲数</param>
        /// <returns></returns>
        private double toPulse(double mm, double mmPulse)
        {
            return (mm * mmPulse);
        }
        public double getCmdPos_mm(int axisIndex)
        {
            return tomm(CmdPos[axisIndex], Config.Axis_MM2PulseNum[axisIndex]);
        }
        public double getActualPos_mm(int axisIndex)
        {
            return tomm(ActualPos[axisIndex], Config.Axis_MM2PulseNum[axisIndex]);
        }
        #endregion



    }
}

