Browse Source

Pre/Post Lot Clean functionality.

sangwq 7 months ago
parent
commit
a5826caf14

+ 2 - 2
Venus/Framework/Common/Jobs/SequenceInfo.cs

@@ -94,7 +94,7 @@ namespace MECF.Framework.Common.Jobs
             if (!ModuleHelper.IsPm(pm))
                 return string.Empty;
 
-            string attr = $"{pm}PreClean";
+            string attr = $"{pm}PreLotClean";
             foreach (var step in Steps)
             {
                 if (step.StepModules.Contains(pm) && step.StepParameter.ContainsKey(attr))
@@ -126,7 +126,7 @@ namespace MECF.Framework.Common.Jobs
             if (!ModuleHelper.IsPm(pm))
                 return string.Empty;
 
-            string attr = $"{pm}PostClean";
+            string attr = $"{pm}PostLotClean";
             foreach (var step in Steps)
             {
                 if (step.StepModules.Contains(pm) && step.StepParameter.ContainsKey(attr))

+ 224 - 100
Venus/Venus_RT/Modules/SystemDispatcher.cs

@@ -47,6 +47,7 @@ namespace Venus_RT.Modules
         public string               wtwCleanRecipe      { get; }
         public float                temperature         { get; }
         public Guid                 waferId             { get; }
+        public Guid                 lotId               { get; }
         public int                  elapseTime          { get { return (int)(DateTime.Now - _scheduledTime).TotalSeconds; } }
         public int                  llDelayTime         { get; }
         public RState               pressureStatus      { get; private set; }
@@ -89,7 +90,7 @@ namespace Venus_RT.Modules
 
         private DateTime _scheduledTime;
 
-        public WaferTask(ModuleName source, int srcSlot, ModuleName dest, int dstSlot, float temp, Guid waferID, string recipeName, string wtwClean, SequenceLLInOutPath inOutPath, int LLDelay, bool needAlign)
+        public WaferTask(ModuleName source, int srcSlot, ModuleName dest, int dstSlot, float temp, Guid waferID, Guid lotID, string recipeName, string wtwClean, SequenceLLInOutPath inOutPath, int LLDelay, bool needAlign)
         {
             sourceMod = currentMod = nextMod = routedMod = source;
             sourceSlot = currentSlot = nextSlot = routedSlot = srcSlot;
@@ -99,6 +100,7 @@ namespace Venus_RT.Modules
             hand = Hand.None;
             temperature = temp;
             waferId = waferID;
+            lotId = lotID;
             processRecipe = recipeName;
             wtwCleanRecipe = wtwClean;
             llInOutPath = inOutPath;
@@ -349,6 +351,8 @@ namespace Venus_RT.Modules
             }
         }
 
+        public bool HasPendingCleanTask => _pendingCleanTask.Count > 0;
+
         private WaferTask _wafer;
         private SchedulerPM _pmScheduler => Scheduler as SchedulerPM;
 
@@ -556,7 +560,7 @@ namespace Venus_RT.Modules
 
         public override void WaferLeaved(WaferTask wafer, int slot)
         {
-            if(!string.IsNullOrWhiteSpace(_wafer.wtwCleanRecipe.Trim()))
+            if(!string.IsNullOrWhiteSpace(_wafer.wtwCleanRecipe.Trim()) && (_pendingCleanTask.Count == 0 || _pendingCleanTask.First() != CleanType.PostJobClean))
             {
                 Status = ModuleStatus.WaitWTWClean;
                 _wtwCleanRecipe = _wafer.wtwCleanRecipe;
@@ -581,6 +585,7 @@ namespace Venus_RT.Modules
         {
             _preJobCleanRecipe = preJobClean;
             _pendingCleanTask.Enqueue(CleanType.PreJobClean);
+            //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, Module, $"Invoke preClean {preJobClean}");
         }
 
         public bool IsPreJobCleanDone()
@@ -592,6 +597,7 @@ namespace Venus_RT.Modules
         {
             _postJobCleanRecipe = postJobClean;
             _pendingCleanTask.Enqueue(CleanType.PostJobClean);
+            //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, Module, $"Invoke postClean {postJobClean}");
         }
 
         public bool IsPostJobCleanDone()
@@ -839,6 +845,28 @@ namespace Venus_RT.Modules
                 
             return  RState.Running;
         }
+
+        public int Distance
+        {
+            get
+            {
+                switch(Status)
+                {
+                    case ModuleStatus.Idle:
+                        return Scheduler.IsVac ? 1 : Scheduler.IsAtm ? 7 : 5;
+                    case ModuleStatus.StartPump:
+                    case ModuleStatus.Pumping:
+                        return 3;
+                    case ModuleStatus.StartCooling:
+                    case ModuleStatus.Cooling:
+                    case ModuleStatus.StartVent:
+                    case ModuleStatus.Venting:
+                        return 9;
+                    default:
+                        return 5;
+                }
+            }
+        }
     }
 
     enum LLSlotInOutOpt
@@ -888,7 +916,9 @@ namespace Venus_RT.Modules
         private Dictionary<ModuleName, int> _lpCycleCount = new Dictionary<ModuleName, int> { { ModuleName.LP1, 0 }, { ModuleName.LP2, 0 }, { ModuleName.LP3, 0 } };
         private Dictionary<ModuleName, int> _lpCycleSP = new Dictionary<ModuleName, int> { { ModuleName.LP1, 1 }, { ModuleName.LP2, 1 }, { ModuleName.LP3, 1 } };
         private Dictionary<ModuleName, float> _lpThroughput = new Dictionary<ModuleName, float>{ {ModuleName.LP1, 0}, { ModuleName.LP2, 0}, { ModuleName.LP3, 0} };
-        private Dictionary<ModuleName, Stopwatch> _lpCycleWatch = new Dictionary<ModuleName, Stopwatch> { { ModuleName.LP1, new Stopwatch() }, { ModuleName.LP2, new Stopwatch()}, { ModuleName.LP3, new Stopwatch()} }; 
+        private Dictionary<ModuleName, Stopwatch> _lpCycleWatch = new Dictionary<ModuleName, Stopwatch> { { ModuleName.LP1, new Stopwatch() }, { ModuleName.LP2, new Stopwatch()}, { ModuleName.LP3, new Stopwatch()} };
+        private Dictionary<ModuleName, List<Guid>> _preLotCleanMarks = new Dictionary<ModuleName, List<Guid>>();
+        private Dictionary<ModuleName, List<Guid>> _postLotCleanMarks = new Dictionary<ModuleName, List<Guid>>();
 
         private Stopwatch _cycleWatch = new Stopwatch();
 
@@ -1482,6 +1512,16 @@ namespace Venus_RT.Modules
                 _loadportControlJobDic[key] = null;
             }
 
