using Aitex.Core.RT.Device; using Aitex.Core.RT.Event; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Mainframe.LLs; using Mainframe.TMs; using Mainframe.UnLoads; using MECF.Framework.Common.Equipment; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadLocks; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.UnLoad; using System; namespace Mainframe.EFEMs { public class EfemSlitValveRoutine : EfemBaseRoutine { enum RoutineStep { ServoRoutine, LiftRoutine, CheckPressureCondition, CheckPressure, SetSlitValve, CheckPressureCondition2, TimeDlay1 } private int _motionTimeout = 30; private ModuleName _paramTarget; //目标腔体 private ModuleName _robot; //机械手 private bool _paramIsOpen; //是否开门 private bool _bothPressureIsATM; //判断两边压力是否都为ATM private SicTM _tm; private LoadLock _loadLock; private UnLoad _unLoad; private LoadLockServoToRoutine _llServoToRoutine; private UnLoadServoToRoutine _unLoadServoToRoutine; private LoadLockLiftRoutine _llLiftRoutine; private UnLoadLiftRoutine _unLoadLiftRoutine; private double _maxPressureDiffOpenSlitValve = SC.GetValue("EFEM.MaxPressureDiffOpenSlitValve"); public void Init(ModuleName targetModule,ModuleName robot, bool isOpen) { _paramTarget = targetModule; _robot = robot; _paramIsOpen = isOpen; } public EfemSlitValveRoutine() { Module = ModuleName.EFEM.ToString(); _tm = DEVICE.GetDevice($"{ ModuleName.System.ToString()}.{ ModuleName.TM.ToString()}"); _loadLock= DEVICE.GetDevice($"{ ModuleName.LoadLock.ToString()}.{ ModuleName.LoadLock.ToString()}"); _unLoad = DEVICE.GetDevice($"{ ModuleName.UnLoad.ToString()}.{ ModuleName.UnLoad.ToString()}"); _llServoToRoutine = new LoadLockServoToRoutine(ModuleName.LoadLock); _unLoadServoToRoutine = new UnLoadServoToRoutine(ModuleName.UnLoad); _llLiftRoutine = new LoadLockLiftRoutine(); _unLoadLiftRoutine = new UnLoadLiftRoutine(); } public override Result Start(params object[] objs) { Reset(); //只有LoadLock和UnLoad需要开门 if (_robot == ModuleName.WaferRobot) { if (_paramTarget != ModuleName.LoadLock && _paramTarget != ModuleName.Load && _paramTarget != ModuleName.UnLoad) { return Result.DONE; } } else if (_robot == ModuleName.TrayRobot) { if (_paramTarget != ModuleName.LoadLock) { return Result.DONE; } } else { return Result.DONE; } if (_paramIsOpen) { if (EfemDevice.CheckSlitValveOpen(_paramTarget, _robot)) { return Result.DONE; } //判断TM到LoadLock或者UnLoad的门是否关上 if (!_tm.CheckSlitValveClose(_paramTarget)) { EV.PostWarningLog(Module, $"can not open slit valve {_paramTarget}, {_paramTarget} to TM slit valve not closed, can not open at same time"); return Result.FAIL; } if (!EfemDevice.CheckSlitValveClose(ModuleName.LoadLock, ModuleName.WaferRobot)) //此门是必须要关上的 { EV.PostWarningLog(Module, $"can not open slit valve {_paramTarget}, {ModuleName.LoadLock} to Efem slit valve not closed, can not open at same time"); return Result.FAIL; } if (!EfemDevice.CheckSlitValveClose(ModuleName.UnLoad, _robot)) { EV.PostWarningLog(Module, $"can not open slit valve {_paramTarget}, {ModuleName.UnLoad} to Efem slit valve not closed, can not open at same time"); return Result.FAIL; } if (!EfemDevice.CheckSlitValveClose(ModuleName.LoadLock, _robot)) { EV.PostWarningLog(Module, $"can not open slit valve {_paramTarget}, {ModuleName.LoadLock} to Efem slit valve not closed, can not open at same time"); return Result.FAIL; } _motionTimeout = SC.GetValue("EFEM.SlitValveMotionTimeout"); _llServoToRoutine.Init(SC.GetValue("LoadLock.AtmPressureBase")); _unLoadServoToRoutine.Init(SC.GetValue("UnLoad.AtmPressureBase")); _llLiftRoutine.Init(false); _unLoadLiftRoutine.Init(false); } else { if (EfemDevice.CheckSlitValveClose(_paramTarget, _robot)) { return Result.DONE; } } Notify("Start"); return Result.RUN; } public override Result Monitor() { try { //开门之前需要对两边腔体进行气压调节,降Lift if (_paramIsOpen) { if (_paramTarget == ModuleName.LoadLock) { CheckPressureConditionATM((int)RoutineStep.CheckPressureCondition, _paramTarget);//先判断Load腔是否在大气,因为EFEM始终在大气 if (!_bothPressureIsATM) { ExecuteRoutine((int)RoutineStep.ServoRoutine, _llServoToRoutine); ExecuteRoutine((int)RoutineStep.LiftRoutine, _llLiftRoutine); } } else if (_paramTarget == ModuleName.UnLoad) { CheckPressureConditionATM((int)RoutineStep.CheckPressureCondition, _paramTarget);//先判断UnLoad腔是否在大气 if (!_bothPressureIsATM) { ExecuteRoutine((int)RoutineStep.ServoRoutine, _unLoadServoToRoutine); ExecuteRoutine((int)RoutineStep.LiftRoutine, _unLoadLiftRoutine); } } CheckPressureCondition((int)RoutineStep.CheckPressureCondition2,_paramTarget); } SetSlitValve((int)RoutineStep.SetSlitValve, _paramTarget, _robot, _paramIsOpen, _motionTimeout); TimeDelay((int)RoutineStep.TimeDlay1, 1); } catch (RoutineBreakException) { return Result.RUN; } catch (RoutineFaildException) { return Result.FAIL; } Notify("Finished"); return Result.DONE; } public void CheckPressureConditionATM(int id, ModuleName target) { Tuple ret = Execute(id, () => { Notify($"check pressure condition to open {target} slit valve"); double targetPressure = 0.0; if (target == ModuleName.LoadLock) { targetPressure = _loadLock.ChamberPressure; } else { targetPressure = _unLoad.ChamberPressure; } _bothPressureIsATM = Math.Abs(EfemDevice.AtmPressureBase - targetPressure) <= _maxPressureDiffOpenSlitValve; return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void CheckPressureCondition(int id, ModuleName target) { Tuple ret = Execute(id, () => { Notify($"check {target} pressure is atm"); double targetPressure = 0.0; if (target == ModuleName.LoadLock) { targetPressure = _loadLock.ChamberPressure; } else { targetPressure = _unLoad.ChamberPressure; } if (Math.Abs(EfemDevice.AtmPressureBase - targetPressure) > _maxPressureDiffOpenSlitValve) { Stop($"pressure difference {Math.Abs(EfemDevice.AtmPressureBase - targetPressure):F3} between Efem and {target} exceed tolerance {_maxPressureDiffOpenSlitValve}"); return false; } return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void SetSlitValve(int id, ModuleName module,ModuleName _robort, bool isOpen, int timeout) { Tuple ret = ExecuteAndWait(id, () => { Notify($"set slit valve {module} " + (isOpen ? "Open" : "Close")); if (!EfemDevice.SetSlitValve(module, _robort, isOpen, out string reason)) { Stop(reason); return false; } return true; }, () => { return isOpen ? EfemDevice.CheckSlitValveOpen(module, _robort) : EfemDevice.CheckSlitValveClose(module, _robort); }, timeout * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) //timeout { Stop($"can not complete in {timeout} seconds"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } } }