using Bro.Common.Helper; using Bro.Common.Interface; using Newtonsoft.Json; using System; using System.ComponentModel; using System.Threading; using static Bro.Common.Helper.EnumHelper; namespace Bro.Common.Base { public abstract class DeviceBase : IDevice { #region Event [JsonIgnore] [Browsable(false)] public Action OnExceptionOccured { get; set; } public event Action OnLog; public event Action OnDeviceStateChanged; public event PropertyChangedEventHandler PropertyChanged; #endregion #region field int RetryTime = 3; /// /// 和设备暂停状态关联的信号量 /// private readonly ManualResetEvent pauseHandle = new ManualResetEvent(true); readonly Timer stateChangedTimer; #endregion #region Property #region State 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 { LogAsync(DateTime.Now, $"设备状态切换:{_currentState.ToString()}->{value.ToString()}", ""); _currentState = value; if (value != EnumHelper.DeviceState.TBD) { OnDeviceStateChanged?.Invoke(this, _currentState); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CurrentState")); } //else //{ // initialState = _currentState; //} } } #endregion /// /// 设备标识符 从数据库获取 /// public string Id { get; set; } /// /// 设备名称 从数据库获取 /// public string Name { get; set; } private IInitialConfig initialConfig = null; /// /// 设备初始化配置 从数据库获取 /// public virtual IInitialConfig InitialConfig { get => initialConfig; set { initialConfig = value; Id = initialConfig.Id; Name = initialConfig.Name; LoggerHelper.LogPath = initialConfig.LogPath; LoggerHelper.LogPrefix = initialConfig.Name; } } #endregion #region 构造函数 public DeviceBase() { stateChangedTimer = new Timer(new TimerCallback(CheckDeviceOpTimeOut), null, Timeout.Infinite, Timeout.Infinite); } #endregion #region 设备抽象方法 protected abstract void Init(); protected abstract void Pause(); protected abstract void Resume(); protected abstract void Start(); protected abstract void Stop(); //public abstract void AttachToProcess(IProcess process); #endregion #region 状态切换 [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}"); } CurrentState = EnumHelper.DeviceState.TBD; CurrentStateToBe = stateToBe; } [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}设备操作超时"); } } 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 (CurrentState != EnumHelper.DeviceState.DSExcept) { throw new ProcessException($"设备{InitialConfig.Name}的{CurrentStateToBe.GetEnumDescription()}操作重复3次失败", ex, ExceptionLevel.Warning); } } } } private void CheckDeviceOpTimeOut(object state) { stateChangedTimer?.Change(Timeout.Infinite, Timeout.Infinite); if (CurrentState != EnumHelper.DeviceState.DSExcept) { StateChange(EnumHelper.DeviceState.DSExcept); } } #endregion #region 日志处理 public LoggerHelper LoggerHelper { get; set; } = new LoggerHelper(); public virtual void LogAsync(DateTime dt, string prefix, string msg) { OnLog?.BeginInvoke(dt, $"{Name}_{ prefix}", msg, null, null); if (InitialConfig.IsEnableLog) { LoggerHelper.LogAsync(dt, prefix, msg); } } #endregion #region IDisposable Support private bool disposedValue = false; // 要检测冗余调用 protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { //释放托管状态(托管对象)。 stateChangedTimer?.Dispose(); pauseHandle?.Dispose(); } // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。 // TODO: 将大型字段设置为 null。 disposedValue = true; } } // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。 // ~DeviceBase() // { // // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。 // Dispose(false); // } // 添加此代码以正确实现可处置模式。 public void Dispose() { // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。 Dispose(true); // TODO: 如果在以上内容中替代了终结器,则取消注释以下行。 // GC.SuppressFinalize(this); } #endregion } }