领胜LDS 键盘AOI检测项目
1. 板卡驱动实现运动暂停/继续功能,板卡动作衔接实现暂停/继续
2. 修复部分调试bug
3. 安全光幕/安全门功能调整
7个文件已修改
527 ■■■■■ 已修改文件
src/Bro.Common.Device/DeviceBase/MotionCardBase.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.Device.GTSCard/GTSCardDriver.cs 204 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.Device.Gocator/GocatorDriver.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.DBManager/ExcelExportHelper.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/M071Process.cs 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/M071Process_MotionCard.cs 271 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.UI.Config/MainFrm.cs 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.Common.Device/DeviceBase/MotionCardBase.cs
@@ -131,7 +131,7 @@
        /// <summary>
        /// 恢复立即暂停
        /// </summary>
        public abstract void ResetImmediatePause();
        public abstract void ResetImmediatePause(bool isResumeMoving);
        #endregion
    }
src/Bro.Device.GTSCard/GTSCardDriver.cs
@@ -46,6 +46,8 @@
        /// 运动轴立即暂停
        /// </summary>
        Dictionary<int, ManualResetEvent> axisImmediatePauseHandleDict = new Dictionary<int, ManualResetEvent>();
        Dictionary<int, bool> axisImmediatePauseFlag = new Dictionary<int, bool>();
        Dictionary<int, bool> axisPauseResumeFlag = new Dictionary<int, bool>();
        //Dictionary<int, CancellationTokenSource> axisMoveCancelDict = new Dictionary<int, CancellationTokenSource>();
