using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.Device; using Aitex.Core.RT.Device.Unit; using Aitex.Core.RT.Event; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using MECF.Framework.Common.DBCore; using MECF.Framework.Common.Equipment; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.TMs; using FurnaceRT.Equipments.PMs; using FurnaceRT.Equipments.PMs.Routines; using System; using System.Collections.Generic; using System.Diagnostics; namespace FurnaceRT.Modules.PMs { public class PMLeakCheckRoutine : PMBaseRoutine { enum RoutineStep { CheckSlitValve, SetValve, SetTV, SetGasLine1, SetGasLine2, SetGasLine3, SetGasLine4, SetTuning, Pump, ContinuePump, ClosePumpValve, DoLeakCheck, CalcLeakCheck, Vent, UnsetTuning, StopVent, } enum LeakCheckType { ChamberOnly, ChamberAndGasline, ChamberAndGaslineToFacility, } private int _paramContinuePumpTime; private int _paramLeakCheckTime; private string _leakCheckType; private bool[] _isMfcChecked; private string _gaslineSelection; private double[] _mfcScale = new double[4]; private double _beginPressure; private int _tvPostion; private double _basePressure; private int _timeoutPump; private bool _enableTuning; private float _tuningPercent; private float _ventAtmPressure; //private TM _tm; private Stopwatch _swTimer = new Stopwatch(); private List _mfc = new List() { "Mfc1", "Mfc2", "Mfc3", "Mfc4" }; public int ElapsedTime { get { return _swTimer.IsRunning ? (int)(_swTimer.ElapsedMilliseconds / 1000) : 0; } } public PMLeakCheckRoutine(ModuleName module, PMModule pm) : base(module, pm) { Module = module.ToString(); Name = "Leak Check"; } internal void Init(int pumpTime, int leakCheckTime, string leakCheckType, bool[] isMfcChecked) { _paramContinuePumpTime = pumpTime; _paramLeakCheckTime = leakCheckTime; _leakCheckType = leakCheckType; _isMfcChecked = isMfcChecked; if (_leakCheckType != LeakCheckType.ChamberOnly.ToString()) { _gaslineSelection = string.Empty; for (int i = 0; i < _isMfcChecked.Length; i++) { if (_isMfcChecked[i]) { _mfcScale[i] = DEVICE.GetDevice($"{Module}.{_mfc[i]}").Scale; _gaslineSelection += _mfc[i] + ","; } } _gaslineSelection = _gaslineSelection.Remove(_gaslineSelection.Length - 1); } } public override Result Start(params object[] objs) { Reset(); _swTimer.Restart(); _tvPostion = SC.GetValue($"PM.{Module}.LeakCheck.TVPosition"); _basePressure = SC.GetValue($"PM.{Module}.LeakCheck.PumpBasePressure"); _timeoutPump = SC.GetValue($"PM.{Module}.LeakCheck.PumpTimeout"); _enableTuning = SC.GetValue($"PM.{Module}.LeakCheck.EnableTuning"); _tuningPercent = (float) SC.GetValue($"PM.{Module}.LeakCheck.TuningPercent"); _ventAtmPressure = (float)SC.GetValue($"PM.{Module}.VentRoutine.VentBasePressure"); return Result.RUN; } public override Result Monitor() { try { CheckSlitValve((int)RoutineStep.CheckSlitValve, PMModule); SetValve((int)RoutineStep.SetValve, PMModule); SetTV((int)RoutineStep.SetTV, PMModule, _tvPostion); if (_leakCheckType == LeakCheckType.ChamberAndGasline.ToString()) { for (int i = 0; i < _isMfcChecked.Length; i++) { if (_isMfcChecked[i]) { SetGasLine((int)Enum.Parse(typeof(RoutineStep), $"SetGasLine{i + 1}"), PMModule, _mfc[i], 0); } } } else if (_leakCheckType == LeakCheckType.ChamberAndGaslineToFacility.ToString()) { for (int i = 0; i < _isMfcChecked.Length; i++) { if (_isMfcChecked[i]) { SetGasLine((int)Enum.Parse(typeof(RoutineStep), $"SetGasLine{i + 1}"), PMModule, _mfc[i], _mfcScale[i]); } } } if (_enableTuning) { SetTuning((int)RoutineStep.SetTuning, PMModule, _tuningPercent); } Pump((int)RoutineStep.Pump, PMModule, _timeoutPump, _basePressure); ContinuePump((int)RoutineStep.ContinuePump, _paramContinuePumpTime); ClosePumpValve((int)RoutineStep.ClosePumpValve, PMModule); DoLeakCheck((int)RoutineStep.DoLeakCheck, _paramLeakCheckTime); CalcLeakCheck((int)RoutineStep.CalcLeakCheck, _paramLeakCheckTime); FastVent((int)RoutineStep.Vent, PMModule, _ventAtmPressure, _timeoutPump); if (_enableTuning) { UnsetTuning((int)RoutineStep.UnsetTuning, PMModule); } StopVent((int)RoutineStep.StopVent, PMModule, _timeoutPump); } catch (RoutineBreakException) { return Result.RUN; } catch (RoutineFaildException) { return Result.FAIL; } _swTimer.Stop(); return Result.DONE; } public override void Abort() { Stop($"{Module} leak check aborted"); _swTimer.Stop(); //LeakCheckDataRecorder.Add((int)_swTimer.ElapsedMilliseconds / 1000, _beginPressure, _tm.ChamberPressure, 0, Result.FAIL.ToString(), _leakCheckType, Module, _gaslineSelection); } private void SetTuning(int id, PMModule pm, float percent) { Tuple ret = Execute(id, () => { Notify($"Start leak check pumping"); //pm.ChamberProcessPressureGauge.SetTuning(_tuningPercent); return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } private void UnsetTuning(int id, PMModule pm ) { Tuple ret = Execute(id, () => { Notify($"Stop leak check venting"); //pm.ChamberProcessPressureGauge.UnsetTuning(); return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } private void StopVent(int id, PMModule pm, int timeout) { Tuple ret = Execute(id, () => { Notify($"Turn off {pm.Name} vent valve"); //if (!pm.Gas4Valve.TurnValve(false, out string reason)) //{ // Stop(reason); // return false; //} return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } private void FastVent(int id, PMModule pm, float ventPressure, int timeout) { Tuple ret = ExecuteAndWait(id, () => { Notify($"Turn {pm.Name} vent valve on, vent to {ventPressure} Torr"); //if (!pm.Gas4Valve.TurnValve(true, out string reason)) //{ // Stop(reason); // return false; //} return true; }, () => { return pm.ChamberPressure >= ventPressure; }, timeout * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) //timeout { Stop($"{pm.Name} vent timeout, over {timeout} seconds"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void CheckSlitValve(int id, PMModule pm) { Tuple ret = Check(id, () => { Notify($"Check {Module} slit valve is closed"); if (!pm.CheckSlitValveClose()) { Stop($"{Module} slit valve is not closed."); return false; } return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } } } public void SetValve(int id, PMModule pm) { Tuple ret = Execute(id, () => { Notify($"Run {pm.Name} close valve all"); string reason = ""; foreach (var stick in PMModule.GasSticks) { if (!stick.SetFlow(out reason, 0, 0)) { Stop(reason); return false; } } return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void SetTV(int id, PMModule pm, float position) { Tuple ret = Check(id, () => { Notify($"Run {Module} set TV position"); //if (!pm.ThrottleValve.SetMode(PressureCtrlMode.TVPositionCtrl, out string reason)) //{ // Stop(reason); // return false; //} //if (!pm.ThrottleValve.SetPosition(position, out reason)) //{ // Stop(reason); // return false; //} return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } } } private void SetGasLine(int id, PMModuleBase pm, string mfcId, double flow) { Tuple ret = Execute(id, () => { Notify($"Set gas {mfcId} flow to {flow} sccm"); //if (!pm.SetGasLine(mfcId, (float)flow, out string reason)) //{ // Stop(reason); // return false; //} return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { Stop($"Set gas {mfcId} flow to {flow} sccm failed."); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void Pump(int id, PMModule pm, int timeout, double pressure) { Tuple ret = ExecuteAndWait(id, () => { Notify($"{pm.Name} pump to {pressure} Torr"); //if (!pm.PumpValve.TurnValve(true, out string reason)) //{ // Stop(reason); // return false; //} return true; }, () => { return pm.ChamberPressure < pressure; }, timeout * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) //timeout { Stop($"{pm.Name} pump timeout, over {timeout} seconds"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void ContinuePump(int id, int delayTime) { Tuple ret = Delay(id, () => { Notify($"continue pump {delayTime} seconds"); return true; }, delayTime * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } throw new RoutineBreakException(); } } public void ClosePumpValve(int id, PMModule pm) { string timeoutReason = string.Empty; Tuple ret = Execute(id, () => { Notify($"Run {pm.Name} close valve all"); //if (!pm.PumpValve.TurnValve(false, out string reason)) //{ // Stop(reason); // return false; //} return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void DoLeakCheck(int id, double time) { Tuple ret = Delay(id, () => { Notify($"Keep pressure for {time} seconds"); _beginPressure = PMModule.ChamberPressure * 1000; // 单位使用mTorr return true; }, time * 1000); if (ret.Item1) { if (ret.Item2 == Result.RUN) { throw (new RoutineBreakException()); } } } public void CalcLeakCheck(int id, int time) { Tuple ret = Execute(id, () => { double endPressure = PMModule.ChamberPressure * 1000; // 单位使用mTorr double leakRate = (endPressure - _beginPressure) / (time / 60.0); LeakCheckDataRecorder.Add(time, _beginPressure, endPressure, leakRate, Result.Succeed.ToString(), _leakCheckType, Module, _gaslineSelection); EV.PostInfoLog(Module, $"{Module} leak check result: end at {DateTime.Now.ToString("HH:mm:ss")}, start: {_beginPressure:F2} mTorr, end: {endPressure:F2} mTorr, using {time} seconds, leak rate: {leakRate:F2}"); return true; }); } } }