using DH.Commons.Enums;
using DH.Devices.Motion;
using MCDLL_NET;
using OpenCvSharp;
using System.Diagnostics;
using static System.Collections.Specialized.BitVector32;


namespace DH.Devices.Motion
{


    public class SLDMotion: MotionBase
    {


     
        /// <summary>
        /// 从板卡中获取的的物件计数
        /// </summary>
        private Dictionary<ushort, uint> piecesCountDic = new Dictionary<ushort, uint>();

        private ushort BoardCount
        {
            get
            {
                switch (ExtBoard)
                {
                    default:
                    case ExtensionBoardEnum.None:
                    case ExtensionBoardEnum.ExtIO_1:
                        return 1;

                    case ExtensionBoardEnum.ExtEC3216_1:
                    case ExtensionBoardEnum.ExtEC3224_1:
                    case ExtensionBoardEnum.ExtEC3416_1:
                        return 2;
                }
            }
        }





        /// <summary>
        /// 转盘数量
        /// </summary>
        private ushort DiskCount
        {
            get
            {
                return MachineDiskType switch
                {
                    MachineDiskType.DoubleDisk => 2,
                    _ => 1,
                };
            }
        }

        /// <summary>
        /// 是否复位标志
        /// </summary>
        private bool _isResetting = false;


        /// <summary>
        /// 是否暂停中
        /// </summary>
        private bool _isPause = false;


        /// <summary>
        /// 运动轴立即暂停
        /// </summary>
        private Dictionary<int, ManualResetEvent> axisImmediatePauseHandleDict = new Dictionary<int, ManualResetEvent>();
        private Dictionary<int, bool> axisImmediatePauseFlag = new Dictionary<int, bool>();
        private Dictionary<int, bool> axisPauseResumeFlag = new Dictionary<int, bool>();

        /// <summary>
        /// int,int  轴号  捕获位置
        /// </summary>
        public event Action<int, uint> OnNewPieces;


        public void NewPieces(int diskIndex, uint pieceNumber)
        {
            _taskFactory.StartNew(() =>
            {
                Thread.CurrentThread.Priority = ThreadPriority.Highest;

                OnNewPieces?.Invoke(diskIndex, pieceNumber);
            });
        }
        public void SetResetFlag(bool isReset)
        {
            _isResetting = isReset;
        }


        public void ResetCount()
        {
            // piecesCountDic = new();

            foreach (var item in piecesCountDic.Keys)
            {
                piecesCountDic[item] = 0;
            }
        }


        public override List<AxisInfo> GetCurrentAxisInfo(params string[] axisName)
        {
            List<AxisInfo> axisInfos = new();
            AxisSettings.FindAll(a => a.IsAxisEnabled).ForEach(axisSetting =>
            {
                AxisInfo axisInfo = new()
                {
                    AxisName = axisSetting.AxisName
                };

                var axisMovingStatus = AxisStatusList.FirstOrDefault(u => u.AxisIndex == axisSetting.AxisIndex);
                axisInfo.AxisLocation = axisMovingStatus == null ? 0 : Convert.ToDouble(axisMovingStatus.CurPosition);

                axisInfos.Add(axisInfo);
            });
            return axisInfos;
        }


        #region DeviceBase

        public override void Init()
        {
            // 根据扩展卡数量,计算卡总数
            //if (0 < IIConfig.)
            //{
            //    _cardCount = (ushort)(1 + IIConfig.CardExtNum);
            //}
            try
            {
                piecesCountDic.Clear();

                for (ushort disk = 0; disk < DiskCount; disk++)
                {
                    piecesCountDic.Add(disk, 0);
                }

                InitialMotionCard();
                axisImmediatePauseHandleDict = AxisSettings
                    .FindAll(a => a.IsAxisEnabled)
                    .ToDictionary(a => a.AxisIndex, a => new ManualResetEvent(true));

                // 初始化时关闭所有轴,停止筛选 begin =======
                //AllMoveStop();
              
                 //  CMCDLL_NET.MCF_Axis_Stop_Net(0, AxisStopMode.AxisStopIMD, 0);
             
                 //CMCDLL_NET.MCF_Set_Axis_Stop_Profile_Net(0, 50000, 0, 0, 0);
                 // CMCDLL_NET.MCF_Axis_Stop_Net(0, AxisStopMode.AxisStopDEC, 0);
                AxisStop();
                //AllAxisOff();
                var ret = CMCDLL_NET.MCF_Set_Servo_Enable_Net(0, (ushort)ServoLogic.Servo_Open, 0);

                StopSorting();

                // 初始化时关闭所有轴,停止筛选 end ======= 

                //AllAxisOn();
                Start();
                MonitorPosition();
                MonitorAxisStatus();
               

                CustomStart();
                

                MonitorPieces();
                isconnected = true;

            }
            catch
            {
                isconnected = false;
            }
        }

        public override void Start()
        {
            var enabledList = AxisSettings.Where(a => a.IsAxisEnabled).ToList();
            AxisStatusList = enabledList.ConvertAll(a =>
            {
                AxisMovingStatus axisSts = new AxisMovingStatus();
                axisSts.AxisIndex = a.AxisIndex;
                axisSts.AxisName = a.AxisName;
                axisSts.IsMonitorStatus = a.IsMonitorStatus;
                axisSts.IsMonitorPosition = a.IsMonitorPosition;

                return axisSts;
            });

            _axisAlarmRaisedFlag = enabledList.ToDictionary(a => a.AxisIndex, a => false);
            _axisLimitTimer = enabledList.ToDictionary(a => a.AxisIndex, a => new System.Threading.Timer(OnAxisLimitAlarm, a.AxisIndex, -1, -1));

            Task.Run(() =>
            {
                Monitor();
            });
        }


        protected virtual void OnAxisLimitAlarm(object state)
        {
            int axisIndex = Convert.ToInt32(state);

            if (!_axisAlarmRaisedFlag[axisIndex])
            {
                var curStatus = GetAxisStatus(axisIndex);
                // lifayu
                var msg = "卡/核:";  //+ IConfig.StationNumber;
                if (((curStatus >> 5) & 1) == 1)
                {
                    msg += $"轴{axisIndex}在 正极限";
                }
                if (((curStatus >> 6) & 1) == 1)
                {
                    msg += $"轴{axisIndex}在 负极限";
                }
                AxisAlarmRaised(axisIndex, msg, true);
            }
        }
        /// <summary>
        /// 报警产生 与  取消
        /// </summary>
        /// <param name="axisIndex"></param>
        /// <param name="msg"></param>
        /// <param name="isAlarm"></param>
        public void AxisAlarmRaised(int axisIndex, string msg, bool isAlarm)
        {
            //_axisAlarmRaisedFlag[axisIndex] = isAlarm;
            //IWarningSet ws = new SimpleWarningSet();
            //ws.WarningCode = msg;
            //ws.WarningDescription = msg;
            //ws.TriggerTime = DateTime.Now;
            //ws.SourceDevice = this.Name;
            //ws.CurrentStatus = isAlarm;

            //SaveAlarmCSVAsync(ws.TriggerTime, this.Name, ws);
            //OnMonitorAlarm?.BeginInvoke(ws.TriggerTime, this, ws, null, null);
        }
        private ushort _stationNumber = 0;
        public void CustomStart()
        {
            // 急停配置
            var ret = CMCDLL_NET.MCF_Set_EMG_Bit_Net(EmgStopSignalIoIndex, (ushort)EMG_Mode.EMG_Trigger_Close, _stationNumber);
            if (IsEnableEmgStop)
            {
                ret = CMCDLL_NET.MCF_Set_EMG_Bit_Net(EmgStopSignalIoIndex, (ushort)EmgMode, _stationNumber);
            }


            if (IsEnableFilter)
            {
                StartSorting();
            }
        }


        /// <summary>
        /// 开启筛选
        /// </summary>
        public void StartSorting()
        {
            short rtn = 0;
            var cardCount = 1;
            switch (ExtBoard)
            {
                default:
                case ExtensionBoardEnum.None:
                case ExtensionBoardEnum.ExtIO_1:
                    break;
                case ExtensionBoardEnum.ExtEC3216_1:
                case ExtensionBoardEnum.ExtEC3224_1:
                case ExtensionBoardEnum.ExtEC3416_1:
                    cardCount = 2;
                    break;
            }
            for (ushort station = 0; station < BoardCount; station++)
            {
                // 关闭调试测试后的位置比较
                //关闭调试测试后的位置比较
                for (int i = 0; i < 16; i++)
                {
                    rtn = CMCDLL_NET.MCF_Set_Compare_Config_Net((ushort)i, 0, 0, station);
                    Console.WriteLine($"MCF_Set_Compare_Config_Net  {i}::{rtn}");
                }

                //2.配置物件设置
                rtn = CMCDLL_NET.MCF_Sorting_Set_Piece_Size_Net(PieceMaxSize, PieceMinSize, station);
                Console.WriteLine($"MCF_Sorting_Set_Piece_Size_Net::{rtn}");

                rtn = CMCDLL_NET.MCF_Sorting_Set_Piece_Place_Net(MinDistance, MinTimeInterval, station);
                Console.WriteLine($"MCF_Sorting_Set_Piece_Place_Net::{rtn}");
            }

            //if (BoardCount < 2)
            //{
            //    // rtn = CMCDLL_NET_Sorting.MCF_Sorting_Camera_Blow_Config_Net(10, 6, 0);
            //    // 3.配置相机设置
            //    rtn = CMCDLL_NET_Sorting.MCF_Sorting_Camera_Blow_Config_Net(10, 6, 0);
            //    //设置来料使能  0 是默认 1是开始
            //    //
            //    rtn = CMCDLL_NET.MCF_Sorting_Set_Input_Enable_Net((ushort)SortingInputSetting.BitInputNumber, 1);
            //    //设置物件检测有效电平 0是低电平 1是高电平
            //    rtn = CMCDLL_NET_Sorting.MCF_Sorting_Set_Input_Logic_Net((ushort)SortingInputSetting.BitInputNumber, 0);
            //    //设置来料检测编码器 双转盘要设置两个轴
            //    /*Bit_Input_Number:设置位号。
            //      取值: Bit_Input_0, Bit_Input_1。
            //        Axis: 轴号。
            //        Source:跟随方式
            //        取值:0:命令
            //        1:编码器(默认)
            //        StationNumber: 站点号;*/
            //    // rtn = CMCDLL_NET_Sorting.MCF_Sorting_Set_Input_Source_Net((ushort)IIConfig.SortingInputSetting.BitInputNumber, 0, 1);
            //    rtn = CMCDLL_NET_Sorting.MCF_Sorting_Set_Input_Source_Net((ushort)SortingInputSetting.BitInputNumber, 1, 1);


            //    //rtn = CMCDLL_NET_Sorting.MCF_Sorting_Camera_Blow_Config_Net(
            //    //    (ushort)IIConfig.SnapshotSettings.Count,
            //    //    (ushort)IIConfig.BlowSettings.Count,
            //    //    0);
            //    // rtn = CMCDLL_NET_Sorting.MCF_Set_Config_Camera_Net();
            //    //为防止转盘第二个盘不触发拍照 设置一键取反功能
            //}
            // 3.配置相机设置

            ConfigCamera();

            // 4.配置气阀
          //  ConfigBlow();




            // 
            //CMCDLL_NET_Sorting.MCF_Sorting_Set_Input_Bind_Net()



            for (ushort card = 0; card < cardCount; card++)
            {
                //5.开启筛选
                rtn = CMCDLL_NET.MCF_Sorting_Start_Net(0, card);
                if (rtn != (short)0)
                {
                   // LogAsync(DateTime.Now, LogLevel.Warning, $"卡{station}开启筛选异常,ret:{rtn}");
                }
                //if (cardCount < 2)
                //{
                //    // 最小值 1  2  2
                //    var ret = CMCDLL_NET_Sorting.MCF_Sorting_Set_Input_Bind_Net(
                //        (ushort)SortingInputSetting.BitInputNumber, // 1
                //        SortingInputSetting.CameraStartNumber,  // 7,
                //        SortingInputSetting.BlowStartNumber, // 2,
                //        card);

                //}

                //for (ushort station = 0; station < cardCount; station++)
                //{
                //    // 5.开启筛选
                //    //开启自动筛选功能
                //    rtn = CMCDLL_NET_Sorting.MCF_Sorting_Start_Net(0, station);
                //    if (rtn != (short)FuncRet.Function_Success)
                //    {
                //        //LogAsync(DateTime.Now, LogLevel.Warning, $"卡{card}开启筛选异常,ret:{rtn}");
                //    }
                //}
            }
        }