+            foreach(var preLot in _preLotCleanMarks)
+            {
+                preLot.Value.Clear();
+            }
+
+            foreach(var postLot in _postLotCleanMarks)
+            {
+                postLot.Value.Clear();
+            }
+
             _lstWaferTasks.Clear();
             _qeWaitInWafers.Clear();
             _tmSchdActions.Clear();
@@ -1625,6 +1665,8 @@ namespace Venus_RT.Modules
                     if(ModuleHelper.IsPm(module))
                     {
                         _dictModuleTask[module] = new PMTask(module);
+                        _preLotCleanMarks[module] = new List<Guid>();
+                        _postLotCleanMarks[module] = new List<Guid>();
                     }
                     else if (ModuleHelper.IsLoadLock(module))
                     {
@@ -1665,6 +1707,7 @@ namespace Venus_RT.Modules
             UpdateControlJobStatus();
             UpdateLLInOutPathProperty();
             PrepareLLPressure();
+            RunLotCleanTasks();
 
             CreateNewWaferTask();
             _lstWaferTasks.RemoveAll(item => ModuleHelper.IsLoadPort(item.destMod) && ModuleHelper.IsLoadPort(item.currentMod) && item.pressureStatus == RState.End);
@@ -1855,9 +1898,7 @@ namespace Venus_RT.Modules
             {
                 if (_qePollingJobs.First() == cj)
                 {
-                    if ( !cj.LotWafers.Exists(wafer => !wafer.IsEmpty && wafer.NextSequenceStep == 0) && 
-                            ( (!IsCtrlJobNeedPostClean(cj) && !_lstWaferTasks.Exists(wt => !string.IsNullOrEmpty(wt.wtwCleanRecipe) && (_qePollingJobs.Count <= 1 || !IsCtrlJobNeedPreClean(_qePollingJobs.ElementAt(1)))) ) || 
-                                (IsAllProcessJobComplete(cj) && IsPostJobCleanDone(cj))))
+                    if ( !cj.LotWafers.Exists(wafer => !wafer.IsEmpty && wafer.NextSequenceStep == 0) && (IsAllJobWaferProcessedOrProcessing(cj) || IsAllProcessJobComplete(cj)))
                     {
                         _qePollingJobs.Dequeue();
                         _qePollingJobs.Enqueue(cj);
@@ -1865,69 +1906,16 @@ namespace Venus_RT.Modules
                 }
             }
 
-
             switch (cj.JetState)
             {
                 case EnumJetCtrlJobState.Quequed:
                     {
-                        if(IsCtrlJobNeedPreClean(cj))
-                        {
-                            cj.JetState = EnumJetCtrlJobState.PreJobClean;
-
-                            var PMs = GetWaitPreCleanPMsByCtrlJob(cj);
-                            foreach (var pm in PMs)
-                            {
-                                var pmTask = _dictModuleTask[pm] as PMTask;
-                                if (pmTask != null && pmTask.Scheduler.IsOnline)
-                                {
-                                    pmTask.InvokePreJobClean(cj.PreJobClean);
-                                }
-                            }
-                        }
-                        else
-                        {
-                            ActiveControlJob(cj);
-                        }
-                    }
-                    break;
-                case EnumJetCtrlJobState.PreJobClean:
-                    {
-                        if (IsPreJobCleanDone(cj))
-                        {
-                            ActiveControlJob(cj);
-                        }
+                        ActiveControlJob(cj);
                     }
                     break;
                 case EnumJetCtrlJobState.Processing:
                     {
-                        if (IsCtrlJobNeedPostClean(cj))
-                        {
-                            if (IsAllJobWaferProcessedOrProcessing(cj))
-                            {
-                                cj.JetState = EnumJetCtrlJobState.PostJobClean;
-                                var PMs = GetWaitPreCleanPMsByCtrlJob(cj);
-                                foreach (var pm in PMs)
-                                {
-                                    var pmTask = _dictModuleTask[pm] as PMTask;
-                                    if (pmTask != null && pmTask.Scheduler.IsOnline)
-                                    {
-                                        pmTask.InvokePostJobClean(cj.PostJobClean);
-                                    }
-                                }
-                            }
-                        }
-                        else
-                        {
-                            if (IsAllProcessJobComplete(cj))
-                            {
-                                cj.JetState = EnumJetCtrlJobState.Completed;
-                            }
-                        }
-                    }
-                    break;
-                case EnumJetCtrlJobState.PostJobClean:
-                    {
-                        if (IsPostJobCleanDone(cj))
+                        if (IsAllProcessJobComplete(cj))
                         {
                             cj.JetState = EnumJetCtrlJobState.Completed;
                         }
@@ -1988,6 +1976,18 @@ namespace Venus_RT.Modules
                     {
                         if(pj.ControlJobName == cj.Name)
                         {
+                            foreach(var marks in _preLotCleanMarks)
+                            {
+                                if (marks.Value.Contains(pj.InnerId))
+                                    marks.Value.Remove(pj.InnerId);
+                            }
+
+                            foreach(var marks in _postLotCleanMarks)
+                            {
+                                if (marks.Value.Contains(pj.InnerId))
+                                    marks.Value.Remove(pj.InnerId);
+                            }
+
                             pj.SetState(EnumProcessJobState.Queued);
                             pj.InnerId = Guid.NewGuid();
                             foreach (var pjSlotWafer in pj.SlotWafers)
@@ -2103,14 +2103,6 @@ namespace Venus_RT.Modules
                 cj.JetState == EnumJetCtrlJobState.PostJobClean;
         }
 
-        private bool IsCtrlJobEndingState(ControlJobInfo cj)
-        {
-            return cj.JetState == EnumJetCtrlJobState.PostJobClean ||
-                (cj.JetState == EnumJetCtrlJobState.Processing
-                && IsAllJobWaferProcessedOrProcessing(cj)
-                && !IsCtrlJobNeedPostClean(cj));
-        }
-
         private bool IsCtrlJobNeedPreClean(ControlJobInfo cj)
         {
             return !string.IsNullOrWhiteSpace(cj.PreJobClean);
@@ -2359,6 +2351,7 @@ namespace Venus_RT.Modules
                                             0,
                                             temperature,
                                             wafer.InnerId,
+                                            wafer.ProcessJob.InnerId,
                                             recipeName,
                                             wafer.ProcessJob.Sequence.GetWTWCleanRecipe(pm),
                                             wafer.ProcessJob.Sequence.LLInOutPath, 
@@ -2371,7 +2364,7 @@ namespace Venus_RT.Modules
             _lstWaferTasks.Add(waferTask);
             _qeWaitInWafers.Enqueue(wafer.InnerId);
 
-            LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, waferTask.sourceMod, $"Routing wafer: {waferTask.sourceMod}.{waferTask.sourceSlot + 1} to {pm}");
+            //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, waferTask.sourceMod, $"Routing wafer: {waferTask.sourceMod}.{waferTask.sourceSlot + 1} to {pm}");
         }
 
         private void ReDispatchBlockingWafers()
@@ -2699,7 +2692,7 @@ namespace Venus_RT.Modules
                 {
                     if (ExchangeWaferWithLL(outLL))
                     {
-                        LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, outLL, $"{outLL} will be ready in {outLLModule.TimeToReady}");
+                        //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, outLL, $"{outLL} will be ready in {outLLModule.TimeToReady}");
                         return;
                     }
                 }
@@ -2711,7 +2704,7 @@ namespace Venus_RT.Modules
                     {
                         if (ForwardATMWafers(inLL))
                         {
-                            LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, inLL, $"{inLL} will be ready in {inLLModule.TimeToReady}");
+                            ////LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, inLL, $"{inLL} will be ready in {inLLModule.TimeToReady}");
                             return;
                         }
                     }
@@ -2722,7 +2715,7 @@ namespace Venus_RT.Modules
                     {
                         if (ForwardATMWafers(inLL))
                         {
-                            LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, inLL, $"{inLL} will be ready in {inLLModule.TimeToReady}");
+                            //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, inLL, $"{inLL} will be ready in {inLLModule.TimeToReady}");
                             return;
                         }
                     }
@@ -2733,7 +2726,7 @@ namespace Venus_RT.Modules
                 {
                     if (ExchangeWaferWithLL(inLL))
                     {
-                        LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, inLL, $"{inLL} will be ready in {inLLModule.TimeToReady}");
+                        //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, inLL, $"{inLL} will be ready in {inLLModule.TimeToReady}");
                         return;
                     }
                 }
