236 lines
6.9 KiB
C#
236 lines
6.9 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using System.Xml;
|
|
using Aitex.Core.RT.DataCenter;
|
|
using Aitex.Core.RT.Device;
|
|
using Aitex.Core.RT.Log;
|
|
using Aitex.Core.RT.SCCore;
|
|
using Aitex.Core.Util;
|
|
using MECF.Framework.Common.Communications;
|
|
|
|
namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Temps;
|
|
|
|
public abstract class TempSensorBase : BaseDevice, IDevice, IConnection, ITempSensor
|
|
{
|
|
#region Variables
|
|
|
|
protected readonly bool IsSimMode;
|
|
protected bool IsEnableLog;
|
|
protected TempBasFunction TempBasFunction;
|
|
|
|
private readonly Random _rndTempGen = new();
|
|
private readonly R_TRIG _rTrigReadTempFailed = new();
|
|
private PeriodicJob _tReadTemp;
|
|
private Misc.FilterTypes _filterType;
|
|
private TempDataFilter[] _tempFilters;
|
|
|
|
private readonly Stopwatch _swSimSineWave = new ();
|
|
private const double SINE_T = 5.0;
|
|
private const double SINE_F = 2.0 * Math.PI * (1 / SINE_T);
|
|
|
|
#endregion
|
|
|
|
#region Ctor
|
|
|
|
protected TempSensorBase(string module, XmlElement node, string ioModule = "")
|
|
: base(module, node, ioModule)
|
|
{
|
|
IsSimMode = SC.SafeGetValue("System.IsSimulatorMode", false);
|
|
|
|
RTrigs.Add(_rTrigReadTempFailed);
|
|
|
|
var maxChStr = node.GetAttribute("MaxChannels");
|
|
if (!string.IsNullOrEmpty(maxChStr) && int.TryParse(maxChStr, out var maxCh))
|
|
MaxChannels = maxCh;
|
|
else
|
|
MaxChannels = 4;
|
|
|
|
var minTempStr = node.GetAttribute("MinimalTemp");
|
|
if (!string.IsNullOrEmpty(minTempStr) && double.TryParse(minTempStr, out var minTemp))
|
|
MinimalTemp = minTemp;
|
|
else
|
|
MinimalTemp = 600.0;
|
|
|
|
if(IsSimMode)
|
|
_swSimSineWave.Start();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
public virtual string Address { get; protected set; }
|
|
|
|
public virtual bool IsConnected { get; }
|
|
|
|
public double MinimalTemp { get; }
|
|
|
|
public int MaxChannels { get; }
|
|
|
|
public double[] Temp { get; private set; }
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
/// <summary>
|
|
/// 生成随机温度。
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private double[] RandomTemps(double baseTemp = 800, double peakPeak = 200, double jitter = 50.0)
|
|
{
|
|
var rndTemps = new double[MaxChannels];
|
|
for (var i = 0; i < MaxChannels; i++)
|
|
{
|
|
var t = _swSimSineWave.Elapsed.TotalSeconds; // current moment
|
|
var tempSine = peakPeak * Math.Sin(SINE_F * t + (i * Math.PI / 3)); //temperature following sine wave with 60 deg(π/3 rad) phase-diff per channel
|
|
tempSine += baseTemp + tempSine + _rndTempGen.NextDouble() * jitter; // add jitter
|
|
rndTemps[i] = tempSine;
|
|
}
|
|
|
|
return rndTemps;
|
|
}
|
|
|
|
private Misc.FilterTypes ConvertToFilterType(string type)
|
|
{
|
|
if (Enum.TryParse<Misc.FilterTypes>(type, true, out var ft))
|
|
return ft;
|
|
else
|
|
{
|
|
LOG.Error($"{this} Unable to convert {type} to filter type.");
|
|
return Misc.FilterTypes.None;
|
|
}
|
|
}
|
|
|
|
private bool DoTempReadThread()
|
|
{
|
|
// get temp. points according to the "IsSimulatorMode" system config.
|
|
var temps = IsSimMode ? RandomTemps() : HandleReadTemp();
|
|
|
|
_rTrigReadTempFailed.CLK = temps == null || temps.Length != MaxChannels;
|
|
if (_rTrigReadTempFailed.Q)
|
|
{
|
|
LOG.Error(temps != null
|
|
? $"{this} {MaxChannels} temp. points wanted but {temps.Length} points read."
|
|
: $"{this} {MaxChannels} no temp. points read from controller.");
|
|
}
|
|
|
|
// Too less temp. points read from the sensor.
|
|
if (_rTrigReadTempFailed.M)
|
|
return false;
|
|
|
|
// Get the right temp value from the filter
|
|
for (var i = 0; i < MaxChannels; i++)
|
|
{
|
|
_tempFilters[i].AddRawTemp(temps![i]);
|
|
|
|
Temp[i] = _filterType switch
|
|
{
|
|
Misc.FilterTypes.None => _tempFilters[i].Raw,
|
|
Misc.FilterTypes.MAF => _tempFilters[i].FilteredMAF,
|
|
_ => _tempFilters[i].Raw
|
|
};
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void InitTempDataFilter()
|
|
{
|
|
_tempFilters = new TempDataFilter[MaxChannels];
|
|
Temp = new double[MaxChannels];
|
|
|
|
for (var i = 0; i < MaxChannels; i++)
|
|
{
|
|
_tempFilters[i] = new TempDataFilter(this, (i + 1).ToString(), MinimalTemp, ScBasePath);
|
|
Temp[i] = MinimalTemp;
|
|
|
|
var ch = i;
|
|
DATA.Subscribe($"TempSensor.{Name}.T{ch + 1}", () => Temp[ch]);
|
|
DATA.Subscribe($"TempSensor.{Name}.T{ch + 1}MAF", () => _tempFilters[ch].FilteredMAF);
|
|
DATA.Subscribe($"TempSensor.{Name}.T{ch + 1}Raw", () => _tempFilters[ch].Raw);
|
|
}
|
|
}
|
|
|
|
protected virtual double[] HandleReadTemp()
|
|
{
|
|
return new double[MaxChannels];
|
|
}
|
|
|
|
protected virtual bool HandleInitialize()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public bool Initialize()
|
|
{
|
|
try
|
|
{
|
|
if (!SC.GetValue<bool>($"{ScBasePath}.{Name}.EnableDevice"))
|
|
{
|
|
IsEnabled = false;
|
|
return true;
|
|
}
|
|
|
|
IsEnableLog = SC.SafeGetValue($"{ScBasePath}.EnableLogMessage", false);
|
|
|
|
_filterType = ConvertToFilterType(SC.SafeGetStringValue($"{ScBasePath}.FilterType", "None"));
|
|
|
|
var pollInvMs = SC.SafeGetValue($"{ScBasePath}.PollInterval", 100);
|
|
|
|
|
|
// 系统参数变更回调
|
|
SC.RegisterValueChangedCallback($"{ScBasePath}.PollInterval",
|
|
(obj) => { _tReadTemp.ChangeInterval((int)obj); });
|
|
|
|
SC.RegisterValueChangedCallback($"{ScBasePath}.FilterType",
|
|
(obj) => { _filterType = ConvertToFilterType(obj?.ToString() ?? ""); });
|
|
|
|
SC.RegisterValueChangedCallback($"{ScBasePath}.EnableLogMessage",
|
|
(obj) => { IsEnableLog = bool.TryParse(obj.ToString(), out var en) && en; });
|
|
|
|
TempBasFunction = new TempBasFunction(Name, MinimalTemp, MaxChannels);
|
|
TempBasFunction.SetPm1Pm2IoForInterlock(false);
|
|
|
|
InitTempDataFilter();
|
|
|
|
// 执行派生类初始化方法
|
|
var userInit = HandleInitialize();
|
|
|
|
_tReadTemp = new PeriodicJob(pollInvMs, DoTempReadThread, $"{Name}", true);
|
|
return userInit;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
LOG.Error(e.Message, e);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public virtual bool Connect()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public virtual bool Disconnect()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public virtual void Terminate()
|
|
{
|
|
}
|
|
|
|
public virtual void Reset()
|
|
{
|
|
foreach (var rt in RTrigs)
|
|
rt.RST = true;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return $"{Module}.{Name}";
|
|
}
|
|
|
|
#endregion
|
|
} |