        /// <summary>
        /// 停止筛选
        /// </summary>
        public void StopSorting()
        {
            // 关闭筛选
            for (ushort station = 0; station < BoardCount; station++)
            {
                short rtn = CMCDLL_NET_Sorting.MCF_Sorting_Close_Net(station);
                if (rtn != (short)FuncRet.Function_Success)
                {
                    //LogAsync(DateTime.Now, LogLevel.Warning, $"卡{station}停止筛选异常,ret:{rtn}");
                }
                piecesCountDic[station] = 0;
            }
        }


        public override void Stop()
        {
            isconnected = false;
            //base.Stop();
            AxisStop();
            int ret = CMCDLL_NET.MCF_Set_Servo_Enable_Net(0, (ushort)ServoLogic.Servo_Open, 0);

           // AllAxisOff();

            for (ushort station = 0; station < BoardCount; station++)
            {
                //2.关闭筛选
                var rtn = CMCDLL_NET_Sorting.MCF_Sorting_Close_Net(station);
                rtn = CMCDLL_NET.MCF_Close_Net();
            }
        }


        #region 源程序运行方法注释掉
        ///// <summary>
        ///// 设备 运行(执行 板卡系列的操作的 集合)
        ///// </summary>
        ///// <param name="config"></param>
        ///// <returns></returns>
        //public override ResponseMessage Run(IOperationConfig config)
        //{
        //    ResponseMessage responseMessage = new ResponseMessage();
        //    if (config is SolidMotionCardOperationConfigBase motionCardOperationConfig)
        //    {
        //        foreach (var operationSet in motionCardOperationConfig.OperationCollection)
        //        {
        //            if (operationSet.DelayBefore > 0)
        //            {
        //                Task.Delay(operationSet.DelayBefore).Wait();
        //            }

        //            responseMessage = RunOperationSet(operationSet);
        //            if (responseMessage.Result != 1)
        //            {
        //                return responseMessage;
        //            }

        //            if (operationSet.DelayAfter > 0)
        //                Task.Delay(operationSet.DelayAfter).Wait();
        //        }
        //    }
        //    return responseMessage;
        //}


        ///// <summary>
        ///// 执行 一个系列的操作
        ///// </summary>
        //private ResponseMessage RunOperationSet(SolidMotionCardOperationSet operationSet)
        //{
        //    ResponseMessage responseMessage = new ResponseMessage();
        //    // 1.预检查
        //    if (CurrentState == DeviceState.DSOpen)
        //    {
        //        foreach (var preCheck in operationSet.PreCheckIOCollection)
        //        {
        //            _pauseHandle.Wait();

        //            IOValue? ioData = null;
        //            if (CurrentState == DeviceState.DSOpen)
        //            {
        //                int timeout = operationSet.PreCheckIOTimeout <= 0 ? 60 * 1000 : operationSet.PreCheckIOTimeout;

        //                while (CurrentState == DeviceState.DSOpen)
        //                {
        //                    Task.Delay(10).Wait();
        //                    ioData = CurrentIOs.FirstOrDefault(u => u.IOIndex == preCheck.IOItem.IOIndex && u.IOType == preCheck.IOItem.IOType)?.IOValue;//IO 是开、关 从MonitorValues 获取
        //                    timeout -= 10;
        //                    if (preCheck.CheckValue == ioData || timeout < 0)
        //                    {
        //                        break;
        //                    }
        //                }
        //                if (timeout < 0)
        //                {
        //                    responseMessage.Result = -1;
        //                    responseMessage.Message = $"{preCheck.GetDisplayText()}预检查超时:{preCheck.IOItem.GetDisplayText()},当前值:{ioData}";
        //                    return responseMessage;
        //                }

        //                if (preCheck.CheckValue != ioData)
        //                {
        //                    responseMessage.Result = -1;
        //                    responseMessage.Message = $"{preCheck.GetDisplayText()}预检查不通过,配置:{preCheck.GetDisplayText()},当前值:{ioData}";
        //                    return responseMessage;
        //                }
        //            }
        //        }
        //    }

        //    // 2.板卡运动
        //    if (CurrentState == DeviceState.DSOpen)
        //    {
        //        _pauseHandle.Wait();

        //        if (CurrentState == DeviceState.DSOpen)
        //        {
        //            responseMessage = MoveToPoint(new SolidMotionOperationCollection()
        //            {
        //                MovingOps = operationSet.MovingOps
        //            });
        //            if (responseMessage.Result != 1)
        //            {
        //                return responseMessage;
        //            }
        //        }
        //    }


        //    // 3.IO输出 不需要超时
        //    if (CurrentState == DeviceState.DSOpen)
        //    {
        //        foreach (var ioOutput in operationSet.IOOutputCollection)
        //        {
        //            _pauseHandle.Wait();

        //            if (CurrentState == DeviceState.DSOpen)
        //            {
        //                WriteOutput((short)ioOutput.IOItem.IOIndex, ioOutput.CheckValue);
        //            }
        //        }
        //    }

        //    // 4.IO确认
        //    if (CurrentState == DeviceState.DSOpen)
        //    {
        //        foreach (var ioConfirm in operationSet.IOConfirmCollection)
        //        {
        //            int timeout = operationSet.IOConfirmTimeout <= 0 ? 60 * 1000 : operationSet.IOConfirmTimeout;
        //            IOValue? ioData = null;
        //            while (CurrentState == DeviceState.DSOpen)
        //            {
        //                Task.Delay(10).Wait();
        //                ioData = CurrentIOs.FirstOrDefault(u => u.IOIndex == ioConfirm.IOItem.IOIndex && u.IOType == ioConfirm.IOItem.IOType)?.IOValue;//IO 是开、关 从MonitorValues 获取
        //                timeout -= 10;
        //                if (ioConfirm.CheckValue == ioData || timeout < 0)
        //                {
        //                    break;
        //                }
        //            }

        //            if (ioConfirm.CheckValue != ioData)
        //            {
        //                responseMessage.Result = -1;
        //                responseMessage.Message = $"IO确认不通过,配置:{ioConfirm.GetDisplayText()},当前值:{ioData}";
        //                return responseMessage;
        //            }
        //        }
        //    }

        //    return responseMessage;
        //}
        #endregion
        #endregion

        #region ImmediatePause
        ManualResetEventSlim _pauseHandle = new ManualResetEventSlim(true);

        /// <summary>
        /// 启动立即暂停
        /// </summary>
        public override void SetImmediatePause()
        {
            if (!_isResetting)
            {
                var immediatePauseAxis = AxisSettings.FindAll(a => a.IsAxisEnabled && a.IsImmediatePause).Select(u => u.AxisIndex).ToList();
                _pauseHandle.Reset();
                immediatePauseAxis.ForEach(async axisIndex =>
                {
                    axisImmediatePauseHandleDict[axisIndex].Reset();
                    axisImmediatePauseFlag[axisIndex] = true;

                    await MoveStop(axisIndex, 0);//所有轴都暂停
                });
            }
        }

        /// <summary>
        /// 恢复立即暂停
        /// </summary>
        public override void ResetImmediatePause(bool isResumeMoving)
        {
            var immediatePauseAxis = AxisSettings.FindAll(a => a.IsAxisEnabled && a.IsImmediatePause).Select(u => u.AxisIndex).ToList();
            _pauseHandle.Set();
            immediatePauseAxis.ForEach(axisIndex =>
            {
                axisImmediatePauseFlag[axisIndex] = false;
                axisImmediatePauseHandleDict[axisIndex].Set();
                if (isResumeMoving)
                {
                    axisPauseResumeFlag[axisIndex] = true;
                }
                else
                {
                    axisPauseResumeFlag[axisIndex] = false;
                }
            });
        }
        #endregion

        #region MotionCard



        public void InitialMotionCard()
        {
            short ret = (short)FuncRet.Function_Success;

            List<ushort> stations = new List<ushort>();
            List<ushort> cardTypes = new List<ushort>();


            // 初始化  
            for (ushort station = 0; station < BoardCount; station++)
            {
                ret = CMCDLL_NET.MCF_Sorting_Init_Net(station);
                stations.Add(station);
                cardTypes.Add(2);
            }

            var stationsArr = stations.ToArray();
            var cardTypesArr = cardTypes.ToArray();

            // 打开卡
            ret = CMCDLL_NET.MCF_Open_Net(BoardCount, ref stationsArr[0], ref cardTypesArr[0]);

            if (ret == (ushort)FuncRet.Function_Success)
            {
                uint Version = 0;
                // 获取第一块控制板的软件版本号
                ret = CMCDLL_NET.MCF_Get_Version_Net(ref Version, _stationNumber);
             
            }
            else
            {
               
            }
            //MCF_Screen_Set_Trigger1();
           // MCF_Screen_Set_Trigger1(1);

        }

        public static short MCF_Screen_Set_Trigger1(ushort StationNumber = 0)
        {
            short rtn = 0;
            //配置触发器电平
            ushort Input_Number = 0;
            uint Trigger_Enable = 1;
            uint Trigger_Logic = 0;
            uint Trigger_Filter_Time = 1;
            uint Trigger_Axis = 0;//跟随轴
            uint Trigger_Source = 1;//跟随源
            uint Tirgger_Piece_Position = 1;//物件触发位置


            //使能
            rtn = CMCDLL_NET_Sorting.MCF_Sorting_Set_Input_Enable_Net(Input_Number, (ushort)Trigger_Enable, StationNumber);
            //有效电平
            //MotionTimeFunction.MCF_Screen_Read_Data(MotionTimeDataIndex.Index_DI00_Tirgger_Logic, out Trigger_Logic, StationNumber);
            rtn = CMCDLL_NET_Sorting.MCF_Sorting_Set_Input_Logic_Net(Input_Number, (ushort)Trigger_Logic, StationNumber);
            //滤波时间
            //MotionTimeFunction.MCF_Screen_Read_Data(MotionTimeDataIndex.Index_DI00_Tirgger_Filter_Time, out Trigger_Filter_Time, ScreenExternData.StationNumber);
            if (Trigger_Filter_Time != 0)
            {
                rtn = CMCDLL_NET_Sorting.MCF_Set_Input_Filter_Time_Bit_Net(Input_Number, Trigger_Filter_Time, StationNumber);
            }
            //默认跟随轴0
            //MotionTimeFunction.MCF_Screen_Read_Data(MotionTimeDataIndex.Index_DI00_Tirgger_Axis, out Trigger_Axis, ScreenExternData.StationNumber);
            //MotionTimeFunction.MCF_Screen_Read_Data(MotionTimeDataIndex.Index_DI00_Tirgger_Source, out Trigger_Source, ScreenExternData.StationNumber);
            rtn = CMCDLL_NET_Sorting.MCF_Sorting_Set_Input_Source_Net(Input_Number, (ushort)Trigger_Axis, (ushort)Trigger_Source, StationNumber);

            //物件触发位置
            // MotionTimeFunction.MCF_Screen_Read_Data(MotionTimeDataIndex.Index_DI00_Tirgger_Piece_Position, out Tirgger_Piece_Position, ScreenExternData.StationNumber);
            CMCDLL_NET_Sorting.MCF_Sorting_Set_Input_Position_Net(Input_Number, (ushort)Tirgger_Piece_Position, StationNumber);


            return rtn;
        }

        public override bool AllAxisOn()
        {
            List<Task<bool>> taskList = new List<Task<bool>>();
            // 如果是多个轴的运动 等每个轴开启
          AxisSettings.FindAll(a => a.IsAxisEnabled)
                .ForEach(axisNum =>
                {
                    var task = AxisOnAsync(axisNum.AxisIndex);
                    taskList.Add(task);
                });
            Task.WaitAll(taskList.ToArray());
            var resultOK = taskList.All(u => u.GetAwaiter().GetResult());
            return resultOK;
        }

        public override bool AllAxisOff()
        {
            List<Task<bool>> taskList = new List<Task<bool>>(); ;
            // 如果是多个轴的运动 等每个轴关闭
            AxisSettings.FindAll(a => a.IsAxisEnabled).ForEach(axisNum =>
            {
                var task = AxisOffAsync(axisNum.AxisIndex);
                taskList.Add(task);
            });
            Task.WaitAll(taskList.ToArray());
            var resultOK = taskList.All(u => u.GetAwaiter().GetResult());
            return resultOK;
        }



        /// <summary>
        /// 单个板卡有4个轴,轴索引从0开始,大于3时,需要计算一下站点号及轴号
        /// </summary>
        /// <param name="axisNum">原始轴号,在配置中累加,如第1张卡轴号0~3,第2张卡轴号4~7</param>
        /// <param name="station">换算后的站点号</param>
        /// <param name="axis">换算后的轴号</param>
        private void ConvertFromAxis(int axisNum, out ushort station, out ushort axis)
        {
            station = (ushort)(axisNum / 4);
            axis = (ushort)(axisNum % 4);
        }