@@ -3370,6 +3363,20 @@ namespace Venus_RT.Modules
             }
         }
 
+        private bool HasPendingCleanTask()
+        {
+            foreach( var mod in _dictModuleTask)
+            {
+                if(ModuleHelper.IsPm(mod.Key) && mod.Value.Scheduler.IsOnline)
+                {
+                    if ((mod.Value as PMTask).HasPendingCleanTask)
+                        return true;
+                }
+            }
+
+            return false;
+        }
+
         private void Routing2SlotVacSystem()
         {
             var robotWafers = _lstWaferTasks.Where(wafer => ModuleHelper.IsTMRobot(wafer.currentMod)).OrderBy(wafer => TimeForNextModuleReady(wafer)).ToList();
@@ -3388,7 +3395,7 @@ namespace Venus_RT.Modules
                     #region special routing pattern
                     if (_specialRoutingPattern != SpecialRoutingPattern.Disable)
                     {
-                        if(_specialRoutingPattern == SpecialRoutingPattern.LongTimeRecipe && freeHands.Count == 2)
+                        if(_specialRoutingPattern == SpecialRoutingPattern.LongTimeRecipe && freeHands.Count == 2 && !HasPendingCleanTask())
                         {
                              if(_dictModuleTask.Where(mod => ModuleHelper.IsPm(mod.Key) && !mod.Value.HasWafer && mod.Value.Scheduler.IsOnline).Count() == 0 && inLLWaferStatus.inSlot.Count > 0)
                             {
@@ -3396,6 +3403,11 @@ namespace Venus_RT.Modules
                                 if(readyOutPMs.Count > 0 && inLLModule.ReayForTMInTime(5) && _lstWaferTasks.Exists(wt => wt.currentMod == inLL && readyOutPMs.Exists(kv => kv.Key == wt.destMod)))
                                 {
                                     var llWafer = _lstWaferTasks.Find(wt => wt.currentMod == inLL && wt.destMod == readyOutPMs.First().Key);
+                                    if(llWafer == null)
+                                    {
+                                        llWafer = _lstWaferTasks.Find(wt => wt.currentMod == inLL && readyOutPMs.Exists( pm => pm.Key == wt.destMod && pm.Value.TimeToReady < 5));
+                                    }
+
                                     if(llWafer != null)
                                     {
                                         _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(inLL, llWafer.currentSlot, ModuleName.TMRobot, (int)freeHands[0], freeHands[0]) });
@@ -3435,13 +3447,13 @@ namespace Venus_RT.Modules
                                 _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(pm.Key, 0, ModuleName.TMRobot, (int)freeHands[pickCount], freeHands[pickCount]) });
                                 placeActions.Add(new MoveItem(ModuleName.TMRobot, (int)freeHands[pickCount], outLL, outLLWaferStatus.emptySlot[pickCount], freeHands[pickCount]));
                                 pickCount++;
-                                LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, pm.Key, $"{pm.Key} will be ready in {pm.Value.TimeToReady} seconds");
+                                //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, pm.Key, $"{pm.Key} will be ready in {pm.Value.TimeToReady} seconds");
                             }
                         }
 
                         if (pickCount > 0)
                         {
-                            LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, outLL, $"{outLL} will be ready in {outLLModule.TimeToReady} seconds");
+                            //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, outLL, $"{outLL} will be ready in {outLLModule.TimeToReady} seconds");
                             _tmSchdActions.Enqueue(placeActions);
                             return;
                         }
