using Bro.Common.Interface; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Bro.Common.Helper; using System.Reflection; using Newtonsoft.Json; using System.Threading; using System.Diagnostics; using System.Dynamic; using System.Linq.Expressions; //using BroCComn.PubSub; using static Bro.Common.Helper.EnumHelper; using System.ComponentModel; namespace Bro.Common.Base { //public delegate void DeviceStateChangedDelegate(EnumHelper.DeviceState initialState); public abstract class DeviceBase : IDevice, IDisposable { #region Event [JsonIgnore] public Action OnDeviceException { get; set; } [JsonIgnore] public Action OnLog { get; set; } [JsonIgnore] public Action OnDeviceStateChanged { get; set; } #endregion int RetryTime = 3; /// /// 和设备暂停状态关联的信号量 /// private ManualResetEvent pauseHandle = new ManualResetEvent(true); Timer stateChangedTimer; internal bool stateChangedFlag = false; private EnumHelper.DeviceState _currentStateToBe = EnumHelper.DeviceState.DSUninit; /// /// 当前设备状态 /// [JsonIgnore] internal EnumHelper.DeviceState CurrentStateToBe { get { return _currentStateToBe; } set { if (value != _currentStateToBe) { var initialState = _currentStateToBe; _currentStateToBe = value; if (_currentStateToBe != EnumHelper.DeviceState.DSExcept) { OnStateChanged(initialState); } else { stateChangedTimer.Change(Timeout.Infinite, Timeout.Infinite); } } } } private EnumHelper.DeviceState initialState = EnumHelper.DeviceState.DSUninit; private EnumHelper.DeviceState _currentState = EnumHelper.DeviceState.DSUninit; public EnumHelper.DeviceState CurrentState { get { return _currentState; } set { _currentState = value; if (value != EnumHelper.DeviceState.TBD) { OnDeviceStateChanged?.Invoke(initialState); OnDeviceStateChangedWithDeviceInfo?.Invoke(this, _currentState); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CurrentState")); } else { initialState = _currentState; } } } /// /// 设备状态 编辑时或者运行时 /// public EnumHelper.DeviceMode DeviceMode { get; set; } = EnumHelper.DeviceMode.Edit; /// /// 设备标识符 从数据库获取 /// public string Id { get; set; } /// /// 设备名称 从数据库获取 /// public string Name { get; set; } private IInitialConfig initialConfig = null; /// /// 设备初始化配置 从数据库获取 /// public virtual IInitialConfig InitialConfig { get => initialConfig; set { initialConfig = value; this.Id = initialConfig.ID; this.Name = initialConfig.Name; } } #region IPorcessId /// /// 设备当前执行工序编号 /// [JsonIgnore] public string ProcessId { get; set; } /// /// 设备当前执行工序名称 /// [JsonIgnore] public string ProcessName { get; set; } #endregion [JsonIgnore] public Dictionary OutputMethods { get; set; } = new Dictionary(); #region 延迟加载方法字典方式 现转移到构造函数中实现 //{ // get // { // if (outputMethods == null) // { // this.GetType().GetMethods().ToList().ForEach(m => // { // var attr = m.GetCustomAttribute(); // if (attr != null) // { // outputMethods[attr.MethodName] = m; // } // }); // } // return outputMethods; // } // set // { // outputMethods = value; // } //} #endregion [JsonIgnore] public Dictionary InputMethods { get; set; } = new Dictionary(); //public event DeviceStateChangedDelegate OnDeviceStateChanged; public DeviceBase() { //预先获取所有设备输出方法 this.GetType().GetMethods().ToList().ForEach(m => { var attrOut = m.GetCustomAttribute(); if (attrOut != null) { OutputMethods[attrOut] = m; } var attrIn = m.GetCustomAttribute(); if (attrIn != null) { InputMethods[attrIn] = m; } }); stateChangedTimer = new Timer(new TimerCallback(CheckDeviceOpTimeOut), null, Timeout.Infinite, Timeout.Infinite); //StateMachine.OnUserLogin = OnCurrentUserLogin; } protected abstract void Init(); protected abstract void Pause(); protected abstract void Resume(); protected abstract void Start(); protected abstract void Stop(); public virtual void Dispose() { } object OpLock = new Object(); //操作锁,一个设备,一次只能做一个动作 public event DeviceStateChangedDelegate OnDeviceStateChangedWithDeviceInfo; public event PropertyChangedEventHandler PropertyChanged; /// /// 设备Run之前工序进入Running状态,设备Run完成之后工序进入Done状态 /// 发生异常时,设备和工序都进入异常状态 /// 考虑使用AOP切面实现前后状态变化 /// /// /// [DeviceExceptionAspect] [DeviceRunAspect] public virtual IOperationConfig SetAndRun(IOperationConfig config) { //try //{ //lock (OpLock) //{ //if (string.IsNullOrWhiteSpace(config.ProcessId)) //{ // DeviceMode = EnumHelper.DeviceMode.Edit; //} //else //{ // DeviceMode = EnumHelper.DeviceMode.Run; // ProcessId = config.ProcessId; // ProcessName = config.ProcessName; //} //pauseHandle.WaitOne(); //if (config.DeviceConfig != null) //{ // DeviceSet(config.DeviceConfig); //} //bool inputFlag = false; //do //{ // pauseHandle.WaitOne(); // inputFlag = DeviceInput(config); //} while (!inputFlag); //if (CurrentState != EnumHelper.DeviceState.DSOpen) //{ // return null; //} pauseHandle.WaitOne(); if (config.IsEnabled) { DeviceRun(config); } pauseHandle.WaitOne(); IOperationConfig output = DeviceOutput(config); //config.InputConfig?.Dispose(); return output; //} //catch (Exception ex) //{ // return null; //} //} } /// /// 根据设备配置信息配置设备参数 /// /// protected abstract void DeviceSet(IDeviceConfig config); protected virtual bool DeviceInput(IOperationConfig config) { ////如果需要设备输入配置判断 //if (config.InputConfig != null && config.InputConfig.IsInputNeed) //{ // //config.InputConfig.BoundFlag = true; // //等待输入配置信号量 // //config.InputConfig.InputHanlderDict[config.ProcessId]?.WaitOne(); // //while (config.InputConfig.InputFlagDict[config.ProcessId] == false && CurrentState == EnumHelper.DeviceState.DSOpen) // //{ // // Thread.Sleep(10); // //} // //config.InputConfig.InputFlagDict[config.ProcessId] = false; // config.InputConfig.InputHandle.WaitOne(); // //Debug.WriteLine(DateTime.Now.ToString("mm:ss.fff") + "\t输入完成,编号:" + config.InputConfig.ProcessId); // if (CurrentState != EnumHelper.DeviceState.DSOpen) // { // return true; // } // //config.InputConfig.InputHanlderDict[config.ProcessId].Reset(); // if (!string.IsNullOrWhiteSpace(config.InputConfig.InputMethodName)) // { // var attr = InputMethods.Keys.FirstOrDefault(u => u.MethodName == config.InputConfig.InputMethodName); // if (attr != null) // { // return Convert.ToBoolean(InputMethods[attr].Invoke(this, new object[] { config })); // } // else // { // //throw new UserException(string.Format("未能获取{0}的方法信息!", config.InputConfig.InputMethodName), EnumHelper.LogType.Exception_Fatal); // throw new Exception(string.Format("未能获取{0}的方法信息!", config.InputConfig.InputMethodName)); // } // } //} return true; } /// /// 设备运行 /// /// protected abstract void DeviceRun(IOperationConfig config); /// /// 具体的输出方法返回IOperationConfig,必须包括ProcessId和ResultOutput /// /// /// protected virtual IOperationConfig DeviceOutput(IOperationConfig config) { //if (string.IsNullOrWhiteSpace(config.OutputMethodName)) //{ return null; //} //else //{ // #region 实时获取输出方法 考虑到效率问题,将方法字典转移到构造函数中实现 // //var methodInfo = this.GetType().GetMethods().FirstOrDefault(m => // // { // // var attr = m.GetCustomAttribute(); // // return attr != null && attr.MethodName == config.OutputMethodName; // // }); // //if (methodInfo == null) // //{ // // throw new UserException(string.Format("未能获取{0}的方法信息!", config.OutputMethodName)); // //} // //else // //{ // // return (methodInfo.Invoke(this, new object[] { config })) as IOperationConfig; // //} // #endregion // var attr = OutputMethods.Keys.FirstOrDefault(u => u.MethodName == config.OutputMethodName); // if (attr != null) // { // return (OutputMethods[attr].Invoke(this, new object[] { config })) as IOperationConfig; // } // else // { // //throw new UserException(string.Format("未能获取{0}的方法信息!", config.OutputMethodName), EnumHelper.LogType.Exception_Fatal); // throw new Exception(string.Format("未能获取{0}的方法信息!", config.OutputMethodName)); // } //} } [DeviceExceptionAspect] public void StateChange(EnumHelper.DeviceState stateToBe) { if (CurrentState == stateToBe) { return; } if (!stateToBe.CheckPreStateValid((int)CurrentStateToBe)) { string currentStateStr = CurrentStateToBe.GetEnumDescription(); string stateToBeStr = stateToBe.GetEnumDescription(); throw new ProcessException($"{InitialConfig.Name}设备的当前状态为{currentStateStr},无法切换至{stateToBeStr}", null); } CurrentState = EnumHelper.DeviceState.TBD; CurrentStateToBe = stateToBe; } [DeviceStateChangedAspect] [DeviceExceptionAspect] private void OnStateChanged(EnumHelper.DeviceState initialState) { try { if (CurrentStateToBe != EnumHelper.DeviceState.DSExcept) { } else { if (CurrentState == EnumHelper.DeviceState.DSExcept) { return; } else { throw new ProcessException($"{InitialConfig.Name}设备操作超时", null); } } if (RetryTime >= 0) { if (initialState == CurrentStateToBe) { CurrentState = CurrentStateToBe; return; } #region 状态切换操作 switch (CurrentStateToBe) { case EnumHelper.DeviceState.DSInit: if (initialState == EnumHelper.DeviceState.DSOpen) { return; } else { Init(); } break; case EnumHelper.DeviceState.DSOpen: if (initialState == EnumHelper.DeviceState.DSInit) { Start(); } else if (initialState == EnumHelper.DeviceState.DSPause) { Resume(); pauseHandle.Set(); } break; case EnumHelper.DeviceState.DSPause: pauseHandle.Reset(); Pause(); break; case EnumHelper.DeviceState.DSClose: if (initialState != DeviceState.DSUninit) { Stop(); } break; default: break; } RetryTime = 3; CurrentState = CurrentStateToBe; #endregion } stateChangedTimer.Change(Timeout.Infinite, Timeout.Infinite); } catch (Exception ex) { RetryTime--; if (RetryTime > 0) { OnStateChanged(initialState); } else { if (this.CurrentState != EnumHelper.DeviceState.DSExcept) { //this.CurrentState = EnumHelper.DeviceState.DSExcept; //this.CurrentStateToBe = EnumHelper.DeviceState.DSExcept; throw new ProcessException($"设备{InitialConfig.Name}的{CurrentStateToBe.GetEnumDescription()}操作重复3次失败", ex); } } } } [DeviceExceptionAspect] private void CheckDeviceOpTimeOut(object state) { stateChangedTimer?.Change(Timeout.Infinite, Timeout.Infinite); if (CurrentState != EnumHelper.DeviceState.DSExcept) { StateChange(EnumHelper.DeviceState.DSExcept); } } #region 用户信息 [JsonIgnore] public string CurrentUserId { get; set; } private void OnCurrentUserLogin(string obj) { CurrentUserId = obj; } #endregion } }