using Aitex.Core.Common.DeviceData; 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; using System; using System.Xml; using VirgoRT.Devices.IODevices; namespace VirgoRT.Devices { public class IoPressureControl : BaseDevice, IDevice { private bool _enableTolerance; public bool EnableTolerance { get { return _enableTolerance; } set { if (_enableTolerance != value) { EV.PostInfoLog(Module, value ? "Start monitor pressure stability" : "Stop monitor pressure stability"); if (value) { _alarmChecker.Reset(_scAlarmTime.DoubleValue); _warningChecker.Reset(_scWarningTime.DoubleValue); _recipeWarningChecker.RST = true; _recipeAlarmChecker.RST = true; } } _enableTolerance = value; } } public bool IsIndependentControl { get { if (_scIsIndependentControl != null) return _scIsIndependentControl.BoolValue; return false; } } public bool IsTvInstalled { get { if (_scTvInstalled != null) return _scTvInstalled.BoolValue; return false; } } public bool IsBoostPumpInstalled { get { if (_scIsBoostPumpInstalled != null) return _scIsBoostPumpInstalled.BoolValue; return false; } } public bool EnableBoostControl { get { return _diLogicProcessGasFlowing == null || _diLogicProcessGasFlowing.Value; } } public readonly IoThrottleValve ThrottleValve; public readonly IoPressureMeter PressureGauge; public readonly IoPressureMeter ProcessGauge; public readonly IoPressureMeter ForelineGauge; //public readonly IoBoostPump _boost; //public readonly IoPump DryPump; private ToleranceChecker _alarmChecker = new ToleranceChecker(); private ToleranceChecker _warningChecker = new ToleranceChecker(); private readonly SCConfigItem _scAlarmRange; private readonly SCConfigItem _scAlarmTime; private readonly SCConfigItem _scWarningRange; private readonly SCConfigItem _scWarningTime; private readonly SCConfigItem _scIsIndependentControl; private readonly SCConfigItem _scIsBoostPumpInstalled; private readonly SCConfigItem _scTvInstalled; private readonly DIAccessor _diLogicProcessGasFlowing; private readonly R_TRIG _trigPressureGauge = new R_TRIG(); private readonly R_TRIG _trigProcessGauge = new R_TRIG(); private readonly R_TRIG _trigForelineGauge = new R_TRIG(); // Properties // public double TargetPressure { get; set; } private string PressureOutOfTolerance = "PressureOutOfTolerance"; private float _recipeAlarmRange; private float _recipeWarningRange; private int _ignoreTimeMS; private ToleranceChecker _recipeAlarmChecker = new ToleranceChecker(); private ToleranceChecker _recipeWarningChecker = new ToleranceChecker(); private DeviceTimer _ignoreTimer = new DeviceTimer(); public IoPressureControl(string module, XmlElement node, string ioModule = "") { base.Module = module; base.Name = node.GetAttribute("id"); base.Display = node.GetAttribute("display"); base.DeviceID = node.GetAttribute("schematicId"); _diLogicProcessGasFlowing = ParseDiNode("diLogicProcessGasFlowing", node, ioModule); _scAlarmRange = SC.GetConfigItem($"{Module}.GasFlowPressureAlarmRange"); _scAlarmTime = SC.GetConfigItem($"{Module}.GasFlowPressureAlarmTime"); _scWarningRange = SC.GetConfigItem($"{Module}.GasFlowPressureWarningRange"); _scWarningTime = SC.GetConfigItem($"{Module}.GasFlowPressureWarningTime"); _scIsIndependentControl = SC.GetConfigItem($"{Module}.IsIndependentControl"); _scIsBoostPumpInstalled = SC.GetConfigItem($"{Module}.EnableBoosterPump"); _scTvInstalled = SC.GetConfigItem($"{Module}.EnableThrottleValve"); //_enableTolerance = true; ThrottleValve = ParseDeviceNode(Module, "tv", node); PressureGauge = ParseDeviceNode(Module, "pressureMeter", node); ProcessGauge = ParseDeviceNode(Module, "processMeter", node); ForelineGauge = ParseDeviceNode(Module, "forelineMeter", node); //DryPump = ParseDeviceNode(Module, "drypump", node); } public bool Initialize() { DEVICE.Register($"{Module}.{Name}.{AITPressureControlOperation.SetTVPressure}", _setTVPressure); DEVICE.Register($"{Module}.{Name}.{AITPressureControlOperation.SetTVPosition}", _setTVPosition); DEVICE.Register($"{Module}.{Name}.{AITPressureControlOperation.SetTVMode}", _setTVMode); //DEVICE.Register($"{Module}.{Name}.{AITPressureControlOperation.SetBoostPressure}", _setBoostPressure); DEVICE.Register($"{Module}.{Name}.{AITPressureControlOperation.SetChamberPressure}", _setChamberPressure); OP.Subscribe($"{Module}.{Name}.{AITPressureControlOperation.SetChamberPressure}", (out string reason, int time, object[] param) => { _setChamberPressure(out reason, 0, param); return true; }); OP.Subscribe($"{Module}.{Name}.{AITPressureControlOperation.SetTVMode}", (out string reason, int time, object[] param) => { _setTVMode(out reason, 0, param); return true; }); OP.Subscribe($"{Module}.{Name}.{AITPressureControlOperation.SetTVPressure}", (out string reason, int time, object[] param) => { _setTVPressure(out reason, 0, param); return true; }); OP.Subscribe($"{Module}.{Name}.{AITPressureControlOperation.SetTVPosition}", (out string reason, int time, object[] param) => { _setTVPosition(out reason, 0, param); return true; }); OP.Subscribe($"{Module}.{Name}.SetRecipeTolerance", (out string reason, int time, object[] param) => { reason = string.Empty; _ignoreTimeMS = Convert.ToInt32(param[0]) * 1000; _recipeWarningRange = Convert.ToSingle(param[1]); _recipeAlarmRange = Convert.ToSingle(param[2]); _recipeAlarmChecker.RST = true; _recipeWarningChecker.RST = true; //if (_recipeIgnoreTimeMS > 0) _ignoreTimer.Start(0); return true; }); EV.Subscribe(new EventItem("Event", PressureOutOfTolerance, "Pressure Out Of Tolerance", EventLevel.Alarm, EventType.HostNotification)); return true; } //public void StartPump(bool on) //{ // this.DryPump?.Start(on); //} public void FullOpenThrottleValve() { this.ThrottleValve.PressureMode = PressureCtrlMode.TVPositionCtrl; this.ThrottleValve.PositionSetpoint = 100; } private bool? _setTVPressure(out string reason, int time, object[] param) { double target = Convert.ToDouble((string)param[0]); if (!IsTvInstalled) { reason = "Throttle valve not config"; return true; } if (ThrottleValve.PressureMode == PressureCtrlMode.TVPositionCtrl) { reason = "Throttle valve is in position control mode, can not set pressure"; return false; } ThrottleValve.PressureSetpoint = (short)target; ThrottleValve.PositionSetpoint = 0.0f; TargetPressure = ThrottleValve.PressureSetpoint; reason = $"TV pressure set to {target} mTorr"; return true; } private bool? _setTVPosition(out string reason, int time, object[] param) { double target = Convert.ToDouble((string)param[0]); if (!IsTvInstalled) { reason = "Throttle valve not config"; return true; } if (ThrottleValve.PressureMode == PressureCtrlMode.TVPressureCtrl) { reason = "Throttle valve is in pressure control mode, can not set position"; return false; } ThrottleValve.PressureSetpoint = 0.0f; ThrottleValve.PositionSetpoint = (short)target; reason = $"TV position set to {target}"; return true; } private bool? _setTVMode(out string reason, int time, object[] param) { reason = string.Empty; if (!IsTvInstalled) { reason = "Throttle valve not config"; return true; } ThrottleValve.PressureMode = (PressureCtrlMode)Enum.Parse(typeof(PressureCtrlMode), (string)param[0], true); reason = $"TV mode set to {ThrottleValve.PressureMode}"; return true; } private bool? _setChamberPressure(out string reason, int time, object[] param) { double setpoint = Convert.ToDouble((string)param[0]); TargetPressure = setpoint; reason = $"Chamber pressure set to {setpoint} mTorr"; return true; } public void Terminate() { } public void Monitor() { CheckTolerance(); _trigProcessGauge.CLK = ProcessGauge.GaugeAlarm; if (_trigProcessGauge.Q) EV.PostAlarmLog(Module, "Process pressure gauge Alarm"); _trigPressureGauge.CLK = PressureGauge.GaugeAlarm; if (_trigPressureGauge.Q) EV.PostAlarmLog(Module, "Chamber pressure gauge Alarm"); _trigForelineGauge.CLK = ForelineGauge.GaugeAlarm; if (_trigForelineGauge.Q) EV.PostAlarmLog(Module, "Foreline pressure gauge Alarm"); } public void CheckTolerance() { if (!EnableTolerance) return; if (ThrottleValve != null && IsTvInstalled && ThrottleValve.PressureMode == PressureCtrlMode.TVPositionCtrl) { return; } double alarmRange = _scAlarmRange.DoubleValue; double alarmTime = _scAlarmTime.DoubleValue; ToleranceChecker alarmChecker = _alarmChecker; if ((_recipeAlarmRange > 0) && (_recipeAlarmRange / 100.0 * TargetPressure < _scAlarmRange.DoubleValue)) { alarmRange = _recipeAlarmRange / 100.0 * TargetPressure; alarmChecker = _recipeAlarmChecker; _alarmChecker.RST = true; } else { _recipeAlarmChecker.RST = true; } if (_ignoreTimer.GetElapseTime() > _ignoreTimeMS) { alarmChecker.Monitor(ProcessGauge.Value, TargetPressure - Math.Abs(alarmRange), TargetPressure + Math.Abs(alarmRange), alarmTime); if (alarmChecker.Trig) { EV.PostAlarmLog(Module, $" Pressure={ProcessGauge.Value}, TargetPressure={TargetPressure}, out of tolerance({TargetPressure - Math.Abs(alarmRange)},{TargetPressure + Math.Abs(alarmRange)}) in {alarmTime:0} seconds"); } } double warningRange = _scWarningRange.DoubleValue; double warningTime = _scWarningTime.DoubleValue; ToleranceChecker warningChecker = _warningChecker; if ((_recipeWarningRange > 0) && (_recipeWarningRange / 100.0 * TargetPressure < _scWarningRange.DoubleValue)) { warningRange = _recipeWarningRange / 100.0 * TargetPressure; warningChecker = _recipeWarningChecker; _warningChecker.RST = true; } else { _recipeWarningChecker.RST = true; } if (_ignoreTimer.GetElapseTime() > _ignoreTimeMS) { warningChecker.Monitor(ProcessGauge.Value, TargetPressure - Math.Abs(warningRange), TargetPressure + Math.Abs(warningRange), warningTime); if (warningChecker.Trig) { EV.PostWarningLog(Module, $" Pressure={ProcessGauge.Value}, TargetPressure={TargetPressure}, out of tolerance({TargetPressure - Math.Abs(warningRange)},{TargetPressure + Math.Abs(warningRange)}) in {warningTime:0} seconds"); } } } public void Reset() { _trigProcessGauge.RST = true; _trigPressureGauge.RST = true; _trigForelineGauge.RST = true; if (_scAlarmTime != null) { _alarmChecker.Reset(_scAlarmTime.DoubleValue); } _alarmChecker.RST = true; _warningChecker.RST = true; _recipeWarningChecker.RST = true; _recipeAlarmChecker.RST = true; } } }