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

371 lines
12 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 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;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.MFCs;
namespace Aitex.Core.RT.Device.Devices
{
public class IoMFC : ErrorDetectableBaseDevice, IMfc
{
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}"
AITMfcData data = new AITMfcData()
{
UniqueName = $"{Module}.{Name}",
Type = "MFC",
Module = Module,
DeviceName = Name,
DeviceSchematicId = DeviceID,
DisplayName = $"{Name}-->{DisplayName}",
FeedBack = FeedBack,
SetPoint = SetPoint,
Scale = Scale,
IsWarning = ErrWarningChecker.Result,
IsError = ErrAlarmChecker.Result,
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;
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)
{
_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);
_isFloatAioType = !string.IsNullOrEmpty(node.GetAttribute("aioType")) && (node.GetAttribute("aioType") == "float");
_scGasName = SC.GetConfigItem($"{ScBasePath}.{Name}.GasName");
//_scEnable = SC.GetConfigItem($"{scBasePath}.{Name}.Enable");
_scN2Scale = ParseScNode("scN2Scale", node, ioModule, $"{ScBasePath}.{Name}.N2Scale");
//_scScaleFactor = ParseScNode("scScaleFactor", node, ioModule, $"{scBasePath}.{Name}.ScaleFactor");
_scDefaultSetPoint = ParseScNode("scDefaultSetPoint", node, ioModule, $"{ScBasePath}.{Name}.DefaultSetPoint");
//_scRegulationFactor = ParseScNode("scFlowRegulationFactor", node, ioModule, $"{scBasePath}.{Name}.RegulationFactor");
}
public override bool Initialize()
{
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()
{
MonitorRamping();
// 当SetPoint大于0.01并且没有Ramp时允许检测误差。
MonitorSpFbError(SetPoint >= 0.01 && _rampTimer.IsIdle(), SetPoint, FeedBack);
}
public void SetToDefaultByRamp(int time)
{
Ramp(DefaultSetPoint, time * 1000);
}
public override void Terminate()
{
Ramp(DefaultSetPoint, 5000);
base.Terminate();
}
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)
{
_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;
}
}
}
}
}