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<DateTime, Exception> OnExceptionOccured { get; set; }
|
public event Action<DateTime, IDevice, string> OnLog;
|
public event Action<IDevice, DeviceState> OnDeviceStateChanged;
|
public event PropertyChangedEventHandler PropertyChanged;
|
#endregion
|
|
#region field
|
int RetryTime = 3;
|
/// <summary>
|
/// 和设备暂停状态关联的信号量
|
/// </summary>
|
private ManualResetEvent pauseHandle = new ManualResetEvent(true);
|
Timer stateChangedTimer;
|
#endregion
|
|
#region Property
|
#region State
|
private EnumHelper.DeviceState _currentStateToBe = EnumHelper.DeviceState.DSUninit;
|
/// <summary>
|
/// 当前设备状态
|
/// </summary>
|
[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(this, _currentState);
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CurrentState"));
|
}
|
else
|
{
|
initialState = _currentState;
|
}
|
}
|
}
|
#endregion
|
|
/// <summary>
|
/// 设备标识符 从数据库获取
|
/// </summary>
|
public string Id { get; set; }
|
|
/// <summary>
|
/// 设备名称 从数据库获取
|
/// </summary>
|
public string Name { get; set; }
|
|
private IInitialConfig initialConfig = null;
|
/// <summary>
|
/// 设备初始化配置 从数据库获取
|
/// </summary>
|
public virtual IInitialConfig InitialConfig
|
{
|
get => initialConfig;
|
set
|
{
|
initialConfig = value;
|
this.Id = initialConfig.Id;
|
this.Name = initialConfig.Name;
|
|
LoggerHelper.LogPath = initialConfig.LogPath;
|
LoggerHelper.LogPrefix = initialConfig.Name;
|
}
|
}
|
#endregion
|
|
public DeviceBase()
|
{
|
stateChangedTimer = new Timer(new TimerCallback(CheckDeviceOpTimeOut), null, Timeout.Infinite, Timeout.Infinite);
|
}
|
|
#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 IDispose
|
public virtual void Dispose()
|
{
|
}
|
#endregion
|
|
[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 (this.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);
|
}
|
}
|
|
#region 日志处理
|
public LoggerHelper LoggerHelper { get; set; } = new LoggerHelper();
|
public virtual void LogAsync(DateTime dt, string prefix, string msg)
|
{
|
OnLog?.BeginInvoke(dt, this, prefix + "\t" + msg, null, null);
|
|
if (InitialConfig.IsEnableLog)
|
{
|
LoggerHelper.LogAsync(dt, prefix, msg);
|
}
|
}
|
#endregion
|
}
|
}
|