        /// <summary>
        /// IO索引转换
        /// </summary>
        /// <param name="ioIndex"></param>
        /// <param name="station"></param>
        /// <param name="io"></param>
        // TODO: 2023-11-14 完善IO索引转换函数
        private void ConvertFromIO(int ioIndex, out ushort station, out ushort io)
        {
            station = 0;
            io = (ushort)ioIndex;


            switch (BoardModel)
            {
                case BoardModelEnum.EC3216:
                    {

                    }
                    break;
                case BoardModelEnum.EC3224:
                    break;
                case BoardModelEnum.EC3416:
                    {
                        switch (ExtBoard)
                        {
                            default:
                            case ExtensionBoardEnum.None:
                                return;

                            case ExtensionBoardEnum.ExtIO_1:
                            case ExtensionBoardEnum.ExtEC3216_1:
                            case ExtensionBoardEnum.ExtEC3416_1:
                                station = (ushort)(ioIndex / 16);
                                io = (ushort)(ioIndex % 16);
                                break;

                            case ExtensionBoardEnum.ExtEC3224_1:
                                break;

                        }
                    }
                    break;
                default:
                    break;
            }




            //if (ExtMainBoard)
            //{
            //    station = (ushort)(ioIndex / 16);
            //    io = (ushort)(ioIndex % 16);
            //}

            //if (ExtIoBoard)
            //{
            //    station = 0;
            //    io = (ushort)ioIndex;
            //}

        }



        /// <summary>
        /// 单个轴开启
        /// </summary>
        /// <returns></returns>
        public override async Task<bool> AxisOnAsync(int axisNum)
        {
            return await Task.Run(() =>
            {
                bool result = false;
                result = ClearStatus(axisNum);
                if (!result)
                {
                    //LogAsync(DateTime.Now, LogLevel.Exception, $"轴:{axisNum} 开启清除状态异常");
                    return result;
                }
                result = PositionReset(axisNum, 1);
                if (!result)
                {
                    //LogAsync(DateTime.Now, LogLevel.Exception, $"轴:{axisNum} 开启位置清零异常");
                    return result;
                }

                // 单个板卡有4个轴,轴索引从0开始,大于3时,需要计算一下站点号及轴号
                ConvertFromAxis(axisNum, out ushort station, out ushort axis);


                var ret = CMCDLL_NET.MCF_Set_Servo_Enable_Net(axis, (ushort)ServoLogic.Servo_Close, station);

                result = ret == 0;
                if (!result)
                {
                    //LogAsync(DateTime.Now, LogLevel.Exception, $"轴:{axisNum} 开启异常");
                }
                return result;
            });
        }

        /// <summary>
        /// 单个轴关闭
        /// </summary>
        /// <returns></returns>
        public override async Task<bool> AxisOffAsync(int axisNum)
        {
            return await Task.Run(() =>
            {
                ConvertFromAxis(axisNum, out ushort station, out ushort axis);

                var ret = CMCDLL_NET.MCF_Set_Servo_Enable_Net(axis, (ushort)ServoLogic.Servo_Open, station);

                return ret == (short)FuncRet.Function_Success;
            });
        }
        //方案2:不使用外部文本框输入参数,直接写入参数
       
        public void JOGRun(double MaxV,double MaxA)
        {
            int ret = CMCDLL_NET.MCF_Set_Pulse_Mode_Net(0, (ushort)PulseMode.Pulse_Dir_H, 0);
            ret = CMCDLL_NET.MCF_Set_Servo_Enable_Net(0, (ushort)ServoLogic.Servo_Close, 0);
            ret=CMCDLL_NET.MCF_JOG_Net(0, MaxV, MaxA, 0);
        }
        /// <summary>
        /// 点位到点位运动
        /// </summary>
        /// <param name="item">运动对象</param>
        /// <returns>运动控制+停止判断</returns>
        public  ResponseMessage MoveToPoint(IOperationConfig opConfig)
        {
            ResponseMessage responseMessage =new ResponseMessage();
            if (opConfig is SolidMotionOperationCollection motionCollection)
            {
                List<Task<bool>> resultList = new List<Task<bool>>();
                motionCollection.MovingOps.ForEach(movingOp =>
                {
                    if (movingOp.AxisIndex >= 0)
                    {
                        axisImmediatePauseFlag[movingOp.AxisIndex] = false;
                        axisPauseResumeFlag[movingOp.AxisIndex] = true;
                        var task = SingleAxisMoving(movingOp);
                        resultList.Add(task);
                    }
                });
                var timeOut = motionCollection.MovingOpsTimeout <= 0 ? 60 * 1000 : motionCollection.MovingOpsTimeout * 1000;
                var isMotionNotTimeout = Task.WaitAll(resultList.ToArray(), timeOut);
                if (!isMotionNotTimeout)
                {
                    responseMessage.Message = $"多轴并发点位运动超时,请设置合理的运动超时时间,或加快轴速度";
                }
                var result = resultList.All(u => u.GetAwaiter().GetResult());
                if (!result)
                {
                    responseMessage.Result = -1;
                    responseMessage.Message = $"多轴并发点位运动异常";
                }
            }
            return responseMessage;
        }

        /// <summary>
        /// 点到点运动设置参数
        /// </summary>
        /// <param name="optionPara">运动参数对象</param>
        /// <returns></returns>
        private bool SetAxisParam(MovingOption optionPara)
        {
            //List<short> resultCode = new List<short>() { 0 };
            //MotionCardAPI.TTrapPrm trapprm = new MotionCardAPI.TTrapPrm();
            ////设置误差带
            //resultCode.Add(MotionCardAPI.GT_SetAxisBand((short)IConfig.CardOrCoreNum, (short)optionPara.AxisIndex, optionPara.ErrorBand, 5));
            //resultCode.Add(MotionCardAPI.GT_PrfTrap((short)IConfig.CardOrCoreNum, (short)optionPara.AxisIndex));
            //resultCode.Add(MotionCardAPI.GT_GetTrapPrm((short)IConfig.CardOrCoreNum, (short)optionPara.AxisIndex, out trapprm));
            //trapprm.smoothTime = 1;

            //if (optionPara.VelocityPara.Acc != 0)
            //{
            //    trapprm.acc = optionPara.VelocityPara.Acc;
            //}

            //if (optionPara.VelocityPara.Dec != 0)
            //{
            //    trapprm.dec = optionPara.VelocityPara.Dec;
            //}

            //resultCode.Add(MotionCardAPI.GT_SetTrapPrm((short)IConfig.CardOrCoreNum, (short)optionPara.AxisIndex, ref trapprm));

            // CMCDLL_NET.MCF_Set_Axis_Profile_Net((ushort)optionPara.AxisIndex,)

            //if (optionPara.VelocityPara.Velocity != 0)
            //{
            //    resultCode.Add(MotionCardAPI.GT_SetVel((short)IConfig.CardOrCoreNum, (short)optionPara.AxisIndex, optionPara.VelocityPara.Velocity * IConfig.AxisVelocityRatio));
            //}

            //var resultOK = resultCode.All(u => u == RetCode.Function_Success);
            //if (!resultOK)
            //{
            //    throw new ProcessException("轴" + optionPara.AxisIndex + "设置参数异常,错误码:" + string.Join(",", resultCode));
            //}
            var resultOK = true;
            return resultOK;
        }

