using System; using System.Collections.Generic; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Venus_RT.Devices; using MECF.Framework.Common.SubstrateTrackings; using System.Text.Json; 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 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 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; } 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]; Recipe recipe = Recipe.Load(recipeName); if(recipe == null) { return RState.Failed; } switch(recipe.Header.Type) { case RecipeType.Process: var chuckRecipe = Recipe.Load(recipe.Header.ChuckRecipe); var dechuckRecipe = Recipe.Load(recipe.Header.DechuckRecipe); if(chuckRecipe == null || dechuckRecipe == null) { return RState.Failed; } ProcessRecipeName = recipeName; ChuckRecipeName = recipe.Header.ChuckRecipe; DechuckRecipeNamae = recipe.Header.DechuckRecipe; _qeRecipes.Enqueue(chuckRecipe); _qeRecipes.Enqueue(recipe); _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; } _tolerance = SC.GetValue($"System.MaxTemperatureToleranceToTarget"); _OffsetTemp = SC.GetValue($"{Module}.Chiller.ChillerTemperatureOffset"); 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); //return true; } private bool IsTempReady() { return CheckCoolantTemp(ChillerTemp, _tolerance); } private bool StartNewRecipe() { if(_qeRecipes.Count > 0) { _currentStep = 0; _currentRecipe = _qeRecipes.Dequeue(); CurrentRunningRecipe = _currentRecipe.Header.Name; _currentRecipe.Steps[_currentStep].Start(); Notify($"Recipe:{CurrentRunningRecipe} start"); return true; } 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 (_currentStep < _currentRecipe.Steps.Count - 1) { _currentStep++; _currentRecipe.Steps[_currentStep].Start(); } else { Notify($"Recipe:{CurrentRunningRecipe} finished"); return !StartNewRecipe(); } } return false; } private bool ProcessDone() { return true; } public void Abort() { CloseAllValves(); } } }