using Aitex.Core.RT.Device; using Aitex.Core.RT.Event; using Aitex.Core.RT.Log; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using MECF.Framework.Common.DBCore; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Aitex.Core.RT.Device.Unit; using JetVirgoPM.Devices; using MECF.Framework.Common.Routine; namespace JetVirgoPM.PMs.Routines { public enum VerifyMode { OnePoint, TenPoint, } class PMMfcVerificationRoutine : PMRoutineBase, IStepRoutine { enum RoutineStep { CheckNeedPumpDown1, CheckNeedPumpDown2, RunPumpRoutine1, RunPumpRoutine2, RunPumpRoutine3, CheckThrottleValveStatus, ClosePumpValve, GetBeginPressure, SetGasFlow, CalcMfcCalibration, Delay1, Delay2, StopGasFlow, CheckFinished, Loop, EndLoop, CheckFlowStable, End, } private readonly PumpDownRoutine _pumpdownRoutine; private int _paramContinuePumpTime; private double _beginPressure; private double _endPressure; private double _elapsedTime; private DeviceTimer _verificationDeviceTimer = new DeviceTimer(); private int _mfcIndex; private float _mfcFlow; private double _flowTime; private double _mfcActualFlow; private double _getBeginPressureDelayTime; private double _maxPressure; private MfcBase1 _mfcDevice; private VerifyMode _paramMode; private Dictionary _paramFlowSet = new Dictionary(); private Dictionary> _calibrationResult = new Dictionary>(); private bool _isPumpDownNeed; private float _pressureStableTolerance = 2;//2mTorr private float _flowStableTolerance = 0.02f;//2% private int _stableTime = 1;//1s private double _chamberVolume; private double _gasTemperature; private double _leakRate; private double _maxDeviation; private int _pumpBasePressure; public PMMfcVerificationRoutine(JetDualPM chamber, PumpDownRoutine pumpDownRoutine) : base(chamber) { Name = "MFC Verification"; bUINotify = true; _pumpdownRoutine = pumpDownRoutine; } internal void Init(string mfc, double flow, int flowCount) { int.TryParse(mfc.Replace("MFC",""), out _mfcIndex); _mfcDevice = DEVICE.GetDevice($"{Module}.MfcGas{_mfcIndex}"); _mfcIndex -= 1;//start from 0 _mfcFlow = (float)flow; if (flowCount == 10) _paramMode = VerifyMode.TenPoint; else _paramMode = VerifyMode.OnePoint; } public RState Start(params object[] objs) { Reset(); if(CheckLid() != RState.Running) { return RState.Failed; } if (CheckSlitDoor1() != RState.Running) { return RState.Failed; } if (CheckSlitDoor2() != RState.Running) { return RState.Failed; } if (CheckDryPump() != RState.Running) { return RState.Failed; } _calibrationResult.Clear(); _paramFlowSet.Clear(); _chamberVolume = SC.GetValue($"{Module}.MFCVerification.ChamberVolume"); _gasTemperature = SC.GetValue($"{Module}.MFCVerification.GasTemperature"); _flowTime = SC.GetValue($"{Module}.MFCVerification.GasFlowTime"); _maxDeviation = SC.GetValue($"{Module}.MFCVerification.MaxDeviation"); _paramContinuePumpTime = 20;//20s _getBeginPressureDelayTime = 2;//2s _pressureStableTolerance = (float)SC.GetValue($"{Module}.MFCVerification.PressureStableTolerance"); _flowStableTolerance = (float)(SC.GetValue($"{Module}.MFCVerification.FlowStableTolerance") / 100.0); _stableTime = 1;//1s _maxPressure = SC.GetValue($"{Module}.MFCVerification.TargetPressure"); _pumpBasePressure = SC.GetValue($"{Module}.Pump.PumpBasePressure"); if (_paramMode == VerifyMode.TenPoint) { for (int i = 0; i < 10; i++) { _paramFlowSet.Add(i, (float)_mfcDevice.Scale * (i + 1) / 10); } } else { if (_mfcFlow <= 0 || _mfcFlow > _mfcDevice.Scale) { EV.PostWarningLog(Module, $"MFC set value {_mfcFlow} not valid"); return RState.Failed; } _paramFlowSet.Add(0, _mfcFlow); } _mfcDevice.ResetVerificationData(); _isPumpDownNeed = true; _leakRate = 0; var dbData = DataQuery.Query($"SELECT * FROM \"leak_check_data\" where \"module_name\" = '{Module}' order by \"operate_time\" DESC;"); if (dbData != null && dbData.Rows.Count > 0 && !dbData.Rows[0]["leak_rate"].Equals(DBNull.Value)) { _leakRate = Convert.ToDouble(dbData.Rows[0]["leak_rate"]); } return Runner.Start(_chamber.Module.ToString(), Name); } public RState Monitor() { Runner.Run(RoutineStep.RunPumpRoutine1, StartPump, CheckPump) .Run(RoutineStep.CheckThrottleValveStatus, FullOpenTV, CheckFullOpenTV, _delay_20s) .LoopStart(RoutineStep.CheckNeedPumpDown1, "", _paramFlowSet.Count, CheckNeedPumpDown, _delay_50ms) //抽到底压 .LoopRun(RoutineStep.RunPumpRoutine2, StartPump, CheckPump) .LoopRun(RoutineStep.SetGasFlow, SetGasFlow, _delay_50ms) //流气 .LoopDelay(RoutineStep.Delay1, _paramContinuePumpTime * 1000) //等待,稳定一下 .LoopRun(RoutineStep.CheckFlowStable, FlowStable, CheckFlowStable, _stableTime * 2 * 1000) //检查Stable .LoopRun(RoutineStep.ClosePumpValve, ClosePumpValve, CheckClosePumpValve, 500) //关闭抽气阀 .LoopDelay(RoutineStep.Delay2, (int)_getBeginPressureDelayTime * 1000) //稳压 .LoopRun(RoutineStep.GetBeginPressure, GetBeginPressure, _delay_50ms) .LoopRun(RoutineStep.CheckFinished, ChamberPressure, CheckChamberPressure, (int)_flowTime * 2 * 1000) //等待,流气时间或者压力到设定值 .LoopRun(RoutineStep.CalcMfcCalibration, CalcMfcCalibration, _delay_50ms) //计算Flow .LoopRun(RoutineStep.StopGasFlow, StopGasFlow, _delay_1s) .LoopEnd(RoutineStep.EndLoop, NullFun, _delay_1s) .Run(RoutineStep.CheckNeedPumpDown2, CheckNeedPumpDown, _delay_50ms) .Run(RoutineStep.RunPumpRoutine3, StartPump, CheckPump) .End(RoutineStep.End, NullFun, _delay_50ms); if (Runner.Status == RState.Failed) { _verificationDeviceTimer.Stop(); _chamber.StopAllGases(); _chamber.OpenValve(ValveType.PROCESS, false); _chamber.OpenValve(ValveType.PURGE, false); _mfcDevice.ResetVerificationData(); } return Runner.Status; } public bool StartPump() { if(!_isPumpDownNeed) { return true; } return _pumpdownRoutine.Start() == RState.Running; } bool CheckPump() { if (!_isPumpDownNeed) { Notify($"{_chamber.Name} 无需设置 Pump "); return true; } var result = _pumpdownRoutine.Monitor(); if (result == RState.Failed || result == RState.Timeout) { Runner.Stop($"设置 Pump {_chamber.Name} failed "); return true; } return result == RState.End; } private bool ClosePumpValve() { _chamber.OpenValve(ValveType.FAST_PUMP, false); Notify($"关闭 {ValveType.FAST_PUMP} 阀"); return true; } private bool CheckClosePumpValve() { return !_chamber.IsFastPumpOpened; } public new void Abort() { _verificationDeviceTimer.Stop(); _chamber.StopAllGases(); _chamber.OpenValve(ValveType.PROCESS, false); _chamber.OpenValve(ValveType.PURGE, false); _mfcDevice.ResetVerificationData(); } private bool CheckNeedPumpDown() { Notify($"Check {Module} need pump down"); _isPumpDownNeed = _chamber.ChamberPressure > _pumpBasePressure; return true; } private bool SetGasFlow() { var flow = _paramMode == VerifyMode.TenPoint ? _paramFlowSet[Runner.LoopCounter] : _mfcFlow; Notify($"Set gas {_mfcIndex} flow to {flow} sccm"); _chamber.OpenValve(ValveType.PROCESS, true); _chamber.OpenValve(ValveType.PURGE, true); if (!_chamber.FlowGas(_mfcIndex, flow)) { return false; } return true; } private bool StopGasFlow() { Notify($"Stop gas {_mfcIndex} flow"); _chamber.OpenValve(ValveType.PROCESS, false); _chamber.OpenValve(ValveType.PURGE, false); if (!_chamber.FlowGas(_mfcIndex, 0)) { return false; } return true; } private bool CalcMfcCalibration() { var flow = _paramMode == VerifyMode.TenPoint ? _paramFlowSet[Runner.LoopCounter] : _mfcFlow; _mfcActualFlow = 273.15 * _chamberVolume / ((273.15 + _gasTemperature) * 760000) * ((_endPressure - _beginPressure) / _elapsedTime - _leakRate); EV.PostInfoLog(Module, $"Calculate flow: calculate flow={_mfcActualFlow}, setpoint={flow}, begin pressure(torr)={_beginPressure:f3}, end pressure(torr)={_endPressure:f3}," + $"elapsed time(minute)={_elapsedTime:f3}"); double deviation = (Math.Abs(_mfcActualFlow) - Math.Abs(flow)) / Math.Abs(flow) * 100; bool isOk = Math.Abs(deviation) <= Math.Abs(_maxDeviation); if (!isOk) { EV.PostWarningLog(Module, $"MFC {_mfcDevice.DisplayName} verify failed, deviation is {deviation}%, exceed max tolerance {_maxDeviation}%"); } if (_paramMode == VerifyMode.TenPoint) { _calibrationResult[flow] = Tuple.Create((float)_mfcActualFlow, (float)_elapsedTime); _mfcDevice.SetVerificationResult((float)flow, (float)_mfcActualFlow, _calibrationResult.Count == 10, _elapsedTime * 60, deviation, isOk); } else { _mfcDevice.SetVerificationResult((float)flow, (float)_mfcActualFlow, true, _elapsedTime * 60, deviation, isOk); } return true; } private bool GetBeginPressure() { Notify($"Get begin pressure {_chamber.ChamberPressure.ToString("f1")}"); _beginPressure = _chamber.ChamberPressure; _verificationDeviceTimer.Start(0); return true; } private bool FlowStable() { Notify($"Check {_mfcDevice.Name} flow stable"); _verificationDeviceTimer.Start(0); _beginPressure = _chamber.ChamberPressure; return true; } bool CheckFlowStable() { if (_verificationDeviceTimer.GetElapseTime() > _stableTime * 1000 && Math.Abs(_chamber.ChamberPressure - _beginPressure) <= _pressureStableTolerance && Math.Abs(_mfcDevice.SetPoint - _mfcDevice.FeedBack) / _mfcDevice.SetPoint < _flowStableTolerance) { return true; } return false; } private bool ChamberPressure() { Notify($"Check finished one point"); return true; } bool CheckChamberPressure() { if (_verificationDeviceTimer.GetElapseTime() > _flowTime * 1000 || _chamber.ChamberPressure / 1000 > _maxPressure) { _endPressure = _chamber.ChamberPressure;//mTorr _elapsedTime = _verificationDeviceTimer.GetElapseTime() / (1000 * 60);//unit minutes return true; } return false; } } }