@@ -3462,7 +3474,7 @@ namespace Venus_RT.Modules
 
                         if(pickActions.Count > 0)
                         {
-                            LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, inLL, $"{inLL} will be ready in {inLLModule.TimeToReady} seconds");
+                            //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, inLL, $"{inLL} will be ready in {inLLModule.TimeToReady} seconds");
                             _tmSchdActions.Enqueue(pickActions);
                             return;
                         }
@@ -3473,7 +3485,7 @@ namespace Venus_RT.Modules
                     #region special routing pattern
                     if (_specialRoutingPattern != SpecialRoutingPattern.Disable)
                     {
-                        if (_specialRoutingPattern == SpecialRoutingPattern.LongTimeRecipe && _tmRobotSingleArmOption == 0)
+                        if (_specialRoutingPattern == SpecialRoutingPattern.LongTimeRecipe && _tmRobotSingleArmOption == 0 && !HasPendingCleanTask())
                         {
                             if(_dictModuleTask.Where(mod => ModuleHelper.IsPm(mod.Key) && !mod.Value.HasWafer && mod.Value.Scheduler.IsOnline).Count() == 0 && ModuleHelper.IsLoadPort(robotWafers[0].destMod))
                             {
@@ -3495,24 +3507,35 @@ namespace Venus_RT.Modules
                         {
                             if (_dictModuleTask[robotWafer.destMod].TimeToReady < 5)
                             {
-                                if (_dictModuleTask[robotWafer.destMod].HasWafer)
+                                var pmWafer = _lstWaferTasks.Find(wt => wt.currentMod == robotWafer.destMod);
+                                if (_dictModuleTask[robotWafer.destMod].HasWafer && pmWafer != null)
                                 {
                                     // PM Swap
                                     if (freeHands.Count > 0)
                                     {
-                                        var pmActions = new List<MoveItem>
+
+                                        if (string.IsNullOrWhiteSpace(pmWafer.wtwCleanRecipe) && !(_dictModuleTask[pmWafer.currentMod] as PMTask).HasPendingCleanTask)
                                         {
-                                            new MoveItem(robotWafer.destMod, 0, ModuleName.TMRobot, (int)freeHands[0], freeHands[0]),
-                                            new MoveItem(ModuleName.TMRobot, robotWafer.currentSlot, robotWafer.destMod, 0, (Hand)robotWafer.currentSlot)
-                                        };
-                                        _tmSchdActions.Enqueue(pmActions);
-                                        LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, robotWafer.destMod, $"{robotWafer.destMod} will be ready in {_dictModuleTask[robotWafer.destMod].TimeToReady} seconds");
-                                        return;
+                                            var pmActions = new List<MoveItem>
+                                            {
+                                                new MoveItem(robotWafer.destMod, 0, ModuleName.TMRobot, (int)freeHands[0], freeHands[0]),
+                                                new MoveItem(ModuleName.TMRobot, robotWafer.currentSlot, robotWafer.destMod, 0, (Hand)robotWafer.currentSlot)
+                                            };
+                                            _tmSchdActions.Enqueue(pmActions);
+                                            //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, robotWafer.destMod, $"{robotWafer.destMod} will be ready in {_dictModuleTask[robotWafer.destMod].TimeToReady} seconds");
+                                            return;
+                                        }
+                                        else
+                                        {
+                                            _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(robotWafer.destMod, 0, ModuleName.TMRobot, (int)freeHands[0], freeHands[0]) });
+                                            return;
+                                        }
+
                                     }
                                 }
                                 else
                                 {
-                                    LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, robotWafer.destMod, $"{robotWafer.destMod} will be ready in {_dictModuleTask[robotWafer.destMod].TimeToReady} seconds");
+                                    //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, robotWafer.destMod, $"{robotWafer.destMod} will be ready in {_dictModuleTask[robotWafer.destMod].TimeToReady} seconds");
                                     _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, robotWafer.currentSlot, robotWafer.destMod, 0, (Hand)robotWafer.currentSlot) });
                                     return;
                                 }
