using System; using System.Collections.Generic; using Aitex.Core.Common; using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.Device; using Aitex.Core.RT.Device.Devices; using Aitex.Core.RT.Event; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using MECF.Framework.Common.Device.Bases; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.OperationCenter; using MECF.Framework.Common.SubstrateTrackings; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.PMs; using SicPM1.Routines; using static SicPM1.PM1Module; namespace SicPM1.RecipeExecutions { public class PreProcess : PMBaseRoutine { public enum RoutineStep { SetServoUp, SetChamberPressure, EnableRotation, OpenH2Valve, EnableHeater, PcCalibartion, RunStepOne, Wait, CheckCondition, WaitTempReach, SetRotation, TimeDelay1, //DelayForTest, //CheckDoor, //CheckDryPump, //CloseSlitValve, //CloseAllVavle, //OpenPumpingValve, //OpenGateVlave, //CheckVAC, //SetRfMatchMode, //SetElectrodeTemp, //NoteInProcess, //NoteProcessFailed, //SetThrottlePressureControlMode, //Pump, //End, //NoteProcessComplete, } private double _pumpBasePressure; private int _pumpTimeout; private string _recipeName; private bool _isCleanRecipe; private bool _withWafer; private bool _isSlitDoorOpened; private ThrottleValveBase _throttleValve; private bool _isThrottlePressureControlMode; private Guid _guidProcess; private bool _isDryRun; private bool _isPSUHeaterJumpMode; private bool _isSCRHeaterJumpMode; private bool _isMFCJumpMode; private int _delayTimeRamp; private int _servoUpDelay; private double _targetPressure; private double _preTemp; private int _rotationSpeed; private IoInterLock _pmInterLock; private PMServoToPressure _pmServoToPressure; private PMPcCalibrationRoutine _pmPcCalibrationRoutine; public PreProcess(ModuleName module, PM1Module pm1) : base(module, pm1) { Module = module.ToString(); Name = "PreProcess"; _pmInterLock = DEVICE.GetDevice($"{Module}.PMInterLock"); _pmServoToPressure = new PMServoToPressure(module, pm1); _pmPcCalibrationRoutine = new PMPcCalibrationRoutine(module, pm1); } public void Init(string recipeName, bool isClean, bool withWafer) { _recipeName = recipeName; _isCleanRecipe = isClean; _withWafer = withWafer; } public override Result Start(params object[] objs) { Reset(); if (!RecipeParser.Parse(_recipeName, Module, out var recipeHead, out var recipeSteps, out string reason)) { Stop($"Load recipe {_recipeName} failed, {reason}"); return Result.FAIL; } if (!RecipeParser.CheckDataAvalible(_recipeName, Module, out string reason1)) { Stop($"Recipe data is error! " + reason1); return Result.FAIL; } if (!_withWafer && WaferManager.Instance.CheckHasWafer(PmDevice.Module, 0)) { EV.PostWarningLog(Module, $"can not run waferless process, Has wafer at {Module}"); return Result.FAIL; } if (_withWafer && !WaferManager.Instance.CheckHasWafer(PmDevice.Module, 0)) { EV.PostWarningLog(Module, $"can not run process, no wafer at {Module}"); return Result.FAIL; } if (!PmDevice.Pump.IsOn || PmDevice.Pump.IsError) { EV.PostWarningLog(Module, $"can not run process, pump state is not correct"); return Result.FAIL; } if (!PmDevice._ioThrottleValve.TVValveEnable) { EV.PostWarningLog(Module, $"can not run process, TV is not enable"); return Result.FAIL; } if (PmDevice._ioThrottleValve.ControlModeFeedback != PressureCtrlMode.TVPressureCtrl) { EV.PostWarningLog(Module, $"can not run process, TV is not Pressure Ctrol Mode"); return Result.FAIL; } if (!PmDevice.CheckIOValueByGroup(IoGroupName.I, true)) { EV.PostAlarmLog(Module, $"can not run process,I valves is not open!"); return Result.FAIL; } if (!PmDevice.CheckIOValueByGroup(IoGroupName.E, false)) { EV.PostAlarmLog(Module, $"can not run process,E valves is not closed!"); return Result.FAIL; } if (!PmDevice.CheckIOValueByGroup(IoGroupName.K, false)) { EV.PostAlarmLog(Module, $"can not run process,K valves is not closed!"); return Result.FAIL; } if (!PmDevice.CheckIOValueByGroup(IoGroupName.VentPump, true)) { EV.PostAlarmLog(Module, $"can not run process,V72 is not open!"); return Result.FAIL; } if (!PmDevice.PSU1.AllHeatEnable) { EV.PostAlarmLog(Module, $"can not run process,Heater is disable!"); return Result.FAIL; } if (!_pmInterLock.SetPMPreProcessRunning(true, out reason)) { EV.PostAlarmLog(Module, $"can not run preProcess, {reason}"); return Result.FAIL; } _rotationSpeed = SC.GetValue($"PM.{Module}.ProcessIdle.RotationSpeed"); _isDryRun = SC.GetValue($"PM.{Module}.DryRun.IsDryRun"); _delayTimeRamp = SC.GetValue($"PM.{Module}.PreProcess.RampDelayTime"); _servoUpDelay = SC.GetValue($"PM.{Module}.PreProcess.ServoBeforeUpDelay"); _targetPressure = SC.GetValue($"PM.{Module}.PreProcess.ChamberPressure"); _preTemp = SC.GetValue($"PM.{Module}.PreProcess.ProcessBeginTempCondition"); //等待温度到达这个温度才开始工艺 _pmServoToPressure.Init(_targetPressure); _guidProcess = Guid.NewGuid(); PmDevice.RecipeRunningInfo.RecipeName = _recipeName; PmDevice.RecipeRunningInfo.Head = recipeHead; PmDevice.RecipeRunningInfo.RecipeStepList = recipeSteps; Notify($"Start"); return Result.RUN; } public override Result Monitor() { try { EnableRotation((int)RoutineStep.EnableRotation, 5); SetRotationValveAndNoWait((int)RoutineStep.SetRotation, _rotationSpeed); TimeDelay((int)RoutineStep.TimeDelay1, _servoUpDelay); SetConfinementRingUpAndWait((int)RoutineStep.SetServoUp, 30); if (SC.GetValue("System.IsSimulatorMode")) { return Result.DONE; } ExecuteRoutine((int)RoutineStep.SetChamberPressure, _pmServoToPressure); OpenH2Valve((int)RoutineStep.OpenH2Valve, PmDevice, 2); EnableHeater((int)RoutineStep.EnableHeater, PmDevice, 5); if (!_isDryRun) // 空跑工艺 { RunStepOne((int)RoutineStep.RunStepOne, PmDevice, _delayTimeRamp); Wait((int)RoutineStep.Wait, $"Chamber:{Name}:Wait", _delayTimeRamp); CheckCondition((int)RoutineStep.CheckCondition, PmDevice, PmDevice.RecipeRunningInfo.RecipeStepList[0].RecipeCommands); WaitTempratureToBeginProcess((int)RoutineStep.WaitTempReach, _preTemp, 10000); } } catch (RoutineBreakException) { return Result.RUN; } catch (RoutineFaildException) { //NoteProcessFailed((int)Routine.NoteProcessFailed); return Result.FAIL; } catch (Exception ex) { LOG.Write(ex, String.Format("Preprocess Monitor has exception")); throw (ex); } _pmInterLock.SetPMPreProcessRunning(false, out string reason); Notify("Finished"); return Result.DONE; } protected void EnableHeater(int id, PMModuleBase pm, int timeout) { Tuple ret = ExecuteAndWait(id, () => { Notify($"Set {pm.Name} Heater Enable"); if (!pm.EnableHeater(true, out string reason)) { Stop($"Set {pm.Name} Heater Enable failed, {reason}"); return false; } return true; }, () => { return pm.CheckHeaterEnable(); }, timeout * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } if (ret.Item2 == Result.TIMEOUT) { Stop($"Set {pm.Name} Heater Enable timeout, over {timeout} seconds"); throw (new RoutineFaildException()); } else { throw (new RoutineBreakException()); } } } protected void RunStepOne(int id, PMModuleBase pm, int delayTime) { Tuple ret = Execute(id, () => { Notify($"Run {pm.Name} recipe step one"); string reason = string.Empty; //执行工艺程序命令 foreach (var recipeCmd in PmDevice.RecipeRunningInfo.RecipeStepList[0].RecipeCommands.Keys) { if (recipeCmd == "SusHeaterSetMode") { if (PmDevice.RecipeRunningInfo.RecipeStepList[0].RecipeCommands[recipeCmd] == "Jump") _isPSUHeaterJumpMode = true; else _isPSUHeaterJumpMode = false; continue; } if (recipeCmd == "WWHeaterSetMode") { if (PmDevice.RecipeRunningInfo.RecipeStepList[0].RecipeCommands[recipeCmd] == "Jump") _isSCRHeaterJumpMode = true; else _isSCRHeaterJumpMode = false; continue; } if (recipeCmd == "FlowSetMode") { if (PmDevice.RecipeRunningInfo.RecipeStepList[0].RecipeCommands[recipeCmd] == "Jump") _isMFCJumpMode = true; else _isMFCJumpMode = false; continue; } if (IsCmdSkip(recipeCmd)) continue; if (!OP.CanDoOperation($"{Module}.{recipeCmd}", out reason, PmDevice.RecipeRunningInfo.RecipeStepList[0].RecipeCommands[recipeCmd])) { Stop($"Can not execute {recipeCmd}, {reason}"); return false; } else { int time = delayTime * 1000; if (recipeCmd.StartsWith("TC1") && _isPSUHeaterJumpMode) { time = 1; } if (recipeCmd.StartsWith("TC2") && _isSCRHeaterJumpMode) { time = 1; } if (recipeCmd.StartsWith("Mfc") && recipeCmd.EndsWith(".Ramp") && _isMFCJumpMode) { time = 1; } //if (recipeCmd == "Pressure5.Ramp") //{ // double pc5Pressure = Convert.ToDouble(PMDevice.RecipeRunningInfo.RecipeStepList[0].RecipeCommands[recipeCmd]) + _pc5Offset; // OP.DoOperation($"{Module}.{recipeCmd}", out string reason1, time, pc5Pressure.ToString()); //} //else if (recipeCmd == "Pressure6.Ramp") //{ // double pc6Pressure = Convert.ToDouble(PMDevice.RecipeRunningInfo.RecipeStepList[0].RecipeCommands[recipeCmd]) + _pc6Offset; // OP.DoOperation($"{Module}.{recipeCmd}", out string reason1, time, pc6Pressure.ToString()); //} //else if (recipeCmd == "Pressure7.Ramp") //{ // double pc7Pressure = Convert.ToDouble(PMDevice.RecipeRunningInfo.RecipeStepList[0].RecipeCommands[recipeCmd]) + _pc7Offset; // OP.DoOperation($"{Module}.{recipeCmd}", out string reason1, time, pc7Pressure.ToString()); //} //else { OP.DoOperation($"{Module}.{recipeCmd}", out string reason1, time, PmDevice.RecipeRunningInfo.RecipeStepList[0].RecipeCommands[recipeCmd]); } } } return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else { throw (new RoutineBreakException()); } } } public void Wait(int id, string stepName, int delayTime) { Tuple ret = Delay(id, () => { Notify($"Wait for {delayTime} seconds"); _stepSpan = new TimeSpan(0, 0, 0, (int)delayTime); _stepStartTime = DateTime.Now; _stepName = stepName; return true; }, delayTime * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else { throw (new RoutineBreakException()); } } } protected void CheckCondition(int id, PMModuleBase pm, Dictionary recipeCommands) { string reason = String.Empty; Tuple ret = Wait(id, () => { if (!pm.CheckPreProcessCondition(recipeCommands, out reason)) { return false; } return true; }, 60 * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { Stop(reason); throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) { Stop(reason); throw (new RoutineFaildException()); } else { throw (new RoutineBreakException()); } } } /// /// 等待温度到达工艺温度 /// protected void WaitTempratureToBeginProcess(int id,double targetTemp,int timeout) { string reason = String.Empty; Tuple ret = Wait(id, () => { if (PmDevice.TC1.L2PVFeedBack >= targetTemp) { return true; } return false; }, timeout * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { Stop(reason); throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) { Stop(reason); throw (new RoutineFaildException()); } else { throw (new RoutineBreakException()); } } } protected void NoteInProcess(int id, int slot) { Tuple ret = Execute(id, () => { Notify($"Update process information, process in {ModuleName.PM1} start"); ModuleName mod = ModuleName.PM1; WaferManager.Instance.UpdateWaferProcessStatus(mod, slot, EnumWaferProcessStatus.InProcess); //_pm.OnProcessStart(_guidProcess.ToString(), _recipeName, false); return true; }); if (ret.Item1) { throw (new RoutineBreakException()); } } protected void NoteProcessComplete(int id, int slot) { Tuple ret = Execute(id, () => { Notify($"Update process information, process in {ModuleName.PM1} completed"); ModuleName mod = ModuleName.PM1; WaferManager.Instance.UpdateWaferProcessStatus(mod, slot, EnumWaferProcessStatus.Completed); return true; }); if (ret.Item1) { throw (new RoutineBreakException()); } } public void Exit() { } public override void Abort() { _pmInterLock.SetPMPreProcessRunning(false, out string reason); PmDevice.AbortRunProcess(out reason); //_pm.StopAllGasFlow(out string reason); //_pm.SetPowerOnOff(false, out reason); //_pm.SetPower(0, false); //_pm.CloseValvesForPumping(out reason); //_executor.RecipeRunningInfo.Step = 0; //_executor.RecipeRunningInfo.ElapsedTime = 0; } } }