Browse Source

redesign wtw clean function and fix auto vent bug.

sangwq 1 year ago
parent
commit
236244c8a0

+ 4 - 0
Venus/Framework/Common/Jobs/ControlJob.cs

@@ -37,6 +37,10 @@ namespace MECF.Framework.Common.Jobs
 
         public DateTime EndTime { get; set; }
 
+        public string PreJobClean { get; set; }
+
+        public string PostJobClean { get; set; }
+
 
         public ControlJobInfo()
         {

+ 0 - 16
Venus/Framework/Common/Jobs/SequenceInfo.cs

@@ -29,15 +29,9 @@ namespace MECF.Framework.Common.Jobs
         public string Name { get; set; }
 
         [DataMember]
-        public string PreCleanRecipe { get; set; }
-
-        [DataMember]
         public string WTWCleanRecipe { get; set; }
 
         [DataMember]
-        public string PostCleanRecipe { get; set; }
-
-        [DataMember]
         public List<ModuleName> PMs { get; set; }
 
         [DataMember]
@@ -173,20 +167,10 @@ namespace MECF.Framework.Common.Jobs
                                 continue;
                             }
 
-                            if(attr.Name == "PreClean")
-                            {
-                                info.PreCleanRecipe = attr.Value;
-                            }
-
                             if(attr.Name == "WTWClean")
                             {
                                 info.WTWCleanRecipe = attr.Value;
                             }
-
-                            if(attr.Name == "PostClean")
-                            {
-                                info.PostCleanRecipe = attr.Value;
-                            }
                         }
 
                         info.Steps.Add(stepInfo);

+ 1 - 3
Venus/Venus_RT/Config/SequenceFormat.xml

@@ -5,7 +5,7 @@
       <Item Name="Position" DisplayName="Position" InputType="ReadOnlySelection" >
         <Selection Name="Aligner" DisplayName="Aligner" Parameter="AlignerSelection,AlignAngle" />
         <Selection Name="LL" DisplayName="LL" Parameter="LLSelection" />
-        <Selection Name="PM" DisplayName="PM" Parameter="PMSelection,PMARecipe,PMBRecipe,PMCRecipe,PMDRecipe,PreClean,WTWClean,PostClean" />
+        <Selection Name="PM" DisplayName="PM" Parameter="PMSelection,PMARecipe,PMBRecipe,PMCRecipe,PMDRecipe,WTWClean" />
         <!--<Selection Name="Cooling" DisplayName="Cooling" Parameter="CoolingSelection,CoolingTime" />-->
       </Item>
     </Catalog>
@@ -54,9 +54,7 @@
 
       <Item Name="AlignAngle" DisplayName="Align Angle" InputType="NumInput"   Min="0" Max="359"  />
 		
-      <Item Name="PreClean" DisplayName="Pre Clean" InputType="RecipeSelection"     Min="0" Max="999999"  />
       <Item Name="WTWClean" DisplayName="WTW Clean" InputType="RecipeSelection"     Min="0" Max="999999"  />
-      <Item Name="PostClean" DisplayName="Post Clean" InputType="RecipeSelection"   Min="0" Max="999999"  />
 
 
 		<!--<Item Name="CoolingTime" DisplayName="Cooling Time(s)" InputType="NumInput"   Min="0" Max="360"  />-->

+ 52 - 86
Venus/Venus_RT/Modules/AutoCycle.cs

@@ -138,7 +138,7 @@ namespace Venus_RT.Modules
 
         private List<ModuleName> _waitPreCleanPMs = new List<ModuleName>();
         private List<ModuleName> _waitPostCleanPMs = new List<ModuleName>();
-        private List<ModuleName> _waitWTWCleanPMs = new List<ModuleName>();
+        private Dictionary<ModuleName, string> _waitWTWCleanPMs = new Dictionary<ModuleName, string>();
 
         private List<Guid> _lstReturnWafers = new List<Guid>();
 
@@ -220,6 +220,9 @@ 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"))
             {
                 LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"slot sequence parameter not valid, length is {slotSequence.Length}, should be {SC.GetValue<int>("EFEM.LoadPort.SlotNumber")}");
