using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; using Aitex.Core.RT.Log; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using Aitex.Sorter.Common; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.Schedulers; using MECF.Framework.Common.SubstrateTrackings; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Documents; using Venus_Core; using Venus_RT.Devices; using Venus_RT.Devices.TM; using Venus_RT.Modules.PMs; namespace Venus_RT.Modules.TM.VenusEntity { public class SEMFPMSwapRoutine : ModuleRoutineBase, IRoutine { private enum SwapStep { WaitPMReady, OpenMFSlitDoor, WaitforControlPressure, PickDelay, PreRotation, PickPrepare, PickExtend, DropDownWafer, PickDelay1, PickRetract, PlacePrepare, PlaceDelay, PlaceExtend, LiftUpWafer, PlaceDelay1, PlaceRetract, NotifyDone, CloseMFSlitDoor, EndDone, EndDelay } private readonly TMBase _TM; private readonly ITransferRobot _robot; private int _swapingTimeout = 120 * 1000; private int _placeDelayTime = 0; private int _pickDelayTime = 0; private ModuleName _targetModule; private PMEntity _pmModule; private int _targetSlot; private Hand _pickHand; private Hand _placeHand; private JetPMBase _chamber; private bool NeedControlPressure; private int _controlPressureSetPoint = 90; private int _controlFlowSetPoint = 90; public SEMFPMSwapRoutine(TMBase tm, ITransferRobot robot, ModuleName module) : base(module) { _TM = tm; _robot = robot; Name = "swap for pm"; } 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; } var swapItem = (Queue)objs[0]; _targetModule = swapItem.Peek().SourceModule; _targetSlot = swapItem.Peek().SourceSlot; _pickHand = swapItem.Peek().RobotHand; _placeHand = _pickHand == Hand.Blade2 ? Hand.Blade1 : Hand.Blade2; if (ModuleHelper.IsPm(_targetModule) && ModuleHelper.IsInstalled(_targetModule)) { _pmModule = Singleton.Instance.GetPM(_targetModule); } else { LOG.Write(eEvent.ERR_TM, Module, $"Invalid target module : {_targetModule} for swap action"); return RState.Failed; } if (WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, (int)_placeHand)) { LOG.Write(eEvent.ERR_TM, Module, $"Cannot Swap Wafer as TM Robot Arm: {_placeHand} has no wafer"); return RState.Failed; } if (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, (int)_pickHand)) { LOG.Write(eEvent.ERR_TM, Module, $"Cannot Swap Wafer as TM Robot Arm: {_pickHand} has a wafer"); return RState.Failed; } if (WaferManager.Instance.CheckNoWafer(_targetModule, _targetSlot)) { LOG.Write(eEvent.ERR_TM, Module, $"Cannot Swap Wafer as {_targetModule} Slot {_targetSlot + 1} has no wafer"); return RState.Failed; } Reset(); _swapingTimeout = SC.GetValue($"{Module}.SwapTimeout") * 1000; _pickDelayTime = SC.GetValue($"{_targetModule}.PickDelayTime"); _placeDelayTime = SC.GetValue($"{_targetModule}.PlaceDelayTime"); if (Singleton.Instance.GetPM(_targetModule).IsOnline) { NeedControlPressure = true; } else { NeedControlPressure = false; } return Runner.Start(Module, $"Swap with {_targetModule}"); } public RState Monitor() { Runner.Wait(SwapStep.WaitPMReady, PMPrepare, _delay_60s) .Run(SwapStep.OpenMFSlitDoor, OpenSlitDoor, CheckSlitDoorOpen) .Run(SwapStep.PickPrepare, PickPrepare, IsModuleReadyForPick) .Delay(SwapStep.PickDelay, _placeDelayTime) .Run(SwapStep.PickExtend, PickExtend, WaitRobotExtendDone) .Run(SwapStep.DropDownWafer, NotifyPMPickWafer, WaitPMWaferDropDown) .Delay(SwapStep.PickDelay1, _pickDelayTime) .Run(SwapStep.PickRetract, PickRetract, WaitRobotRetractDone) .Run(SwapStep.PlacePrepare, PlacePrepare, IsModuleReadyForPlace) .Delay(SwapStep.PlaceDelay, _pickDelayTime) .Run(SwapStep.PlaceExtend, PlaceExtend, WaitRobotExtendDone) .Run(SwapStep.LiftUpWafer, NotifyLiftUpWafer, WaitPMWaferLiftUp) .Delay(SwapStep.PlaceDelay1, _placeDelayTime) .Run(SwapStep.PlaceRetract, PlaceRetract, WaitRobotRetractDone) .Run(SwapStep.CloseMFSlitDoor, CheckDoorClose, WaitPMDoorClose, 5000) .Run(SwapStep.NotifyDone, NotifyPMDone, _delay_50ms) .Delay(SwapStep.EndDelay, _delay_50ms) .End(SwapStep.EndDone, NullFun, _delay_50ms); return Runner.Status; } private bool PMPrepare() { return IsPressureReady(_targetModule)&& _pmModule.IsIdle; } private bool IsPressureReady(ModuleName _targetModule) { if (Singleton.Instance.GetPM(_targetModule).IsOnline) { double PMPressure = _pmModule.ChamberPressure; double ControlPressure = SC.GetValue($"{_targetModule}.ControlPressureSetPoint"); double range = SC.GetValue($"{_targetModule}.ControlPressureOffset"); if ((PMPressure >= (ControlPressure - range)) && (PMPressure <= (ControlPressure + range))) { return true; } else return false; } else return true; } private bool OpenSlitDoor() { return _TM.TurnSlitDoor(_targetModule, true); } private bool CheckSlitDoorOpen() { return _TM.CheckSlitValveOpen(_targetModule); } private bool PickPrepare() { _pmModule.PostMsg(PMEntity.MSG.PreparePick); //_TM.TurnSlitDoor(_targetModule, true); return true; } private bool PlacePrepare() { _pmModule.PostMsg(PMEntity.MSG.PreparePlace); //_TM.TurnSlitDoor(_targetModule, true); return true; } private bool IsModuleReadyForPick() { return _pmModule.Status == PMEntity.PMStatus.Ready_For_Pick && _pmModule.IsSlitDoorOpen; } private bool PickExtend() { return _robot.PickExtend(_targetModule, _targetSlot, _pickHand); } private bool PickRetract() { return _robot.PickRetract(_targetModule, _targetSlot, _pickHand); } private bool IsModuleReadyForPlace() { return _pmModule.Status == PMEntity.PMStatus.Ready_For_Place && _pmModule.IsSlitDoorOpen; } private bool PlaceExtend() { return _robot.PlaceExtend(_targetModule, _targetSlot, _placeHand); } private bool PlaceRetract() { return _robot.PlaceRetract(_targetModule, _targetSlot, _placeHand); } private bool WaitRobotExtendDone() { if (_robot.Status == RState.Running) { return false; } else if (_robot.Status == RState.End) { return true; } else { Runner.Stop($"TM Robot Place Extend failed, {_robot.Status}"); Singleton.Instance.GetPM(_targetModule).PostMsg(PMEntity.MSG.Error); return true; } } //private bool RotateArm() //{ // _pmModule.PostMsg(PMEntity.MSG.PreparePick); // Notify PM to Serv pressure in advance for throughput enhancement // return _robot.Goto(_JetTM.PreRotateModules[_targetModule], 0, _placeHand); //} //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 NotifyPMPickWafer() { _pmModule.PostMsg(PMEntity.MSG.DropDownWafer); return true; } private bool WaitPMWaferDropDown() { if (_pmModule.Status == PMEntity.PMStatus.Exchange_Ready) { WaferManager.Instance.WaferMoved(_targetModule, _targetSlot, ModuleName.TMRobot, (int)_pickHand); return true; } return false; } private bool WaitRobotRetractDone() { if (_robot.Status == RState.Running) { return false; } else if (_robot.Status == RState.End) { return true; } else { Runner.Stop($"TM Robot Swap Retract failed, {_robot.Status}"); Singleton.Instance.GetPM(_targetModule).PostMsg(PMEntity.MSG.Error); return true; } } private bool NotifyLiftUpWafer() { _pmModule.PostMsg(PMEntity.MSG.LiftUpWafer); return true; } private bool WaitPMWaferLiftUp() { if (_pmModule.Status == PMEntity.PMStatus.Exchange_Ready) { WaferManager.Instance.WaferMoved(ModuleName.TMRobot, (int)_placeHand, _targetModule, _targetSlot); return true; } return false; } private bool NotifyPMDone() { _pmModule.PostMsg(PMEntity.MSG.PlaceReady); //_TM.TurnSlitDoor(_targetModule, false); return true; } private bool CheckDoorClose() { LOG.Write(eEvent.WARN_TM, Module, $"PMSwap Close Door Again"); return _TM.TurnSlitDoor(_targetModule, false); } private bool WaitPMDoorClose() { if (_TM.CheckSlitValveClose(_targetModule)) { LOG.Write(eEvent.WARN_TM, Module, $"PMSwap Check Door Close"); return true; } else { if (DEVICE.GetDevice($"{Module}.{_targetModule}SlitDoor").SetPoint != (int)CylinderState.Close) { LOG.Write(eEvent.WARN_TM, Module, $"PMSwap {_targetModule}SlitDoor set close again"); DEVICE.GetDevice($"{Module}.{_targetModule}SlitDoor").SetCylinder(false, out string reason); } //LOG.Write(eEvent.WARN_TM, Module, $"PMSwap Check not Close Door"); return false; } } public void Abort() { _robot.Halt(); } } }