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 VirgoRT.Devices; using VirgoRT.Devices.IODevices; namespace VirgoRT.Modules.PMs { public enum VerifyMode { OnePoint, TenPoint, } class PMMfcVerificationRoutine: PMRoutineBase { enum RoutineStep { CloseN2BallastValve, CheckNeedPumpDown1, CheckNeedPumpDown2, RunPumpRoutine1, RunPumpRoutine2, RunPumpRoutine3, SetGasSplitterRatio, CheckThrottleValveStatus, ClosePumpValve, StopAllGasFlow, GetBeginPressure, SetGasFlow, CalcMfcCalibrationConstant, CalcMfcCalibration, Delay1, Delay2, StopGasFlow, OpenAssociateValves, CloseAssociateValves, CheckFinished, OpenUEGasDeliveryValves, Loop, EndLoop, CheckFlowStable, WaitGetBeginPressure1, WaitGetBeginPressure2, } private readonly PumpDownRoutine _pumpdownRoutine; private int _paramContinuePumpTime; private double _beginPressure; private double _endPressure; private double _elapsedTime; private DeviceTimer _verificationDeviceTimer = new DeviceTimer(); private DeviceTimer _getBeginPressureTimer = new DeviceTimer(); private int _mfcIndex; private float _mfcFlow; private double _flowTime; private double _mfcActualFlow; private double _getBeginPressureDelayTimeInMFCCalibration; private double _maxPressureInMFCCalibration; 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; public PMMfcVerificationRoutine(JetPM 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 Result Start(params object[] objs) { Reset(); if(CheckLid() != Result.RUN) { return Result.FAIL; } if (CheckSlitDoor() != Result.RUN) { return Result.FAIL; } if (CheckDryPump() != Result.RUN) { return Result.FAIL; } _calibrationResult.Clear(); _paramFlowSet.Clear(); _chamberVolume = SC.GetValue($"{Module}.ChamberVolume"); _gasTemperature = SC.GetValue($"{Module}.GasTemperature"); _flowTime = SC.GetValue($"{Module}.GasFlowTimeInMFCVerification"); // default = 3 min //_paramContinuePumpTime = SC.GetValue($"{Module}.ContinuePumpTimeInMFCCalibration"); _paramContinuePumpTime = 20;//20s // = SC.GetValue($"{Module}.GetBeginPressureDelayTimeInMFCCalibration"); _getBeginPressureDelayTimeInMFCCalibration = 2;//2s _maxPressureInMFCCalibration = SC.GetValue($"{Module}.TargetPressureInMFCVerification"); // default = 9 torr 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 Result.FAIL; } _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 Result.RUN; } public Result Monitor() { try { if (_isPumpDownNeed) { ExecuteRoutine((int)RoutineStep.RunPumpRoutine1, _pumpdownRoutine); } CheckThrottleValveFullOpen((int)RoutineStep.CheckThrottleValveStatus); StartLoop((int)RoutineStep.Loop, "", _paramFlowSet.Count, Notify, Stop); CheckNeedPumpDown((int)RoutineStep.CheckNeedPumpDown1); if (_isPumpDownNeed) { ExecuteRoutine((int)RoutineStep.RunPumpRoutine2, _pumpdownRoutine); } SetGasFlow((int)RoutineStep.SetGasFlow, _mfcIndex, _paramMode == VerifyMode.TenPoint ? _paramFlowSet[LoopCounter] : _mfcFlow); Delay((int)RoutineStep.Delay1, _paramContinuePumpTime); CheckFlowStable((int)RoutineStep.CheckFlowStable, _mfcDevice, _flowStableTolerance, _pressureStableTolerance, _stableTime); OpenValve((int)RoutineStep.ClosePumpValve, ValveType.FAST_PUMP, false); Delay((int)RoutineStep.Delay2, _getBeginPressureDelayTimeInMFCCalibration); GetBeginPressure((int)RoutineStep.GetBeginPressure); CheckFinished((int)RoutineStep.CheckFinished, _flowTime, _maxPressureInMFCCalibration); CalcMfcCalibration((int)RoutineStep.CalcMfcCalibration, _paramMode == VerifyMode.TenPoint ? _paramFlowSet[LoopCounter] : _mfcFlow); StopGasFlow((int)RoutineStep.StopGasFlow, _mfcIndex); EndLoop((int)RoutineStep.EndLoop, Notify, Stop); CheckNeedPumpDown((int)RoutineStep.CheckNeedPumpDown2); if (_isPumpDownNeed) { ExecuteRoutine((int)RoutineStep.RunPumpRoutine3, _pumpdownRoutine); } } catch (RoutineBreakException) { return Result.RUN; } catch (RoutineFaildException) { _verificationDeviceTimer.Stop(); _chamber.StopAllGases(); _chamber.OpenValve(ValveType.PROCESS, false); _mfcDevice.ResetVerificationData(); return Result.FAIL; } return Result.DONE; } public new void Abort() { _verificationDeviceTimer.Stop(); _chamber.StopAllGases(); _chamber.OpenValve(ValveType.PROCESS, false); _mfcDevice.ResetVerificationData(); } private void CheckNeedPumpDown(int id) { string reason = string.Empty; Tuple ret = Execute(id, () => { Notify($"Check {Module} need pump down"); _isPumpDownNeed = _chamber.ChamberPressure > SC.GetValue($"{Module}.Pump.PumpBasePressure"); return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } private void SetGasFlow(int id, int mfcId, double flow) { string reason = string.Empty; Tuple ret = Execute(id, () => { Notify($"Set gas {mfcId} flow to {flow} sccm"); _chamber.OpenValve(ValveType.PROCESS, true); if (!_chamber.FlowGas(mfcId, flow)) { return false; } return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { Stop($"Set gas {mfcId} flow to {flow} sccm failed, for {reason}"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } private void StopGasFlow(int id, int mfcId) { string reason = string.Empty; Tuple ret = Execute(id, () => { Notify($"Stop gas {mfcId} flow"); _chamber.OpenValve(ValveType.PROCESS, false); if (!_chamber.FlowGas(mfcId, 0)) { return false; } return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { Stop($"Stop gas {mfcId} flow failed, for {reason}"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } private void CalcMfcCalibration(int id, float flow) { Tuple ret = Execute(id, () => { _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.ToString("f3")}, end pressure(torr)={_endPressure.ToString("f3")}," + $"elapsed time(minute)={_elapsedTime.ToString("f3")}"); if (_paramMode == VerifyMode.TenPoint) { _calibrationResult[flow] = Tuple.Create((float)_mfcActualFlow, (float)_elapsedTime); _mfcDevice.SetVerificationResult((float)flow, (float)_mfcActualFlow, _calibrationResult.Count == 10); } else { _mfcDevice.SetVerificationResult((float)flow, (float)_mfcActualFlow, true); } return true; }); } private void GetBeginPressure(int id) { Tuple ret = Execute(id, () => { Notify($"Get begin pressure {_chamber.ChamberPressure.ToString("f1")}"); _beginPressure = _chamber.ChamberPressure; _verificationDeviceTimer.Start(0); return true; }); } private void CheckFlowStable(int id, MfcBase1 mfc, float flowStable, float pressureStable, int time) { Tuple ret = ExecuteAndWait(id, () => { Notify($"Check {mfc.Name} flow stable"); _verificationDeviceTimer.Start(0); _beginPressure = _chamber.ChamberPressure; return true; }, () => { if (_verificationDeviceTimer.GetElapseTime() > time * 1000 && Math.Abs(_chamber.ChamberPressure - _beginPressure) <= pressureStable && Math.Abs((mfc.SetPoint - mfc.FeedBack)) / mfc.SetPoint < flowStable) { return true; } return false; }, time * 2 * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { Stop($"Check {mfc.Name} flow {mfc.SetPoint} stable failed."); throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) //timeout { Stop($"Check {mfc.Name} flow stable timeout in {time * 2} seconds"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } private void CheckFinished(int id, double flowTime, double maxPressure) { Tuple ret = ExecuteAndWait(id, () => { Notify($"Check finished one point"); return true; }, () => { if (_verificationDeviceTimer.GetElapseTime() > flowTime * 1000 || _chamber.ChamberPressure/1000 > maxPressure) { _endPressure = _chamber.ChamberPressure;//mTorr _elapsedTime = _verificationDeviceTimer.GetElapseTime() / (1000 * 60);//unit minutes return true; } return false; }, flowTime * 2 * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) //timeout { Stop($"Check finished one point can not finished in {flowTime * 2} seconds"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } } }