using System; 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.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; namespace VirgoRT.Devices { public class IoThrottleValve : BaseDevice, IDevice { public struct Context { public string tvName; public string aoPressureModeName; public string aoPressureSetPointName; public string aoPositionSetPointName; public string aiPressureFeedbackName; public string aiPositionFeedbackName; public string aiStateName; }; public PressureCtrlMode PressureMode { get { if (_aoPressureMode == null) return PressureCtrlMode.TVPositionCtrl; byte[] high = BitConverter.GetBytes(_aoPositionSetPoint.Buffer[_aoPressureMode.Index]); byte[] low = BitConverter.GetBytes(_aoPositionSetPoint.Buffer[_aoPressureMode.Index + 1]); float _pressureMode = BitConverter.ToSingle(new[] { high[0], high[1], low[0], low[1] }, 0); return Math.Abs(_pressureMode - 2) < 0.1 ? PressureCtrlMode.TVPositionCtrl : PressureCtrlMode.TVPressureCtrl; } set { if (_aoPositionSetPoint == null || _aoPressureSetPoint == null || _aoPressureMode == null) return; short setpoint = (short)(value == PressureCtrlMode.TVPositionCtrl ? 2 : 1); byte[] high = BitConverter.GetBytes(_aoPositionSetPoint.Buffer[_aoPressureMode.Index]); byte[] low = BitConverter.GetBytes(_aoPositionSetPoint.Buffer[_aoPressureMode.Index + 1]); float _pressureMode = BitConverter.ToSingle(new[] { high[0], high[1], low[0], low[1] }, 0); if (Math.Abs(_pressureMode - setpoint) > 0.01) { if (value == PressureCtrlMode.TVPositionCtrl) { //_aoPositionSetPoint.Value = PositionFeedback; byte[] _position = BitConverter.GetBytes(PositionFeedback); _aoPositionSetPoint.Buffer[_aoPositionSetPoint.Index] = BitConverter.ToInt16(_position, 0); _aoPositionSetPoint.Buffer[_aoPositionSetPoint.Index + 1] = BitConverter.ToInt16(_position, 2); } else { //_aoPressureSetPoint.Value = PressureFeedback; byte[] _pressure = BitConverter.GetBytes(PressureFeedback); _aoPressureSetPoint.Buffer[_aoPressureSetPoint.Index] = BitConverter.ToInt16(_pressure, 0); _aoPressureSetPoint.Buffer[_aoPressureSetPoint.Index + 1] = BitConverter.ToInt16(_pressure, 2); } //_aoPressureMode.Value = setpoint; byte[] flow = BitConverter.GetBytes((float)setpoint); _aoPressureMode.Buffer[_aoPressureMode.Index] = BitConverter.ToInt16(flow, 0); _aoPressureMode.Buffer[_aoPressureMode.Index + 1] = BitConverter.ToInt16(flow, 2); } } } public int State => _aiState == null ? 1 : (int)_aiState.Value; [Subscription("ProcessPressureOffset")] public double ProcessPressureOffset { get { if (_scProcessPressureOffset != null) return _scProcessPressureOffset.DoubleValue; return 0; } } [Subscription(AITThrottleValvePropertyName.TVPositionSetPoint)] public float PositionSetpoint { get { if (_aoPositionSetPoint != null) { byte[] high = BitConverter.GetBytes(_aoPositionSetPoint.Buffer[_aoPositionSetPoint.Index]); byte[] low = BitConverter.GetBytes(_aoPositionSetPoint.Buffer[_aoPositionSetPoint.Index + 1]); float flow = BitConverter.ToSingle(new[] { high[0], high[1], low[0], low[1] }, 0); return flow; } return 0; } set { if (_aoPositionSetPoint != null) { byte[] flow = BitConverter.GetBytes(value); _aoPositionSetPoint.Buffer[_aoPositionSetPoint.Index] = BitConverter.ToInt16(flow, 0); _aoPositionSetPoint.Buffer[_aoPositionSetPoint.Index + 1] = BitConverter.ToInt16(flow, 2); } } } [Subscription(AITThrottleValvePropertyName.TVPosition)] public float PositionFeedback //=> _aiPositionFeedback?.Value ?? 0; { get { if (_aiPositionFeedback != null) { byte[] high = BitConverter.GetBytes(_aiPositionFeedback.Buffer[_aiPositionFeedback.Index]); byte[] low = BitConverter.GetBytes(_aiPositionFeedback.Buffer[_aiPositionFeedback.Index + 1]); float flow = BitConverter.ToSingle(new[] { high[0], high[1], low[0], low[1] }, 0); return flow; } return 0; } } [Subscription(AITThrottleValvePropertyName.TVPressureSetPoint)] public float PressureSetpoint { get { if (_aoPressureSetPoint != null) { byte[] high = BitConverter.GetBytes(_aoPressureSetPoint.Buffer[_aoPressureSetPoint.Index]); byte[] low = BitConverter.GetBytes(_aoPressureSetPoint.Buffer[_aoPressureSetPoint.Index + 1]); float flow = BitConverter.ToSingle(new[] { high[0], high[1], low[0], low[1] }, 0); return flow; } return 0; } set { if (_aoPressureSetPoint != null) { byte[] flow = BitConverter.GetBytes(value); _aoPressureSetPoint.Buffer[_aoPressureSetPoint.Index] = BitConverter.ToInt16(flow, 0); _aoPressureSetPoint.Buffer[_aoPressureSetPoint.Index + 1] = BitConverter.ToInt16(flow, 2); } } } [Subscription(AITThrottleValvePropertyName.TVPressure)] public float PressureFeedback //=> _aiPressureFeedback?.Value ?? 0; { get { if (_aiPressureFeedback != null) { byte[] high = BitConverter.GetBytes(_aiPressureFeedback.Buffer[_aiPressureFeedback.Index]); byte[] low = BitConverter.GetBytes(_aiPressureFeedback.Buffer[_aiPressureFeedback.Index + 1]); float flow = BitConverter.ToSingle(new[] { high[0], high[1], low[0], low[1] }, 0); return flow; } return 0; } } public bool IsIndependent { get; set; } public bool IsOffline => _diOffline != null && _diOffline.RawData; private readonly DIAccessor _diOffline; private readonly AIAccessor _aiPressureFeedback; private readonly AIAccessor _aiPositionFeedback; private readonly AOAccessor _aoPressureSetPoint; private readonly AOAccessor _aoPositionSetPoint; private readonly AOAccessor _aoPressureMode; private readonly AIAccessor _aiState; private SCConfigItem _scProcessPressureOffset; private readonly R_TRIG _tvStatusAlmTrig = new R_TRIG(); private readonly R_TRIG _trigOffline = new R_TRIG(); public IoThrottleValve(string module, XmlElement node, string ioModule = "") { base.Module = module; base.Name = node.GetAttribute("id"); base.Display = node.GetAttribute("display"); base.DeviceID = node.GetAttribute("schematicId"); _aiPositionFeedback = ParseAiNode("aiPositionFeedback", node, ioModule); _aiPressureFeedback = ParseAiNode("aiPressureFeedback", node, ioModule); _aoPositionSetPoint = ParseAoNode("aoPositionSetPoint", node, ioModule); _aoPressureSetPoint = ParseAoNode("aoPressureSetPoint", node, ioModule); _aiState = ParseAiNode("aiState", node, ioModule); _aoPressureMode = ParseAoNode("aoPressureMode", node, ioModule); _diOffline = ParseDiNode("diOffline", node, ioModule); _scProcessPressureOffset = SC.GetConfigItem($"{Module}.ProcessPressureOffset"); } public bool Initialize() { DATA.Subscribe($"{Module}.{Name}", Getter, SubscriptionAttribute.FLAG.IgnoreSaveDB); PressureMode = PressureCtrlMode.TVPressureCtrl; DEVICE.Register($"{Module}.{Name}.{AITThrottleValveOperation.SetMode}", _setMode); DEVICE.Register($"{Module}.{Name}.{AITThrottleValveOperation.SetPosition}", _setPosition); DEVICE.Register($"{Module}.{Name}.{AITThrottleValveOperation.SetPressure}", _setPressure); OP.Subscribe($"{Module}.{Name}.{AITThrottleValveOperation.SetMode}", _setMode2); OP.Subscribe($"{Module}.{Name}.{AITThrottleValveOperation.SetPressure}", _setPressure2); OP.Subscribe($"{Module}.{Name}.{AITThrottleValveOperation.SetPosition}", _setPosition2); return true; } private bool _setPosition2(string arg1, object[] arg2) { return this._setPosition(out string str1, 0, arg2).Value; } private bool _setMode2(string arg1, object[] arg2) { return this._setMode(out string str, 0, arg2).Value; } private bool _setPressure2(string arg1, object[] arg2) { return this._setPressure(out string str, 0, arg2).Value; } private bool? _setPressure(out string reason, int time, object[] param) { PressureMode = PressureCtrlMode.TVPressureCtrl; //double target = Convert.ToDouble((string) param[0]); double target = (double)param[0]; PositionSetpoint = 0.0f; PressureSetpoint = (float)target - (float)ProcessPressureOffset; reason = $"pressure set {target} mTorr"; return true; } private bool? _setPosition(out string reason, int time, object[] param) { //double target = Convert.ToDouble((string) param[0]); double target = (double)param[0]; PressureMode = PressureCtrlMode.TVPositionCtrl; PositionSetpoint = (short) target; PressureSetpoint = 0.0f; reason = $"position set to {target:F1}%"; return true; } private bool? _setMode(out string reason, int time, object[] param) { PressureMode = (PressureCtrlMode) Enum.Parse(typeof(PressureCtrlMode), (string) param[0], true); reason = $"Throttle valve set to {PressureMode} mode"; return true; } private object Getter() { AITThrottleValveData data = new AITThrottleValveData() { Module = Module, DeviceName = Name, DeviceSchematicId = DeviceID, DisplayName = Display, Mode = (int) PressureMode, PositionFeedback = PositionFeedback, PositionSetPoint = PositionSetpoint, PressureFeedback = PressureFeedback, PressureSetPoint = PressureSetpoint, State = State, }; return data; } public void Terminate() { } public void Monitor() { try { _tvStatusAlmTrig.CLK = State != 1; if (_tvStatusAlmTrig.Q) { EV.PostAlarmLog(Module, "Throttle valve status error"); } _trigOffline.CLK = IsOffline; if (_trigOffline.Q) { EV.PostAlarmLog(Module, "Throttle valve offline"); } } catch (Exception ex) { LOG.Write(ex); throw ex; } } public void Reset() { _tvStatusAlmTrig.RST = true; _trigOffline.RST = true; } public void SetPositionMode(int position) { PressureMode = PressureCtrlMode.TVPositionCtrl; PositionSetpoint = (short)position; } } }