@@ -3525,8 +3548,8 @@ namespace Venus_RT.Modules
                                     var readyOutWafer = _lstWaferTasks.Find(wt => ModuleHelper.IsPm(wt.currentMod) && ModuleHelper.IsLoadPort(wt.destMod));
                                     if (readyOutWafer != null && _dictModuleTask[readyOutWafer.currentMod].TimeToReady < 5)
                                     {
-                                        LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, readyOutWafer.currentMod, $"{readyOutWafer.currentMod} will be ready in {_dictModuleTask[readyOutWafer.currentMod].TimeToReady} seconds");
-                                        LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, outLL, $"{outLL} will be ready in {outLLModule.TimeToReady} seconds");
+                                        //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, readyOutWafer.currentMod, $"{readyOutWafer.currentMod} will be ready in {_dictModuleTask[readyOutWafer.currentMod].TimeToReady} seconds");
+                                        //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, outLL, $"{outLL} will be ready in {outLLModule.TimeToReady} seconds");
                                         _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(readyOutWafer.currentMod, 0, ModuleName.TMRobot, (int)freeHands[0], freeHands[0]) });
                                         _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, (int)freeHands[0], outLL, outLLWaferStatus.emptySlot[0], freeHands[0]) });
                                         return;
@@ -3540,8 +3563,8 @@ namespace Venus_RT.Modules
                                     {
                                         if (!_dictModuleTask[inWafer.destMod].HasWafer && _dictModuleTask[inWafer.destMod].TimeToReady < 10)
                                         {
-                                            LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, inWafer.destMod, $"{inWafer.destMod} will be ready in {_dictModuleTask[inWafer.destMod].TimeToReady} seconds");
-                                            LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, inLL, $"{inLL} will be ready in {inLLModule.TimeToReady} seconds");
+                                            //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, inWafer.destMod, $"{inWafer.destMod} will be ready in {_dictModuleTask[inWafer.destMod].TimeToReady} seconds");
+                                            //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, inLL, $"{inLL} will be ready in {inLLModule.TimeToReady} seconds");
                                             _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(inLL, inWafer.currentSlot, ModuleName.TMRobot, (int)freeHands[0], freeHands[0]) });
                                             _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, (int)freeHands[0], inWafer.destMod, 0, freeHands[0]) });
                                             return;
