using System; using System.Collections.Generic; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Aitex.Core.Common; using Aitex.Core.RT.RecipeCenter; using Venus_RT.Devices; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.SubstrateTrackings; using Venus_Core; using System.Diagnostics; using MECF.Framework.Common.DBCore; using Venus_Unity; using System.Threading.Tasks; using Aitex.Core.RT.Event; namespace Venus_RT.Modules.PMs { class PMProcessRoutine : PMRoutineBase, IRoutine { private enum ProcessStep { PreparePressure, PrepareTemperature, RunChuckRecipe, RunProcessRecipe, RunDechuckRecipe, RunCleanRecipe, End, } public string CurrentRunningRecipe { get; set; } public string ProcessRecipeName { get; set; } public string ChuckRecipeName { get; set; } public string DechuckRecipeName { get; set; } public string CleanRecipeName { get; set; } public RecipeHead ProcessRecipeHead { get; set; } public DateTime RecipeStartTime { get; private set; } public DateTime RecipeEndTime { get; private set; } public string WaferId { get; set; } public string SlotID { get; set; } public string LotID { get; set; } public string RecipeId { get; set; } //public bool CurrentRecipeType { get; set; } //int Timeall; private Stopwatch Recipetime = new Stopwatch(); private readonly PumpDownRoutine _pumpDownRoutine; private readonly ProcessHelper _processHelper; private bool _withWafer = true; //private bool _needPumpDown = false; public Recipe _currentRecipe = null; private int _currentStep = 0; private List Recipelist = new List(); private double _tolerance; private double _OffsetTemp = 0.0f; private bool _bLoopMode = false; private int _loopStartStep = 0; private int _loopCounter = 0; private int _recipeRunningMode = 0; private Stopwatch _stepTime = new Stopwatch(); public RecipeResult currentRecipeResult; public bool isMaualEndStep; private RecipeFACallback _faCallback; private JetChamber _jetChamber; private RecipeType _recipeType; private Recipe ProcessRecipe; private Recipe ChuckRecipe; private Recipe DechuckRecipe; private Recipe CleanRecipe; private bool needprocess; private bool needdechuck; private bool needchuck; private bool needclean; 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(JetPMBase chamber, PumpDownRoutine pdRoutine) : base(chamber) { Name = "Process"; _pumpDownRoutine = pdRoutine; _processHelper = new ProcessHelper(chamber); _faCallback = new RecipeFACallback(); _jetChamber = (JetChamber)SC.GetValue($"{chamber.Module}.ChamberType"); } 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) { needprocess = false; needchuck = false; needclean = false; needdechuck = false; Recipelist.Clear(); string recipeName = (string)objs[0]; if (objs.Length >= 2) { _recipeType = (RecipeType)Enum.Parse(typeof(RecipeType), objs[2].ToString()); if (_recipeType == RecipeType.Clean) { _withWafer = false; } else { _withWafer = true; } } if (objs.Length >= 4) { LotID = objs[3].ToString(); } else { LotID = ""; } if (_withWafer && WaferManager.Instance.CheckNoWafer(Module, 0)) { Stop($"can not run process, no wafer at {Module}"); EV.PostAlarmLog(Module.ToString(), $"can not run process, no wafer at {Module}"); return RState.Failed; } else if (!_withWafer && WaferManager.Instance.CheckHasWafer(Module, 0)) { Stop($"can not run clean recipe{recipeName}, a wafer at {Module}"); EV.PostAlarmLog(Module.ToString(), $"can not run clean recipe, a wafer at {Module}"); return RState.Failed; } if (!_chamber.IsRFGInterlockOn) { Stop("射频电源 Interlock条件不满足"); EV.PostAlarmLog(Module.ToString(), "射频电源 Interlock条件不满足"); return RState.Failed; } if (!CheckSlitDoor() || !CheckDryPump() || !CheckTurboPump()) { return RState.Failed; } currentRecipeResult = new RecipeResult(); currentRecipeResult.RecipeName = recipeName; string recipeContent = RecipeFileManager.Instance.LoadRecipe(_chamber.Name, recipeName, false, objs[2].ToString()); Recipe recipe = Recipe.Load(recipeContent); currentRecipeResult.RecipeStepCount = recipe.Steps.Count; if (recipe == null) { Stop($"Load Recipe:{recipeName} failed"); EV.PostAlarmLog(Module.ToString(), $"Load Recipe:{recipeName} failed"); return RState.Failed; } _recipeRunningMode = SC.GetValue($"{Module}.RecipeRunningMode"); _processHelper.m_RecipeHead = recipe.Header; switch (recipe.Header.Type) { case RecipeType.Process: if (_recipeRunningMode == 1 && recipe.Header.ChuckRecipe != null && !string.IsNullOrEmpty(recipe.Header.ChuckRecipe)) { string chuckcontent = RecipeFileManager.Instance.LoadRecipe(_chamber.Name, recipe.Header.ChuckRecipe, false, RecipeType.Chuck.ToString()); ChuckRecipe = Recipe.Load(chuckcontent); if (ChuckRecipe != null) { ChuckRecipeName = recipe.Header.ChuckRecipe; needchuck = true; Recipelist.Add(ChuckRecipe); } } needprocess = true; ProcessRecipeHead = recipe.Header; ProcessRecipe = recipe; ProcessRecipeName = recipeName; Recipelist.Add(recipe); if (_recipeRunningMode == 1 && recipe.Header.DechuckRecipe != null && !string.IsNullOrEmpty(recipe.Header.DechuckRecipe)) { string dechuckcontent = RecipeFileManager.Instance.LoadRecipe(_chamber.Name, recipe.Header.DechuckRecipe, false, RecipeType.DeChuck.ToString()); DechuckRecipe = Recipe.Load(dechuckcontent); if (DechuckRecipe != null) { DechuckRecipeName = recipe.Header.DechuckRecipe; needdechuck = true; Recipelist.Add(DechuckRecipe); } } break; case RecipeType.Chuck: ChuckRecipeName = recipeName; ChuckRecipe = recipe; Recipelist.Add(ChuckRecipe); needchuck = true; break; case RecipeType.DeChuck: DechuckRecipeName = recipeName; Recipelist.Add(DechuckRecipe); DechuckRecipe = recipe; needdechuck = true; break; case RecipeType.Clean: CleanRecipe = recipe; CleanRecipeName = recipeName; Recipelist.Add(CleanRecipe); needclean = true; break; } foreach (Recipe rcp in Recipelist) { if (AssignFuns(rcp) == false) { Stop($"Associate process alogrithm with recipe:{rcp.Header.Name} failed"); EV.PostAlarmLog(Module.ToString(), $"Associate process alogrithm with recipe:{rcp.Header.Name} failed"); return RState.Failed; } } _bLoopMode = false; _loopStartStep = 0; _loopCounter = 0; _processHelper.isLoop = false; _processHelper.loopsteps = 0; _processHelper.currentStepIndex = 0; _tolerance = SC.GetValue($"System.MaxTemperatureToleranceToTarget"); _OffsetTemp = SC.GetValue($"{Module}.Chiller.ChillerTemperatureOffset"); _faCallback.RecipeStart(_chamber.Module.ToString(), recipeName); WaferManager.Instance.UpdateWaferProcessStatus(Module, 0, EnumWaferProcessStatus.InProcess); return Runner.Start(Module, Name); } public RState Monitor() { Runner .Run(ProcessStep.PreparePressure, PreparePressure, IsPressureReady) .Run(ProcessStep.PrepareTemperature, PrepareTemp, IsTempReady) .RunIf(ProcessStep.RunChuckRecipe, needchuck, StartChuckRecipe, CheckRecipeDone, 5 * 60 * 60 * 1000) .RunIf(ProcessStep.RunProcessRecipe, needprocess, StartProcessRecipe, CheckRecipeDone, 5 * 60 * 60 * 1000) .RunIf(ProcessStep.RunDechuckRecipe, needdechuck, StartDechuckRecipe, CheckRecipeDone, 5 * 60 * 60 * 1000) .RunIf(ProcessStep.RunCleanRecipe, needclean, StartCleanRecipe, CheckRecipeDone, 5 * 60 * 60 * 1000) .End(ProcessStep.End, ProcessDone, _delay_1s); return Runner.Status; } private bool PreparePressure() { //2023/09/02 tps remove //if(_chamber.ProcessHighPressure < 5 && _chamber.ProcessLowPressure _currentStep + 1 && _currentRecipe.Steps[_currentStep + 1].Type != StepType.OverEtch) { _currentRecipe.Steps[_currentStep].End(); } if (_currentRecipe.Steps[_currentStep].CycleEnd) { if (_loopCounter > 0) { _loopCounter--; currentRecipeResult.RecipeCurrentCounter += 1; _currentStep = _loopStartStep; return StartNewStep() != RState.Running; } else { _bLoopMode = false; _loopStartStep = 0; //_processHelper.loopStep(false, 0, 0); _processHelper.isLoop = false; _processHelper.loopsteps = 0; _processHelper.currentStepIndex = 0; } } if (_currentStep < _currentRecipe.Steps.Count - 1 || isMaualEndStep == true) { result = RState.End; isMaualEndStep = false; _currentStep++; return StartNewStep() != RState.Running; } else { Notify($"Recipe:{CurrentRunningRecipe} finished"); //FaEvent.FaPostInfo(Module.ToString(), $"Recipe:{CurrentRunningRecipe} finished"); UpdateWaferStatus(); //if (_currentRecipe.Header.Type == RecipeType.Process) //{ // processRecipe = (Recipe)SerializeHelper.Instance.Clone(_currentRecipe); //} _chamber.EPDRecipeStop(); RecipeDone("Success"); return true; } } return false; } public void RecipeDone(string result) { Recipetime.Stop(); WaferInfo waferInfo = WaferManager.Instance.GetWafer(ModuleHelper.Converter(Module.ToString()), 0); if (!waferInfo.IsEmpty) { WaferId = waferInfo.InnerId.ToString(); SlotID = waferInfo.OriginSlot.ToString(); //LotID = waferInfo.ProcessJob == null || string.IsNullOrEmpty(waferInfo.ProcessJob.ControlJobName) ? "" : waferInfo.ProcessJob.ControlJobName; } RecipeEndTime = RecipeStartTime + Recipetime.Elapsed; switch (_currentRecipe.Header.Type) { case RecipeType.Clean: ProcessDataRecorder.RecordPrecess(RecipeId, RecipeStartTime, RecipeEndTime, _currentRecipe.Header.Name, result, "", _chamber.Name, "", "", _currentRecipe.Header.Type.ToString()); break; case RecipeType.Chuck: case RecipeType.DeChuck: case RecipeType.Process: ProcessDataRecorder.RecordPrecess(RecipeId, RecipeStartTime, RecipeEndTime, _currentRecipe.Header.Name, result, WaferId, _chamber.Name, LotID, SlotID, _currentRecipe.Header.Type.ToString()); break; } } private bool ProcessDone() { _currentRecipe.Steps[_currentStep].End(); RecipeFileManager.Instance.SaveAsRecipe2(Module.ToString(), _currentRecipe.Header.Type.ToString(), _currentRecipe.Header.Name, RecipeUnity.RecipeToString(_currentRecipe)); _stepTime.Stop(); WaferManager.Instance.UpdateWaferProcessStatus(Module, 0, EnumWaferProcessStatus.Idle); WaferManager.Instance.UpdateWaferProcessStatus(Module, 0, EnumWaferProcessStatus.Completed); CloseAllValves(500); _chamber.GeneratorSetpower(0); _chamber.GeneratorBiasSetpower(0); _chamber.GeneratorBiasPowerOn(false); _chamber.GeneratorPowerOn(false); _chamber.OpenValve(ValveType.TurboPumpPumping, true); _chamber.OpenValve(ValveType.TurboPumpPurge, true); _chamber.OpenValve(ValveType.Guage, true); _chamber.SetPVPostion(1000); if (_jetChamber == JetChamber.Venus && _chamber.IsHVOn == true) { _chamber.OnOffSetESCHV(false); } return true; } private void UpdateWaferStatus(bool bDone = true) { if (bDone == false) { WaferManager.Instance.UpdateWaferProcessStatus(Module, 0, EnumWaferProcessStatus.Failed); if (_currentRecipe.Header.Type == RecipeType.Chuck) { // set wafer chucked flag even if the chuck recipe failed. WaferManager.Instance.UpdateWaferChuckStatus(Module, 0, EnumWaferChuckStatus.Chucked); } } switch (_currentRecipe.Header.Type) { case RecipeType.Process: break; case RecipeType.Chuck: WaferManager.Instance.UpdateWaferChuckStatus(Module, 0, EnumWaferChuckStatus.Chucked); break; case RecipeType.DeChuck: WaferManager.Instance.UpdateWaferProcessStatus(Module, 0, EnumWaferProcessStatus.Completed); WaferManager.Instance.UpdateWaferChuckStatus(Module, 0, EnumWaferChuckStatus.Dechucked); break; } } public async void Abort() { if (_currentRecipe!=null) { RecipeDone("Abort"); } _chamber.GeneratorBiasPowerOn(false); _chamber.GeneratorPowerOn(false); _chamber.TurnPendulumValve(false); CloseAllValves(500); _chamber.OpenValve(ValveType.TurboPumpPumping, true); _chamber.OpenValve(ValveType.TurboPumpPurge, true); if (_chamber.ChamberType == JetChamber.Venus) { await Task.Delay(3000); _chamber.OnOffSetESCHV(false); } } } }