using Bro.Common.Base; using Bro.Common.Helper; using Bro.Common.Interface; using Bro.Common.Model; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing.Design; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using static Bro.Common.Helper.EnumHelper; namespace Bro.M071.Process { public partial class M071Process { public Timer ResetTimer = null; object machineStateLock = new object(); //MachineState _machineStatePre = MachineState.Unknown; MachineState machineState = MachineState.Unknown; public MachineState MachineState { get => machineState; set { if (machineState == value) return; LogAsync(DateTime.Now, $"设备状态切换:{machineState.ToString()}->{value.ToString()}", ""); machineState = value; Task.Run(() => { switch (machineState) { case MachineState.Ready: lock (machineStateLock) { SwitchBeep(false); SwitchLightRed(false); SwitchLightYellow(false); } Task.Run(() => { while (MachineState == MachineState.Ready) { lock (machineStateLock) { SwitchLightGreen(true); Thread.Sleep(1000); SwitchLightGreen(false); Thread.Sleep(1000); } } }); break; case MachineState.Running: lock (machineStateLock) { SwitchBeep(false); SwitchLightRed(false); SwitchLightYellow(false); SwitchLightGreen(true); } break; case MachineState.Alarm: lock (machineStateLock) { SwitchBeep(true); SwitchLightRed(true); SwitchLightYellow(false); SwitchLightGreen(false); } break; case MachineState.Pause: lock (machineStateLock) { SwitchBeep(false); SwitchLightRed(false); } Task.Run(() => { while (MachineState == MachineState.Pause) { lock (machineStateLock) { SwitchLightYellow(true); SwitchLightGreen(true); Thread.Sleep(1000); SwitchLightYellow(false); SwitchLightGreen(false); Thread.Sleep(1000); } } }); break; case MachineState.Resetting: lock (machineStateLock) { SwitchBeep(false); SwitchLightRed(false); SwitchLightGreen(false); } Task.Run(() => { while (MachineState == MachineState.Resetting) { lock (machineStateLock) { SwitchLightYellow(true); Thread.Sleep(1000); SwitchLightYellow(false); Thread.Sleep(1000); } } }); break; default: break; } }); OnMachineStateChanged?.Invoke(machineState); } } 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() { IDevice device = DeviceCollection.FirstOrDefault(u => u is IMotionCard); if (device?.InitialConfig is MotionCardInitialConfigBase iConfig) { outputCtrlCard = device as MotionCardBase; var redDefinition = iConfig.IODefinitionCollection.FirstOrDefault(u => u.IOPreStatement == IOPrestatement.Light_Red); if (redDefinition != null) { index_RedLight = redDefinition.IONum; } else { LogAsync(DateTime.Now, $"{iConfig.Name}未配置红色灯输出索引", ""); } var greenDefinition = iConfig.IODefinitionCollection.FirstOrDefault(u => u.IOPreStatement == IOPrestatement.Light_Green); if (greenDefinition != null) { index_GreenLight = greenDefinition.IONum; } else { LogAsync(DateTime.Now, $"{iConfig.Name}未配置绿色灯输出索引", ""); } var yellowDefinition = iConfig.IODefinitionCollection.FirstOrDefault(u => u.IOPreStatement == IOPrestatement.Light_Yellow); if (yellowDefinition != null) { index_YellowLight = yellowDefinition.IONum; } else { LogAsync(DateTime.Now, $"{iConfig.Name}未配置黄色灯输出索引", ""); } var beepDefinition = iConfig.IODefinitionCollection.FirstOrDefault(u => u.IOPreStatement == IOPrestatement.Beep); if (beepDefinition != null) { index_Beep = beepDefinition.IONum; } else { LogAsync(DateTime.Now, $"{iConfig.Name}未配置蜂鸣器输出索引", ""); } var lightDefinition = iConfig.IODefinitionCollection.FirstOrDefault(u => u.IOPreStatement == IOPrestatement.Light); if (lightDefinition != null) { index_NormalLight = lightDefinition.IONum; } else { LogAsync(DateTime.Now, $"{iConfig.Name}未配置日光灯输出索引", ""); } } else { LogAsync(DateTime.Now, "未配置板卡设备", ""); } } [ProcessMethod("MotionCardBase", "GotoReadyPosition", "运动到预备位置", InvokeType.TestInvoke)] public ProcessResponse GotoReadyPosition(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) { MotionCardDefaultRun("GotoReadyPosition", ref opConfig, ref invokeDevice); LogAsync(DateTime.Now, "运动到预备位置完成", ""); return new ProcessResponse(true); } [ProcessMethod("MotionCardBase", "Reset", "简单复位操作", InvokeType.TestInvoke)] public ProcessResponse Reset(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) { if (ResetTimer == null) { ResetTimer = new Timer(FullReset, null, -1, -1); } if (opConfig?.InputPara != null && opConfig.InputPara.Count > 0) { //大复位信号 ResetTimer.Change(opConfig.InputPara[0] == 1 ? Config.FullResetRequiredDuration * 1000 : -1, -1); if (opConfig.InputPara[0] == 0) return new ProcessResponse(true); } if (!IsAllowedWork) { LogAsync(DateTime.Now, $"{SafetyMsg},复位失败", ""); return new ProcessResponse(false); } MotionCardDefaultRun("Reset", ref opConfig, ref invokeDevice); (invokeDevice as MotionCardBase).ResetAlarm(); RaisedAlarm(""); //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); } LogAsync(DateTime.Now, "普通复位动作完成", ""); return new ProcessResponse(true); } private void FullReset(object state) { try { FullReset(null, null, null); } catch (Exception ex) { ExceptionRaisedInMonitor(ex); } } //[ProcessMethod("MotionCardOperationConfigCollection", "FullReset", "大复位操作", InvokeType.TestInvoke)] [ProcessMethod("MotionCardBase", "FullReset", "大复位操作", InvokeType.TestInvoke)] public ProcessResponse FullReset(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) { if (!IsAllowedWork) { LogAsync(DateTime.Now, $"{SafetyMsg},大复位失败", ""); return new ProcessResponse(false); } if (MachineState == MachineState.Pause) { Resume(false); } MachineState = MachineState.Resetting; MotionCardDefaultRun("FullReset", ref opConfig, ref invokeDevice); lock (productionLock) { productionList.ForEach(u => u.Dispose()); productionList.Clear(); } OnFullResetDone?.Invoke(); isFullResetCovered = true; LogAsync(DateTime.Now, "大复位动作完成", ""); RaisedAlarm(""); MachineState = MachineState.Ready; GotoReadyPosition(null, null, null); return new ProcessResponse(true); } /// /// 暂停标志 /// WaitHandle 暂停句柄 默认为非阻塞 可执行 /// WaitResult 暂停标志 true 正常执行 false 暂停中 /// //ManualWaitConfirm _pauseHandle = new ManualWaitConfirm() //{ // WaitHandle = new ManualResetEvent(true), // WaitResult = true, //}; List _statesAllowPause = new List() { MachineState.Running, MachineState.Ready, MachineState.Pause }; [ProcessMethod("", "SwitchJobStatus", "流程状态切换", InvokeType.TestInvoke)] public ProcessResponse SwitchJobStatus(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) { if (!_statesAllowPause.Contains(MachineState)) return new ProcessResponse(-999); MotionCardBase motionDevice = sourceDevice as MotionCardBase; if (motionDevice == null) { motionDevice = DeviceCollection.FirstOrDefault(u => u is MotionCardBase) as MotionCardBase; } if (motionDevice == null) throw new ProcessException("未获取板卡设备"); bool? isToPause = null; //true 暂停 false 继续 if (opConfig.InputPara[0] == 10) { isToPause = false; } else if (opConfig.InputPara[0] == 11) { isToPause = true; } if (isToPause == null) { IsManualPaused = !IsManualPaused; } else { //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.Set(); // //_pauseHandle.WaitResult = false; // MachineState = _machineStatePre; // } //} IsManualPaused = isToPause.Value; } return new ProcessResponse(IsManualPaused); } ////[ProcessMethod("", "PauseJob", "暂停流程", InvokeType.TestInvoke)] //public ProcessResponse PauseJob(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) //{ // if (!_pauseHandle.WaitResult) // { // #region 板卡暂停动作 // #endregion // _pauseHandle.WaitHandle.Reset(); // } // _pauseHandle.WaitResult = !_pauseHandle.WaitResult; // return new ProcessResponse(_pauseHandle.WaitResult); //} ////[ProcessMethod("", "ResumeJob", "继续流程", InvokeType.TestInvoke)] //public ProcessResponse ResumeJob(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) //{ // if (_pauseHandle.WaitResult) // { // #region 板卡恢复动作 // #endregion // _pauseHandle.WaitHandle.Set(); // } // _pauseHandle.WaitResult = !_pauseHandle.WaitResult; // return new ProcessResponse(_pauseHandle.WaitResult); //} #region 三色灯 & 蜂鸣器 //[ProcessMethod("MotionCardBase", "SwitchLightRed", "切换指示灯-红", InvokeType.TestInvoke)] //public ProcessResponse SwitchLightRed(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) //{ // MotionCardDefaultRun("SwitchLightRed", ref opConfig, ref invokeDevice); // return new ProcessResponse(true); //} //[ProcessMethod("MotionCardBase", "SwitchLightYellow", "切换指示灯-黄", InvokeType.TestInvoke)] //public ProcessResponse SwitchLightYellow(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) //{ // return new ProcessResponse(true); //} //[ProcessMethod("MotionCardBase", "SwitchLightGreen", "切换指示灯-绿", InvokeType.TestInvoke)] //public ProcessResponse SwitchLightGreen(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) //{ // return new ProcessResponse(true); //} //[ProcessMethod("MotionCardBase", "SwitchBeep", "切换蜂鸣器", InvokeType.TestInvoke)] //public ProcessResponse SwitchBeep(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) //{ // return new ProcessResponse(true); //} //[ProcessMethod("MotionCardBase", "SwitchNormalLight", "切换日光灯", InvokeType.TestInvoke)] //public ProcessResponse SwitchNormalLight(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) //{ // MotionCardDefaultRun("SwitchNormalLight", ref opConfig, ref invokeDevice); // return new ProcessResponse(true); //} int index_RedLight = -1; int index_GreenLight = -1; int index_YellowLight = -1; int index_Beep = -1; int index_NormalLight = -1; MotionCardBase outputCtrlCard = null; public void SwitchLightRed(bool isOn) { if (index_RedLight >= 0) { if (outputCtrlCard != null) { outputCtrlCard.WriteOutput((short)index_RedLight, isOn ? IOValue.TRUE : IOValue.FALSE); } else { LogAsync(DateTime.Now, "未设置板卡输出设备", ""); } } else { LogAsync(DateTime.Now, "红色灯未配置正确输出索引", ""); } } public void SwitchLightYellow(bool isOn) { if (index_YellowLight >= 0) { if (outputCtrlCard != null) { outputCtrlCard.WriteOutput((short)index_YellowLight, isOn ? IOValue.TRUE : IOValue.FALSE); } else { LogAsync(DateTime.Now, "未设置板卡输出设备", ""); } } else { LogAsync(DateTime.Now, "黄色灯未配置正确输出索引", ""); } } public void SwitchLightGreen(bool isOn) { if (index_GreenLight >= 0) { if (outputCtrlCard != null) { outputCtrlCard.WriteOutput((short)index_GreenLight, isOn ? IOValue.TRUE : IOValue.FALSE); } else { LogAsync(DateTime.Now, "未设置板卡输出设备", ""); } } else { LogAsync(DateTime.Now, "绿色灯未配置正确输出索引", ""); } } public void SwitchLight(bool isOn) { if (index_NormalLight >= 0) { if (outputCtrlCard != null) { outputCtrlCard.WriteOutput((short)index_NormalLight, isOn ? IOValue.TRUE : IOValue.FALSE); } else { LogAsync(DateTime.Now, "未设置板卡输出设备", ""); } } else { LogAsync(DateTime.Now, "照明灯未配置正确输出索引", ""); } } public void SwitchBeep(bool isOn) { if (Config.IsBeepBlocked) return; if (index_Beep >= 0) { if (outputCtrlCard != null) { outputCtrlCard.WriteOutput((short)index_Beep, isOn ? IOValue.TRUE : IOValue.FALSE); } else { LogAsync(DateTime.Now, "未设置板卡输出设备", ""); } } else { LogAsync(DateTime.Now, "蜂鸣器未配置正确输出索引", ""); } } #endregion private void MotionCardDefaultRun(string methodCode, ref IOperationConfig opConfig, ref IDevice invokeDevice) { IMonitorSet monitorSet = null; if (opConfig == null || !(opConfig is MotionCardOperationConfigBase)) { monitorSet = Config.MonitorSetCollection.FirstOrDefault(u => u.MethodCode == methodCode); 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 (invokeDevice is MotionCardBase motionCard) { var response = motionCard.Run(opConfig); if (!response.Result) { throw new ProcessException($"{motionCard.Name}异常,{response.Message}", null, ExceptionLevel.Fatal); } } } bool IsAllowedWork { get => !(IsSafetyBeamTrigged || IsSafetyDoorTrigged || IsEmergencyStopped); } string SafetyMsg { get => $"{(IsSafetyBeamTrigged ? "安全光幕" : "")}{(IsSafetyDoorTrigged ? " 安全门" : "")}{(IsEmergencyStopped ? " 急停按钮" : "")}触发中"; } #region 安全门 & 安全光线 bool isSafetyDoorTrigged = false; bool isSafetyBeamTrigged = false; bool isManualPaused = false; public bool IsSafetyDoorTrigged { get => (!Config.IsSafetyDoorBlocked) && isSafetyDoorTrigged; set { isSafetyDoorTrigged = value; CheckMachinePauseState(); } } public bool IsSafetyBeamTrigged { 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 void CheckMachinePauseState() { //await Task.Run(() => { if (IsMachinePaused) { if (MachineState == MachineState.Ready || MachineState == MachineState.Running) { _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("安全门监控未配置输入信号"); IsSafetyDoorTrigged = opConfig.InputPara[0] == 0; if (IsSafetyDoorTrigged) { RaisedAlarm("安全门未正常关闭"); } return new ProcessResponse(true); } [ProcessMethod("", "SafetyBeamSignal", "安全光幕信号监控,正常ON,OFF时报警", InvokeType.TestInvoke)] public ProcessResponse SafetyBeamSignal(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) { if (opConfig.InputPara == null || opConfig.InputPara.Count == 0) throw new ProcessException("安全光幕监控未配置输入信号"); IsSafetyBeamTrigged = opConfig.InputPara[0] == 0; if (IsSafetyBeamTrigged) { RaisedAlarm("安全光线被遮挡"); } return new ProcessResponse(true); } #endregion #region 急停 bool isEmergencyStopped = false; bool isFullResetCovered = true; public bool IsEmergencyStopped { get => isEmergencyStopped && isFullResetCovered; set { if (value) { isFullResetCovered = false; isEmergencyStopped = true; } else { isEmergencyStopped = false; } } } [ProcessMethod("", "EmergencyStop", "急停按钮被拍下", InvokeType.TestInvoke)] public ProcessResponse EmergencyStop(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) { if (opConfig.InputPara == null || opConfig.InputPara.Count == 0) throw new ProcessException("急停按钮未配置输入信号"); IsEmergencyStopped = opConfig.InputPara[0] == 0; if (isEmergencyStopped) { RaisedAlarm("急停按钮被拍下"); MachineState = MachineState.Alarm; } return new ProcessResponse(true); } #endregion } }