@@ -262,6 +265,8 @@ namespace Venus_RT.Modules
             cj.LotWafers = new List<WaferInfo>();
             cj.SetState(EnumControlJobState.WaitingForStart);
             cj.JetState = EnumJetCtrlJobState.Created;
+            cj.PreJobClean = preCleanRecipe;
+            cj.PostJobClean = postCleanRecipe;
 
             Dictionary<string, bool[]> seqSlot = new Dictionary<string, bool[]>();
             Dictionary<string, List<Tuple<ModuleName, int>>> seqSlotWafers = new Dictionary<string, List<Tuple<ModuleName, int>>>();
@@ -553,6 +558,10 @@ namespace Venus_RT.Modules
             _movingItems.Clear();
             _efemMovingItems.Clear();
 
+            _waitPreCleanPMs.Clear();
+            _waitPostCleanPMs.Clear();
+            _waitWTWCleanPMs.Clear();
+
             _vacMoveFinishTrig.RST = true;
             _atmMoveFinishTrig.RST = true;
 
@@ -999,7 +1008,7 @@ namespace Venus_RT.Modules
                             }
 
                             // check whether match swap pattern
-                            if (inCount == 0 && !IsPMNeedWTWClean(slot.Key.Module))
+                            if (inCount == 0 && !IsPMWaferNeedWTWClean(slot.Key.Module, out string wtwClean))
                             {
                                 int swapCount = 0;
                                 var in_slots = SearchWaitInSlots(slot.Key.Module);
@@ -1076,7 +1085,7 @@ namespace Venus_RT.Modules
                             }
 
                             // check whether match swap pattern