@@ -3577,14 +3600,14 @@ namespace Venus_RT.Modules
                                         new MoveItem(ModuleName.TMRobot, 1, outLL, 1, Hand.Blade2)
                                     };
 
-                                    LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, outLL, $"{outLL} will be ready in {outLLModule.TimeToReady} seconds");
+                                    //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, outLL, $"{outLL} will be ready in {outLLModule.TimeToReady} seconds");
                                     _tmSchdActions.Enqueue(doublePlace);
                                     return;
                                 }
 
                                 if(outLLWaferStatus.emptySlot.Count > 0)
                                 {
-                                    LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, outLL, $"{outLL} will be ready in {outLLModule.TimeToReady} seconds");
+                                    //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, outLL, $"{outLL} will be ready in {outLLModule.TimeToReady} seconds");
                                     _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, robotWafer.currentSlot, outLL, outLLWaferStatus.emptySlot[0], (Hand)robotWafer.currentSlot) });
                                     return;
                                 }
@@ -3601,8 +3624,8 @@ namespace Venus_RT.Modules
                         var inWafer = _lstWaferTasks.Find(wt => wt.currentMod == inLL && wt.currentSlot == inLLWaferStatus.inSlot.First());
                         if(inWafer != null && !_dictModuleTask[inWafer.destMod].HasWafer && _dictModuleTask[inWafer.destMod].TimeToReady < 20)
                         {
-                            LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, inWafer.destMod, $"{inWafer.destMod} will be ready in {_dictModuleTask[inWafer.destMod].TimeToReady} seconds");
-                            LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, inLL, $"{inLL} will be ready in {inLLModule.TimeToReady} seconds");
+                            //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, inWafer.destMod, $"{inWafer.destMod} will be ready in {_dictModuleTask[inWafer.destMod].TimeToReady} seconds");
+                            //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, inLL, $"{inLL} will be ready in {inLLModule.TimeToReady} seconds");
                             _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(inLL, inLLWaferStatus.inSlot.First(), ModuleName.TMRobot, (int)freeHands[0], freeHands[0])});
                             _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, (int)freeHands[0], inWafer.destMod, 0, freeHands[0]) });
                             return;