        /// <summary>
        /// 单个轴 运动(点到点 jog 回零...)
        /// </summary>
        /// <param name="optionPara">运动参数对象</param>
        public  Task<bool> SingleAxisMoving(MovingOption optionPara)
        {
            return _taskFactory.StartNew(() =>
            {
                bool isSuccessAndStop = false;
                do
                {
                    axisImmediatePauseHandleDict[optionPara.AxisIndex].WaitOne();

                    if (axisPauseResumeFlag.ContainsKey(optionPara.AxisIndex) && !axisPauseResumeFlag[optionPara.AxisIndex])
                        return true;

                    try
                    {
                        if (AxisSettings.FirstOrDefault(a => a.AxisIndex == optionPara.AxisIndex)?.IsAxisEnabled ?? false)
                        {
                            string motionType = optionPara.MoveMode == MotionMode.P2P ? (optionPara.IsAbsolute ? "Abs" : "Rel") : optionPara.MoveMode.ToString();

                            switch (optionPara.MoveMode)
                            {
                                case MotionMode.P2P: // 点到点
                                    {
                                        if (_isResetting)
                                        {
                                            //LogAsync(DateTime.Now, LogLevel.Exception, $"复位中启动运动异常 {optionPara.AxisIndex}");
                                            return false;
                                        }

                                        if (optionPara.IsAbsolute)
                                        {
                                            isSuccessAndStop = P2PMoveAbs(optionPara);
                                        }
                                        else
                                        {
                                            isSuccessAndStop = P2PMoveRel(optionPara);
                                        }

                                    }
                                    break;
                                case MotionMode.GoHome: // 回零
                                    {
                                        var axisSetting = AxisSettings.FirstOrDefault(u => u.AxisIndex == optionPara.AxisIndex);
                                        if (axisSetting != null)
                                        {
                                            isSuccessAndStop = SmartGoHome((ushort)optionPara.AxisIndex, axisSetting.GoHomePara);
                                        }
                                        else
                                        {
                                            isSuccessAndStop = false;
                                            //LogAsync(DateTime.Now, LogLevel.Exception, $"轴{optionPara.AxisIndex}回零异常,未获取到轴配置");
                                        }
                                    }
                                    break;
                                case MotionMode.Jog: // Jog
                                    {
                                        isSuccessAndStop = JogMove(optionPara);
                                    }
                                    break;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        isSuccessAndStop = false;
                        //LogAsync(DateTime.Now, LogLevel.Exception, $"轴{optionPara.AxisIndex}运动异常 {ex.GetExceptionMessage()}");
                    }
                } while (axisImmediatePauseFlag.ContainsKey(optionPara.AxisIndex) && axisImmediatePauseFlag[optionPara.AxisIndex]);
                return isSuccessAndStop;
            });
        }

        /// <summary>
        /// 获取规划位置
        /// </summary>
        /// <param name="axisNum">Axis number</param>
        /// <returns></returns>
        public  int GetPrfPosition(int axisNum)
        {
            int prfpos = 0;

            ConvertFromAxis(axisNum, out ushort station, out ushort axis);

            var ret = CMCDLL_NET.MCF_Get_Position_Net(axis, ref prfpos, station);
            if (ret == (short)FuncRet.ERR_Open_Station_Fail)
            {
                // LogAsync(DateTime.Now, LogLevel.Exception, $"轴{axisNum}获取规划位置异常,{IConfig.Name}未打开");
            }
            else if (ret != (short)FuncRet.Function_Success)
            {
                // LogAsync(DateTime.Now, LogLevel.Exception, "轴" + axisNum + "获取规划位置异常,错误码:" + ret);
                // throw new ProcessException("轴" + axisNum + "获取规划位置异常,错误码:" + ret);
            }
            return prfpos;
        }


        /// <summary>
        /// 获取目前当前位置
        /// </summary>
        /// <param name="axisNum">Axis number</param>
        /// <returns></returns>
        public  int GetCurPosition(int axisNum)
        {
            int pPos = 0;

            ConvertFromAxis(axisNum, out ushort station, out ushort axis);

            int ret = CMCDLL_NET.MCF_Get_Encoder_Net(axis, ref pPos, station);
            if (ret == (short)FuncRet.ERR_Open_Station_Fail)
            {
                // LogAsync(DateTime.Now, LogLevel.Exception, $"轴{axisNum}获取目标当前位置异常,{IConfig.Name}未打开");
            }
            else if (ret != (short)FuncRet.Function_Success)
            {
                // LogAsync(DateTime.Now, LogLevel.Exception, "轴" + axisNum + "获取目标当前位置异常,错误码:" + ret);
                // throw new ProcessException("轴" + axisNum + "获取目标当前位置异常,错误码:" + ret);
            }
            return pPos;
        }


        /// <summary>
        /// 获取规划速度及实际速度
        /// </summary>
        /// <param name="axisNum">Axis number</param>
        /// <returns>速度脉冲</returns>
        public bool GetVelocity(int axisNum, ref double commandVel, ref double encodeVel)
        {
            ConvertFromAxis(axisNum, out ushort station, out ushort axis);

            var ret = CMCDLL_NET.MCF_Get_Vel_Net(axis, ref commandVel, ref encodeVel, station);
            if (ret == (short)FuncRet.ERR_Open_Station_Fail)
            {
                // LogAsync(DateTime.Now, LogLevel.Exception, $"轴{axisNum}获取速度异常,{IConfig.Name}未打开");
            }
            else if (ret != (short)FuncRet.Function_Success)
            {
                // LogAsync(DateTime.Now, LogLevel.Exception, "轴" + axisNum + "获取速度异常,错误码:" + ret);
                //throw new ProcessException("轴" + axisNum + "获取速度异常,错误码:" + ret);
            }
            return true;
        }



        /// <summary>
        /// Set Single Axis Do Jog Move  
        /// </summary>
        /// <param name="axisNum">AxisNo</param>
        /// <param name="nDirection">Motion Direction 0: Negative, 1: Positive</param>
        /// <param name="nMaxVel">max velocity</param>
        /// <returns></returns>
        public bool JogMove(MovingOption optionPara)
        {
            try
            {
                //MotionCardAPI.TJogPrm jogprm = new MotionCardAPI.TJogPrm();
                short ret = 0;
                int repeatTime = 100;
                do
                {
                    ConvertFromAxis(optionPara.AxisIndex, out ushort station, out ushort axis);


                    ret = CMCDLL_NET_Sorting.MCF_Set_Pulse_Mode_Net(axis, (ushort)optionPara.MoveDir, station);
                    ret = CMCDLL_NET_Sorting.MCF_Set_Servo_Enable_Net(axis, (ushort)ServoLogic.Servo_Close, station);
                    ret = CMCDLL_NET_Sorting.MCF_JOG_Net(axis, optionPara.VelocityPara.Velocity, optionPara.VelocityPara.Acc, station);


                    //ret = CMCDLL_NET.MCF_Set_Pulse_Mode_Net(axis, (ushort)PulseMode.Pulse_Dir_H, station);
                    //ret = CMCDLL_NET.MCF_Set_Servo_Enable_Net(axis, (ushort)ServoLogic.Servo_Close, station);
                    //ret = CMCDLL_NET.MCF_JOG_Net(axis, optionPara.VelocityPara.Velocity, optionPara.VelocityPara.Acc, station);

                    if (ret != (short)FuncRet.Function_Success)
                    {
                        //LogAsync(DateTime.Now, LogLevel.Exception, "轴" + optionPara.AxisIndex + "JogMove异常 ,错误码:" + ret + ";" + "重试次数:" + repeatTime);
                        Task.Delay(10).Wait();
                    }
                    repeatTime--;
                } while (ret != (short)FuncRet.Function_Success && repeatTime > 0);

                return (ret == (short)FuncRet.Function_Success);
            }
            catch (Exception ex)
            {
                AllMoveStop(true);
                //OnExceptionOccured?.Invoke(DateTime.Now, ex);
                return false;
            }
        }

        /// <summary>
        /// 相对位置运动 
        /// </summary>
        /// <param name="axisNum">AxisNo</param>
        /// <param name="nDistance">run distance</param>
        /// <returns></returns>
        public bool P2PMoveRel(MovingOption optionPara)
        {
            try
            {
                axisImmediatePauseHandleDict[optionPara.AxisIndex].WaitOne();
                int currentPosition = (int)GetCurPosition(optionPara.AxisIndex);
                int dPosition = optionPara.Destination + currentPosition;
                if (Math.Abs(dPosition - currentPosition) <= optionPara.ErrorBand)
                {
                    //已经在位 直接返回
                    return true;
                }
                if (_isResetting)
                {
                    //LogAsync(DateTime.Now, LogLevel.Exception, "复位过程异常,轴" + optionPara.AxisIndex + "试图在复位过程中运动");
                    //throw new ProcessException("轴" + optionPara.AxisIndex + "试图在复位过程中运动");
                }

                int repeatTime = 30;
                //while (CurrentState != EnumHelper.DeviceState.DSOpen && repeatTime > 0)
                //{
                //    Task.Delay(10).Wait();
                //    repeatTime--;
                //}

                //if (CurrentState == EnumHelper.DeviceState.DSExcept)
                //{
                //    LogAsync(DateTime.Now, LogLevel.Exception, "板卡异常状态,轴" + optionPara.AxisIndex + "试图异常状态运动");
                //    return false;
                //}

                //if (CurrentState != EnumHelper.DeviceState.DSOpen)
                //{
                //    LogAsync(DateTime.Now, LogLevel.Exception, "非正常状态异常,轴" + optionPara.AxisIndex + $"试图在非正常状态({CurrentState})运动");
                //    throw new ProcessException("轴" + optionPara.AxisIndex + "试图在非正常状态运动", null);
                //}

                short ret = 0;
                bool isSuccessSetAxisParam = false;
                int timeout = optionPara.MovingTimeout <= 0 ? 60 * 1000 : optionPara.MovingTimeout;
                int timeout2 = optionPara.MovingTimeout <= 0 ? 60 * 1000 : optionPara.MovingTimeout;
                int repeatTime2 = 0;
                //LogAsync(DateTime.Now, LogLevel.Action, $"轴{optionPara.AxisIndex} 开始运动,当前位置:{currentPosition} 目标位置:{dPosition}");
                //while (CurrentState == DeviceState.DSOpen)
                while (isconnected) 
                {
                    // 设置 运动参数
                    isSuccessSetAxisParam = SetAxisParam(optionPara);

                    ConvertFromAxis(optionPara.AxisIndex, out ushort station, out ushort axis);

                    // 设置速度参数
                    ret = CMCDLL_NET.MCF_Set_Axis_Profile_Net(axis,
                        optionPara.VelocityPara.Velocity,
                        optionPara.VelocityPara.Velocity,
                        optionPara.VelocityPara.Acc,
                        optionPara.VelocityPara.Acc,
                        optionPara.VelocityPara.Velocity,
                        (ushort)Profile.Profile_T,
                        station);


                    ret = CMCDLL_NET.MCF_Uniaxial_Net(axis, optionPara.Destination, (ushort)PositionMode.Position_Opposite, station);

                    if (ret != (short)FuncRet.Function_Success)
                    {
                       // LogAsync(DateTime.Now, LogLevel.Exception, $"轴{optionPara.AxisIndex} APS_rel_move异常,错误码:{ret};重试次数:{repeatTime2}");
                        repeatTime2++;
                        Task.Delay(20).Wait();
                    }
                    timeout -= 20;
                    if ((ret == (short)FuncRet.Function_Success && isSuccessSetAxisParam) || timeout < 0)
                    {
                        break;
                    }
                }

                if (timeout < 0)
                {
                   // LogAsync(DateTime.Now, LogLevel.Exception, $"轴{optionPara.AxisIndex}APS_rel_move参数设置超时,错误码:{ret}");
                    return false;
                }

                //运动开始后 检查运动是否停止
                bool isStopSuccess = false;
                int prfPosition = 0;
                int curPosition = 0;
                do
                {
                    Task.Delay(20).Wait();
                    prfPosition = GetPrfPosition(optionPara.AxisIndex);
                    curPosition = GetCurPosition(optionPara.AxisIndex);
                    isStopSuccess = IsStop((short)optionPara.AxisIndex)
                        && Math.Abs(dPosition - prfPosition) <= optionPara.ErrorBand
                        && Math.Abs(dPosition - curPosition) <= optionPara.ErrorBand;
                    timeout2 -= 20;
                } while (!isStopSuccess && timeout2 > 0);

                if (timeout2 < 0)
                {
                   // LogAsync(DateTime.Now, LogLevel.Exception, $"轴{optionPara.AxisIndex}APS_rel_move运动到位超时,目标位置:{dPosition};规划位置:{prfPosition};当前位置:{curPosition}");
                    return false;
                }
               // LogAsync(DateTime.Now, LogLevel.Action, $"轴{optionPara.AxisIndex}APS_rel_move运动到位,目标位置:{optionPara.Destination};规划位置:{prfPosition};当前位置:{curPosition}");
                return (ret == (short)FuncRet.Function_Success) && isStopSuccess;
            }
            catch (Exception ex)
            {
               // LogAsync(DateTime.Now, LogLevel.Exception, $"轴{optionPara.AxisIndex}运动异常:{ex.GetExceptionMessage()}");
                AllMoveStop(true);
               // OnExceptionOccured?.Invoke(DateTime.Now, ex);
                return false;
            }
        }

        /// <summary>
        /// 绝对位置运动
        /// </summary>
        /// <param name="optionPara">运动参数对象</param>
        public bool P2PMoveAbs(MovingOption optionPara)
        {
            try
            {
                axisImmediatePauseHandleDict[optionPara.AxisIndex].WaitOne();

                int currentPosition = GetCurPosition(optionPara.AxisIndex);

                // 步进电机没有编码器
                if (currentPosition == 0)
                {
                    currentPosition = GetPrfPosition(optionPara.AxisIndex);
                }


                if (Math.Abs(optionPara.Destination - currentPosition) <= optionPara.ErrorBand)
                {
                    // 已经在位 直接返回
                    return true;
                }
                //if (_isResetting)
                //{
                //    LogAsync(DateTime.Now, LogLevel.Exception, $"复位过程异常,轴{optionPara.AxisIndex}试图在复位过程中运动");
                //    throw new ProcessException("轴" + optionPara.AxisIndex + "试图在复位过程中运动");
                //}
                int repeatTime = 30;
                //while (CurrentState != EnumHelper.DeviceState.DSOpen && repeatTime > 0)
                //{
                //    Task.Delay(10).Wait();
                //    repeatTime--;
                //}
                //if (CurrentState == EnumHelper.DeviceState.DSExcept)
                //{
                //    LogAsync(DateTime.Now, LogLevel.Exception, $"板卡异常状态,轴{optionPara.AxisIndex}试图异常状态运动");
                //    return false;
                //}

                //if (CurrentState != EnumHelper.DeviceState.DSOpen)
                //{
                //    LogAsync(DateTime.Now, LogLevel.Exception, $"非正常状态异常,轴{optionPara.AxisIndex}试图在非正常状态({CurrentState})运动");
                //    throw new ProcessException("轴" + optionPara.AxisIndex + "试图在非正常状态运动", null);
                //}
                short ret = 0;
                // bool isSuccessSetAxisParam = false;
                int timeout = optionPara.MovingTimeout <= 0 ? 60 * 1000 : optionPara.MovingTimeout;
                int timeout2 = optionPara.MovingTimeout <= 0 ? 60 * 1000 : optionPara.MovingTimeout;
                int repeatTime2 = 0;
               // LogAsync(DateTime.Now, LogLevel.Action, $"轴{optionPara.AxisIndex}开始运动,当前位置:{currentPosition} 目标位置:{optionPara.Destination}");
                //while (CurrentState == DeviceState.DSOpen && !_isPause)
                while (true) 
                {
                    // 设置 运动参数
                    // isSuccessSetAxisParam = SetAxisParam(optionPara);

                    ConvertFromAxis(optionPara.AxisIndex, out ushort station, out ushort axis);

                    // 设置速度参数
                    ret = CMCDLL_NET.MCF_Set_Axis_Profile_Net(axis,
                        optionPara.VelocityPara.Velocity,
                        optionPara.VelocityPara.Velocity,
                        optionPara.VelocityPara.Acc,
                        optionPara.VelocityPara.Acc,
                        optionPara.VelocityPara.Velocity,
                        (ushort)Profile.Profile_S,
                        station);

                    // 开始运动
                    ret = CMCDLL_NET.MCF_Uniaxial_Net(axis, optionPara.Destination, (ushort)PositionMode.Position_Absolute, station);

                    if (ret != (short)FuncRet.Function_Success)
                    {
                       // LogAsync(DateTime.Now, LogLevel.Exception, $"轴{optionPara.AxisIndex}APS_absolute_move异常,错误码:{ret};重试次数:{repeatTime2}");
                        repeatTime2++;
                        Task.Delay(20).Wait();
                    }
                    timeout -= 20;
                    // if ((ret == (short)RetCode.Function_Success && isSuccessSetAxisParam) || timeout < 0)
                    if (ret == (short)FuncRet.Function_Success || timeout < 0)
                    {
                        break;
                    }
                }

                if (timeout < 0)
                {
                    //LogAsync(DateTime.Now, LogLevel.Exception, $"轴{optionPara.AxisIndex}APS_absolute_move参数设置超时,错误码:{ret}");
                    return false;
                }

                //运动开始后 检查运动是否停止
                bool isStopSuccess = false;
                int prfPosition = 0;
                int curPosition = 0;
                do
                {
                    Task.Delay(20).Wait();
                    prfPosition = GetPrfPosition(optionPara.AxisIndex);
                    curPosition = GetCurPosition(optionPara.AxisIndex);

                    var isStop = IsStop((short)optionPara.AxisIndex);
                    var prfOk = Math.Abs(optionPara.Destination - prfPosition) <= optionPara.ErrorBand;
                    var encoderOk = Math.Abs(optionPara.Destination - curPosition) <= optionPara.ErrorBand;

                    // 步进电机没有编码器,curPosition一直为0,所以单独做一下处理
                    if (prfOk && !encoderOk && curPosition == 0)
                    {
                        encoderOk = true;
                    }

                    isStopSuccess = isStop && prfOk && encoderOk;

                    timeout2 -= 20;
                } while (!isStopSuccess && timeout2 > 0);

                if (optionPara.MovingTimeout > 0 && timeout2 < 0)
                {
                   // LogAsync(DateTime.Now, LogLevel.Exception, $"轴{optionPara.AxisIndex}APS_absolute_move运动到位超时,目标位置:{optionPara.Destination};规划位置:{prfPosition};当前位置:{curPosition}");
                    return false;
                }
              //  LogAsync(DateTime.Now, LogLevel.Action, $"轴{optionPara.AxisIndex}APS_absolute_move运动到位,目标位置:{optionPara.Destination};规划位置:{prfPosition};当前位置:{curPosition}");
                return (ret == (short)FuncRet.Function_Success) && isStopSuccess;
            }
            catch (Exception ex)
            {
               // LogAsync(DateTime.Now, LogLevel.Exception, $"轴{optionPara.AxisIndex}运动异常 {ex.GetExceptionMessage()}");
                AllMoveStop(true);
               // OnExceptionOccured?.Invoke(DateTime.Now, ex);
                return false;
            }
        }



        public void AxisStop()
        {
            short rtn;
            ushort StationNumber = 0;
            for (ushort a = 0; a < 4; a++)
            {
                rtn = CMCDLL_NET.MCF_Set_Axis_Stop_Profile_Net(a, 10000, 100000, 1, StationNumber);//设置轴S型停止曲线参数
                rtn = CMCDLL_NET.MCF_Axis_Stop_Net(a, 1, StationNumber);//设置轴为平滑停止模式
            }
        }
        public  bool CArdReset()
        {

           // ConvertFromAxis(startAxisIndex, out ushort station, out ushort axis);

            var ret = CMCDLL_NET.MCF_Set_Position_Net(0, 0, 0);
            var ret2 = CMCDLL_NET.MCF_Set_Encoder_Net(0, 0, 0);
            
            return ret2 == 0 ? true : false; 

        }


        /// <summary>
        /// 某个轴运动停止
        /// </summary>
        /// <param name="axisNum">axisNo</param>
        /// <param name="option">0表示平滑停止,1表示紧急停止</param>
        /// <returns></returns>
        public async Task<bool> MoveStop(int axisNum, int option)
        {
            return await _taskFactory.StartNew(() =>
            {
                bool isStop = false;
                if (option == 1)
                {
                   // StateChange(EnumHelper.DeviceState.DSExcept);
                }
                short ret = 0;

                ConvertFromAxis(axisNum, out ushort station, out ushort axis);


                if (option == 1)
                {
                    ret = CMCDLL_NET.MCF_Axis_Stop_Net(axis, AxisStopMode.AxisStopIMD, station);
                }
                else
                {
                    ret = CMCDLL_NET.MCF_Set_Axis_Stop_Profile_Net(0, 50000, 0, 0, station);
                    ret = CMCDLL_NET.MCF_Axis_Stop_Net(axis, AxisStopMode.AxisStopDEC, station);
                }


                if (ret != (short)FuncRet.Function_Success)
                {
                   // LogAsync(DateTime.Now, LogLevel.Exception, $"轴{axisNum}运动停止异常,错误码:{ret}");
                }
                int repeatTime = 100;
                do
                {
                    Task.Delay(20).Wait();
                    isStop = IsStop((short)axisNum);
                    repeatTime--;
                } while (!isStop && repeatTime > 0);
                if (isStop)
                {
                    //LogAsync(DateTime.Now, LogLevel.Action, "轴" + axisNum + "运动停止");
                }

                return (ret == (short)FuncRet.Function_Success) && isStop;
            });
        }

        /// <summary>
        /// 所有开启的轴停止
        /// </summary>
        /// <param name="emergencyStop"></param>
        public void AllMoveStop(bool emergencyStop = false)
        {
            int option = emergencyStop ? 1 : 0;
            List<Task<bool>> taskList = new List<Task<bool>>();
            // 如果是多个轴的运动 等每个轴运动结束
            AxisSettings.Where(a => a.IsAxisEnabled).ToList().ForEach(axisNum =>
            {
                var task = MoveStop(axisNum.AxisIndex, option);
                taskList.Add(task);
            });
            Task.WaitAll(taskList.ToArray());
            var resultOK = taskList.All(u => u.GetAwaiter().GetResult());
        }


        /// <summary>
        /// 读取IO输入
        /// </summary>
        /// <param name="cardNum">卡号</param>
        /// <param name="index">输入口</param>
        /// <returns>有输入返回true,无输入返回false</returns>
        public  bool GetDi(short index)
        {
            int value = 0;

            if ((value & (1 << index)) == 0)
            {
                return true;//有输入返回true
            }
            else
            {
                return false;          //无输入返回false
            }
        }

        /// <summary>
        /// 读取IO输出
        /// </summary>
        /// <param name="index">io索引</param>
        /// <returns></returns>
        public bool GetDoSts(short index)
        {
            int outSts = 0;
            short outNum = (short)(index % 100);
            //  MotionCardAPI.GT_GetDo((short)IConfig.CardOrCoreNum, MotionCardAPI.MC_GPO, out outSts);
            if ((outSts & (1 << outNum)) == 0) return true;
            else return false;
        }

        /// <summary>
        /// 按位设置数字 IO 输出状态
        /// </summary>
        /// <param name="index">输出口,返回0-15</param>
        /// <param name="value">false表示关,true表示开,板卡要设置取反</param>
        public  void WriteOutput(short index, IOValue value)
        {

            ConvertFromIO(index, out ushort station, out ushort ioIndex);

            if ((int)value <= 1) // 输出电平
            {
                CMCDLL_NET.MCF_Set_Output_Bit_Net(ioIndex, (ushort)(value == IOValue.TRUE ? 0 : 1), station);
            }
            else // 反转
            {
                var currentValue = (int)CurrentIOs.FirstOrDefault(u => u.IOIndex == index && u.IOType == IOType.OUTPUT).IOValue;
                CMCDLL_NET.MCF_Set_Output_Bit_Net(ioIndex, (ushort)(currentValue == 1 ? 0 : 1), station);
            }
        }

        /// <summary>
        /// 读取轴状态,判断电机是否停止
        /// </summary>
        /// <param name="cardNum">板卡号</param>
        /// <param name="axisNum">轴号</param>
        /// <returns></returns>
        public bool IsStop(short axisNum)
        {
            int sts = GetAxisStatus(axisNum);
            return sts == 0;
        }


        /// <summary>
        /// 读取轴状态
        /// </summary>
        /// <param name="axisNum">轴号</param>
        /// <returns></returns>
        public  int GetAxisStatus(int axisNum)
        {
            short reason = 0;

            ConvertFromAxis(axisNum, out ushort station, out ushort axis);

            CMCDLL_NET.MCF_Get_Axis_State_Net(axis, ref reason, station);

            return reason;
        }


        public  AxisMovingStatus GetAxisStatus2(int axisNum)
        {
            ConvertFromAxis(axisNum, out ushort station, out ushort axis);


            short reason = 0;
            CMCDLL_NET.MCF_Get_Axis_State_Net(axis, ref reason, station);

            ushort positiveLimit = 0;
            CMCDLL_NET.MCF_Get_Positive_Limit_Net(axis, ref positiveLimit, station);

            ushort negativeLimit = 0;
            CMCDLL_NET.MCF_Get_Negative_Limit_Net(axis, ref negativeLimit, station);

            ushort enable = 0;
            CMCDLL_NET.MCF_Get_Servo_Enable_Net(axis, ref enable, station);

            ushort alarm = 0;
            CMCDLL_NET.MCF_Get_Servo_Alarm_Net(axis, ref alarm, station);

            AxisMovingStatus status = new AxisMovingStatus
            {
                AxisIndex = axisNum,
                AxisStatus = reason,
                Alarm = alarm == 0,
                Enable = enable == 0,
                PositiveLimit = positiveLimit == 0,
                NegativeLimit = negativeLimit == 0,
            };


            return status;
        }


        public  bool ClearStatus(int startAxisIndex)
        {
            /* 固高板卡原函数的含义:清除驱动器报警标志、跟随误差越限标志、限位触发标志
                1. 只有当驱动器没有报警时才能清除轴状态字的报警标志
                2. 只有当跟随误差正常以后,才能清除跟随误差越限标志
                3. 只有当离开限位开关,或者规划位置在软限位行程以内时才能清除轴状态字的限位触发标志 
             */

            ConvertFromAxis(startAxisIndex, out ushort station, out ushort axisIndex);


            // 清除轴报警原本寄存器
            short ret = CMCDLL_NET.MCF_Clear_Axis_State_Net(axisIndex, station);

            if (ret != (short)FuncRet.Function_Success)
            {
                return false;
            }


            // 设置伺服报警复位
            var axisSetting = AxisSettings.First(a => a.AxisIndex == startAxisIndex);// IConfig.AxisSettings[startAxisIndex];

            if (axisSetting.IsUseAlarm)
            {
                ret = CMCDLL_NET.MCF_Set_Servo_Alarm_Reset_Net(axisIndex, (ushort)axisSetting.AlarmLogic, station);
            }
            return ret == (short)FuncRet.Function_Success;
        }


        /// <summary>
        /// 位置回零
        /// </summary>
        /// <param name="startAxisIndex"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public  bool PositionReset(int startAxisIndex, int count)
        {

            ConvertFromAxis(startAxisIndex, out ushort station, out ushort axis);

            var ret = CMCDLL_NET.MCF_Set_Position_Net(axis, 0, station);
            var ret2 = CMCDLL_NET.MCF_Set_Encoder_Net(axis, 0, station);

            return ret == (ushort)FuncRet.Function_Success && ret2 == (ushort)FuncRet.Function_Success;

        }

        #endregion


        #region IMonitor

        /// <summary>
        /// 位置捕获监听,入料检测。
        /// 入料检测对射开关接到了HOME口,每当有新料到达入料检测传感器时,程序把当前位置当作原点,并调用<see cref="SolidMotionCardBase.CapturePositionChanged(int, int)"/>函数
        /// </summary>
        private void MonitorPieces()
        {
            var axisList = AxisSettings.Where(u => u.IsMonitorCapture).ToList();
            if (axisList.Count == 0)
            {
                return;
            }

            axisList.ForEach(axis =>
            {
                #region 注释掉之前的实现
                //Task.Run(() =>
                //{
                //    int ai = (int)axis.AxisIndex;

                //    // 物件大小,返回10组数据
                //    uint[] Piece_Size = new uint[10];
                //    // 物件间距,返回10组数据
                //    uint[] Piece_Distance_To_next = new uint[10];
                //    // 物件经过所有相机个数
                //    uint Piece_Cross_Camera = 0;

                //    Thread.CurrentThread.Priority = ThreadPriority.Highest;
                //    while (CurrentState != DeviceState.DSClose && CurrentState != DeviceState.DSExcept && CurrentState != DeviceState.DSUninit)
                //    {
                //        // 50us循环一次 
                //        Stopwatch sw = new Stopwatch();
                //        uint tmpPieceNumber = 0;


                //        sw.Start();
                //        short ret = CMCDLL_NET.MCF_Sorting_Get_Piece_State_Net(0,
                //              ref tmpPieceNumber,
                //              ref Piece_Size[0],
                //              ref Piece_Distance_To_next[0],
                //              ref Piece_Cross_Camera,
                //              IConfig.StationNumber);
                //        sw.Stop();
                //        // Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")} 读取板卡数据,物料编号{tmpPieceNumber},结果{ret},耗时{sw.ElapsedMilliseconds}ms");

                //        //if (tmpPieceNumber > piecesCount)
                //        //{
                //        //    Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")} 物料编号:{tmpPieceNumber}\t耗时:{sw.ElapsedMilliseconds}ms");
                //        //}

                //        if (ret == 0 && tmpPieceNumber > piecesCount)
                //        {

                //            sw.Start();
                //            Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")} 产品入列触发{tmpPieceNumber}");
                //            // LogAsync(DateTime.Now, LogLevel.Information, $"产品入列触发 {piecesCount}");
                //            if (tmpPieceNumber != piecesCount + 1)
                //            {
                //                // LogAsync(DateTime.Now, LogLevel.Information, $"产品入列触发丢失,{piecesCount}\t{tmpPieceNumber}");
                //                Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")}\t产品入列触发丢失,{piecesCount}\t{tmpPieceNumber}");
                //            }
                //            piecesCount = tmpPieceNumber;
                //            NewPieces(ai, piecesCount);
                //            sw.Stop();
                //            Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")} 物料编号:{tmpPieceNumber}\t耗时:{sw.ElapsedMilliseconds}ms");

                //        }
                //        // Thread.SpinWait(5);
                //        Thread.Sleep(30);
                //        // Task.Delay(5).Wait();

                //    }
                //});

                #endregion

                {
                    ParameterizedThreadStart ts = new ParameterizedThreadStart(MonitorPiecesImpl);
                    Thread th = new Thread(ts);
                    th.Priority = ThreadPriority.AboveNormal;
                    th.IsBackground = false;
                    th.Start(axis.AxisIndex);
                }

            });
        }



        /// <summary>
        /// 入料监听
        /// </summary>
        /// <param name="axisIndex"></param>
        private void MonitorPiecesImpl(object axisIndex)
        {
            int ai = (int)axisIndex;

            ushort station = (ushort)(ai / 4);

            // 物件大小,返回10组数据
            uint[] Piece_Size = new uint[10];
            // 物件间距,返回10组数据
            uint[] Piece_Distance_To_next = new uint[10];
            // 物件经过所有相机个数
            uint Piece_Cross_Camera = 0;

            Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
            while (isconnected)
            {
                // for (ushort station = 0; station < _cardCount; station++)
                // for (ushort disk = 0; disk < (ushort)IIConfig.MachineDiskType; disk++)
                {
                    Stopwatch sw = new Stopwatch();
                    uint tmpPieceNumber = 0;

                    sw.Start();
                    var disk = (ushort)(int)axisIndex;

                    short ret = CMCDLL_NET_Sorting.MCF_Sorting_Get_Piece_State_Net(0,
                          ref tmpPieceNumber,
                          ref Piece_Size[0],
                          ref Piece_Distance_To_next[0],
                          ref Piece_Cross_Camera,
                          station);

                    var sum = Piece_Size.Sum(x => x);
                    if (sum > 0)
                    {
                        Console.WriteLine();
                    }

                    sw.Stop();

                    if (ret == 0 && tmpPieceNumber > piecesCountDic[station])
                    {
                        sw.Start();
                        //string Picese_sizeStr="";
                        //string Picese_DistanceizeStr="";
                        //for (int i = 0; i < Piece_Size.Length; i++)
                        //{
                        //    Picese_sizeStr += i.ToString()+":"+Piece_Size[i]+"\t";
                        //    Picese_DistanceizeStr += i.ToString()+":"+ Piece_Distance_To_next[i]+"\t";
                        //}
                       // LogAsync(DateTime.Now, LogLevel.Information, $"转盘{station}产品入列 ,  {piecesCountDic[station]} size:{Piece_Size[Piece_Size.Length - 1]}。");
                        // LogAsync(DateTime.Now, LogLevel.Information, $"转盘{station}产品入列 ,监听piece_find{tmpPieceNumber} 监听物件大小" + Picese_sizeStr+",物件间距"+ Picese_DistanceizeStr+"相机经过个数"+Piece_Cross_Camera);
                        if (tmpPieceNumber != piecesCountDic[station] + 1)
                        {
                           // LogAsync(DateTime.Now, LogLevel.Information, $"转盘{station}入列触发丢失,{piecesCountDic[station]}\t{tmpPieceNumber}");
                        }
                        piecesCountDic[station] = tmpPieceNumber;

                        NewPieces(station + 1, piecesCountDic[station]);
                        sw.Stop();

                    }

                    Thread.Sleep(1);
                }


            }
        }


        /// <summary>
        /// 配置相机
        /// </summary>
        private void ConfigCamera()
        {
            if (!IsEnableFilter)
            {
                return;
            }

            var settingsGroup = SnapshotSettings.Where(s => s.IsEnabled).GroupBy(s => s.StationNumber)
                  .ToList();
            for (int group = 0; group < settingsGroup.Count; group++)
            {
                var camSettings = settingsGroup[group].ToList();

                // 配置所有相机
                for (ushort i = 1; i <= camSettings.Count; i++)
                {
                    var camSetting = camSettings[i - 1];

                    if (!camSetting.IsEnabled)
                    {
                        continue;
                    }

                    var rtn = CMCDLL_NET.MCF_Sorting_Set_Trig_Camera_Delay_Count_Net(i,
                        camSetting.CameraDelayCountMS, camSetting.StationNumber);


                    int CameraPositionReal = camSetting.CameraPosition;
                    ushort RotationDirectionReal = (ushort)camSetting.RotationDirection;
                    RotationDirectionEnum rotationDirectionEnum = camSetting.RotationDirection;
                    if (DiskSnaptChange && i >= SortingInputSetting.CameraStartNumber)//转盘2
                    {
                        CameraPositionReal = -CameraPositionReal;
                        if (RotationDirectionReal == 0)
                        {
                            RotationDirectionReal = 1;
                            rotationDirectionEnum = RotationDirectionEnum.AntiClockwise;
                        }
                        else
                        {
                            RotationDirectionReal = 0;
                            rotationDirectionEnum = RotationDirectionEnum.Clockwise;
                        }
                    }
                    //修改板卡的IO
                    if (BoardCount == 2)
                    {
                        var ioIndex = camSetting.CameraIO.IOIndex - (camSetting.StationNumber * 16);
                        rtn = CMCDLL_NET_Sorting.MCF_Sorting_Set_Camera_Net(
                   i, // CCD0
                   CameraPositionReal,
                   RotationDirectionReal,
                   (ushort)camSetting.ActionMode,
                   (ushort)ioIndex, // 8
                   camSetting.StationNumber);
                    }
                    else
                    {
                        rtn = CMCDLL_NET.MCF_Sorting_Set_Camera_Net(
                   i, // CCD0
                   CameraPositionReal,
                   RotationDirectionReal,
                   (ushort)camSetting.ActionMode,
                   (ushort)camSetting.CameraIO.IOIndex, // 8
                   camSetting.StationNumber);
                    }

                    //rtn = CMCDLL_NET_Sorting.MCF_Sorting_Set_Camera_Net(
                    //i, // CCD0
                    //camSetting.CameraPosition,
                    //(ushort)camSetting.RotationDirection,
                    //(ushort)camSetting.ActionMode,
                    //(ushort)camSetting.CameraIO.IOIndex, // 8
                    //camSetting.StationNumber);

                   // LogAsync(DateTime.Now, LogLevel.Action, $"相机{i}\t方向{rotationDirectionEnum.GetEnumDescription()}");

                    //配置图像处理时间
                    // rtn = CMCDLL_NET_Sorting.MCF_Sorting_Set_Camera_Handle_Time_Net((ushort)(i + 1), (double)Handle_Time_1MS[i], (double)Handle_TimeOut_1MS[i], (uint)Handle_TimeOut_Number[i], StationNumber);

                }

            }



            // List<SnapshotSetting> settings = IIConfig.SnapshotSettings.Where(s => s.IsEnabled).ToList();

            // 配置所有相机
            //for (ushort i = 1; i <= settings.Count; i++)
            //{
            //    var setting = settings[i - 1];

            //    if (!setting.IsEnabled)
            //    {
            //        continue;
            //    }

            //    var rtn = CMCDLL_NET.MCF_Sorting_Set_Trig_Camera_Delay_Count_Net(i, setting.CameraDelayCountMS, setting.StationNumber);

            //    rtn = CMCDLL_NET.MCF_Sorting_Set_Camera_Net(
            //        i,
            //        setting.CameraPosition,
            //        (ushort)IIConfig.MotionDir,
            //        (ushort)setting.ActionMode,
            //        (ushort)setting.CameraIO.IOIndex,
            //        setting.StationNumber);
            //}
        }


        private void ConfigBlow()
        {
            if (!IsEnableFilter)
            {
                return;
            }

            //// 从检测配置中找到相应的转盘起始相机起始气阀配置
            //Dictionary<ushort, ushort> listBlowStartD = new Dictionary<ushort, ushort>();
            //var SortingInputGroup = IIConfig.SortingInputSettings.Where(s => s.Enable).ToList();
            //for (int group = 0; group < SortingInputGroup.Count; group++)
            //{
            //    if (!SortingInputGroup[group].EnableBindBlow)
            //        continue;
            //    var sets = SortingInputGroup[group].BlowStartNumber;
            //    listBlowStartD.Add((ushort)SortingInputGroup[group].BitInputNumber, sets);
            //}
            //// List<BlowSetting> settings = IIConfig.BlowSettings.Where(s => s.IsEnabled).ToList();


            var settingsGroup = BlowSettings.Where(s => s.IsEnabled).GroupBy(s => s.StationNumber)
                .ToList();
            for (int group = 0; group < settingsGroup.Count; group++)
            {
                var blowSettings = settingsGroup[group].ToList();

                // 配置所有吹气口
                for (ushort i = 0; i < blowSettings.Count; i++)
                {
                    var blowSetting = blowSettings[i];
                    //修改板卡的IO
                    var ioIndex = blowSetting.BlowIO.IOIndex - (blowSetting.StationNumber * 16);
                    if (!blowSetting.IsEnabled)
                    {
                        continue;
                    }
                    int CameraPositionReal = blowSetting.BlowPosition;

                    RotationDirectionEnum rotationDirectionEnum = blowSetting.RotationDirection;
                    if (DiskSnaptChange)//转盘2
                    {
                        CameraPositionReal = -CameraPositionReal;
                        if (rotationDirectionEnum == RotationDirectionEnum.Clockwise)
                        {

                            rotationDirectionEnum = RotationDirectionEnum.AntiClockwise;
                        }
                        else
                        {

                            rotationDirectionEnum = RotationDirectionEnum.Clockwise;
                        }
                    }

                    switch (blowSetting.BlowType)
                    {
                        case BlowType.OK:
                            CMCDLL_NET.MCF_Sorting_Set_Blow_OK_Net(CameraPositionReal, (ushort)rotationDirectionEnum, (ushort)blowSetting.ActionMode, (ushort)ioIndex, blowSetting.StationNumber);
                            break;
                        case BlowType.NG:
                            CMCDLL_NET.MCF_Sorting_Set_Blow_NG_Net(CameraPositionReal, (ushort)rotationDirectionEnum, (ushort)blowSetting.ActionMode, (ushort)ioIndex, blowSetting.StationNumber);
                            break;
                        case BlowType.Blow1:
                            CMCDLL_NET.MCF_Sorting_Set_Blow_1_Net(blowSetting.BlowPosition, (ushort)rotationDirectionEnum, (ushort)blowSetting.ActionMode, (ushort)blowSetting.BlowIO.IOIndex, blowSetting.StationNumber);
                            break;
                        ///第一路绑定OK NG 吹起口1 
                        case BlowType.Blow2:
                            CMCDLL_NET.MCF_Sorting_Set_Blow_2_Net(blowSetting.BlowPosition, (ushort)rotationDirectionEnum, (ushort)blowSetting.ActionMode, (ushort)blowSetting.BlowIO.IOIndex, blowSetting.StationNumber);
                            break;
                        case BlowType.Blow3:
                            CMCDLL_NET.MCF_Sorting_Set_Blow_3_Net(blowSetting.BlowPosition, (ushort)rotationDirectionEnum, (ushort)blowSetting.ActionMode, (ushort)blowSetting.BlowIO.IOIndex, blowSetting.StationNumber);
                            break;
                        case BlowType.Blow4:
                            CMCDLL_NET.MCF_Sorting_Set_Blow_4_Net(blowSetting.BlowPosition, (ushort)rotationDirectionEnum, (ushort)blowSetting.ActionMode, (ushort)blowSetting.BlowIO.IOIndex, blowSetting.StationNumber);
                            break;
                        case BlowType.Blow5:
                            CMCDLL_NET.MCF_Sorting_Set_Blow_5_Net(blowSetting.BlowPosition, (ushort)rotationDirectionEnum, (ushort)blowSetting.ActionMode, (ushort)blowSetting.BlowIO.IOIndex, blowSetting.StationNumber);
                            break;
                        case BlowType.Blow6:
                            CMCDLL_NET.MCF_Sorting_Set_Blow_6_Net(blowSetting.BlowPosition, (ushort)rotationDirectionEnum, (ushort)blowSetting.ActionMode, (ushort)blowSetting.BlowIO.IOIndex, blowSetting.StationNumber);
                            break;
                        default:
                            break;
                        //case BlowType.OK:
                        //    CMCDLL_NET_Sorting.MCF_Sorting_Set_Blow_OK_Net(setting.BlowPosition, (ushort)IIConfig.MotionDir, (ushort)setting.ActionMode, (ushort)setting.BlowIO.IOIndex, setting.StationNumber);
                        //    break;
                        //case BlowType.NG:
                        //    CMCDLL_NET_Sorting.MCF_Sorting_Set_Blow_NG_Net(setting.BlowPosition, (ushort)IIConfig.MotionDir, (ushort)setting.ActionMode, (ushort)setting.BlowIO.IOIndex, setting.StationNumber);
                        //    break;
                        // TODO: 20231108 更新DLL调用类
                        //case BlowType.Blow1:
                        //    CMCDLL_NET_Sorting.MCF_Sorting_Set_Blow_1_Net(setting.BlowPosition, (ushort)IIConfig.MotionDir, (ushort)setting.ActionMode, (ushort)setting.BlowIO.IOIndex, setting.StationNumber);
                        //    break;
                        //case BlowType.Blow2:
                        //    CMCDLL_NET_Sorting.MCF_Sorting_Set_Blow_2_Net(setting.BlowPosition, (ushort)IIConfig.MotionDir, (ushort)setting.ActionMode, (ushort)setting.BlowIO.IOIndex, setting.StationNumber);
                        //    break;
                        //case BlowType.Blow3:
                        //    CMCDLL_NET_Sorting.MCF_Sorting_Set_Blow_3_Net(setting.BlowPosition, (ushort)IIConfig.MotionDir, (ushort)setting.ActionMode, (ushort)setting.BlowIO.IOIndex, setting.StationNumber);
                        //    break;
                        //case BlowType.Blow4:
                        //    CMCDLL_NET_Sorting.MCF_Sorting_Set_Blow_4_Net(setting.BlowPosition, (ushort)IIConfig.MotionDir, (ushort)setting.ActionMode, (ushort)setting.BlowIO.IOIndex, setting.StationNumber);
                        //    break;
                        //case BlowType.Blow5:
                        //    CMCDLL_NET_Sorting.MCF_Sorting_Set_Blow_5_Net(setting.BlowPosition, (ushort)IIConfig.MotionDir, (ushort)setting.ActionMode, (ushort)setting.BlowIO.IOIndex, setting.StationNumber);
                        //    break;
                        //case BlowType.Blow6:
                        //    CMCDLL_NET_Sorting.MCF_Sorting_Set_Blow_6_Net(setting.BlowPosition, (ushort)IIConfig.MotionDir, (ushort)setting.ActionMode, (ushort)setting.BlowIO.IOIndex, setting.StationNumber);
                        //    break;
                       
                    }
                }

            }

        }

        /// <summary>
        /// 读取监听配置中的所有监听值
        /// </summary>
        /// <returns></returns>
        public List<IOItem> GetMonitorValues()
        {
            var result = new List<IOItem>();


            for (ushort station = 0; station < 2; station++)
            {
                // 读取IO输入
                uint inValue = 0;
                uint inValue2 = 0;
                var ret = CMCDLL_NET.MCF_Get_Input_Net(ref inValue, ref inValue2, station);

                if (ret != (short)FuncRet.Function_Success)
                {
                    return null;
                }


                // 读取IO输出
                uint outValue = 0;
                ret = CMCDLL_NET.MCF_Get_Output_Net(ref outValue, station);
                if (ret != (short)FuncRet.Function_Success)
                {
                    return null;
                }
                var cardCount = 1;
                switch (ExtBoard)
                {
                    default:
                    case ExtensionBoardEnum.None:
                    case ExtensionBoardEnum.ExtIO_1:
                        break;
                    case ExtensionBoardEnum.ExtEC3216_1:
                    case ExtensionBoardEnum.ExtEC3224_1:
                    case ExtensionBoardEnum.ExtEC3416_1:
                        cardCount = 2;
                        break;
                }
                // 解析结果
                for (var index = 0; index < 16; index++)
                //for (int index = 16 * station; index < 16 * (station + 1); index++)
                {
                    IOItem inItem = new IOItem()
                    {
                        IOIndex = index + (station * 16),
                        IOValue = (inValue & (1 << index)) == 0 ? IOValue.TRUE : IOValue.FALSE,
                        IOType = IOType.INPUT
                    };
                    IOItem outItem = new IOItem()
                    {
                        IOIndex = index + (station * 16),
                        IOValue = (outValue & (1 << index)) == 0 ? IOValue.TRUE : IOValue.FALSE,
                        IOType = IOType.OUTPUT
                    };
                    result.Add(inItem);
                    result.Add(outItem);
                }
            }


            return result;
        }


        private void MonitorPosition()
        {
            Task.Run(() =>
            {
                Thread.CurrentThread.Priority = ThreadPriority.Highest;
                while (isconnected)
                {
                    try
                    {
                        if (!IsEnableMonitor)
                        {
                            return;
                        }

                        Parallel.ForEach(AxisStatusList, a =>
                        {
                            if (a.IsMonitorPosition)
                            {
                                int prfPosition = GetPrfPosition(a.AxisIndex);
                                int curPosition = GetCurPosition(a.AxisIndex);
                                a.PrfPosition = prfPosition;

                                if (a.CurPosition != curPosition)
                                {
                                    a.CurPosition = curPosition;
                                    AxisPositionChangedAsync(a.AxisIndex, curPosition);
                                }
                            }
                        });
                    }
                    catch (Exception ex)
                    {
                        //if (CurrentState == DeviceState.DSOpen)
                        //{
                        //    LogAsync(DateTime.Now, LogLevel.Exception, $"{Name}监听轴信息异常{ex.GetExceptionMessage()}");
                        //}
                    }
                }
            });
        }
        public void AxisPositionChangedAsync(int axisIndex, int currentPosition)
        {
            //OnAxisPositionChanged?.Invoke(axisIndex, currentPosition);
        }

        private void MonitorAxisStatus()
        {
            Task.Run(() =>
            {
                while (isconnected)
                {
                    try
                    {
                        if (!IsEnableMonitor)
                            return;

                        AxisStatusList.ForEach(axis =>
                        {
                            if (!axis.IsMonitorStatus)
                            {
                                return;
                            }

                            double prfVel = 0;
                            double curVel = 0;
                            GetVelocity(axis.AxisIndex, ref prfVel, ref curVel);

                            axis.PrfVelocity = prfVel;
                            axis.CurVelocity = curVel;

                            // int status = GetAxisStatus(axis.AxisIndex);
                            //if (axis.AxisStatus != status)
                            //{
                            //    int temp = axis.AxisStatus;
                            //    axis.AxisStatus = status;

                            //    LogAsync(DateTime.Now, LogLevel.Exception, $"{Name}监听轴信息MonitorAxisStatus:{status}");

                            //    AxisAlarmCheckAsync(axis.AxisIndex, temp, status);
                            //    AxisStatusChanged(axis.AxisIndex, temp, status);
                            //}

                            AxisMovingStatus status = GetAxisStatus2(axis.AxisIndex);

                            axis.Alarm = status.Alarm;
                            axis.Enable = status.Enable;
                            axis.PositiveLimit = status.PositiveLimit;
                            axis.NegativeLimit = status.NegativeLimit;


                            if (axis.AxisStatus != status.AxisStatus)
                            {
                                int temp = axis.AxisStatus;
                                axis.AxisStatus = status.AxisStatus;

                                AxisAlarmCheckAsync(axis.AxisIndex, temp, status.AxisStatus);
                                AxisStatusChanged(axis.AxisIndex, temp, status.AxisStatus);
                            }


                        });
                    }
                    catch (Exception ex)
                    {
                        //if (CurrentState == DeviceState.DSOpen)
                        //{
                        //    // LogAsync(DateTime.Now, LogLevel.Exception, $"{Name}监听轴信息异常{ex.GetExceptionMessage()}");
                        //}
                    }
                }
            });
        }
        public void AxisStatusChanged(int axisIndex, int preStatus, int curStatus)
        {
            //OnAxisStatusChanged?.BeginInvoke(axisIndex, preStatus, curStatus, null, null);
        }
        private void AxisAlarmCheckAsync(int axisIndex, int temp, int curStatus)
        {
            ////TODO: 2022/10/22 13:00 暂时屏蔽报警
            return;

            if (curStatus >= 14 && curStatus <= 21)
            {
                #region 正负极限
                if (!_axisAlarmRaisedFlag[axisIndex])
                {
                    _axisLimitTimer[axisIndex].Change(3000, -1);
                }
                #endregion
            }
            else if (curStatus == 22 || curStatus == 23)
            {
                if (!_axisAlarmRaisedFlag[axisIndex])
                {
                    _axisLimitTimer[axisIndex].Change(3000, -1);
                }
            }
            else
            {
                _axisLimitTimer[axisIndex].Change(-1, -1);
                // 极限报警 可以自动清除
                if (_axisAlarmRaisedFlag[axisIndex])
                {
                    AxisAlarmRaised(axisIndex, $"轴{axisIndex}在 正极限", false);
                    AxisAlarmRaised(axisIndex, $"轴{axisIndex}在 负极限", false);
                }

                bool flag = false;
                string msg = "";
                if (((curStatus >> 1) & 1) == 1)
                {
                    #region 轴报警
                    if (!_axisAlarmRaisedFlag[axisIndex])
                    {
                        flag = true;
                        msg = $"轴{axisIndex}伺服报警";
                    }
                    #endregion
                }
                else if (((curStatus >> 8) & 1) == 1)
                {
                    #region 轴急停
                    if (!_axisAlarmRaisedFlag[axisIndex])
                    {
                        flag = true;
                        msg = $"轴{axisIndex}急停报警";
                    }
                    #endregion
                }
                if (flag)
                {
                    //伺服报警 无法自动清除
                    AxisAlarmRaised(axisIndex, msg, flag);
                }
            }
        }

        private static readonly object ioLock = new object();


        public  void Monitor()
        {
            //SpinWait _monitorWait = new SpinWait();
            if (!IsEnableMonitor)
                return;

            Task.Run(() =>
            {
                //Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
                Thread.CurrentThread.Priority = ThreadPriority.Highest;

                while (isconnected)
                {
                    try
                    {
                        var newValues = GetMonitorValues();

                        //if (CurrentState == DeviceState.DSClose || CurrentState == DeviceState.DSExcept || CurrentState == DeviceState.DSUninit)
                        //{
                        //    break;
                        //}


                        if (newValues == null || newValues.Count == 0)
                            continue;

                        if (CurrentIOs.Count == newValues.Count)
                        {
                            //if (IConfig.IsEnableMonitor)
                            //{
                            var tempNew = new List<IOItem>(newValues);//clone
                            var tempOld = new List<IOItem>(CurrentIOs);
                            MonitorCheckAndInvoke(tempNew, tempOld);
                            //}

                        }
                        CurrentIOs = new List<IOItem>(newValues);

                        if (MonitorInterval > 0)
                        {
                            Task.Delay(MonitorInterval).Wait();
                        }
                    }
                    catch (Exception ex)
                    {
                        //if (CurrentState == DeviceState.DSOpen)
                        //{
                        //    LogAsync(DateTime.Now, LogLevel.Exception, $"{Name}监听IO异常{ex.GetExceptionMessage()}");
                        //}
                    }
                }
            });
        }



        public  void OnMethodInvoked(IAsyncResult ar)
        {
            //MotionCardMonitorSet monitorSet = ar.AsyncState as MotionCardMonitorSet;
            //ProcessResponse resValues = monitorSet.Response;
            //if (resValues.ResultValue == (int)ReplyValue.IGNORE)
            //{
            //    return;
            //}

            //Stopwatch sw = new Stopwatch();
            //sw.Start();
            //// 将指定IOItem写入板卡
            //foreach (var replyIOData in monitorSet.ReplyIODatas)
            //{
            //    //写入IO输出
            //    if (replyIOData.IOType == IOType.OUTPUT)
            //    {
            //        GTSCardAPI.GT_SetDoBit((short)IConfig.CardNum, GTSCardAPI.MC_GPI, (short)replyIOData.IONum, (short)replyIOData.Value);
            //    }
            //    // in只读不能写
            //}
            //sw.Stop();
            //LogAsync(DateTime.Now, $"{Name}反馈完成,耗时{sw.ElapsedMilliseconds}ms", $"{resValues.GetDisplayText()}");
        }

        protected async void MonitorCheckAndInvoke(List<IOItem> tempNew, List<IOItem> tempOld)
        {
            //await Task.Run(() =>
            //{
            //    Thread.CurrentThread.Priority = ThreadPriority.Highest;
            //    #region 警报信息
            //    WarningSetCollection.ForEach(wSet =>
            //    {
            //        IOWarningSet warningSet = wSet as IOWarningSet;

            //        var temp = tempNew.FirstOrDefault(u => u.IOIndex == warningSet.TriggerIndex && u.IOType == warningSet.IOType);
            //        if (temp != null)
            //        {
            //            bool isOn = ((int)temp.IOValue == (warningSet.TriggerValue ? 1 : 0));
            //            if (warningSet.CurrentStatus != isOn)
            //            {
            //                warningSet.CurrentStatus = isOn;
            //                warningSet.TriggerTime = DateTime.Now;
            //                SaveAlarmCSVAsync(DateTime.Now, this.Name, warningSet);
            //                ExcuteMonitorAlarm(DateTime.Now, this, warningSet);
            //            }
            //        }
            //    });
            //    #endregion

            //    #region 监听信息
            //    Parallel.ForEach(IConfig.MonitorSetCollection, mSet =>
            //   MonitorSetCollection.ForEach(mSet =>
            //    {
            //        IOMonitorSet monitorSet = mSet as IOMonitorSet;
            //        if (monitorSet.TriggerIndex < 0 || monitorSet.TriggerIndex > tempNew.Count)
            //        {
            //            return;
            //        }

            //        if (monitorSet.MethodCode.Equals("InitialAirAlarm"))
            //        {
            //            Console.WriteLine("");
            //        }


            //        if (!monitorSet.JumpEdgeMonitor)
            //        {
            //            var newIOItem = tempNew.FirstOrDefault(u => u.IOIndex == monitorSet.TriggerIndex && u.IOType == monitorSet.IOType);

            //            if (monitorSet.TriggerValue == -999 || (int)newIOItem.IOValue == monitorSet.TriggerValue)
            //            {
            //                if (monitorSet.OpConfig == null)
            //                {
            //                    monitorSet.OpConfig = new OperationConfigBase();
            //                }

            //                monitorSet.OpConfig.TriggerValue = (int)newIOItem.IOValue;

            //                ExcuteMonitorInvoke(DateTime.Now, monitorSet.ExecuteDevice, this, monitorSet);
            //            }

            //        }
            //        else
            //        {
            //            var newIOItem = tempNew.FirstOrDefault(u => u.IOIndex == monitorSet.TriggerIndex && u.IOType == monitorSet.IOType);
            //            var oldIOItem = tempOld.FirstOrDefault(u => u.IOIndex == monitorSet.TriggerIndex && u.IOType == monitorSet.IOType);

            //            if (newIOItem?.IOValue != oldIOItem?.IOValue)
            //            {
            //                if (monitorSet.TriggerValue == -999 || (int)newIOItem.IOValue == monitorSet.TriggerValue)
            //                {
            //                    if (monitorSet.OpConfig == null)
            //                    {
            //                        monitorSet.OpConfig = new OperationConfigBase();
            //                    }

            //                    monitorSet.OpConfig.InputPara = monitorSet.InputDataIndex.ConvertAll(index =>
            //                    {
            //                        return tempNew[index].Value == IOValue.TRUE ? 1 : 0;
            //                    }).ToList();

            //                    monitorSet.OpConfig.TriggerValue = (int)newIOItem.IOValue;
            //                    monitorSet.OpConfig.InputPara = new List<int>() { (int)newIOItem.IOValue };
            //                    LogAsync(DateTime.Now, $"newIOItem:{newIOItem.GetDisplayText()}", $"oldIOItem:{oldIOItem.GetDisplayText()}");
            //                    ExcuteMonitorInvoke(DateTime.Now, monitorSet.ExecuteDevice, this, monitorSet);
            //                }
            //            }
            //        }
            //    });
            //    #endregion
            //});
        }

        public  void ResetAlarm()
        {
            //int axis_sts;
            //var axisSettings = IConfig.AxisSettings.FindAll(u => u.IsAxisEnabled);

            //axisSettings.ForEach(axisSetting => ClearStatus(axisSetting.AxisIndex));

            //foreach (var axisSetting in axisSettings)
            //{
            //    ConvertFromAxis(axisSetting.AxisIndex, out ushort station, out ushort axis);

            //    axis_sts = AxisStatusList.FirstOrDefault(u => u.AxisIndex == axisSetting.AxisIndex)?.AxisStatus ?? 0;
            //    if ((axis_sts & 0x200) == 0) // 0010 0000 0000
            //    {
            //        // 关闭电机使能
            //        var rst = CMCDLL_NET.MCF_Set_Servo_Enable_Net(axis, (ushort)ServoLogic.Servo_Close, station);
            //    }

            //    // 正极限报警
            //    if ((axis_sts & 0x20) != 0)
            //    {
            //        // 负向移动
            //        MovingOption movingOption = new MovingOption();
            //        movingOption.AxisIndex = (short)axisSetting.AxisIndex;
            //        movingOption.Destination = -50; // 负向移动
            //        movingOption.VelocityPara.Velocity = 50;
            //        P2PMoveAbs(movingOption);
            //    }

            //    // 负极限报警
            //    if ((axis_sts & 0x40) != 0)
            //    {
            //        // 正向移动
            //        MovingOption movingOption = new MovingOption();
            //        movingOption.AxisIndex = (short)axisSetting.AxisIndex;
            //        movingOption.Destination = 50; // 正向移动
            //        movingOption.VelocityPara.Velocity = 50;
            //        P2PMoveAbs(movingOption);
            //    }
            //}

            //// 清除状态 
            //axisSettings.ForEach(axisSetting => ClearStatus(axisSetting.AxisIndex));

            //_axisAlarmRaisedFlag.Values.ToList().ForEach(u => u = false);
            //_axisLimitTimer.Values.ToList().ForEach(u => u.Change(-1, -1));
            //base.ResetAlarm();
        }

        public  bool SmartGoHome(ushort AxisIndex, GoHomePara goHomePara)
        {
            bool result = false;


            result = ClearStatus(AxisIndex);



            if (!result)
            {
                //LogAsync(DateTime.Now, LogLevel.Exception, "SmartGoHome清除状态异常-Before");
                return result;
            }
            result = PositionReset(AxisIndex, 1);
            if (!result)
            {
                //LogAsync(DateTime.Now, LogLevel.Exception, "SmartGoHome清除位置异常-Before");
                return result;
            }
            short sRtn;

            ConvertFromAxis(AxisIndex, out ushort station, out ushort axis);

            sRtn = CMCDLL_NET.MCF_Search_Home_Stop_Time_Net(axis, goHomePara.SearchHomeStopTime, station);
            sRtn = CMCDLL_NET.MCF_Search_Home_Set_Net(axis,
                (ushort)goHomePara.HomeMode,
                (ushort)goHomePara.LimitLogic,
                (ushort)goHomePara.HomeLogic,
                (ushort)goHomePara.IndexLogic,
                goHomePara.H_dMaxV, goHomePara.L_dMaxV,
                goHomePara.OffsetPosition,
                (ushort)goHomePara.TriggerSource,
                station);
            sRtn = CMCDLL_NET.MCF_Search_Home_Start_Net(axis, station);


            Console.WriteLine($">>>> {AxisIndex}\t{goHomePara.SearchHomeStopTime}");
            Console.WriteLine($">>>> {AxisIndex}\t" +
                $"{(ushort)goHomePara.HomeMode}\t" +
                $"{(ushort)goHomePara.LimitLogic}\t" +
                $"{(ushort)goHomePara.HomeLogic}\t" +
                $"{(ushort)goHomePara.IndexLogic}\t" +
                $"{goHomePara.H_dMaxV}\t" +
                $"{goHomePara.L_dMaxV}\t" +
                $"{goHomePara.OffsetPosition}\t" +
                $"{(ushort)goHomePara.TriggerSource}");

            //var rtn = CMCDLL_NET.MCF_Search_Home_Stop_Time_Net(1, 0, 0);
            //rtn = CMCDLL_NET.MCF_Search_Home_Set_Net(1, 30, 0, 0, 0, 10000, 3000, 0, 0, 0);
            //rtn = CMCDLL_NET.MCF_Search_Home_Start_Net(1, 0);


            int timeout = goHomePara.GoHomeTimeOut * 1000;

            ushort homeState = 1;
            do
            {
                sRtn = CMCDLL_NET.MCF_Search_Home_Get_State_Net(axis, ref homeState, station);

                Task.Delay(MonitorInterval).Wait();
                timeout -= MonitorInterval;
            } while (homeState != (short)SearchHomeState.HomeSucess && timeout > 0);//100表示回原点完成

            if (timeout < 0)
            {
                //LogAsync(DateTime.Now, LogLevel.Exception, $"轴号:{AxisIndex}-SmartGoHome超时");
                return false;
            }

            timeout = goHomePara.GoHomeTimeOut * 1000;
            result = ClearStatus(AxisIndex);
            do
            {
                Task.Delay(20).Wait();
                result = ClearStatus(AxisIndex);
                timeout -= 20;
            } while (!result && timeout > 0);
            if (timeout < 0)
            {
                //LogAsync(DateTime.Now, LogLevel.Exception, $"轴号:{AxisIndex}-SmartGoHome:ClearStatus超时");
                return false;
            }

            timeout = goHomePara.GoHomeTimeOut * 1000;
            result = PositionReset(AxisIndex, 1);
            do
            {
                Task.Delay(20).Wait();
                result = PositionReset(AxisIndex, 1);
                timeout -= 20;
            } while (!result && timeout > 0);
            if (timeout < 0)
            {
                //LogAsync(DateTime.Now, LogLevel.Exception, $"轴号:{AxisIndex}-SmartGoHome:PositionReset超时");
                return false;
            }

            return result;
        }

        public  bool SmartGetHomeStatus(ushort AxisIndex, GoHomeStatus homeStatus)
        {
            ConvertFromAxis(AxisIndex, out ushort station, out ushort axis);

            ushort homeState = (ushort)SearchHomeState.Homing;
            CMCDLL_NET.MCF_Search_Home_Get_State_Net(axis, ref homeState, station);
            homeStatus.Status = homeState;

            return true;
        }
        #endregion

        public  bool SetDac(short channel, short sValue)
        {
            short ret = 0;
            return ret == (short)FuncRet.Function_Success;
        }

        public  short GetDac(short channel)
        {
            short resultValue = 0;
            //short ret = MotionCardAPI.GT_GetDac((short)IConfig.CardOrCoreNum, channel, out short value, 1, out uint pLock);
            //if (ret != RetCode.Function_Success)
            //{
            //    LogAsync(DateTime.Now, LogLevel.Exception, "通道" + channel + "读取模拟量输出异常,错误码:" + ret + ";");
            //}
            //short resultValue = (short)((value - 3200) / 50);
            return resultValue;
        }

        public  double GetAdc(short channel)
        {
            var resultValue = 0f;
            //short ret = MotionCardAPI.GT_GetAdc((short)IConfig.CardOrCoreNum, channel, out double resultValue, 1, out uint pLock);
            //if (ret != RetCode.Function_Success)
            //{
            //    LogAsync(DateTime.Now, LogLevel.Exception, "通道" + channel + "读取模拟量输入异常,错误码:" + ret + ";");
            //}
            return resultValue;
        }

        public  short GetAdcValue(short channel)
        {
            short resultValue = 0;
            //short ret = MotionCardAPI.GT_GetAdcValue((short)IConfig.CardOrCoreNum, channel, out short resultValue, 1, out uint pLock);
            //if (ret != RetCode.Function_Success)
            //{
            //    LogAsync(DateTime.Now, LogLevel.Exception, "通道" + channel + "读取模拟量输入数字转换值异常, 错误码:" + ret + ";");
            //}
            return resultValue;
        }


        /// <summary>
        /// 吹气
        /// </summary>
        /// <param name="pieceNumber"></param>
        /// <param name="blowType"></param>
        /// <returns></returns>
        public void Blow(uint pieceNumber, BlowType blowType)
        {
            var bSetting = BlowSettings.FirstOrDefault(b => b.IsEnabled && b.BlowType == blowType);
            if (bSetting == null)
            {
                return;
            }

            // 板卡1队列及时处理
            switch (blowType)
            {
                case BlowType.OK:
                    CMCDLL_NET_Sorting.MCF_Sorting_Set_Trig_Blow_OK_Net(pieceNumber, bSetting.StationNumber);
                    break;
                case BlowType.NG:
                    CMCDLL_NET_Sorting.MCF_Sorting_Set_Trig_Blow_NG_Net(pieceNumber, bSetting.StationNumber);
                    break;

                default:
                    CMCDLL_NET_Sorting.MCF_Sorting_Set_Trig_Blow_Net((ushort)blowType, pieceNumber, bSetting.StationNumber);
                    break;

            }
        }


        ///// <summary>
        ///// 吹气
        ///// </summary>
        ///// <param name="pieceNumber"></param>
        ///// <param name="blowType"></param>
        ///// <returns></returns>
        //public override void Blow(uint pieceNumber, ushort index)
        //{
        //    //var bSetting = IIConfig.BlowSettings.FirstOrDefault(b => b.IsEnabled && b.BlowType == blowType);
        //    //if (bSetting == null)
        //    //{
        //    //    return;
        //    //} 
        //    CMCDLL_NET_Sorting.MCF_Sorting_Set_Trig_Blow_Net(index, pieceNumber); 
        //}


    }



}