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; using System.Linq; using MECF.Framework.Common.DBCore; namespace Venus_RT.Modules.TM { class MFSwapRoutine : ModuleRoutineBase, IRoutine { private enum SwapStep { WaitModuleReady, PreRotation, ModulePrepare, WaitPressreStable, OpenSlitDoor, MoveWafer, WaitMaferMoved, QueryAwc, CheckAwc, MoveEnd, CloseSlitDoor, NotifyDone, } private readonly JetTM _JetTM; private readonly ITransferRobot _robot; private int _moveTimeout = 30 * 1000; private ModuleName _targetModule; private LLEntity _llModule; //private int _autoVentOptInWafer = 0; //private int _autoVentOptOutWafer = 4; private SequenceLLInOutPath _sequencePattern = SequenceLLInOutPath.DInDOut; //private bool _bAutoMode = true; private bool _isAWC; Queue _actionList = new Queue(); MoveItem _currentAction; double maxPressureDifference; List _currentactionList=new List(); private DateTime _starttime; int awcAlarmRange; private bool _pickQueryAWC; private bool _placeQueryAWC; 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)); } 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_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(); //_autoVentOptInWafer = SC.GetValue("TM.LLAutoVentInWaferOpt"); //_autoVentOptOutWafer = SC.GetValue("TM.LLAutoVentOutWaferOpt"); _sequencePattern = Singleton.Instance.LLInOutPath; //_bAutoMode = Singleton.Instance.IsAutoMode; maxPressureDifference = SC.GetValue("System.TMLLMaxPressureDifference"); _currentactionList = _actionList.ToList(); awcAlarmRange = SC.GetValue($"TM.EnterLLAWCAlarmLimit"); int queryAWCType = SC.GetValue($"TM.QueryAWCOption"); if (queryAWCType == 0) { _pickQueryAWC = false; _placeQueryAWC = false; } else if(queryAWCType == 1) { _pickQueryAWC = true; } else if (queryAWCType == 2) { _placeQueryAWC = true; } else if (queryAWCType == 3) { _pickQueryAWC = true; _placeQueryAWC = true; } return Runner.Start(Module, $"Swap with {_targetModule}"); } public RState Monitor() { Runner.Wait(SwapStep.WaitModuleReady, () => _llModule.IsIdle, _delay_3m) .RunIf(SwapStep.PreRotation, _JetTM.PreRotateModules.ContainsKey(_targetModule), RotateArm, WaitRotateDone, _delay_30s) .Run(SwapStep.ModulePrepare, ModulePrepare, IsModulePrepareReady) .Wait(SwapStep.WaitPressreStable, TMLLPressureIsOK, _delay_60s) .Run(SwapStep.OpenSlitDoor, OpenSlitDoor, IsSlitDoorOpen, _delay_30s) .LoopStart(SwapStep.MoveWafer, loopName(), _actionList.Count, MoveWafer) .LoopRun(SwapStep.WaitMaferMoved, NullFun, WaitWaferMoved) .LoopRunIf(SwapStep.QueryAwc, _isAWC, QueryAwc, WaitQueryDoneAndRecord,_delay_30s) .LoopRunIf(SwapStep.CheckAwc, _isAWC, CheckAwc) .LoopEnd(SwapStep.MoveEnd, NullFun) .Run(SwapStep.CloseSlitDoor, CloseSlitDoor, IsSlitDoorClosed, _delay_30s) .End(SwapStep.NotifyDone, NotifyLLDone, _delay_50ms); return Runner.Status; } private bool TMLLPressureIsOK() { if (RouteManager.IsATMMode) { return _JetTM.IsTMATM && _JetTM.IsModuleATM(_targetModule); } else { double llPressure = 0; if (_targetModule == ModuleName.LLA) { llPressure = _JetTM.LLAPressure; } else if (_targetModule == ModuleName.LLB) { llPressure = _JetTM.LLBPressure; } if (Math.Abs((llPressure - _JetTM.ChamberPressure)) < maxPressureDifference - 2) { return true; } else { return false; } } } 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; if (_targetModule == ModuleName.LLA) { if (_JetTM.IsLLASlitDoorOpen) { //_llModule.IsDoorsAllClosed = false; return true; } return false; } else { if (_JetTM.IsLLBSlitDoorOpen) { //_llModule.IsDoorsAllClosed = false; return true; } return false; } } private bool IsSlitDoorClosed() { if (_targetModule == ModuleName.LLA) { if (_JetTM.IsLLASlitDoorClosed) { //_llModule.IsDoorsAllClosed = true; return true; } return false; } else { if (_JetTM.IsLLBSlitDoorClosed) { //_llModule.IsDoorsAllClosed = true; return true; } return false; } //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(); _starttime=DateTime.Now; _isAWC= (_currentAction.TransferType == EnumMoveType.Pick && _pickQueryAWC == true) || (_currentAction.TransferType == EnumMoveType.Place && _placeQueryAWC == true); 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)) { //if (ModuleHelper.IsLoadLock(_targetModule)) //{ // _llModule.PostMsg(LLEntity.MSG.Transfer_TM_SlotInfo, _currentAction.DestinationSlot); //} 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) { if (Runner.StepElapsedMS > _moveTimeout) { WaferManager.Instance.CreateDuplicatedWafer(_currentAction.SourceModule, _currentAction.SourceSlot, _currentAction.DestinationModule, _currentAction.DestinationSlot); Runner.Stop($"TM Robot moving wafer from {_currentAction.SourceModule}.{_currentAction.SourceSlot + 1} to {_currentAction.DestinationModule}.{_currentAction.DestinationSlot + 1} timeout, {_moveTimeout}ms"); return true; } return false; } else if (_robot.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($"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() { _llModule.PostMsg(LLEntity.MSG.TM_Exchange_Ready, _currentactionList.Exists(ac => ModuleHelper.IsLoadLock(ac.DestinationModule))); return true; } private bool QueryAwc() { if (_robot.QueryAwc()) return true; else return false; } private bool WaitQueryDoneAndRecord() { if (_robot.Status == RState.Running) { return false; } else if (_robot.Status == RState.End) { var wafer = WaferManager.Instance.GetWafer(_currentAction.DestinationModule, _currentAction.DestinationSlot); string _origin_module = $"LP{wafer.OriginStation}"; int _origin_slot = wafer.OriginSlot; //查询完毕 插入数据 OffsetDataRecorder.RecordOffsetData( Guid.NewGuid().ToString(), _currentAction.SourceModule, _currentAction.SourceSlot, _currentAction.DestinationModule, _currentAction.DestinationSlot, _origin_module, _origin_slot, _currentAction.RobotHand, RobotArmPan.None, _robot.Offset_X, _robot.Offset_Y, _robot.Offset_D, _starttime, DateTime.Now); return true; } else { Runner.Stop($"TM Robot Query Awc failed, {_robot.Status}"); return true; } } private bool CheckAwc() { if (Math.Abs(_robot.Offset_X) > awcAlarmRange) { Stop($"Wafer from {_currentAction.SourceModule} {_currentAction.SourceSlot} to {_currentAction.DestinationModule} {_currentAction.DestinationSlot} {_currentAction.TransferType},Check AWC 失败, 当前 X AWC [{_robot.Offset_X}]um, 高于Alarm最大值: [{awcAlarmRange}]um"); return false; } if (Math.Abs(_robot.Offset_Y) > awcAlarmRange) { Stop($"Wafer from {_currentAction.SourceModule} {_currentAction.SourceSlot} to {_currentAction.DestinationModule} {_currentAction.DestinationSlot} {_currentAction.TransferType},Check AWC 失败, 当前 Y AWC [{_robot.Offset_Y}]um, 高于Alarm最大值: [{awcAlarmRange}]um"); return false; } return true; } public void Abort() { //_robot.Halt(); } } }