using System; using System.Xml; using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device.Unit; using Aitex.Core.RT.IOCore; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using MECF.Framework.Common.Aitex.Core.RT.Device; namespace Aitex.Core.RT.Device.Devices { public class IoPressure : ErrorDetectableBaseDevice, IPressureMeter { public double FeedBack => _isFloatAioType ? _aiValue.Value : _aiValue.Value; public double SetPoint { get { if (_aoValue != null) return _isFloatAioType ? _aoValue.Value : _aoValue.Value; else return 0; } set { if (_aoValue != null) { if (_isFloatAioType) _aoValue.Value = (float)value; else _aoValue.Value = (short)value; } } } public double OpenDegree { get { if (_aiOpenDegree != null) { return _aiOpenDegree.Value; } return 0; } } public double ActMode { get { if (_aiActMode != null) { return _aiActMode.Value; } return 0; } } public double SetMode { get { if (_aoSetMode != null) { return _aoSetMode.Value; } return 0; } set { if (_aoSetMode != null) { if (_isFloatAioType) _aoSetMode.Value = (float)value; else _aoSetMode.Value = (short)value; } } } public double DefaultValue { get { return _scDefaultSetPoint == null ? 1000 : _scDefaultSetPoint.DoubleValue; } } private AITPressureMeterData DeviceData { get { AITPressureMeterData data = new AITPressureMeterData() { Module =Module, DeviceName = Name, DeviceSchematicId = DeviceID, DisplayName = Display, SetPoint = SetPoint, FeedBack = FeedBack, Unit = Unit, FormatString = _formatString, DisplayWithUnit = true, IsError = IsError, IsWarning = IsWarning, //Precision = Precision, Scale = MaxPressure, ActMode = ActMode, SetMode = SetMode, OpenDegree = OpenDegree, DefaultValue = DefaultValue }; return data; } } public bool IsWarning => ErrWarningChecker.Result; public bool IsError { get { return ErrAlarmChecker.Result; } } public double MaxPressure => _scMaxValue?.DoubleValue ?? 100; public bool IsOutOfRange => (FeedBack > MaxPressure); private readonly AIAccessor _aiValue = null; private readonly AOAccessor _aoValue = null; private readonly AIAccessor _aiActMode; private readonly AOAccessor _aoSetMode; private readonly AIAccessor _aiOpenDegree; private readonly string _formatString = "0.0"; private SCConfigItem _scUnitValue; private readonly SCConfigItem _scMaxValue; private readonly SCConfigItem _scDefaultSetPoint; private readonly bool _isFloatAioType = false; private readonly DeviceTimer _rampTimer = new DeviceTimer(); private double _rampTarget; private double _rampInitValue; private int _rampTime; private string _infoText = ""; public IoPressure(string module, XmlElement node, string ioModule = ""): base(module, node, ioModule) { _isFloatAioType = !string.IsNullOrEmpty(node.GetAttribute("aioType")) && (node.GetAttribute("aioType") == "float"); _aiValue = ParseAiNode("aiValue", node, ioModule); _aoValue = ParseAoNode("aoValue", node, ioModule); _aiActMode = ParseAiNode("aiActMode", node, ioModule); _aoSetMode = ParseAoNode("aoSetMode", node, ioModule); _aiOpenDegree = ParseAiNode("aiOpenDegree", node, ioModule); if (node.HasAttribute("formatString")) _formatString = string.IsNullOrEmpty(node.GetAttribute("formatString")) ? "F5" : node.GetAttribute("formatString"); _scMaxValue = ParseScNode("", node, "", $"{ScBasePath}.{Display}.Scale"); _scDefaultSetPoint = ParseScNode("scDefaultSetPoint", node, ioModule, $"{ScBasePath}.{Display}.DefaultSetPoint"); } public override bool Initialize() { DATA.Subscribe($"{Module}.{Name}.SetPoint", () => SetPoint); DATA.Subscribe($"{Module}.{Name}.FeedBack", () => FeedBack); DATA.Subscribe($"{Module}.{Name}.DeviceData", () => DeviceData); DATA.Subscribe($"{Module}.{Name}.SetMode", () => SetMode); OP.Subscribe($"{Module}.{Name}.Ramp", (out string reason, int time, object[] param) => { reason = ""; double target = Convert.ToDouble(param[0].ToString()); if (target < 0 || target > MaxPressure) { reason = $"set {Display} value {target} out of range [0, {MaxPressure}] {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); return true; } private bool SetContrlMode(out string reason, int time, object[] param) { return SetPcMode((PcCtrlMode)Enum.Parse(typeof(PcCtrlMode), (string)param[0], true), out reason); } public bool SetPcMode(PcCtrlMode mode, out string reason) { switch (mode) { case PcCtrlMode.Normal: SetMode = (double)PcCtrlMode.Normal; break; case PcCtrlMode.Close: SetMode = (double)PcCtrlMode.Close; break; case PcCtrlMode.Open: SetMode = (double)PcCtrlMode.Open; break; case PcCtrlMode.Hold: SetMode = (double)PcCtrlMode.Hold; break; default: break; } reason = $"{Display} set to {mode}"; return true; } public void Ramp(double target) { _aoValue.Value = (float)target; } public void Ramp(double target, int time) { _rampTimer.Stop(); target = Math.Max(0, target); target = Math.Min(MaxPressure, target); _rampInitValue = SetPoint; //ramp 初始值取当前设定值,而非实际读取值.零漂问题 _rampTime = time; _rampTarget = target; _rampTimer.Start(_rampTime); } public override void Terminate() { _aoValue.Value = (float)DefaultValue; } 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; } } } protected override void HandleMonitor() { MonitorRamping(); // 当SetPoint大于0.01,并且没有Ramp时,允许检测误差。 MonitorSpFbError(SetPoint >= 0.01 && _rampTimer.IsIdle(), SetPoint, FeedBack); } } }