MoS2/Framework/MECF.Framework.RT.EquipmentLibrary/HardwareUnits/Temps/TempSensorBase.cs

230 lines
6.7 KiB
C#
Raw Normal View History

2026-06-15 10:56:30 +08:00
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 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} temperature data wanted but {temps.Length} points read."
: $"{this} None temperature data read from controller.");
}
// Too less temp. points read from the sensor.
if (_rTrigReadTempFailed.M)
return true;
// Get the right temp value from the filter
for (var i = 0; i < MaxChannels; i++)
{
Temp[i] = temps[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}.CH{ch + 1}", () => Temp[ch]);
//DATA.Subscribe($"TempSensor.{Name}.CH{ch + 1}MAF", () => _tempFilters[ch].FilteredMAF);
//DATA.Subscribe($"TempSensor.{Name}.CH{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($"TempSensors.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($"TempSensors.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
}