using System; using System.Collections.Generic; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Aitex.Core.Common; using Aitex.Common.Util; using Aitex.Core.RT.RecipeCenter; using Venus_RT.Devices; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.SubstrateTrackings; using Venus_Core; namespace Venus_RT.Modules.PMs { class PMProcessRoutine : PMRoutineBase, IRoutine { private enum ProcessStep { kPreparePressure, kPrepareTemperature, kRunRecipes, kEnd, } public string CurrentRunningRecipe { get; set; } public string ProcessRecipeName { get; set; } public string ChuckRecipeName { get; set; } public string DechuckRecipeNamae { get; set; } public string CleanRecipeName { get; set; } public RecipeHead ProcessRecipeHead { get; set; } public DateTime RecipeStartTime { get; private set; } private readonly PumpDownRoutine _pumpDownRoutine; private readonly ProcessHelper _processHelper; private bool _withWafer = true; private bool _needPumpDown = false; private Recipe _currentRecipe = null; private int _currentStep = 0; private Queue _qeRecipes = new Queue(); private double _tolerance; private double _OffsetTemp = 0.0f; private bool _bLoopMode = false; private int _loopStartStep = 0; private int _loopCounter = 0; private double ChillerTemp { get { if (ProcessRecipeHead != null) { if (!string.IsNullOrEmpty(ProcessRecipeHead.ChillerTemp)) { double setpoint = Convert.ToDouble(ProcessRecipeHead.ChillerTemp); if (setpoint > 0 && setpoint < 600) return setpoint; } } return 0; } } private double BasePressure { get { if (ProcessRecipeHead != null) { if (!string.IsNullOrEmpty(ProcessRecipeHead.BasePressure)) { double setpoint = Convert.ToDouble(ProcessRecipeHead.BasePressure); if (setpoint > 0 && setpoint < 750000) return setpoint; } } return SC.GetValue($"{Module}.Pump.PumpBasePressure"); } } public double EstimatedTotalLeftTime { get; private set; } public PMProcessRoutine(JetPM chamber, PumpDownRoutine pdRoutine) : base(chamber) { Name = "Process"; _pumpDownRoutine = pdRoutine; _processHelper = new ProcessHelper(chamber); } private bool AssignFuns(Recipe recipe) { foreach(var step in recipe.Steps) { if (ProcessHelper.LoadStepFuns(step) == false) return false; foreach(ProcessUnitBase unit in step.LstUnit) { if (ProcessHelper.LoadMethods(unit) == false) { Stop($"Cannot find the process routine for unit:{unit.GetType()}"); return false; } } } return true; } public RState Start(params object[] objs) { if (_withWafer && WaferManager.Instance.CheckNoWafer(Module.ToString(), 0)) { Stop($"can not run process, no wafer at {Module}"); return RState.Failed; } if (!CheckSlitDoor() || !CheckDryPump() || !CheckTurboPump()) { return RState.Failed; } // Load/Validate Recipe _qeRecipes.Clear(); string recipeName = (string)objs[0]; string recipeContent = RecipeFileManager.Instance.LoadRecipe(_chamber.Name, recipeName, false); Recipe recipe = Recipe.Load(recipeContent); if(recipe == null) { Stop($"Load Recipe:{recipeName} failed"); return RState.Failed; } if (AssignFuns(recipe) == false) { Stop($"Associate process alogrithm with recipe:{recipeName} failed"); return RState.Failed; } switch(recipe.Header.Type) { case RecipeType.Process: if(recipe.Header.ChuckRecipe != null) { var chuckRecipe = Recipe.Load(recipe.Header.ChuckRecipe); if(chuckRecipe != null) { ChuckRecipeName = recipe.Header.ChuckRecipe; _qeRecipes.Enqueue(chuckRecipe); } } ProcessRecipeHead = recipe.Header; ProcessRecipeName = recipeName; _qeRecipes.Enqueue(recipe); if(recipe.Header.DechuckRecipe != null) { var dechuckRecipe = Recipe.Load(recipe.Header.DechuckRecipe); if(dechuckRecipe != null) { DechuckRecipeNamae = recipe.Header.DechuckRecipe; _qeRecipes.Enqueue(dechuckRecipe); } } break; case RecipeType.Chuck: ChuckRecipeName = recipeName; _qeRecipes.Enqueue(recipe); break; case RecipeType.DeChuck: DechuckRecipeNamae = recipeName; _qeRecipes.Enqueue(recipe); break; case RecipeType.Clean: CleanRecipeName = recipeName; _qeRecipes.Enqueue(recipe); break; } _bLoopMode = false; _loopStartStep = 0; _loopCounter = 0; _tolerance = SC.GetValue($"System.MaxTemperatureToleranceToTarget"); _OffsetTemp = SC.GetValue($"{Module}.Chiller.ChillerTemperatureOffset"); WaferManager.Instance.UpdateWaferProcessStatus(Module, 0, EnumWaferProcessStatus.InProcess); return Runner.Start(Module, Name); } public RState Monitor() { Runner.Run((int)ProcessStep.kPreparePressure, PreparePressure, IsPressureReady) .Run((int)ProcessStep.kPrepareTemperature, PrepareTemp, IsTempReady) .Run((int)ProcessStep.kRunRecipes, StartNewRecipe, RunRecipes) .End((int)ProcessStep.kEnd, ProcessDone, _delay_1s); return Runner.Status; } private bool PreparePressure() { if(_chamber.ChamberPressure < BasePressure) { _needPumpDown = false; return true; } _needPumpDown = true; return _pumpDownRoutine.Start(BasePressure) == RState.Running; } private bool IsPressureReady() { if (_needPumpDown == false) return true; var status = _pumpDownRoutine.Monitor(); if(status == RState.End) { return true; } else if (status == RState.Failed || status == RState.Timeout) { Runner.Stop($"Pump down to {BasePressure} failed."); return true; } return false; } private bool PrepareTemp() { return SetCoolantTemp(ChillerTemp, _OffsetTemp); } private bool IsTempReady() { return CheckCoolantTemp(ChillerTemp, _tolerance); } private RState StartNewStep() { var state = _currentRecipe.Steps[_currentStep].Start(); if (state != RState.Running) return state; if (_currentRecipe.Steps[_currentStep].CycleStart) { if (!_bLoopMode) { _bLoopMode = true; _loopStartStep = _currentStep; _loopCounter = _currentRecipe.Steps[_currentStep].CycleNumber; } } return RState.Running; } private bool StartNewRecipe() { if(_qeRecipes.Count > 0) { _currentStep = 0; _currentRecipe = _qeRecipes.Dequeue(); CurrentRunningRecipe = _currentRecipe.Header.Name; Notify($"Recipe:{CurrentRunningRecipe} start"); return StartNewStep() == RState.Running; } return false; } private bool RunRecipes() { var step = _currentRecipe.Steps[_currentStep]; var result = step.Run(); if(result == RState.Failed) { Runner.Stop($"Recipe:{CurrentRunningRecipe}, Step:{_currentStep + 1} Failed"); return true; } else if(result == RState.End) { if(_currentRecipe.Steps.Count > _currentStep + 1 && _currentRecipe.Steps[_currentStep + 1].Type != StepType.OverEtch) _currentRecipe.Steps[_currentStep].End(); if(_currentRecipe.Steps[_currentStep].CycleEnd) { if(_loopCounter > 0) { _loopCounter--; _currentStep = _loopStartStep; return StartNewStep() != RState.Running; } else { _bLoopMode = false; _loopStartStep = 0; } } if (_currentStep < _currentRecipe.Steps.Count - 1) { _currentStep++; return StartNewStep() != RState.Running; } else { Notify($"Recipe:{CurrentRunningRecipe} finished"); return !StartNewRecipe(); } } return false; } private bool ProcessDone() { WaferManager.Instance.UpdateWaferProcessStatus(Module, 0, EnumWaferProcessStatus.Completed); return true; } public void Abort() { CloseAllValves(); } } }