-                            if (inCount == 0 && !IsPMNeedWTWClean(slot.Key.Module))
+                            if (inCount == 0 && !IsPMWaferNeedWTWClean(slot.Key.Module, out string wtwClean))
                             {
                                 int swapCount = 0;
                                 var in_slots = SearchWaitInSlots(slot.Key.Module);
@@ -1216,7 +1225,7 @@ namespace Venus_RT.Modules
                     if (wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(mod.Key))
                     {
                         if ((WaferManager.Instance.CheckNoWafer(mod.Key, 0) && !_movingItems.Exists(item => item.DestinationModule == mod.Key)) ||
-                            (WaferManager.Instance.CheckHasWafer(mod.Key, 0) && _movingItems.Exists(item => item.SourceModule == mod.Key) && !_movingItems.Exists(item => item.DestinationModule == mod.Key) && !IsPMNeedWTWClean(mod.Key)))
+                            (WaferManager.Instance.CheckHasWafer(mod.Key, 0) && _movingItems.Exists(item => item.SourceModule == mod.Key) && !_movingItems.Exists(item => item.DestinationModule == mod.Key) && !IsPMWaferNeedWTWClean(mod.Key, out string wtwClean)))
                         {
                             inSlot.Module = mod.Key;
                             inSlot.Slot = 0;
@@ -1456,12 +1465,9 @@ namespace Venus_RT.Modules
                                 break;
                             case MovingStatus.Processing:
                                 {
-                                    var pmScheduler = _vacSchedulers[mod.Key] as SchedulerPM;
-                                    string WTWCleanRecipe = string.Empty;
-                                    var wtwJob = _lstControlJobs.Find(cj => cj.JetState == EnumJetCtrlJobState.Processing && IsCtrlJobNeedWTWClean(cj, mod.Key, out WTWCleanRecipe) && !IsAllJobWaferProcessedOrProcessing(cj));
-                                    if (wtwJob != null && WTWCleanRecipe.Length > 0)
+                                    if (IsPMWaferNeedWTWClean(mod.Key, out string WTWCleanRecipe))
                                     {
-                                        _waitWTWCleanPMs.Add(mod.Key);
+                                        _waitWTWCleanPMs.Add(mod.Key, WTWCleanRecipe);
                                     }
 
                                     mod.Value.MovingStatus = MovingStatus.Idle;
@@ -1478,11 +1484,15 @@ namespace Venus_RT.Modules
                                     var pmScheduler = _vacSchedulers[mod.Key] as SchedulerPM;
                                     if (IsPMKeepEmpty(mod.Key))
                                     {
-                                        if (_waitPreCleanPMs.Contains(mod.Key))
+                                        if (_waitWTWCleanPMs.ContainsKey(mod.Key))
+                                        {
+                                            mod.Value.MovingStatus = MovingStatus.WaitWTWClean;
+                                        }
+                                        else if (_waitPreCleanPMs.Contains(mod.Key))
                                         {
                                             mod.Value.MovingStatus = MovingStatus.WaitPreJobClean;
                                         }
-                                        else if (_lstControlJobs.FindIndex(cj => cj.JetState == EnumJetCtrlJobState.PostJobClean) != -1 && _waitPostCleanPMs.Contains(mod.Key))
+                                        else if (_waitPostCleanPMs.Contains(mod.Key))
                                         {
                                             mod.Value.MovingStatus = MovingStatus.WaitPostJobClean;
                                         }
@@ -1533,11 +1543,10 @@ namespace Venus_RT.Modules
                                 {
                                     mod.Value.MovingStatus = MovingStatus.Idle;
                                     var pmScheduler = _vacSchedulers[mod.Key] as SchedulerPM;
-                                    if (IsPMKeepEmpty(mod.Key) && _waitWTWCleanPMs.Contains(mod.Key))
+                                    if (IsPMKeepEmpty(mod.Key) && _waitWTWCleanPMs.ContainsKey(mod.Key))
                                     {
-                                        string WTWCleanRecipe = string.Empty;
-                                        var wtwJob = _lstControlJobs.Find(cj => cj.JetState == EnumJetCtrlJobState.Processing && IsCtrlJobNeedWTWClean(cj, mod.Key, out WTWCleanRecipe) && !IsAllJobWaferProcessedOrProcessing(cj));
-                                        if (wtwJob != null && WTWCleanRecipe.Length > 0)
+                                        string WTWCleanRecipe = _waitWTWCleanPMs[mod.Key].Trim();
+                                        if (WTWCleanRecipe.Length > 0)
                                         {
                                             if (pmScheduler.RunJobCleanTask(WTWCleanRecipe))
                                             {
@@ -1891,7 +1900,7 @@ namespace Venus_RT.Modules
             {
                 if (cj.JetState == EnumJetCtrlJobState.PreJobClean && _waitPreCleanPMs.Contains(pm))
                 {
-                    preCleanRecipe = GetFirstProcessJob(cj).Sequence.PreCleanRecipe;
+                    preCleanRecipe = cj.PreJobClean;
                     return true;
                 }
             }
@@ -1906,7 +1915,7 @@ namespace Venus_RT.Modules
             {
                 if (cj.JetState == EnumJetCtrlJobState.PostJobClean && _waitPostCleanPMs.Contains(pm))
                 {
-                    postCleanRecipe = GetFirstProcessJob(cj).Sequence.PostCleanRecipe;
+                    postCleanRecipe = cj.PostJobClean;
                     return true;
                 }
             }
@@ -1914,20 +1923,6 @@ namespace Venus_RT.Modules
             return false;
         }
 
-        private bool IsWTWJobCleanPending(ModuleName pm, out string wtwCleanRecipe)
-        {
-            wtwCleanRecipe = string.Empty;
-            foreach (var cj in _lstControlJobs)
-            {
-                if (cj.JetState == EnumJetCtrlJobState.Processing && _waitWTWCleanPMs.Contains(pm))
-                {
-                    wtwCleanRecipe = GetFirstProcessJob(cj).Sequence.WTWCleanRecipe;
-                    return true;
-                }
-            }
-
-            return false;
-        }
 
         private (int processed, int unprocessed, int empty) GetLLProcessStatusCount(ModuleName ll)
         {
@@ -2119,9 +2114,6 @@ namespace Venus_RT.Modules
                                     if (!wafer.IsEmpty && wafer.NextSequenceStep == 0)
                                     {
                                         inSlots.Add(pjSlotWafer.Item2);
-
-                                        if (inSlots.Count >= 2)
-                                            return inSlots;
                                     }
                                 }
 
@@ -2131,7 +2123,7 @@ namespace Venus_RT.Modules
                 }
             }
 
-            return inSlots;
+            return inSlots.OrderBy(item => item).Take(2).ToList();
         }
 
         private bool ProcessAlignerEFEMRobotTask(ModuleName aligner)
@@ -2522,13 +2514,13 @@ namespace Venus_RT.Modules
                             var curItem = _movingItems.Find(item => item.DestinationModule == tar.Key.Module && item.DestinationSlot == tar.Key.Slot);
                             if (ModuleHelper.IsPm(curItem.SourceModule) && _movingItems.FindIndex(item => item.DestinationModule == curItem.SourceModule) == -1)
                             {
-                                if (_waitPostCleanPMs.Contains(curItem.SourceModule))
+                                if (_waitWTWCleanPMs.ContainsKey(curItem.SourceModule))
                                 {
-                                    _vacModules[curItem.SourceModule].MovingStatus = MovingStatus.WaitPostJobClean;
+                                    _vacModules[curItem.SourceModule].MovingStatus = MovingStatus.WaitWTWClean;
                                 }
-                                else if (_waitWTWCleanPMs.Contains(curItem.SourceModule))
+                                else if (_waitPostCleanPMs.Contains(curItem.SourceModule))
                                 {
-                                    _vacModules[curItem.SourceModule].MovingStatus = MovingStatus.WaitWTWClean;
+                                    _vacModules[curItem.SourceModule].MovingStatus = MovingStatus.WaitPostJobClean;
                                 }
                             }
                         }
@@ -2934,11 +2926,7 @@ namespace Venus_RT.Modules
                             foreach (var pjSlotWafer in pj.SlotWafers)
                             {
                                 WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
-                                if (!wafer.IsEmpty && wafer.ProcessJob != null && wafer.ProcessJob.Sequence != null
-                                    && !IsWaferNeedGotoModule(wafer, ModuleName.PMA)
-                                    && !IsWaferNeedGotoModule(wafer, ModuleName.PMB)
-                                    && !IsWaferNeedGotoModule(wafer, ModuleName.PMC)
-                                    && !IsWaferNeedGotoModule(wafer, ModuleName.PMD))
+                                if (!wafer.IsEmpty && wafer.ProcessState == EnumWaferProcessStatus.Completed)
                                     countProcessed++;
                             }
 
@@ -3119,63 +3107,41 @@ namespace Venus_RT.Modules
 
         private bool IsCtrlJobNeedPreClean(ControlJobInfo cj)
         {
-            if (cj.ProcessJobNameList.Count != 1)
-                return false;
-
-            var processJob = _lstProcessJobs.Find(pj => pj.Name == cj.ProcessJobNameList.First());
-            if (processJob == null || processJob.Sequence == null || processJob.Sequence.PreCleanRecipe == null)
-                return false;
-
-            return processJob.Sequence.PreCleanRecipe.Trim().Length > 0;
+            return cj.PreJobClean.Trim().Length > 0;
         }
 
         private bool IsCtrlJobNeedPostClean(ControlJobInfo cj)
         {
-            if (cj.ProcessJobNameList.Count != 1)
-                return false;
-
-            var processJob = _lstProcessJobs.Find(pj => pj.Name == cj.ProcessJobNameList.First());
-            if (processJob == null || processJob.Sequence == null || processJob.Sequence.PostCleanRecipe == null)
-                return false;
-
-            return processJob.Sequence.PostCleanRecipe.Trim().Length > 0;
-        }
-
-        private bool IsPMNeedWTWClean(ModuleName pm)
-        {
-            foreach(var cj in _lstControlJobs)
-            {
-                if(IsCtrlJobNeedWTWClean(cj, pm, out string wtwClean))
-                {
-                    return true;
-                }
-            }
-
-            return false;
+            return cj.PostJobClean.Trim().Length > 0;
         }
 
-        private bool IsCtrlJobNeedWTWClean(ControlJobInfo cj, ModuleName pm,  out string WTWCleanRecipe)
+        private bool IsPMWaferNeedWTWClean(ModuleName pm, out string WTWCleanRecipe)
         {
             WTWCleanRecipe = string.Empty;
-            if (cj.ProcessJobNameList.Count != 1)
-                return false;
-
-            var processJob = _lstProcessJobs.Find(pj => pj.Name == cj.ProcessJobNameList.First());
-            if (processJob == null || processJob.Sequence == null || processJob.Sequence.WTWCleanRecipe == null)
+            var wafer = WaferManager.Instance.GetWafer(pm, 0);
+            if (wafer.IsEmpty || wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null || wafer.ProcessJob.Sequence.WTWCleanRecipe.Trim().Length == 0)
                 return false;
 
-            WTWCleanRecipe = processJob.Sequence.WTWCleanRecipe.Trim();
-            return processJob.Sequence.PMs.Contains(pm) && WTWCleanRecipe.Length > 0;
+            WTWCleanRecipe = wafer.ProcessJob.Sequence.WTWCleanRecipe;
+            return true;
         }
 
         private List<ModuleName> GetWaitPreCleanPMsByCtrlJob(ControlJobInfo cj)
         {
-            if (cj.ProcessJobNameList.Count != 1)
-                return new List<ModuleName>();
-
-            var processJob = _lstProcessJobs.Find(pj => pj.Name == cj.ProcessJobNameList.First());
+            var pmlist = new List<ModuleName>();
+            foreach(var pj in _lstProcessJobs)
+            {
+                if(pj.ControlJobName == cj.Name)
+                {
+                    foreach(var pm in pj.Sequence.PMs)
+                    {
+                        if (!pmlist.Contains(pm))
+                            pmlist.Add(pm);
+                    }
+                }
+            }
 
-            return processJob.Sequence.PMs;
+            return pmlist;
         }
 
         private static WaferInfo GetCloneWafer(ModuleName mod, int slot)

+ 1 - 1
Venus/Venus_RT/Modules/Schedulers/SchedulerEfemRobot.cs

@@ -29,7 +29,7 @@ namespace Venus_RT.Scheduler
     {
         public override bool IsAvailable
         {
-            get { return _entity.IsIdle && /*(_entity.IsOnline || !Singleton<RouteManager>.Instance.IsAutoMode) &&*/ CheckTaskDone() && RunSchedulers(); }
+            get { return _entity.IsIdle && (_entity.IsOnline || !Singleton<RouteManager>.Instance.IsAutoMode) && CheckTaskDone() && RunSchedulers(); }
         }
         public override bool IsOnline
         {

+ 6 - 0
Venus/Venus_RT/Modules/TM/MFPMPickRoutine.cs

@@ -1,6 +1,7 @@
 using Aitex.Core.RT.Routine;
 using Aitex.Core.RT.SCCore;
 using Aitex.Sorter.Common;
+using Aitex.Core.Common;
 using Venus_RT.Devices;
 using MECF.Framework.Common.Routine;
 using MECF.Framework.Common.Equipment;
@@ -100,6 +101,11 @@ namespace Venus_RT.Modules.TM
             }
 
             var wafer = WaferManager.Instance.GetWafer(_targetModule, _targetSlot);
+            if(wafer.ChuckState == EnumWaferChuckStatus.Chucked)
+            {
+                LOG.Write(eEvent.ERR_TM, Module, $"Cannot pick the wafer in {_targetModule }as the wafer is chucked");
+                return RState.Failed;
+            }
             LOG.Write(eEvent.INFO_TM_ROBOT, ModuleName.TMRobot, $"{wafer.WaferOrigin} will be move from {_targetModule} {_targetSlot + 1} to TM Robot {_hand}");
 
             Reset();

+ 8 - 0
Venus/Venus_RT/Modules/TM/MFPMSwapRoutine.cs

@@ -2,6 +2,7 @@
 using Aitex.Core.RT.SCCore;
 using Aitex.Sorter.Common;
 using Venus_RT.Devices;
+using Aitex.Core.Common;
 using MECF.Framework.Common.Routine;
 using MECF.Framework.Common.Equipment;
 using MECF.Framework.Common.SubstrateTrackings;
@@ -102,6 +103,13 @@ namespace Venus_RT.Modules.TM
                 return RState.Failed;
             }
 
+            var wafer = WaferManager.Instance.GetWafer(_targetModule, _targetSlot);
+            if (wafer.ChuckState == EnumWaferChuckStatus.Chucked)
+            {
+                LOG.Write(eEvent.ERR_TM, Module, $"Cannot pick the wafer in {_targetModule } as the wafer is chucked");
+                return RState.Failed;
+            }
+
             Reset();
             _swapingTimeout = SC.GetValue<int>($"TM.SwapTimeout") * 1000;
             _pickDelayTime = SC.GetValue<int>($"{_targetModule}.PickDelayTime");

+ 39 - 1
Venus/Venus_RT/Modules/TM/MFPickRoutine.cs

@@ -2,6 +2,7 @@
 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;
@@ -40,6 +41,12 @@ namespace Venus_RT.Modules.TM
         private DateTime _starttime;
         private bool _queryAwc;
 
+        private int _autoVentOptInWafer = 0;
+        private int _autoVentOptOutWafer = 4;
+
+        private SequenceLLInOutPath _sequencePattern = SequenceLLInOutPath.DInDOut;
+        private bool _bAutoMode = true;
+
         public MFPickRoutine(JetTM tm, ITransferRobot robot) :base(ModuleName.TMRobot)
         {
             _JetTM = tm;
@@ -91,6 +98,12 @@ namespace Venus_RT.Modules.TM
             Reset();
             _pickingTimeout = SC.GetValue<int>("TM.PickTimeout") * 1000;
 
+            _autoVentOptInWafer = SC.GetValue<int>("TM.LLAutoVentInWaferOpt");
+            _autoVentOptOutWafer = SC.GetValue<int>("TM.LLAutoVentOutWaferOpt");
+
+            _sequencePattern = Singleton<RouteManager>.Instance.LLInOutPath;
+            _bAutoMode = Singleton<RouteManager>.Instance.IsAutoMode;
+
             return Runner.Start(Module, $"Pick from {_targetModule}");
         }
 
@@ -214,7 +227,32 @@ namespace Venus_RT.Modules.TM
 
         private bool NotifyLLDone()
         {
-            _llModule.PostMsg(LLEntity.MSG.TM_Exchange_Ready);
+            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;
         }
 

+ 40 - 2
Venus/Venus_RT/Modules/TM/MFPlaceRoutine.cs

@@ -2,6 +2,7 @@
 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;
@@ -41,6 +42,12 @@ namespace Venus_RT.Modules.TM
         private DateTime _starttime;
         private bool _queryAwc;
 
+        private int _autoVentOptInWafer = 0;
+        private int _autoVentOptOutWafer = 4;
+
+        private SequenceLLInOutPath _sequencePattern = SequenceLLInOutPath.DInDOut;
+        private bool _bAutoMode = true;
+
         public MFPlaceRoutine(JetTM tm, ITransferRobot robot) : base(ModuleName.TMRobot)
         {
             _JetTM = tm;
@@ -90,7 +97,13 @@ namespace Venus_RT.Modules.TM
 
             Reset();
             _placingTimeout = SC.GetValue<int>($"TM.PlaceTimeout") * 1000;
-            
+
+            _autoVentOptInWafer = SC.GetValue<int>("TM.LLAutoVentInWaferOpt");
+            _autoVentOptOutWafer = SC.GetValue<int>("TM.LLAutoVentOutWaferOpt");
+
+            _sequencePattern = Singleton<RouteManager>.Instance.LLInOutPath;
+            _bAutoMode = Singleton<RouteManager>.Instance.IsAutoMode;
+
             return Runner.Start(Module, $"Place to {_targetModule}");
         }
 
@@ -235,7 +248,32 @@ namespace Venus_RT.Modules.TM
 
         private bool NotifyLLDone()
         {
-            _llModule.PostMsg(LLEntity.MSG.TM_Exchange_Ready);
+            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;
         }