@@ -3616,8 +3639,8 @@ namespace Venus_RT.Modules
                         var readyReturnPMs = _dictModuleTask.Where(mod => ModuleHelper.IsPm(mod.Key) && mod.Value.HasWafer && mod.Value.TimeToReady < 5).OrderBy(mod => mod.Value.TimeToReady).ToList();
                         if(readyReturnPMs.Count > 0)
                         {
-                            LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, readyReturnPMs.First().Key, $"{readyReturnPMs.First().Key} will be ready in {readyReturnPMs.First().Value.TimeToReady} seconds");
-                            LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, outLL, $"{outLL} will be ready in {outLLModule.TimeToReady} seconds");
+                            //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, readyReturnPMs.First().Key, $"{readyReturnPMs.First().Key} will be ready in {readyReturnPMs.First().Value.TimeToReady} seconds");
+                            //LOG.Write(eEvent.INFO_TROUGHPUT_ENHANCE_TRACE, outLL, $"{outLL} will be ready in {outLLModule.TimeToReady} seconds");
                             _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(readyReturnPMs.First().Key, 0, ModuleName.TMRobot, (int)freeHands[0], freeHands[0]) });
                             _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, (int)freeHands[0], outLL, outLLWaferStatus.emptySlot.First(), freeHands[0]) });
                             return;
@@ -3658,12 +3681,16 @@ namespace Venus_RT.Modules
                     {
                         var pmActions = new List<MoveItem>();
                         var pmWafer = _lstWaferTasks.Find(wafer => (wafer.movingStatus == RState.End || wafer.movingStatus == RState.Init) && wafer.currentMod == robotWafers[0].destMod && ModuleHelper.IsLoadPort(wafer.destMod));
-                        if (pmWafer != null && string.IsNullOrWhiteSpace(pmWafer.wtwCleanRecipe))
+                        if (pmWafer != null)
                         {
                             int pickSlot = 1 - robotWafers[0].currentSlot;
                             pmWafer.RouteTo(ModuleName.TMRobot, pickSlot);
                             pmActions.Add(new MoveItem(pmWafer.currentMod, 0, ModuleName.TMRobot, pickSlot, (Hand)pickSlot));
-                            pmActions.Add(new MoveItem(ModuleName.TMRobot, robotWafers[0].currentSlot, pmWafer.currentMod, 0, (Hand)robotWafers[0].currentSlot));
+
+                            if (string.IsNullOrWhiteSpace(pmWafer.wtwCleanRecipe) && !(_dictModuleTask[robotWafers[0].destMod] as PMTask).HasPendingCleanTask)
+                            {
+                                pmActions.Add(new MoveItem(ModuleName.TMRobot, robotWafers[0].currentSlot, pmWafer.currentMod, 0, (Hand)robotWafers[0].currentSlot));
+                            }
                             _tmSchdActions.Enqueue(pmActions);
                             return;
                         }
@@ -4598,6 +4625,103 @@ namespace Venus_RT.Modules
             }
         }
 