@@ -145,16 +147,22 @@
            {
                foreach (var preCheck in operationSet.PreCheckIOCollection)
                {
                    int timeout = operationSet.PreCheckIOTimeout;
                    _pauseHandle.Wait();
                    IOValue? ioData = null;
                    while (CurrentState == DeviceState.DSOpen)
                    if (CurrentState == DeviceState.DSOpen)
                    {
                        Thread.Sleep(10);
                        ioData = MonitorValues.FirstOrDefault(u => u.IONum == preCheck.IOItem.IONum && u.IOType == preCheck.IOItem.IOType)?.Value;//IO 是开、关 从MonitorValues 获取
                        timeout -= 10;
                        if (preCheck.CheckValue == ioData || (operationSet.PreCheckIOTimeout > 0 && timeout < 0))
                        int timeout = operationSet.PreCheckIOTimeout;
                        while (CurrentState == DeviceState.DSOpen)
                        {
                            break;
                            Thread.Sleep(10);
                            ioData = MonitorValues.FirstOrDefault(u => u.IONum == preCheck.IOItem.IONum && u.IOType == preCheck.IOItem.IOType)?.Value;//IO 是开、关 从MonitorValues 获取
                            timeout -= 10;
                            if (preCheck.CheckValue == ioData || (operationSet.PreCheckIOTimeout > 0 && timeout < 0))
                            {
                                break;
                            }
                        }
                    }
@@ -170,10 +178,15 @@
            // 2.板卡运动
            if (CurrentState == DeviceState.DSOpen)
            {
                responseMessage = MoveToPoint(new MotionOperationCollection() { MovingOps = operationSet.MovingOps });
                if (!responseMessage.Result)
                _pauseHandle.Wait();
                if (CurrentState == DeviceState.DSOpen)
                {
                    return responseMessage;
                    responseMessage = MoveToPoint(new MotionOperationCollection() { MovingOps = operationSet.MovingOps });
                    if (!responseMessage.Result)
                    {
                        return responseMessage;
                    }
                }
            }
@@ -181,18 +194,24 @@
            // 3.IO输出 不需要超时
            if (CurrentState == DeviceState.DSOpen)
            {
                foreach (var ioOutput in operationSet.IOOutputCollection)
                {
                    WriteOutput((short)ioOutput.IOItem.IONum, ioOutput.CheckValue);
                    _pauseHandle.Wait();
                    //var ioData = MonitorValues.FirstOrDefault(u => u.IONum == ioOutput.IOItem.IONum && u.IOType == ioOutput.IOItem.IOType)?.Value;//IO 是开、关 从MonitorValues 获取
                    if (CurrentState == DeviceState.DSOpen)
                    {
                        WriteOutput((short)ioOutput.IOItem.IONum, ioOutput.CheckValue);
                    //if (ioOutput.CheckValue != ioData)
                    //{
                    //    responseMessage.Result = false;
                    //    responseMessage.Message = $"IO输出不通过,配置:{ioOutput.GetDisplayText()},当前值:{ioData}";
                    //    return responseMessage;
                    //}
                        //var ioData = MonitorValues.FirstOrDefault(u => u.IONum == ioOutput.IOItem.IONum && u.IOType == ioOutput.IOItem.IOType)?.Value;//IO 是开、关 从MonitorValues 获取
                        //if (ioOutput.CheckValue != ioData)
                        //{
                        //    responseMessage.Result = false;
                        //    responseMessage.Message = $"IO输出不通过,配置:{ioOutput.GetDisplayText()},当前值:{ioData}";
                        //    return responseMessage;
                        //}
                    }
                }
            }
@@ -228,6 +247,8 @@
        #endregion
        #region ImmediatePause
        ManualResetEventSlim _pauseHandle = new ManualResetEventSlim(true);
        /// <summary>
        /// 启动立即暂停
        /// </summary>
@@ -236,12 +257,11 @@
            if (!_isResetting)
            {
                var immediatePauseAxis = IConfig.AxisSettings.FindAll(a => a.IsAxisEnabled && a.IsImmediatePause).Select(u => u.AxisIndex).ToList();
                _pauseHandle.Reset();
                immediatePauseAxis.ForEach(async axisIndex =>
                {
                    axisImmediatePauseHandleDict[axisIndex].Reset();
                    //axisMoveCancelDict[axisIndex].Cancel();
                    axisImmediatePauseFlag[axisIndex] = true;
                    await MoveStop(axisIndex, 0);//所有轴都暂停
                });
@@ -251,15 +271,22 @@
        /// <summary>
        /// 恢复立即暂停
        /// </summary>
        public override void ResetImmediatePause()
        public override void ResetImmediatePause(bool isResumeMoving)
        {
            var immediatePauseAxis = IConfig.AxisSettings.FindAll(a => a.IsAxisEnabled && a.IsImmediatePause).Select(u => u.AxisIndex).ToList();
            _pauseHandle.Set();
            immediatePauseAxis.ForEach(axisIndex =>
            {
                //axisMoveCancelDict[axisIndex] = new CancellationTokenSource();
                axisImmediatePauseFlag[axisIndex] = false;
                axisImmediatePauseHandleDict[axisIndex].Set();
                if (isResumeMoving)
                {
                    axisPauseResumeFlag[axisIndex] = true;
                }
                else
                {
                    axisPauseResumeFlag[axisIndex] = false;
                }
            });
        }
        #endregion
@@ -347,19 +374,11 @@
            ResponseMessage responseMessage = new ResponseMessage();
            if (opConfig is MotionOperationCollection gtsOperationCollection)
            {
                //List<Task<bool>> taskList = new List<Task<bool>>();
                //foreach (var movingOp in gtsOperationCollection.MovingOps)
                //{
                //    var task = SingleAxisMoving(movingOp);
                //    taskList.Add(task);
                //    task.Start();
                //}
                //Task.WaitAll(taskList.ToArray());
                //responseMessage.Result = taskList.All(u => u.GetAwaiter().GetResult());
                List<bool> resultList = new List<bool>();
                Parallel.ForEach(gtsOperationCollection.MovingOps, movingOp =>
                {
                    axisImmediatePauseFlag[movingOp.AxisIndex] = false;
                    axisPauseResumeFlag[movingOp.AxisIndex] = true;
                    resultList.Add(SingleAxisMoving(movingOp).Result);
                });
                responseMessage.Result = resultList.All(u => u == true);
@@ -418,63 +437,64 @@
        public override Task<bool> SingleAxisMoving(MovingOption optionPara)
        {
            return Task.Run(() =>
             {
                 axisImmediatePauseHandleDict[optionPara.AxisIndex].WaitOne();
                 bool isSuccessAndStop = false;
                 try
                 {
                     if (IConfig.AxisSettings.FirstOrDefault(a => a.AxisIndex == optionPara.AxisIndex)?.IsAxisEnabled ?? false)
                     {
                         // string _position = "";
                         string motionType = optionPara.MoveMode == EnumHelper.MotionMode.Normal ? (optionPara.IsAbsolute ? "Abs" : "Rel") : optionPara.MoveMode.ToString();
            {
                bool isSuccessAndStop = false;
                do
                {
                    axisImmediatePauseHandleDict[optionPara.AxisIndex].WaitOne();
                         // _position = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff},{optionPara.AxisIndex},{motionType},{GetPosition(optionPara.AxisIndex)},{GetPrfPosition(optionPara.AxisIndex)},{optionPara.Destination},";
                    if (!axisPauseResumeFlag[optionPara.AxisIndex])
                        return true;
                         switch (optionPara.MoveMode)
                         {
                             case MotionMode.Normal:
                                 {
                                     if (_isResetting)
                                     {
                                         LogAsync(DateTime.Now, "复位中启动运动异常", optionPara.AxisIndex + "启动运动异常");
                                         return false;
                                     }
                    try
                    {
                        if (IConfig.AxisSettings.FirstOrDefault(a => a.AxisIndex == optionPara.AxisIndex)?.IsAxisEnabled ?? false)
                        {
                            string motionType = optionPara.MoveMode == EnumHelper.MotionMode.Normal ? (optionPara.IsAbsolute ? "Abs" : "Rel") : optionPara.MoveMode.ToString();
                                     if (optionPara.IsAbsolute)
                                     {
                                         isSuccessAndStop = P2PMoveAbs(optionPara);
                                     }
                                     else
                                     {
                                         isSuccessAndStop = P2PMoveRel(optionPara);
                                     }
                            switch (optionPara.MoveMode)
                            {
                                case MotionMode.Normal:
                                    {
                                        if (_isResetting)
                                        {
                                            LogAsync(DateTime.Now, "复位中启动运动异常", optionPara.AxisIndex + "启动运动异常");
                                            return false;
                                        }
                                 }
                                 break;
                             case MotionMode.FindOri:
                                 {
                                     //isSuccessAndStop = GoHome(optionPara);
                                     isSuccessAndStop = P2PGoHome(optionPara);
                                 }
                                 break;
                             case MotionMode.Jog:
                                 {
                                     isSuccessAndStop = JogMove(optionPara);
                                 }
                                 break;
                         }
                         //_position += $"{GetPosition(optionPara.AxisIndex)},";
                         //_position += $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}";
                         //LogAsync(DateTime.Now, "", _position);
                     }
                 }
                 catch (Exception ex)
                 {
                     isSuccessAndStop = false;
                     LogAsync(DateTime.Now, $"轴{optionPara.AxisIndex}运动异常", ex.GetExceptionMessage());
                 }
                 return isSuccessAndStop;
             });
                                        if (optionPara.IsAbsolute)
                                        {
                                            isSuccessAndStop = P2PMoveAbs(optionPara);
                                        }
                                        //else
                                        //{
                                        //    isSuccessAndStop = P2PMoveRel(optionPara);
                                        //}
                                    }
                                    break;
                                case MotionMode.FindOri:
                                    {
                                        //isSuccessAndStop = GoHome(optionPara);
                                        isSuccessAndStop = P2PGoHome(optionPara);
                                    }
                                    break;
                                case MotionMode.Jog:
                                    {
                                        isSuccessAndStop = JogMove(optionPara);
                                    }
                                    break;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        isSuccessAndStop = false;
                        LogAsync(DateTime.Now, $"轴{optionPara.AxisIndex}运动异常", ex.GetExceptionMessage());
                    }
                } while (axisImmediatePauseFlag[optionPara.AxisIndex]);
                return isSuccessAndStop;
            });
        }
        /// <summary>
@@ -1282,10 +1302,16 @@
            int axis_sts;
            var axisSettings = IConfig.AxisSettings.FindAll(u => u.IsAxisEnabled);
            ClearStatus(1, axisSettings.Count);
            if (AxisStatusList.Count == 0)
            {
                Thread.Sleep(10);
            }
            foreach (var axisSetting in axisSettings)
            {
                //axis_sts = GetAxisStatus((short)axisSetting.AxisIndex);
                axis_sts = AxisStatusList.FirstOrDefault(u => u.AxisIndex == axisSetting.AxisIndex).AxisStatus;
                axis_sts = AxisStatusList.FirstOrDefault(u => u.AxisIndex == axisSetting.AxisIndex)?.AxisStatus ?? 0;
                if ((axis_sts & 0x200) == 0)
                {
                    var rst = GTSCardAPI.GT_AxisOn((short)IConfig.CardNum, (short)axisSetting.AxisIndex);
src/Bro.Device.Gocator/GocatorDriver.cs
@@ -110,8 +110,6 @@
                            {
                                imgSet.HImage = new HImage();
                                imgSet.HImage.GenImage1("uint2", (int)width, zoomHeight, zoomPtr);
                                //imgSet.HImage = imgSet.HImage.ZoomImageSize((int)width, zoomHeight, "constant");
                                imgSet.HImage_2 = new HImage();
                                imgSet.HImage_2.GenImage1("uint2", (int)width, zoomHeight, zoomPtr);
src/Bro.M071.DBManager/ExcelExportHelper.cs
@@ -107,7 +107,7 @@
                    {
                        // autofit width of cells with small content 
                        ExcelRange columnCells = workSheet.Cells[workSheet.Dimension.Start.Row, columnIndex, workSheet.Dimension.End.Row, columnIndex];
                        int maxLength = columnCells.Max(cell => cell.Value.ToString().Count());
                        int maxLength = columnCells.Max(cell => (cell.Value ?? "").ToString().Count());
                        if (maxLength < 150)
                        {
                            workSheet.Column(columnIndex).AutoFit();
@@ -258,7 +258,7 @@
        {
            try
            {
                return obj.ToString();
                return (obj ?? "").ToString();
            }
            catch (Exception)
            {
src/Bro.M071.Process/M071Process.cs
@@ -61,7 +61,6 @@
            Reset(null, null, null);
            FullReset(null);
        }
        private void InitialMotionCardBaseAxisAlarm()
@@ -82,7 +81,7 @@
        private void InitialSetting()
        {
            //数据库迁移检查
            DatabaseInitialize.Initialize();
            //DatabaseInitialize.Initialize();
            MotionCardSettingCheck();
@@ -196,7 +195,7 @@
            }
            MachineState = MachineState.Running;
            OnMeasureStart?.BeginInvoke(null, null);
            OnMeasureStart?.Invoke();
            var measurements = Config.MeasurementUnitCollection.Where(u => u.IsEnabled).ToList().DeepSerializeClone();
            measurements.ForEach(m =>
@@ -226,9 +225,12 @@
            Config.SnapshotPointCollection.Where(u => u.IsEnabled).ToList().ForEach(s =>
                  {
                      _pauseHandle.WaitHandle.WaitOne();
                      _pausedHandle.Wait();
                      if (MachineState != MachineState.Running)
                      if (MachineState == MachineState.Ready)
                          return;
                      if (MachineState != MachineState.Running && MachineState != MachineState.Pause)
                      {
                          throw new ProcessException("机台状态不在运行中,退出检测");
                      }
@@ -336,10 +338,14 @@
        {
            if (sender is ProductionMeasurement pMeasure)
            {
                lock (pMeasure)
                var production = productionList.FirstOrDefault(u => u.Barcode == pMeasure.Barcode);
                if (production == null)
                    return;
                lock (production)
                {
                    //检查是否全部完成
                    pMeasure.Measurements.ForEach(m =>
                    pMeasure.Measurements?.ForEach(m =>
                    {
                        if (m.KeyUnitCollection.All(k => k.IsDone != null))
                        {
@@ -381,7 +387,7 @@
                                indicator.ResultState = m.Spec.MeasureResult;
                                pMeasure.ElementList.Add(indicator);
                                //输出图形基元到界面 
                                OnElementUpdated?.BeginInvoke(indicator, null, null);
                                OnElementUpdated?.Invoke(indicator);
                                SaveKeyImages(pMeasure.Barcode, m);
@@ -494,7 +500,7 @@
                    MeasurementUnitResult measurementUnitResult = new MeasurementUnitResult();
                    measurementUnitResult.ProductionMeasurementRecordsId = productionMeasurementRecords.ID;
                    measurementUnitResult.ProductionBarcode = productionMeasurementRecords.ProductionBarcode;
                    measurementUnitResult.MeasurementName = measurementUnit.Name;
                    measurementUnitResult.MeasurementName = measurementUnit.GetDisplayText();
                    measurementUnitResult.MeasurementType = measurementUnit.MeasureType;
                    measurementUnitResult.MeasurementValue = measurementUnit.Spec.ActualValue.ToString();
                    measurementUnitResult.MeasurementResult = measurementUnit.Spec.MeasureResult.Value ? "OK" : "NG";
@@ -723,14 +729,14 @@
                          });
                 }
                 string dir = Path.Combine(Config.ImageSaveFolder, "Clips", $"{snapshotName}_{DateTime.Now.ToString("HHmmss")}");
                 string dir = Path.Combine(Config.ImageSaveFolder, "Clips", $"{DateTime.Now.ToString("yyyyMMdd")}", $"{snapshotName}_{DateTime.Now.ToString("HHmmss")}");
                 if (!Directory.Exists(dir))
                 {
                     Directory.CreateDirectory(dir);
                 }
                 Parallel.For(1, count.I + 1, (i) =>
                 //for (int i = 1; i <= count.I; i++)
                 //Parallel.For(1, count.I + 1, (i) =>
                 for (int i = 1; i <= count.I; i++)
                 {
                     HOperatorSet.SelectObj(images, out HObject image, i);
@@ -762,10 +768,11 @@
                                     var results = _halconToolDict[keyToolKey].GetResultTuple("OUTPUT_Results").HTupleToDouble();
                                     if (results.Count == 0 || results.Any(u => u < 0))
                                     {
                                         LogAsync(DateTime.Now, $"{k.AliasName}检测结果异常", "");
                                         LogAsync(DateTime.Now, $"{k.AliasName}原始数据异常", "");
                                     }
                                     else
                                     {
                                         LogAsync(DateTime.Now, $"{k.AliasName}原始数据", $"{string.Join(" ", results)}");
                                         resultDict = k.KeyResultList.ToDictionary(u => u, u =>
                                              {
                                                  int index = k.KeyResultList.IndexOf(u);
@@ -784,7 +791,7 @@
                     //image.Dispose();
                 }
                 );
                 //);
                 //if (count.I != 1)
                 //{
src/Bro.M071.Process/M071Process_MotionCard.cs
@@ -20,6 +20,7 @@
        const int FULLRESETTIME = 5;
        object machineStateLock = new object();
        //MachineState _machineStatePre = MachineState.Unknown;
        MachineState machineState = MachineState.Unknown;
        public MachineState MachineState
        {
@@ -28,6 +29,8 @@
            {
                if (machineState == value)
                    return;
                //_machineStatePre = machineState;
                machineState = value;
@@ -124,7 +127,36 @@
                }
                OnMachineStateChanged?.Invoke(machineState);
                //if (_machineStatePre == MachineState.Running && machineState == MachineState.Pause)
                //{
                //    Pause();
                //}
                //else if (_machineStatePre == MachineState.Pause && (machineState == MachineState.Running || machineState == MachineState.Ready))
                //{
                //    Resume();
                //}
            }
        }
        private void Pause()
        {
            #region 板卡暂停动作
            outputCtrlCard.SetImmediatePause();
            #endregion
            //_pauseHandle.WaitHandle.Reset();
            //_pauseHandle.WaitResult = true;
        }
        private void Resume(bool isResumeContinueMoving)
        {
            #region 板卡恢复动作
            outputCtrlCard.ResetImmediatePause(isResumeContinueMoving);
            #endregion
            //_pauseHandle.WaitHandle.Set();
            //_pauseHandle.WaitResult = false;
        }
        private void MotionCardSettingCheck()
@@ -203,24 +235,6 @@
        [ProcessMethod("MotionCardBase", "Reset", "简单复位操作", InvokeType.TestInvoke)]
        public ProcessResponse Reset(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice)
        {
            //if (opConfig == null)
            //{
            //    var monitorSet = Config.MonitorSetCollection.FirstOrDefault(u => u.MethodCode == "Reset");
            //    if (monitorSet == null)
            //        throw new ProcessException("未配置默认复位操作");
            //    opConfig = monitorSet.OpConfig;
            //    if (opConfig == null)
            //        throw new ProcessException("未配置复位操作具体配置动作");
            //    if (invokeDevice == null)
            //    {
            //        invokeDevice = DeviceCollection.FirstOrDefault(u => u.Id == monitorSet.InvokeDevice);
            //        if (invokeDevice == null)
            //            throw new ProcessException("未配置复位操作执行设备");
            //    }
            //}
            if (ResetTimer == null)
            {
                ResetTimer = new Timer(FullReset, null, -1, -1);
@@ -245,26 +259,23 @@
            (invokeDevice as MotionCardBase).ResetAlarm();
            RaisedAlarm("");
            MachineState = MachineState.Ready;
            if (MachineState != MachineState.Pause)
            {
                MachineState = MachineState.Ready;
            }
            else
            {
                LogAsync(DateTime.Now, "设备暂停中,无法复位", "");
                return new ProcessResponse(true);
            }
            if (IsEmergencyStopped)
            {
                RaisedAlarm("急停按钮未恢复,请执行大复位");
                MachineState = MachineState.Alarm;
                return new ProcessResponse(true);
            }
            //if (opConfig.InputPara?.Count > 0)
            //{
            //    //大复位信号
            //    ResetTimer.Change(-1, opConfig.InputPara[0] == 1 ? FULLRESETTIME * 1000 : -1);
            //}
            //if (invokeDevice is MotionCardBase motionCard)
            //{
            //    motionCard.Run(opConfig);
            //}
            LogAsync(DateTime.Now, "普通复位动作完成", "");
@@ -287,28 +298,16 @@
        [ProcessMethod("MotionCardBase", "FullReset", "大复位操作", InvokeType.TestInvoke)]
        public ProcessResponse FullReset(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice)
        {
            //if (opConfig == null)
            //{
            //    var monitorSet = Config.MonitorSetCollection.FirstOrDefault(u => u.MethodCode == "FullReset");
            //    if (monitorSet == null)
            //        throw new ProcessException("未配置默认大复位操作");
            if (!IsAllowedWork)
            {
                LogAsync(DateTime.Now, $"{SafetyMsg},大复位失败", "");
                return new ProcessResponse(false);
            }
            //    opConfig = monitorSet.OpConfig;
            //    if (opConfig == null)
            //        throw new ProcessException("未配置大复位操作具体配置动作");
            //    if (invokeDevice == null)
            //    {
            //        invokeDevice = DeviceCollection.FirstOrDefault(u => u.Id == monitorSet.InvokeDevice);
            //        if (invokeDevice == null)
            //            throw new ProcessException("未配置大复位操作执行设备");
            //    }
            //}
            //if (invokeDevice is MotionCardBase motionCard)
            //{
            //    motionCard.Run(opConfig);
            //}
            if (MachineState == MachineState.Pause)
            {
                Resume(false);
            }
            MachineState = MachineState.Resetting;
            MotionCardDefaultRun("FullReset", ref opConfig, ref invokeDevice);
@@ -335,12 +334,12 @@
        /// WaitHandle 暂停句柄  默认为非阻塞 可执行
        /// WaitResult 暂停标志 true 正常执行  false 暂停中
        /// </summary>
        ManualWaitConfirm _pauseHandle = new ManualWaitConfirm()
        {
            WaitHandle = new ManualResetEvent(true),
            WaitResult = true,
        };
        MachineState _machineStateBeforePause = MachineState.Unknown;
        //ManualWaitConfirm _pauseHandle = new ManualWaitConfirm()
        //{
        //    WaitHandle = new ManualResetEvent(true),
        //    WaitResult = true,
        //};
        List<MachineState> _statesAllowPause = new List<MachineState>() { MachineState.Running, MachineState.Ready, MachineState.Pause };
        [ProcessMethod("", "SwitchJobStatus", "流程状态切换", InvokeType.TestInvoke)]
        public ProcessResponse SwitchJobStatus(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice)
@@ -358,10 +357,7 @@
                throw new ProcessException("未获取板卡设备");
            bool? isToPause = null; //true 暂停 false 继续
            //if (opConfig.InputPara != null && opConfig.InputPara.Count > 0)
            //{
            //    isToPause = opConfig.InputPara[0] == 1;
            //}
            if (opConfig.InputPara[0] == 10)
            {
                isToPause = false;
@@ -373,59 +369,41 @@
            if (isToPause == null)
            {
                if (!_pauseHandle.WaitResult)
                {
                    #region 板卡暂停动作
                    motionDevice.SetImmediatePause();
                    #endregion
                    _pauseHandle.WaitHandle.Reset();
                    _pauseHandle.WaitResult = true;
                    _machineStateBeforePause = MachineState;
                    MachineState = MachineState.Pause;
                }
                else if (!_pauseHandle.WaitResult)
                {
                    #region 板卡恢复动作
                    motionDevice.ResetImmediatePause();
                    #endregion
                    _pauseHandle.WaitHandle.Set();
                    _pauseHandle.WaitResult = false;
                    MachineState = _machineStateBeforePause;
                }
                IsManualPaused = !IsManualPaused;
            }
            else
            {
                if (isToPause.Value)
                {
                    if (!_pauseHandle.WaitResult)
                    {
                        #region 板卡暂停动作
                        motionDevice.SetImmediatePause();
                        #endregion
                //if (isToPause.Value)
                //{
                //    if (!_pauseHandle.WaitResult)
                //    {
                //        //#region 板卡暂停动作
                //        //motionDevice.SetImmediatePause();
                //        //#endregion
                        _pauseHandle.WaitHandle.Reset();
                        _pauseHandle.WaitResult = true;
                        MachineState = MachineState.Pause;
                    }
                }
                else
                {
                    if (!_pauseHandle.WaitResult)
                    {
                        #region 板卡恢复动作
                        motionDevice.ResetImmediatePause();
                        #endregion
                //        //_pauseHandle.WaitHandle.Reset();
                //        //_pauseHandle.WaitResult = true;
                //        MachineState = MachineState.Pause;
                //    }
                //}
                //else
                //{
                //    if (!_pauseHandle.WaitResult)
                //    {
                //        //#region 板卡恢复动作
                //        //motionDevice.ResetImmediatePause();
                //        //#endregion
                        _pauseHandle.WaitHandle.Set();
                        _pauseHandle.WaitResult = false;
                        MachineState = _machineStateBeforePause;
                    }
                }
                //        //_pauseHandle.WaitHandle.Set();
                //        //_pauseHandle.WaitResult = false;
                //        MachineState = _machineStatePre;
                //    }
                //}
                IsManualPaused = isToPause.Value;
            }
            return new ProcessResponse(_pauseHandle.WaitResult);
            return new ProcessResponse(IsManualPaused);
        }
        ////[ProcessMethod("", "PauseJob", "暂停流程", InvokeType.TestInvoke)]
@@ -633,6 +611,7 @@
        {
            get => !(IsSafetyBeamTrigged || IsSafetyDoorTrigged || IsEmergencyStopped);
        }
        string SafetyMsg
        {
            get => $"{(IsSafetyBeamTrigged ? "安全光幕" : "")}{(IsSafetyDoorTrigged ? " 安全门" : "")}{(IsEmergencyStopped ? " 急停按钮" : "")}触发中";
@@ -641,21 +620,81 @@
        #region 安全门 & 安全光线
        bool isSafetyDoorTrigged = false;
        bool isSafetyBeamTrigged = false;
        bool isManualPaused = false;
        public bool IsSafetyDoorTrigged
        {
            get => !Config.IsSafetyDoorBlocked && isSafetyDoorTrigged;
            set => isSafetyDoorTrigged = value;
            get => (!Config.IsSafetyDoorBlocked) && isSafetyDoorTrigged;
            set
            {
                isSafetyDoorTrigged = value;
                CheckMachinePauseState();
            }
        }
        public bool IsSafetyBeamTrigged
        {
            get => !Config.IsSafetyBeamBlocked && isSafetyBeamTrigged;
            set => isSafetyBeamTrigged = value;
            get => (!Config.IsSafetyBeamBlocked) && isSafetyBeamTrigged;
            set
            {
                isSafetyBeamTrigged = value;
                CheckMachinePauseState();
            }
        }
        public bool IsManualPaused
        {
            get => isManualPaused;
            set
            {
                isManualPaused = value;
                CheckMachinePauseState();
            }
        }
        ManualResetEventSlim _pausedHandle = new ManualResetEventSlim(true);
        MachineState _machineStateBeforePause = MachineState.Unknown;
        private async void CheckMachinePauseState()
        {
            await Task.Run(() =>
            {
                if (IsMachinePaused)
                {
                    _machineStateBeforePause = MachineState;
                    MachineState = MachineState.Pause;
                    _pausedHandle.Reset();
                    if (_machineStateBeforePause == MachineState.Running)
                    {
                        Pause();
                    }
                }
                else
                {
                    if (MachineState == MachineState.Pause)
                    {
                        if (_machineStateBeforePause == MachineState.Running)
                        {
                            Resume(true);
                        }
                        _pausedHandle.Set();
                        RaisedAlarm("");
                        MachineState = _machineStateBeforePause;
                    }
                }
            });
        }
        public bool IsMachinePaused
        {
            get => IsSafetyBeamTrigged || IsSafetyDoorTrigged || IsManualPaused;
        }
        [ProcessMethod("", "SafetyDoorSignal", "安全门信号监控,正常ON,OFF时报警", InvokeType.TestInvoke)]
        public ProcessResponse SafetyDoorSignal(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice)
        {
            //if (MachineState != MachineState.Running && MachineState != MachineState.Pause)
            //    return new ProcessResponse(true);
            if (opConfig.InputPara == null || opConfig.InputPara.Count == 0)
                throw new ProcessException("安全门监控未配置输入信号");
@@ -664,7 +703,6 @@
            if (IsSafetyDoorTrigged)
            {
                RaisedAlarm("安全门未正常关闭");
                MachineState = MachineState.Alarm;
            }
            return new ProcessResponse(true);
@@ -673,8 +711,8 @@
        [ProcessMethod("", "SafetyBeamSignal", "安全光幕信号监控,正常ON,OFF时报警", InvokeType.TestInvoke)]
        public ProcessResponse SafetyBeamSignal(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice)
        {
            if (MachineState != MachineState.Running && MachineState != MachineState.Alarm)
                return new ProcessResponse(true);
            //if (MachineState != MachineState.Running && MachineState != MachineState.Pause)
            //    return new ProcessResponse(true);
            if (opConfig.InputPara == null || opConfig.InputPara.Count == 0)
                throw new ProcessException("安全光幕监控未配置输入信号");
@@ -684,7 +722,6 @@
            if (IsSafetyBeamTrigged)
            {
                RaisedAlarm("安全光线被遮挡");
                MachineState = MachineState.Alarm;
            }
            return new ProcessResponse(true);
src/Bro.UI.Config/MainFrm.cs
@@ -331,9 +331,14 @@
            {
                foreach (var dock in dockPanelMain.Contents)
                {
                    MenuFrmBase m = dock as MenuFrmBase;
                    //MenuFrmBase m = dock as MenuFrmBase;
                    m.DownloadProcess(_process);
                    //m.DownloadProcess(_process);
                    if (dock is MenuFrmBase menuFrm)
                    {
                        menuFrm.DownloadProcess(_process);
                    }
                }
            }
            catch (Exception ex)