using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; 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; namespace MECF.Framework.Common.Device.Bases { public abstract class MfcBase : BaseDevice, IDevice { public string Unit { get; set; } public float Scale { get { if (_scN2Scale == null || _scScaleFactor == null) return 0; return (float)( _scN2Scale.DoubleValue * _scScaleFactor.DoubleValue); } } public virtual float SetPoint { get; set; } public virtual float FeedBack { get; set; } public bool IsOutOfTolerance { get { return _toleranceChecker.Result; } } public bool EnableAlarm { get { if (_scEnableAlarm != null) return _scEnableAlarm.BoolValue; return false; } } public double AlarmRange { get { if (_scAlarmRange != null) return _scAlarmRange.DoubleValue; return 0; } } public double AlarmTime { get { if (_scAlarmTime != null) return _scAlarmTime.IntValue; return 0; } } public string DisplayName { get { if (_scGasName != null) return _scGasName.StringValue; return Display; } } public virtual AITMfcData DeviceData { get { AITMfcData data = new AITMfcData() { UniqueName = _uniqueName, Type = "MFC", DeviceName = Name, DeviceSchematicId = DeviceID, DisplayName = DisplayName, FeedBack = FeedBack, SetPoint = SetPoint, Scale = Scale, }; return data; } } private DeviceTimer rampTimer = new DeviceTimer(); private float rampTarget; private float rampInitValue; private int rampTime; private ToleranceChecker _toleranceChecker = new ToleranceChecker(); private SCConfigItem _scGasName; private SCConfigItem _scEnable; private SCConfigItem _scN2Scale; private SCConfigItem _scScaleFactor; private SCConfigItem _scAlarmRange; private SCConfigItem _scEnableAlarm; private SCConfigItem _scAlarmTime; private SCConfigItem _scDefaultSetPoint; private SCConfigItem _scRegulationFactor; private R_TRIG _trigOffline = new R_TRIG(); private string _uniqueName; public MfcBase( ):base() { } public MfcBase(string module, XmlElement node, string ioModule = "") { Unit = node.GetAttribute("unit"); base.Module = string.IsNullOrEmpty(node.GetAttribute("module")) ? module : node.GetAttribute("module"); base.Name = node.GetAttribute("id"); base.Display = node.GetAttribute("display"); base.DeviceID = node.GetAttribute("schematicId"); _scGasName = ParseScNode("scGasName", node); _scEnable = ParseScNode("scEnable", node); _scN2Scale = ParseScNode("scN2Scale", node, ioModule, $"{Module}.{Name}.N2Scale"); _scScaleFactor = ParseScNode("scScaleFactor", node, ioModule, $"{Module}.{Name}.ScaleFactor"); _scAlarmRange = ParseScNode("scAlarmRange", node, ioModule, $"{Module}.{Name}.AlarmRange"); _scEnableAlarm = ParseScNode("scEnableAlarm", node, ioModule, $"{Module}.{Name}.EnableAlarm"); _scAlarmTime = ParseScNode("scAlarmTime", node, ioModule, $"{Module}.{Name}.AlarmTime"); _scDefaultSetPoint = ParseScNode("scDefaultSetPoint", node); _scRegulationFactor = ParseScNode("scFlowRegulationFactor", node, ioModule, $"{Module}.{Name}.RegulationFactor"); _uniqueName = $"{Module}.{Name}"; } public virtual bool Initialize() { DATA.Subscribe($"{Module}.{Name}.DeviceData", () => DeviceData); DATA.Subscribe($"{Module}.{Name}.FlowFeedback", () => FeedBack); DATA.Subscribe($"{Module}.{Name}.FlowSetPoint", () => SetPoint); OP.Subscribe($"{Module}.{Name}.SetMfcFlow", (function, args) => { SetMfcFlow(Convert.ToSingle(args[0])); return true; }); OP.Subscribe($"{Module}.{Name}.Ramp", (function, args) => { SetMfcFlow(Convert.ToSingle(args[0])); return true; }); InitSc(); return true; } public virtual void InitSc() { _scGasName = SC.GetConfigItem($"{ScBasePath}.{Name}.GasName"); _scEnable = SC.GetConfigItem($"{ScBasePath}.{Name}.Enable"); _scN2Scale = SC.GetConfigItem($"{ScBasePath}.{Name}.N2Scale"); _scScaleFactor = SC.GetConfigItem($"{ScBasePath}.{Name}.ScaleFactor"); _scEnableAlarm = SC.GetConfigItem($"{ScBasePath}.{Name}.EnableAlarm"); _scAlarmRange = SC.GetConfigItem($"{ScBasePath}.{Name}.AlarmRange"); _scAlarmTime = SC.GetConfigItem($"{ScBasePath}.{Name}.AlarmTime"); } public virtual void SetMfcFlow(float flow) { } public virtual bool SetMfcFlow(int time, float flow, out string reason) { reason = ""; return true; } private bool InvokeRamp(string method, object[] args) { float target = Convert.ToSingle((string)(args[0].ToString())); target = Math.Min(target, Scale); target = Math.Max(target, 0); int time = 0; if (args.Length >= 2) time = Convert.ToInt32((string)(args[1].ToString())); Ramp(target, time); EV.PostInfoLog(Module, $"{_uniqueName} ramp to {target}{Unit} in {time} seconds"); return true; } public virtual void Monitor() { MonitorRamping(); MonitorTolerance(); } public virtual void Reset() { _toleranceChecker.Reset(AlarmTime); _trigOffline.RST = true; } public virtual void Terminate() { Ramp(0, 0); } public void Ramp(int time) { Ramp(0, time); } public void Ramp(float target, int time) { target = Math.Max(0, target); target = Math.Min(Scale, target); rampInitValue = SetPoint; //ramp 初始值取当前设定值,而非实际读取值。零漂问题 rampTime = time; rampTarget = target; rampTimer.Start(rampTime); } public void StopRamp() { Ramp(SetPoint, 0); } private void MonitorRamping() { if (rampTimer.IsTimeout() || rampTime == 0) { SetPoint = rampTarget; } else { SetPoint = (float)(rampInitValue + (rampTarget - rampInitValue) * rampTimer.GetElapseTime() / rampTime); } } private void MonitorTolerance() { if (!EnableAlarm) return; _toleranceChecker.Monitor(FeedBack, (SetPoint - Math.Abs(AlarmRange)), (SetPoint + Math.Abs(AlarmRange)), AlarmTime); if (_toleranceChecker.Trig) { EV.PostMessage(Module, EventEnum.ToleranceAlarm, Module, Display, String.Format("Out of range in {0} seconds", AlarmTime.ToString("0"))); } } } }