+        private void RunLotCleanTasks()
+        {
+            foreach(var pm in _dictModuleTask)
+            {
+                if (!ModuleHelper.IsPm(pm.Key))
+                    continue;
+
+                var pmTask = pm.Value as PMTask;
+                if(pmTask.HasWafer)
+                {
+                    var pmWafer = _lstWaferTasks.Find(wt => wt.currentMod == pm.Key);
+                    if (pmWafer != null && IsProcessJobEnding(pmWafer.lotId, pm.Key) && !_postLotCleanMarks[pm.Key].Contains(pmWafer.lotId))
+                    {
+                        var pj = _lstProcessJobs.Find(process => process.InnerId == pmWafer.lotId);
+                        if (pj != null)
+                        {
+                            var postClean = pj.Sequence.GetPostCleanRecipe(pm.Key);
+                            if (!string.IsNullOrWhiteSpace(postClean))
+                            {
+                                pmTask.InvokePostJobClean(postClean);
+                                _postLotCleanMarks[pm.Key].Add(pmWafer.lotId);
+                            }
+                        }
+                    }
+                }
+
+
+                // pre clean
+                var waitInWafer = GetFirstWaitInWafer(pm.Key);
+                if (waitInWafer != null && !_preLotCleanMarks[pm.Key].Contains(waitInWafer.lotId))
+                {
+                    var pj = _lstProcessJobs.Find(process => process.InnerId == waitInWafer.lotId);
+                    if (pj != null)
+                    {
+                        var preClean = pj.Sequence.GetPreCleanRecipe(pm.Key);
+                        if (!string.IsNullOrWhiteSpace(preClean))
+                        {
+                            pmTask.InvokePreJobClean(preClean);
+                            _preLotCleanMarks[pm.Key].Add(waitInWafer.lotId);
+                        }
+                    }
+                }
+            }
+        }
+
+        bool IsProcessJobEnding(Guid pjId, ModuleName pm)
+        {
+            if(!_lstWaferTasks.Exists(wt => wt.lotId == pjId && wt.destMod == pm && !ModuleHelper.IsPm(wt.currentMod)))
+            {
+                var processJob = _lstProcessJobs.Find(pj => pj.InnerId == pjId);
+                if (processJob == null)
+                    return false;
+
+                foreach(var slot in processJob.SlotWafers)
+                {
+                    if(WaferManager.Instance.CheckHasWafer(slot.Item1, slot.Item2))
+                    {
+                        if (WaferManager.Instance.GetWafer(slot.Item1, slot.Item2).NextSequenceStep == 0)
+                            return false;
+                    }
+                }
+
+                return true;
+            }
+
+            return false;
+        }
+
+        WaferTask GetFirstWaitInWafer(ModuleName pm)
+        {
+            int distance(WaferTask wafer)
+            {
+                if (ModuleHelper.IsTMRobot(wafer.currentMod))
+                    return 0;
+                else if (ModuleHelper.IsLoadLock(wafer.currentMod))
+                {
+                    return (_dictModuleTask[wafer.currentMod] as LoadlockTask).Distance;
+                }
+                else if(ModuleHelper.IsEFEMRobot(wafer.currentMod))
+                {
+                    if (wafer.IsAligned)
+                        return 15;
+                    else
+                        return 19;
+                }
+
+                return 17;
+            }
+
+            var waitInWafers = _lstWaferTasks.Where(wt => (wt.destMod == pm) && !ModuleHelper.IsPm(wt.currentMod) && !ModuleHelper.IsLoadPort(wt.currentMod)).OrderBy(wt => distance(wt));
+
+            if (waitInWafers.Count() > 0)
+                return waitInWafers.First();
+
+            return null;
+        }
+
         private void ReturnVacWafers()
         {
             if (_tmSchdActions.Count > 0 || _curTmAction.Count > 0)

+ 1 - 5
Venus/Venus_RT/Modules/VenusDispatcher.cs

@@ -579,9 +579,6 @@ namespace Venus_RT.Modules
             if (param.ContainsKey("LotId"))
                 lotId = (string)param["LotId"];
 
-            string preCleanRecipe = param.ContainsKey("PreCleanRecipeName") ? (string)param["PreCleanRecipeName"] : string.Empty;
-            string postCleanRecipe = param.ContainsKey("PostCleanRecipeName") ? (string)param["PostCleanRecipeName"] : string.Empty;
-
             if (slotSequence.Length != SC.GetValue<int>("EFEM.LoadPort.SlotNumber"))
             {
                 reason = $"slot sequence parameter not valid, length is {slotSequence.Length}, should be {SC.GetValue<int>("EFEM.LoadPort.SlotNumber")}";
@@ -614,8 +611,6 @@ namespace Venus_RT.Modules
             cj.LotWafers = new List<WaferInfo>();
             cj.SetState(EnumControlJobState.WaitingForStart);
             cj.JetState = EnumJetCtrlJobState.Quequed;
-            cj.PreJobClean = preCleanRecipe;
-            cj.PostJobClean = postCleanRecipe;
             cj.SequenceNameList = slotSequence;
             cj.CycleNumber = _cycleSetPoint;  // only for temperary debug
 
@@ -2082,6 +2077,7 @@ namespace Venus_RT.Modules
                                             0,
                                             temperature,
                                             wafer.InnerId,
+                                            wafer.ProcessJob.Sequence.InnerId,
                                             recipeName,
                                             wafer.ProcessJob.Sequence.WTWCleanRecipe,
                                             wafer.ProcessJob.Sequence.LLInOutPath,