Sic.Framework-Nanjing-Baishi/MECF.Framework.RT.Equipment.../Devices/IoPSU.cs

528 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Aitex.Core.Common.DeviceData.IoDevice;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.IOCore;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using System;
using System.Xml;
namespace Aitex.Core.RT.Device.Devices
{
public class IoPSU : BaseDevice, IDevice
{
#region Variables
private float _resLimitMax;
private float _outputLimitHighTuningTemp = 1600;
private readonly bool _isFloatAioType;
private readonly AIAccessor _aiOutputVoltage;
private readonly AIAccessor _aiOutputArms;
private readonly AIAccessor _aiOutputPower;
private readonly AIAccessor _aiSimVoltage;
private readonly AIAccessor _aiSimArms;
//private AOAccessor _aoEnable = null;
//private AOAccessor _aoReset = null;
private readonly AOAccessor _aoConstant;
private readonly AOAccessor _aoOutputLimitHigh;
private readonly AOAccessor _aoOutputLimitLow;
private readonly DIAccessor _diStatus;
private readonly DIAccessor _diAlarm;
private readonly DIAccessor _diHeatEnable;
private DIAccessor _diCommunicationError;
private readonly DOAccessor _doReset;
private readonly DOAccessor _doStatus;
private readonly DOAccessor _doHeatEnable;
private readonly DOAccessor _doRelatedEnable; //每个Enable同时关联的InnerMiddleOut Enable
private readonly R_TRIG _alarmTrig = new();
private readonly R_TRIG _commAlarmTrig = new();
private readonly R_TRIG _enableTrig = new();
private readonly R_TRIG _enableTrig2 = new();
private readonly R_TRIG _trigVoltage = new();
private readonly R_TRIG _trigCurrent = new();
private readonly R_TRIG _trigResOutOfRange = new();
private readonly DeviceTimer _timResetPulse = new();
private readonly DeviceTimer _timResOutOfRange = new();
private readonly IoPsuData _deviceData = new();
#endregion
#region Constructors
public IoPSU(string module, XmlElement node, string ioModule = "") : base(module, node, ioModule)
{
_aiOutputVoltage = ParseAiNode("aiOutputVoltage", node, ioModule);
_aiOutputArms = ParseAiNode("aiOutputArms", node, ioModule);
_aiOutputPower = ParseAiNode("aiOutputPower", node, ioModule);
_aiSimVoltage = ParseAiNode("aiSimVoltage", node, ioModule);
_aiSimArms = ParseAiNode("aiSimArms", node, ioModule);
_aoConstant = ParseAoNode("aoConstant", node, ioModule);
_aoOutputLimitHigh = ParseAoNode("aoOutputLimitHigh", node, ioModule);
_aoOutputLimitLow = ParseAoNode("aoOutputLimitLow", node, ioModule);
_doReset = ParseDoNode("doReset", node, ioModule);
_doStatus = ParseDoNode("doStatus", node, ioModule);
_diStatus = ParseDiNode("diStatus", node, ioModule);
_diAlarm = ParseDiNode("diAlarm", node, ioModule);
_doHeatEnable = ParseDoNode("doHeatEnable", node, ioModule);
_diHeatEnable = ParseDiNode("diHeatEnable", node, ioModule);
_doRelatedEnable = ParseDoNode("doRelatedEnable", node, ioModule);
_diCommunicationError = ParseDiNode("diCommunicationError", node, ioModule);
_isFloatAioType = !string.IsNullOrEmpty(node.GetAttribute("aioType")) && (node.GetAttribute("aioType") == "float");
}
#endregion
#region Properties
public float OutputVoltageFeedBack => _aiOutputVoltage == null ? 0 : (_isFloatAioType ? _aiOutputVoltage.Value : _aiOutputVoltage.Value);
public float OutputArmsFeedBack => _aiOutputArms == null ? 0 : (_isFloatAioType ? _aiOutputArms.Value : _aiOutputArms.Value);
public float ResistanceLimitMax => _resLimitMax;
public float Resistance => OutputArmsFeedBack == 0 ? 0 : OutputVoltageFeedBack / OutputArmsFeedBack;
public bool IsResistanceOutOfRange => IsResistanceTooHigh;
public bool IsResistanceTooHigh
{
get;
private set;
}
public float OutputPowerFeedBack => _aiOutputPower == null ? 0 : (_isFloatAioType ? _aiOutputPower.Value : _aiOutputPower.Value);
public bool StatusFeedBack => _diStatus?.Value ?? false;
public float SimVoltageFeedBack => _aiSimVoltage == null ? 0 : (_isFloatAioType ? _aiSimVoltage.Value : _aiSimVoltage.Value);
public float SimArmsFeedBack => _aiSimArms == null ? 0 : (_isFloatAioType ? _aiSimArms.Value : _aiSimArms.Value);
public bool AlarmFeedBack => _diAlarm?.Value ?? false;
public float ConstantSetPoint
{
get => _aoConstant == null ? 0 : (_isFloatAioType ? _aoConstant.Value : _aoConstant.Value);
set
{
if (_isFloatAioType)
{
_aoConstant.Value = value;
}
else
{
_aoConstant.Value = (short)value;
}
}
}
public float OutputLimitHigh => _aoOutputLimitHigh?.Value ?? 0;
public float OutputLimitLow => _aoOutputLimitLow?.Value ?? 0;
public bool AllHeatEnable => _diHeatEnable?.Value ?? false;
private IoPsuData DeviceData
{
get
{
_deviceData.IsAlarm = AlarmFeedBack;
_deviceData.OutputStatusFeedBack = StatusFeedBack;
_deviceData.AllHeatEnable = AllHeatEnable;
_deviceData.ConstantSetPoint = ConstantSetPoint;
_deviceData.OutputArmsFeedBack = OutputArmsFeedBack;
_deviceData.OutputPowerFeedBack = OutputPowerFeedBack;
_deviceData.OutputVoltageFeedback = OutputVoltageFeedBack;
_deviceData.ResistanceLimitMax = ResistanceLimitMax;
_deviceData.Resistance = Resistance;
_deviceData.IsResistanceOutOfRange = IsResistanceOutOfRange;
_deviceData.IsResistanceTooHigh = IsResistanceTooHigh;
_deviceData.OutputLimitHighTuningTemp = _outputLimitHighTuningTemp;
_deviceData.OutputLimitHigh = OutputLimitHigh;
_deviceData.OutputLimitLow = OutputLimitLow;
return _deviceData;
}
}
public Func<bool, bool> FuncCheckInterLock { get; set; }
#endregion
#region Methods
public bool Initialize()
{
DATA.Subscribe($"{Module}.{Name}.OutputVoltageFeedBack", () => OutputVoltageFeedBack);
DATA.Subscribe($"{Module}.{Name}.OutputArmsFeedBack", () => OutputArmsFeedBack);
DATA.Subscribe($"{Module}.{Name}.ResistanceLimitMax", () => ResistanceLimitMax);
DATA.Subscribe($"{Module}.{Name}.Resistance", () => Resistance);
DATA.Subscribe($"{Module}.{Name}.IsResistanceOutOfRange", () => IsResistanceOutOfRange);
DATA.Subscribe($"{Module}.{Name}.IsResistanceTooHigh", () => IsResistanceTooHigh);
DATA.Subscribe($"{Module}.{Name}.OutputPowerFeedBack", () => OutputPowerFeedBack);
DATA.Subscribe($"{Module}.{Name}.StatusFeedBack", () => StatusFeedBack);
DATA.Subscribe($"{Module}.{Name}.SimVoltageFeedBack", () => SimVoltageFeedBack);
DATA.Subscribe($"{Module}.{Name}.SimArmsFeedBack", () => SimArmsFeedBack);
DATA.Subscribe($"{Module}.{Name}.ConstantSetPoint", () => ConstantSetPoint);
/*DATA.Subscribe($"{Module}.{Name}.OutputLimitHigh", () => OutputLimitHigh);
DATA.Subscribe($"{Module}.{Name}.OutputLimitLow", () => OutputLimitLow);
DATA.Subscribe($"{Module}.{Name}.OutputLimitHighTuningTemp", () => _outputLimitHighTuningTemp);*/
DATA.Subscribe($"{Module}.{Name}.AlarmFeedBack", () => AlarmFeedBack);
DATA.Subscribe($"{Module}.{Name}.AllHeatEnable", () => AllHeatEnable);
DATA.Subscribe($"{Module}.{Name}.DeviceData", () => DeviceData);
OP.Subscribe($"{Module}.{Name}.SetHeadHeaterEnable", (function, args) =>
{
var isTrue = Convert.ToBoolean(args[0]);
SetHeadHeaterEnable(isTrue, out _);
return true;
});
OP.Subscribe($"{Module}.{Name}.SetPSUEnable", (function, args) =>
{
var isTrue = Convert.ToBoolean(args[0]);
SetPSUEnable(isTrue, out _);
return true;
});
OP.Subscribe($"{Module}.{Name}.SetPSUReset", (function, args) =>
{
var isTrue = Convert.ToBoolean(args[0]);
SetPSUReset(isTrue, out _);
return true;
});
/*
OP.Subscribe($"{Module}.{Name}.SetOutputLimitHighTuningTemp", (function, args) =>
{
if (args.Length == 1 && args[0] is double value)
{
SC.SetItemValue($"PM.{Module}.Heater.PSU2OutputLimitHighTuningTemp", value);
return true;
}
EV.PostWarningLog(Module, $"SetOutputLimitHighTuningTemp fail, args error");
return false;
});
OP.Subscribe($"{Module}.{Name}.SetOutputLimitHighByRecipe", (out string reason, int time, object[] args) =>
{
reason = string.Empty;
if (_aoOutputLimitHigh == null)
{
return true;
}
if (args.Length == 1 && double.TryParse(args[0].ToString(), out var value))
{
var tunedByRecipe = SC.GetValue<bool>($"PM.{Module}.Heater.PSU2OutputLimitHighTuningByRecipe");
if(tunedByRecipe)
_aoOutputLimitHigh.Value = Convert.ToSingle(value);
return true;
}
EV.PostWarningLog(Module, $"SetOutputLimitHighByRecipe fail, args error");
return true;
});
OP.Subscribe($"{Module}.{Name}.SetOutputLimitHigh", (function, args) =>
{
if (args.Length == 1 && args[0] is double value)
{
SetOutputLimitHigh(value);
return true;
}
EV.PostWarningLog(Module, $"SetOutputLimitHigh fail, args error");
return false;
});
OP.Subscribe($"{Module}.{Name}.SetOutputLimitLow", (function, args) =>
{
if (args.Length == 1 && args[0] is double value)
{
SetOutputLimitLow(value);
return true;
}
EV.PostWarningLog(Module, $"SetOutputLimitLow fail, args error");
return false;
});
*/
return true;
}
public bool SetPSUEnable(bool setValue, out string reason)
{
if (!_doStatus.Check(setValue, out reason))
{
EV.PostWarningLog(Module, reason);
return false;
}
if (!_doRelatedEnable.Check(setValue, out reason))
{
EV.PostWarningLog(Module, reason);
return false;
}
if (!_doStatus.SetValue(setValue, out reason))
{
EV.PostWarningLog(Module, reason);
return false;
}
if (!_doRelatedEnable.SetValue(setValue, out reason))
{
EV.PostWarningLog(Module, reason);
return false;
}
return true;
}
public bool SetHeadHeaterEnable(bool setValue, out string reason)
{
reason = "";
if (FuncCheckInterLock != null)
{
if (!FuncCheckInterLock(setValue))
{
EV.PostInfoLog(Module, $"Set PSU Enable fialed for Interlock!");
return false;
}
}
if (!_doHeatEnable.Check(setValue, out reason))
{
EV.PostWarningLog(Module, reason);
return false;
}
if (!_doHeatEnable.SetValue(setValue, out reason))
{
EV.PostWarningLog(Module, reason);
return false;
}
return true;
}
public void SetOutputLimitHigh(double value)
{
SC.SetItemValue($"PM.{Module}.Heater.PSU2OutputLimitHigh", value);
}
public void SetOutputLimitLow(double value)
{
SC.SetItemValue($"PM.{Module}.Heater.PSU2OutputLimitLow", value);
}
public bool SetPSUReset(bool setValue, out string reason)
{
if (!_doReset.Check(setValue, out reason))
{
EV.PostWarningLog(Module, reason);
return false;
}
if (!_doReset.SetValue(setValue, out reason))
{
EV.PostWarningLog(Module, reason);
return false;
}
_timResetPulse.Start(1000);
return true;
}
public bool CheckPSUEnable()
{
return _doStatus.Value;
}
public void Terminate()
{
}
protected override void HandleMonitor()
{
try
{
// MonitorPsu2OutputLimit();
MonitorEnableTimer();
MonitorAlarm();
MonitorDoResetDone();
}
catch (Exception ex)
{
LOG.Write(ex);
}
}
public void Reset()
{
_alarmTrig.RST = true;
_commAlarmTrig.RST = true;
_trigVoltage.RST = true;
_trigCurrent.RST = true;
ResetResistanceMonitorResult();
}
private void MonitorDoResetDone()
{
if (_timResetPulse.IsTimeout())
{
_timResetPulse.Stop();
if (_doReset.Value)
_doReset.Value = false;
ResetResistanceMonitorResult();
}
}
/// <summary>
/// 复位加热器电阻监测结果。
/// </summary>
private void ResetResistanceMonitorResult()
{
IsResistanceTooHigh = false;
_trigResOutOfRange.RST = true;
_timResOutOfRange.Stop();
}
private void MonitorAlarm()
{
//检查电阻值是否在合理范围
_resLimitMax = (float)SC.GetValue<double>($"PM.{Module}.Heater.{Name}ResistanceMax");
var timeOut = SC.GetValue<int>($"PM.{Module}.Heater.ResistanceMonitorHysteresis");
if (Resistance > _resLimitMax && _timResOutOfRange.IsIdle())
{
_timResOutOfRange.Start(timeOut * 1000);
}
if (Resistance <= _resLimitMax)
{
IsResistanceTooHigh = false;
_timResOutOfRange.Stop();
}
_trigResOutOfRange.CLK = _timResOutOfRange.IsTimeout();
if (_trigResOutOfRange.Q)
{
IsResistanceTooHigh = true;
EV.PostWarningLog(Module, $"{Name} Current resistance {Resistance}ohm exceeds the high limit {_resLimitMax}ohm.");
}
}
private void MonitorEnableTimer()
{
if (Name == "PSU2")
{
_enableTrig.CLK = !_diHeatEnable.Value;
if (_enableTrig.Q)
{
SC.SetItemValue($"PM.{Module}.OpenLidCountDownTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
}
_enableTrig2.CLK = _diHeatEnable.Value;
if (_enableTrig2.Q)
{
SC.SetItemValue($"PM.{Module}.OpenLidCountDownTime", "");
}
}
}
#region PSU2 Output Limit (Obsolete)
/*private readonly R_TRIG _trigBelow1600 = new();
private readonly R_TRIG _trigAbove1600 = new();
private void MonitorPsu2OutputLimit()
{
if (Name == "PSU2")
{
var tunedByRecipe = SC.GetValue<bool>($"PM.{Module}.Heater.PSU2OutputLimitHighTuningByRecipe");
tunedByRecipe = false; // 该功能用于测试,在发行版上屏蔽
if (!tunedByRecipe)
{
var limitHigh = (float)SC.GetValue<double>($"PM.{Module}.Heater.PSU2OutputLimitHigh");
var limitLow = (float)SC.GetValue<double>($"PM.{Module}.Heater.PSU2OutputLimitLow");
_outputLimitHighTuningTemp =
(float)SC.GetValue<double>($"PM.{Module}.Heater.PSU2OutputLimitHighTuningTemp");
_trigAbove1600.CLK = AETemp >= _outputLimitHighTuningTemp;
if (_trigAbove1600.Q)
EV.PostInfoLog(Module, $"Temp above {_outputLimitHighTuningTemp}℃, limit PSU2 Output level to {limitLow}%-{limitHigh}%");
_trigBelow1600.CLK = AETemp < _outputLimitHighTuningTemp;
if (_trigAbove1600.Q)
EV.PostInfoLog(Module, $"Temp below {_outputLimitHighTuningTemp}℃, limit PSU2 Output level to 100%");
if (AETemp >= _outputLimitHighTuningTemp)
{
if (Math.Abs(_aoOutputLimitHigh.Value - limitHigh) > 1E-6)
_aoOutputLimitHigh.Value = limitHigh;
if (Math.Abs(_aoOutputLimitLow.Value - limitLow) > 1E-6)
_aoOutputLimitLow.Value = limitLow;
}
else
{
_aoOutputLimitHigh.Value = 100;
_aoOutputLimitLow.Value = 100;
}
}
}
}*/
#endregion
private double AETemp
{
get
{
object temp = null;
if (SC.GetConfigItem("AETemp.EnableDevice").BoolValue)
{
temp = DATA.Poll($"{Module}.AETemp.Middle");
}
if (SC.GetConfigItem("AKunTemp.EnableDevice").BoolValue)
{
temp = DATA.Poll($"{Module}.AKunTemp.Middle");
}
return temp == null ? 0 : (double)temp;
}
}
#endregion
}
}