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 System; using System.Text; using System.Collections.Generic; using MECF.Framework.Common.Schedulers; namespace Venus_RT.Modules.TM { class MFSwapRoutine : ModuleRoutineBase, IRoutine { private enum SwapStep { WaitModuleReady, PreRotation, ModulePrepare, OpenSlitDoor, MoveWafer, WaitMaferMoved, CloseSlitDoor, NotifyDone, } private readonly JetTM _JetTM; private readonly ITransferRobot _robot; private int _swapTimeout = 120 * 1000; private ModuleName _targetModule; private LLEntity _llModule; private int _autoVentOptInWafer = 0; private int _autoVentOptOutWafer = 4; private SequenceLLInOutPath _sequencePattern = SequenceLLInOutPath.DInDOut; private bool _bAutoMode = true; Queue _actionList = new Queue(); MoveItem _currentAction; public MFSwapRoutine(JetTM tm, ITransferRobot robot) : base(ModuleName.TMRobot) { _JetTM = tm; _robot = robot; Name = "Swap"; } public RState Start(params object[] objs) { if (!_robot.IsHomed) { LOG.Write(eEvent.ERR_TM, Module, $"TM Robot 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)); } 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_TM, 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_TM, Module, $"Invalid Loadlock: {_targetModule}, maybe not installed"); return RState.Failed; } Reset(); _swapTimeout = SC.GetValue($"TM.SwapTimeout") * 1000; _autoVentOptInWafer = SC.GetValue("TM.LLAutoVentInWaferOpt"); _autoVentOptOutWafer = SC.GetValue("TM.LLAutoVentOutWaferOpt"); _sequencePattern = Singleton.Instance.LLInOutPath; _bAutoMode = Singleton.Instance.IsAutoMode; return Runner.Start(Module, $"Swap with {_targetModule}"); } public RState Monitor() { Runner.Wait(SwapStep.WaitModuleReady, () => _llModule.IsIdle, _delay_60s) .RunIf(SwapStep.PreRotation, _JetTM.PreRotateModules.ContainsKey(_targetModule), RotateArm, WaitRotateDone) .Run(SwapStep.ModulePrepare, ModulePrepare, IsModulePrepareReady) .Run(SwapStep.OpenSlitDoor, OpenSlitDoor, IsSlitDoorOpen) .LoopStart(SwapStep.MoveWafer, loopName(), _actionList.Count, MoveWafer) .LoopEnd(SwapStep.WaitMaferMoved, NullFun, WaitWaferMoved) .Run(SwapStep.CloseSlitDoor, CloseSlitDoor, IsSlitDoorClosed) .End(SwapStep.NotifyDone, NotifyLLDone, _delay_50ms); return Runner.Status; } private bool ModulePrepare() { _llModule.PostMsg(LLEntity.MSG.Prepare_TM); return true; } private string loopName() { return "LoadLock Swap" ; } private bool IsModulePrepareReady() { return _llModule.Status == LLEntity.LLStatus.Ready_For_TM; } private bool OpenSlitDoor() { return _JetTM.TurnMFSlitDoor(_targetModule, true, out _); } private bool CloseSlitDoor() { return _JetTM.TurnMFSlitDoor(_targetModule, false, out _); } private bool IsSlitDoorOpen() { if (_targetModule == ModuleName.LLA) return _JetTM.IsLLASlitDoorOpen; else return _JetTM.IsLLBSlitDoorOpen; } private bool IsSlitDoorClosed() { if (_targetModule == ModuleName.LLA) return _JetTM.IsLLASlitDoorClosed; else return _JetTM.IsLLBSlitDoorClosed; } private bool VerifyWaferExistence(MoveItem item) { if (WaferManager.Instance.CheckHasWafer(item.DestinationModule, item.DestinationSlot)) { LOG.Write(eEvent.ERR_TM, Module, $"Cannot move wafer as desitination {_currentAction.DestinationModule},{_currentAction.DestinationSlot + 1} already a wafer: "); return false; } if (WaferManager.Instance.CheckNoWafer(_currentAction.SourceModule, _currentAction.SourceSlot)) { LOG.Write(eEvent.ERR_TM, Module, $"Cannot move wafer as source {_currentAction.SourceModule}, {_currentAction.SourceSlot + 1} has no wafer"); return false; } return true; } private bool MoveWafer() { _currentAction = _actionList.Dequeue(); if (!VerifyWaferExistence(_currentAction)) return false; var wafer = WaferManager.Instance.GetWafer(_currentAction.SourceModule, _currentAction.SourceSlot); LOG.Write(eEvent.INFO_TM_ROBOT, ModuleName.TMRobot, $"{wafer.WaferOrigin} will be move from {_currentAction.SourceModule} {_currentAction.SourceSlot + 1} to {_currentAction.DestinationModule} {_currentAction.DestinationSlot + 1}"); if (ModuleHelper.IsLoadLock(_currentAction.SourceModule) && ModuleHelper.IsTMRobot(_currentAction.DestinationModule)) { return _robot.Pick(_currentAction.SourceModule, _currentAction.SourceSlot, (Hand)_currentAction.DestinationSlot); } else if(ModuleHelper.IsTMRobot(_currentAction.SourceModule) && ModuleHelper.IsLoadLock(_currentAction.DestinationModule)) { return _robot.Place(_currentAction.DestinationModule, _currentAction.DestinationSlot, (Hand)_currentAction.SourceSlot); } else { LOG.Write(eEvent.ERR_TM_ROBOT, ModuleName.TMRobot, $"Invalid move parameter, source:{_currentAction.SourceModule},{_currentAction.SourceSlot}, destination: {_currentAction.DestinationModule}, {_currentAction.DestinationSlot}"); return false; } } private bool WaitWaferMoved() { if (_robot.Status == RState.Running) { return false; } else if (_robot.Status == RState.End) { WaferManager.Instance.WaferMoved(_currentAction.SourceModule, _currentAction.SourceSlot, _currentAction.DestinationModule, _currentAction.DestinationSlot); return true; } else { Runner.Stop($"TM Robot moving wafer failed, {_robot.Status}"); return true; } } private bool RotateArm() { ModuleName preModule = _targetModule; Hand rotateHand = Hand.Blade1; if (ModuleHelper.IsLoadLock(_actionList.Peek().DestinationModule) && ModuleHelper.IsTMRobot(_actionList.Peek().SourceModule)) { rotateHand = (Hand)_actionList.Peek().SourceSlot; preModule = _JetTM.PreRotateModules[_targetModule]; } else { rotateHand = (Hand)_actionList.Peek().DestinationSlot; } _llModule.PostMsg(LLEntity.MSG.Prepare_TM); // Notify Loadlock to Serv pressure in advance for throughput enhancement return _robot.Goto(preModule, 0, rotateHand); } private bool WaitRotateDone() { if (_robot.Status == RState.Running) { return false; } else if (_robot.Status == RState.End) { return true; } else { Runner.Stop($"TM Robot Rotate Arm failed, {_robot.Status}"); return true; } } private bool NotifyLLDone() { bool bAutoVent = false; var waferStatus = _llModule.GetWaferProcessStatus(); if(_bAutoMode) { if (((_sequencePattern == SequenceLLInOutPath.AInBOut && _targetModule == ModuleName.LLA) || (_sequencePattern == SequenceLLInOutPath.BInAOut && _targetModule == ModuleName.LLB)) && waferStatus.unprocessed <= _autoVentOptInWafer) { bAutoVent = true; } else if (((_sequencePattern == SequenceLLInOutPath.AInBOut && _targetModule == ModuleName.LLB) || (_sequencePattern == SequenceLLInOutPath.BInAOut && _targetModule == ModuleName.LLA)) && waferStatus.processed >= _autoVentOptOutWafer) { bAutoVent = true; } else if(_sequencePattern == SequenceLLInOutPath.DInDOut && waferStatus.processed >= _autoVentOptOutWafer && waferStatus.unprocessed <= _autoVentOptInWafer) { bAutoVent = true; } } LOG.Write(eEvent.INFO_TM, Module, $"NotifyLLDone() => {_targetModule}, Sequence Pattern{_sequencePattern}, unprocessed wafer:{waferStatus.unprocessed}, processed wafer: {waferStatus.processed},bAutoVent = {bAutoVent}, Config Option:{_autoVentOptInWafer},{_autoVentOptOutWafer}"); _llModule.PostMsg(bAutoVent ? LLEntity.MSG.AutoVent : LLEntity.MSG.TM_Exchange_Ready); return true; } public void Abort() { _robot.Halt(); } } }