Sic.Framework/MECF.Framework.RT.Equipment.../Devices/IoMFC.cs

371 lines
12 KiB
C#
Raw Normal View History

2023-04-13 11:51:03 +08:00
using System;
using System.Xml;
using Aitex.Core.Common.DeviceData;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.IOCore;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.SCCore;
using Aitex.Core.RT.Tolerance;
using Aitex.Core.Util;
using MECF.Framework.Common.Aitex.Core.RT.Device;
2023-04-13 11:51:03 +08:00
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.MFCs;
namespace Aitex.Core.RT.Device.Devices
{
public class IoMFC : ErrorDetectableBaseDevice, IMfc
2023-04-13 11:51:03 +08:00
{
public double Scale
{
get
{
if (_scN2Scale == null )
return 0;
return _scN2Scale.DoubleValue ;
}
}
public double SetPoint
{
get
{
if (_aoFlow != null)
{
return _isFloatAioType ? _aoFlow.FloatValue : _aoFlow.Value;
}
return 0;
}
set
{
if (_aoFlow != null)
{
if (_isFloatAioType)
_aoFlow.FloatValue = (float)value;
else
_aoFlow.Value = (short)value;
}
}
}
public double DefaultSetPoint
{
get
{
if (_scDefaultSetPoint != null)
return _scDefaultSetPoint.DoubleValue;
return 0;
}
}
public double FeedBack
{
get
{
if (_aiFlow != null)
{
double aiValue = _isFloatAioType ? _aiFlow.FloatValue : _aiFlow.Value;
return aiValue; // (_scRegulationFactor != null && _scRegulationFactor.DoubleValue > 0.001) ? aiValue / _scRegulationFactor.DoubleValue : aiValue;
}
return 0;
}
}
public double ActMode
{
get
{
if (_aiActMode != null)
{
return _aiActMode.FloatValue;
}
return 0;
}
}
public double SetMode
{
get
{
if (_aoSetMode != null)
{
return _aoSetMode.FloatValue;
}
return 0;
}
set
{
if (_aoSetMode != null)
{
if (_isFloatAioType)
_aoSetMode.FloatValue = (float)value;
else
_aoSetMode.Value = (short)value;
}
}
}
private AITMfcData DeviceData
{
get
{
//原DisplayName = DisplayName 改成DisplayName = $"{Name}-->{DisplayName}"
2023-04-13 11:51:03 +08:00
AITMfcData data = new AITMfcData()
{
UniqueName = $"{Module}.{Name}",
Type = "MFC",
Module = Module,
DeviceName = Name,
DeviceSchematicId = DeviceID,
DisplayName = $"{Name}-->{DisplayName}",
2023-04-13 11:51:03 +08:00
FeedBack = FeedBack,
SetPoint = SetPoint,
Scale = Scale,
IsWarning = ErrWarningChecker.Result,
IsError = ErrAlarmChecker.Result,
2023-04-13 11:51:03 +08:00
DefaultValue = DefaultSetPoint,
ActMode = ActMode,
SetMode = SetMode,
};
//if (Module.Equals("PM1") && Name.Equals("Mfc1"))
// Console.WriteLine("Mfc3:" + FeedBack);
return data;
}
}
public string DisplayName
{
get
{
if (_scGasName != null)
return _scGasName.StringValue;
return Display;
}
}
private DeviceTimer _rampTimer = new DeviceTimer();
private double _rampTarget;
private double _rampInitValue;
private double _rampSetMode;
private int _rampTime;
2023-04-13 11:51:03 +08:00
private ToleranceChecker _toleranceCheckerWarning = new ToleranceChecker();
private ToleranceChecker _toleranceCheckerAlarm = new ToleranceChecker();
private AIAccessor _aiFlow;
private AIAccessor _aiActMode;
private AOAccessor _aoFlow;
private AOAccessor _aoSetMode;
private DIAccessor _diAlarm;
protected SCConfigItem _scGasName;
protected SCConfigItem _scEnable;
private SCConfigItem _scN2Scale;
private SCConfigItem _scScaleFactor;
private SCConfigItem _scDefaultSetPoint;
private SCConfigItem _scRegulationFactor;
private bool _isFloatAioType = false;
private R_TRIG _alamrTrig = new R_TRIG();
public IoMFC(string module, XmlElement node, string ioModule = "") : base(module, node, ioModule)
2023-04-13 11:51:03 +08:00
{
_aiFlow = ParseAiNode("aiFlow", node, ioModule);
_aoFlow = ParseAoNode("aoFlow", node, ioModule);
_aiActMode = ParseAiNode("aiActMode", node, ioModule);
_aoSetMode = ParseAoNode("aoSetMode", node, ioModule);
_diAlarm = ParseDiNode("diAlarm", node, ioModule);
2023-04-13 11:51:03 +08:00
_isFloatAioType = !string.IsNullOrEmpty(node.GetAttribute("aioType")) && (node.GetAttribute("aioType") == "float");
_scGasName = SC.GetConfigItem($"{ScBasePath}.{Name}.GasName");
2023-04-13 11:51:03 +08:00
//_scEnable = SC.GetConfigItem($"{scBasePath}.{Name}.Enable");
_scN2Scale = ParseScNode("scN2Scale", node, ioModule, $"{ScBasePath}.{Name}.N2Scale");
2023-04-13 11:51:03 +08:00
//_scScaleFactor = ParseScNode("scScaleFactor", node, ioModule, $"{scBasePath}.{Name}.ScaleFactor");
_scDefaultSetPoint = ParseScNode("scDefaultSetPoint", node, ioModule, $"{ScBasePath}.{Name}.DefaultSetPoint");
2023-04-13 11:51:03 +08:00
//_scRegulationFactor = ParseScNode("scFlowRegulationFactor", node, ioModule, $"{scBasePath}.{Name}.RegulationFactor");
}
public override bool Initialize()
2023-04-13 11:51:03 +08:00
{
DATA.Subscribe($"{Module}.{Name}.DeviceData", () => DeviceData);
DATA.Subscribe($"{Module}.{Name}.FeedBack", () => FeedBack);
DATA.Subscribe($"{Module}.{Name}.SetPoint", () => SetPoint);
DATA.Subscribe($"{Module}.{Name}.SetMode", () => SetMode);
OP.Subscribe($"{Module}.{Name}.Ramp", (out string reason, int time, object[] param) =>
{
double target = Convert.ToDouble(param[0].ToString());
if (target < 0 || target > Scale)
{
reason = $"set {Display} value {target} out of range [0, {Scale}] {Unit}";
return false;
}
Ramp(target, time);
if (time > 0)
{
reason = $"{Display} ramp to {target} {Unit} in {time} seconds";
}
else
{
reason = $"{Display} ramp to {target} {Unit}";
}
return true;
});
OP.Subscribe($"{Module}.{Name}.SetMode", SetContrlMode);
//OP.Subscribe($"{Module}.{Name}.SetMode", (function, args) =>
//{
// if (!Enum.TryParse((string)args[0], out PressureCtrlMode mode))
// {
// EV.PostWarningLog(Module, $"Argument {args[0]}not valid");
// return false;
// }
// SetMode();
// return true;
//});
return true;
}
private bool SetContrlMode(out string reason, int time, object[] param)
{
return SetMfcMode((MfcCtrlMode)Enum.Parse(typeof(MfcCtrlMode), (string)param[0], true),
out reason);
}
public bool SetMfcMode(MfcCtrlMode mode, out string reason)
{
switch (mode)
{
case MfcCtrlMode.Normal:
SetMode = (double)MfcCtrlMode.Normal;
break;
case MfcCtrlMode.Close:
SetMode = (double)MfcCtrlMode.Close;
break;
case MfcCtrlMode.Open:
SetMode = (double)MfcCtrlMode.Open;
break;
case MfcCtrlMode.Hold:
SetMode = (double)MfcCtrlMode.Hold;
break;
default:
break;
}
reason = $"{Display} set to {mode}";
return true;
}
public override void Monitor()
2023-04-13 11:51:03 +08:00
{
MonitorRamping();
// 当SetPoint大于0.01并且没有Ramp时允许检测误差。
MonitorSpFbError(SetPoint >= 0.01 && _rampTimer.IsIdle(), SetPoint, FeedBack);
2023-04-13 11:51:03 +08:00
}
public void SetToDefaultByRamp(int time)
{
Ramp(DefaultSetPoint, time * 1000);
}
public override void Terminate()
2023-04-13 11:51:03 +08:00
{
Ramp(DefaultSetPoint, 5000);
base.Terminate();
2023-04-13 11:51:03 +08:00
}
public bool Ramp(double flowSetPoint, int time, out string reason)
{
if (HasAlarm)
{
reason = $"{DisplayName} in error status, can not flow";
return false;
}
if (flowSetPoint < 0 || flowSetPoint > Scale)
{
reason = $"{DisplayName} range is [0, {Scale}], can not flow {flowSetPoint}";
return false;
}
if (time > 0)
{
EV.PostInfoLog(Module, $"Set {DisplayName} flow to {flowSetPoint} {Unit} in {time / 1000:F0} seconds");
}
else
{
EV.PostInfoLog(Module, $"Set {DisplayName} flow to {flowSetPoint} {Unit}");
}
Ramp(flowSetPoint, time);
reason = string.Empty;
return true;
}
public void Ramp(int time)
{
Ramp(DefaultSetPoint, time);
}
public void Ramp(double target, int time)
2023-04-13 11:51:03 +08:00
{
_rampTimer.Stop();
target = Math.Max(0, target);
target = Math.Min(Scale, target);
_rampInitValue = SetPoint; //ramp 初始值取当前设定值,而非实际读取值.零漂问题
_rampTime = time;
_rampTarget = target;
_rampTimer.Start(_rampTime);
_rampSetMode = SetMode;
//EV.PostInfoLog(Module, $"{Name}.Ramp {_rampTarget} in {_rampTime} senconds,Mode {_rampSetMode/1000}");
}
public void StopRamp()
{
if (!_rampTimer.IsIdle())
{
if (_rampTime != 0)
{
Ramp(SetPoint, 0);
}
}
}
private void MonitorRamping()
{
if (!_rampTimer.IsIdle())
{
if (_rampTimer.IsTimeout() || _rampTime == 0)
{
_rampTimer.Stop();
SetPoint = _rampTarget;
}
else
{
SetPoint = _rampInitValue + (_rampTarget - _rampInitValue) * _rampTimer.GetElapseTime() / _rampTime;
}
if(_rampSetMode == 0 || _rampSetMode == 1 || _rampSetMode == 2 || _rampSetMode == 3)
{
SetMode = _rampSetMode;
}
}
}
}
}