using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Aitex.Sorter.Common; using Venus_RT.Devices; using MECF.Framework.Common.Jobs; using MECF.Framework.Common.Routine; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.SubstrateTrackings; using Venus_Core; using Aitex.Core.RT.Log; using Aitex.Core.Util; using MECF.Framework.Common.Schedulers; using System.Collections.Generic; using Venus_RT.Devices.EFEM; namespace Venus_RT.Modules.EFEM { class EfemSwapRoutine : ModuleRoutineBase, IRoutine { private enum SwapStep { WaitModuleReady, ModulePrepare, OpenSlitDoor, WaitEFEMIdle, MoveWafer, WaferMoved, CloseSlitDoor, NotifyDone, } private readonly EfemBase _efem; private int _moveTimeout = 20 * 1000; private ModuleName _targetModule; private LLEntity _llModule; private TMEntity _tmModule; Queue _actionList = new Queue(); MoveItem _currentAction; private int _actionCount = 0; private int _autoPumpOptInWafer = 4; private int _autoPumpOptOutWafer = 0; private SequenceLLInOutPath _sequencePattern = SequenceLLInOutPath.DInDOut; private bool _bAutoMode = true; public EfemSwapRoutine(EfemBase efem) : base(ModuleName.EfemRobot) { _efem = efem; Name = "Swap"; } public RState Start(params object[] objs) { if (!_efem.IsHomed) { LOG.Write(eEvent.ERR_EFEM_COMMON_FAILED, Module, $"EFEM is not homed, please home it first"); return RState.Failed; } _actionList.Clear(); foreach (var item in (Queue)objs[0]) { _actionList.Enqueue(new MoveItem(item.SourceModule, item.SourceSlot, item.DestinationModule, item.DestinationSlot, item.RobotHand)); } if (!WaferManager.Instance.CheckDuplicatedWafersBeforeMove(_actionList)) return RState.Failed; var firtItem = _actionList.Peek(); if (ModuleHelper.IsLoadLock(firtItem.SourceModule)) _targetModule = firtItem.SourceModule; else if (ModuleHelper.IsLoadLock(firtItem.DestinationModule)) _targetModule = firtItem.DestinationModule; else { LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Invalid move parameter: {firtItem.SourceModule},{firtItem.SourceSlot + 1} => {firtItem.DestinationModule},{firtItem.DestinationSlot + 1} "); return RState.Failed; } _llModule = Singleton.Instance.GetLL(_targetModule); if (_llModule == null) { LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Invalid Loadlock: {_targetModule}, maybe not installed"); return RState.Failed; } _tmModule = Singleton.Instance.GetTM(); if(_tmModule == null) { LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Get TM Entity failed."); return RState.Failed; } _moveTimeout = SC.GetValue("EFEM.MotionTimeout") * 1000; _autoPumpOptInWafer = SC.GetValue("EFEM.LLAutoPumpInWaferOpt"); _autoPumpOptOutWafer = SC.GetValue("EFEM.LLAutoPumpOutWaferOpt"); _sequencePattern = Singleton.Instance.LLInOutPath; _bAutoMode = Singleton.Instance.IsAutoMode; _actionCount = _actionList.Count; return Runner.Start(Module, $"EFEM Swap with {_targetModule}"); } public RState Monitor() { Runner.Wait(SwapStep.WaitModuleReady, () => _llModule.IsIdle, _delay_60s) .Run(SwapStep.ModulePrepare, ModulePrepare, IsModulePrepareReady) .Run(SwapStep.OpenSlitDoor, OpenSlitDoor, IsSlitDoorOpen, _delay_30s) .LoopStart(SwapStep.WaitEFEMIdle, loopName(), _actionCount, NullFun, WaitRobotReady, _delay_60s) .LoopRun(SwapStep.MoveWafer, MoveWafer, WaitWaferMoved, _moveTimeout + _delay_1s) .LoopEnd(SwapStep.WaferMoved, NullFun, _delay_5ms) .Run(SwapStep.CloseSlitDoor, CloseSlitDoor, IsSlitDoorClosed, _delay_30s) .End(SwapStep.NotifyDone, NotifyLLDone, _delay_50ms); return Runner.Status; } private bool ModulePrepare() { _llModule.PostMsg(LLEntity.MSG.Prepare_EFEM); return true; } private string loopName() { return "EFEM Swap"; } private bool IsModulePrepareReady() { return _llModule.Status == LLEntity.LLStatus.Ready_For_EFEM; } private bool OpenSlitDoor() { return _tmModule.TurnEFEMSlitDoor(_targetModule, true, out _); } private bool CloseSlitDoor() { return _tmModule.TurnEFEMSlitDoor(_targetModule, false, out _); } private bool IsSlitDoorOpen() { return _tmModule.IsLLSlitDoorOpen(_targetModule); } private bool IsSlitDoorClosed() { return _tmModule.IsLLSlitDoorClosed(_targetModule); } private bool WaitRobotReady() { return _efem.Status == RState.End; } private bool VerifyWaferExistence(MoveItem item) { if (WaferManager.Instance.CheckHasWafer(item.DestinationModule, item.DestinationSlot)) { LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Cannot move wafer as desitination {item.DestinationModule},{item.DestinationSlot} already a wafer: "); return false; } if (WaferManager.Instance.CheckNoWafer(item.SourceModule, item.SourceSlot)) { LOG.Write(eEvent.ERR_EFEM_ROBOT, Module, $"Cannot move wafer as source {item.SourceModule}, {item.SourceSlot} has no wafer"); return false; } return true; } private bool MoveWafer() { if(_actionList.Count <= 0) { Runner.Stop("no action"); return true; } _currentAction = _actionList.Dequeue(); if (!VerifyWaferExistence(_currentAction)) return false; var wafer = WaferManager.Instance.GetWafer(_currentAction.SourceModule, _currentAction.SourceSlot); LOG.Write(eEvent.EV_EFEM_ROBOT, ModuleName.EfemRobot, $"{wafer.WaferOrigin} will be move from {_currentAction.SourceModule} {_currentAction.SourceSlot + 1} to {_currentAction.DestinationModule} {_currentAction.DestinationSlot + 1}"); if (ModuleHelper.IsLoadLock(_currentAction.SourceModule) && ModuleHelper.IsEFEMRobot(_currentAction.DestinationModule)) { return _efem.Pick(_currentAction.SourceModule, _currentAction.SourceSlot, (Hand)_currentAction.DestinationSlot); } else if (ModuleHelper.IsEFEMRobot(_currentAction.SourceModule) && ModuleHelper.IsLoadLock(_currentAction.DestinationModule)) { return _efem.Place(_currentAction.DestinationModule, _currentAction.DestinationSlot, (Hand)_currentAction.SourceSlot); } else { LOG.Write(eEvent.ERR_EFEM_ROBOT, ModuleName.EfemRobot, $"Invalid move parameter, source:{_currentAction.SourceModule},{_currentAction.SourceSlot}, destination: {_currentAction.DestinationModule}, {_currentAction.DestinationSlot}"); return false; } } private bool WaitWaferMoved() { if (_efem.Status == RState.Running) { if(Runner.StepElapsedMS > _moveTimeout) { WaferManager.Instance.CreateDuplicatedWafer(_currentAction.SourceModule, _currentAction.SourceSlot, _currentAction.DestinationModule, _currentAction.DestinationSlot); Runner.Stop($"EFEM Robot moving wafer from {_currentAction.SourceModule}.{_currentAction.SourceSlot + 1} to {_currentAction.DestinationModule}.{_currentAction.DestinationSlot + 1}, {_moveTimeout}ms"); return true; } return false; } else if (_efem.Status == RState.End) { WaferManager.Instance.WaferMoved(_currentAction.SourceModule, _currentAction.SourceSlot, _currentAction.DestinationModule, _currentAction.DestinationSlot); return true; } else { WaferManager.Instance.CreateDuplicatedWafer(_currentAction.SourceModule, _currentAction.SourceSlot, _currentAction.DestinationModule, _currentAction.DestinationSlot); Runner.Stop($"EFEM Robot moving wafer failed, {_efem.Status}"); return true; } } private bool NotifyLLDone() { var waferStatus = _llModule.GetWaferProcessStatus(); bool bAutoPump = false; if (_bAutoMode) { if (((_sequencePattern == SequenceLLInOutPath.AInBOut && _targetModule == ModuleName.LLA) || (_sequencePattern == SequenceLLInOutPath.BInAOut && _targetModule == ModuleName.LLB)) && waferStatus.unprocessed >= _autoPumpOptInWafer) { bAutoPump = true; } else if (((_sequencePattern == SequenceLLInOutPath.AInBOut && _targetModule == ModuleName.LLB) || (_sequencePattern == SequenceLLInOutPath.BInAOut && _targetModule == ModuleName.LLA)) && waferStatus.processed <= _autoPumpOptOutWafer) { bAutoPump = true; } else if (_sequencePattern == SequenceLLInOutPath.DInDOut && waferStatus.processed <= _autoPumpOptOutWafer && waferStatus.unprocessed >= _autoPumpOptInWafer) { bAutoPump = true; } } LOG.Write(eEvent.EV_EFEM_ROBOT, Module, $"NotifyLLDone() => {_targetModule}, Sequence Pattern{_sequencePattern}, unprocessed wafer:{waferStatus.unprocessed}, processed wafer: {waferStatus.processed},bAutoPump = {bAutoPump}, Config Option:{_autoPumpOptInWafer},{_autoPumpOptOutWafer}"); _llModule.PostMsg(bAutoPump ? LLEntity.MSG.AutoPump : LLEntity.MSG.EFEM_Exchange_Ready); return true; } public void Abort() { //_efem.Halt(); } } }