using Aitex.Core.Account;
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;
using System;
using System.Diagnostics;
using System.Xml;
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();
protected readonly R_TRIG _rTrigReadTempFailed = new();
private PeriodicJob _tReadTemp;
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; protected set; }
#endregion
#region Methods
///
/// 生成随机温度。
///
///
protected double[] RandomTemps(int channels, double baseTemp = 800, double peakPeak = 200, double jitter = 50.0)
{
var rndTemps = new double[channels];
for (var i = 0; i < channels; 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;
}
protected virtual bool DoTempReadThread()
{
// get temp. points according to the "IsSimulatorMode" system config.
var temps = IsSimMode ? RandomTemps(MaxChannels) : 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];
}
return true;
}
protected virtual void InitTempDataFilter()
{
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]);
}
}
protected virtual double[] HandleReadTemp()
{
return new double[MaxChannels];
}
protected virtual bool HandleInitialize()
{
return true;
}
public bool Initialize()
{
try
{
if (!SC.GetValue($"{ScBasePath}.{Name}.EnableDevice"))
{
IsEnabled = false;
return true;
}
IsEnableLog = SC.SafeGetValue($"TempSensors.EnableLogMessage", false);
var pollInvMs = SC.SafeGetValue($"{ScBasePath}.PollInterval", 100);
// 系统参数变更回调
SC.RegisterValueChangedCallback($"{ScBasePath}.PollInterval",
(obj) => { _tReadTemp.ChangeInterval((int)obj); });
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 bool IsProcess()
{
return DATA.Poll($"{Module}.Status").ToString() == "Process";
}
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
}