Browse Source

1. add the function of WTWClean by WTWInterval

zhouhr 4 months ago
parent
commit
82d289e21c

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

@@ -62,6 +62,7 @@ namespace MECF.Framework.Common.Jobs
 
         public int LLDelayTime { get; set; }
 
+
         public SequenceInfo(string name)
         {
             Name = name;
@@ -88,6 +89,33 @@ namespace MECF.Framework.Common.Jobs
             return string.Empty;
         }
 
+        public string GetLongIdleCleanRecipe(ModuleName pm, out int idletime)
+        {
+            idletime = -1;
+            if (!ModuleHelper.IsPm(pm))
+                return string.Empty;
+
+            string attr = $"{pm}IdleClean";
+            string timeattr = $"{pm}IdleTime";
+
+            foreach (var step in Steps)
+            {
+                if (step.StepModules.Contains(pm) && step.StepParameter.ContainsKey(timeattr))
+                {
+                    idletime = Convert.ToInt32(step.StepParameter[timeattr]);
+                }
+            }
+
+            foreach (var step in Steps)
+            {
+                if (step.StepModules.Contains(pm) && step.StepParameter.ContainsKey(attr))
+                {
+                    return (string)step.StepParameter[attr];
+                }
+            }
+
+            return string.Empty;
+        }
 
         public string GetPreCleanRecipe(ModuleName pm)
         {
@@ -121,6 +149,24 @@ namespace MECF.Framework.Common.Jobs
 
             return string.Empty;
         }
+
+        public int GetWTWCleanInterval(ModuleName pm)
+        {
+            if (!ModuleHelper.IsPm(pm))
+                return -1;
+
+            string attr = $"{pm}WTWInterval";
+            foreach (var step in Steps)
+            {
+                if (step.StepModules.Contains(pm) && step.StepParameter.ContainsKey(attr))
+                {
+                    return Convert.ToInt32(step.StepParameter[attr]);
+                }
+            }
+
+            return -1;
+        }
+
         public string GetPostCleanRecipe(ModuleName pm)
         {
             if (!ModuleHelper.IsPm(pm))

+ 1 - 59
Venus/Venus_MainPages/ViewModels/SequenceViewModel.cs

@@ -469,7 +469,7 @@ namespace Venus_MainPages.ViewModels
         public void SelectRecipe(object select)
         {
             PathFileParam param = (PathFileParam)select;
-            KeplerRecipeSequenceSelectView dialog = new KeplerRecipeSequenceSelectView(param.Value)
+            VenusRecipeSequenceSelectView dialog = new VenusRecipeSequenceSelectView(param.Value)
             {
                 Owner = Application.Current.MainWindow
             };
@@ -496,68 +496,10 @@ namespace Venus_MainPages.ViewModels
             Process.Add($"{moduleName}\\Process\\");
             dataContext.Files.AddRange(new ObservableCollection<FileNode>(RecipeSequenceTreeBuilder.GetFiles("", Clean)));
             dataContext.Files.AddRange(new ObservableCollection<FileNode>(RecipeSequenceTreeBuilder.GetFiles("", Process)));
-            //if (param.Name.Contains("PMA"))
-            //{
-
-
-
-            //}
-            //else if (param.Name.Contains("PMB"))
-            //{
-            //    lstFiles.AddRange(provider.GetRecipesByPath($"{param.PrefixPath}").Where(x => x.Split('\\')[0] == "PMB" && x.Split('\\')[1] == "Clean").ToList());//m_uiSequenceManager.GetRecipesByPath($"{param.PrefixPath}");
-
-            //    lstFiles = provider.GetRecipesByPath($"{param.PrefixPath}").Where(x => x.Split('\\')[0] == "PMB" && x.Split('\\')[1] == "Process").ToList();
-            //}
-            //else if (param.Name.Contains("PMC"))
-            //{
-            //    lstFiles.AddRange(provider.GetRecipesByPath($"{param.PrefixPath}").Where(x => x.Split('\\')[0] == "PMC" && x.Split('\\')[1] == "Clean").ToList());//m_uiSequenceManager.GetRecipesByPath($"{param.PrefixPath}");
-
-            //    lstFiles = provider.GetRecipesByPath($"{param.PrefixPath}").Where(x => x.Split('\\')[0] == "PMC" && x.Split('\\')[1] == "Process").ToList();
-            //}
-            //else if (param.Name.Contains("PMD"))
-            //{
-            //    lstFiles.AddRange(provider.GetRecipesByPath($"{param.PrefixPath}").Where(x => x.Split('\\')[0] == "PMD" && x.Split('\\')[1] == "Clean").ToList());//m_uiSequenceManager.GetRecipesByPath($"{param.PrefixPath}");
-
-            //    lstFiles = provider.GetRecipesByPath($"{param.PrefixPath}").Where(x => x.Split('\\')[0] == "PMD" && x.Split('\\')[1] == "Process").ToList();
-            //}
-            //else
-            //{
-            //    lstFiles.AddRange(provider.GetRecipesByPath($"{param.PrefixPath}").Where(x => x.Split('\\')[1] == "Clean").ToList());//m_uiSequenceManager.GetRecipesByPath($"{param.PrefixPath}");
-
-            //    lstFiles = provider.GetRecipesByPath($"{param.PrefixPath}").Where(x => x.Split('\\')[1] == "Process").ToList();
-            //}
-
-            //if (param.Name.Contains("Clean"))
-            //{
-            //}
-            //else
-            //{
-
-            //}
-
-            //lstFiles.ForEach(x => 
-            //{
-            //    dataContext.Files.Add(new ObservableCollection<FileNode>(RecipeSequenceTreeBuilder.GetFiles("", x)));
-            //});
-            //dataContext.Files = new ObservableCollection<FileNode>(RecipeSequenceTreeBuilder.GetFiles("", lstFiles));
 
             if (dialog.ShowDialog() == true)
             {
-                //param.Value = dialog.FullPath;
-                //param.Value = $"{param.PrefixPath}\\" + dialog.FullPath;
-                //param.FileName = param.Value;
                 string path = dialog.FullPath;
-                //int index = path.LastIndexOf("\\");
-                //if (index > -1)
-                //{
-                //    param.FileName = path.Substring(index + 1);
-                //    param.Value = path.Substring(index + 1);
-                //}
-                //else
-                //{
-                //    param.FileName = path;
-                //    param.Value = path;
-                //}
                 param.FileName = path;
                 param.Value = path;
 

+ 13 - 5
Venus/Venus_MainPages/Views/VenusRecipeSequenceSelectView.xaml

@@ -87,13 +87,21 @@
                 <GroupBox Header="WTW Clean" FontSize="14" Grid.Column="2" >
                     <Grid>
                         <Grid.RowDefinitions>
-                            <RowDefinition Height="30"/>
+                            <RowDefinition Height="50"/>
                             <RowDefinition/>
                         </Grid.RowDefinitions>
                         <Border BorderBrush="Black" BorderThickness="1 1 1 0" Background="White" >
-                            <StackPanel Orientation="Horizontal">
-                                <TextBlock Text="Recipe:" VerticalAlignment="Center" FontSize="14" Padding="5 0 0 0"/>
-                                <TextBlock x:Name="wtwSelectedRecipeTextBlock" Width="Auto" VerticalAlignment="Center"  FontSize="14"/>
+                            <StackPanel Orientation="Vertical">
+                                <StackPanel Orientation="Horizontal" Margin="0,5,0,0">
+                                    <TextBlock Text="Recipe:" VerticalAlignment="Center" FontSize="14" Padding="5 0 0 0"/>
+                                    <TextBlock x:Name="wtwSelectedRecipeTextBlock" Width="Auto" VerticalAlignment="Center"  FontSize="14"/>
+                                </StackPanel>
+
+                                <StackPanel Orientation="Horizontal">
+                                    <TextBlock Text="Interval:" Width="Auto" VerticalAlignment="Center"  FontSize="14" Margin="5,0,0,0"/>
+                                    <TextBox Width="60" Margin="6,4" x:Name="WTWInterval" InputScope="Number"/>
+                                    <TextBlock Text="(pcs)" Width="Auto" VerticalAlignment="Center"  FontSize="14"/>
+                                </StackPanel>
                             </StackPanel>
                         </Border>
 
@@ -142,7 +150,7 @@
 
                 </GroupBox>
 
-                <GroupBox Header="Idle Clean" FontSize="14" Grid.Column="4" >
+                <GroupBox Header="Long Idle Clean" FontSize="14" Grid.Column="4" >
                     <Grid>
                         <Grid.RowDefinitions>
                             <RowDefinition Height="50"/>

+ 6 - 0
Venus/Venus_MainPages/Views/VenusRecipeSequenceSelectView.xaml.cs

@@ -68,10 +68,12 @@ namespace Venus_MainPages.Views
             if (wtw_currentFileNode != null && wtw_currentFileNode.Parent.Name == "Clean")
             {
                 recipeDictionary.Add("WTWClean", wtw_currentFileNode.Name);
+                recipeDictionary.Add("WTWInterval", WTWInterval.Text);
             }
             else
             {
                 recipeDictionary.Add("WTWClean", "");
+                recipeDictionary.Add("WTWInterval", "");
             }
             if (post_currentFileNode != null && post_currentFileNode.Parent.Name == "Clean")
             {
@@ -223,6 +225,10 @@ namespace Venus_MainPages.Views
             {
                 IdleTime.Text = dictionary["IdleTime"];
             }
+            if (dictionary.Keys.Contains("WTWInterval"))
+            {
+                WTWInterval.Text = dictionary["WTWInterval"];
+            }
 
         }
 

+ 4 - 1
Venus/Venus_RT/Modules/PMs/PMEntity.cs

@@ -149,7 +149,7 @@ namespace Venus_RT.Modules.PMs
 
         //private readonly PMHeatRoutine _pmHeatRoutine;
 
-
+        private DateTime _lastProcessDone;
 
         private AutoFlag _AutoMode;
         private bool _isOnline = false;
@@ -168,6 +168,8 @@ namespace Venus_RT.Modules.PMs
 
         private int _controlPressureSetPoint = 90;
         private int _controlFlowSetPoint = 90;
+
+        public DateTime LastProcessDone => _lastProcessDone;
         public JetChamber ChamberType => _chamber.ChamberType;
         public bool IsIdle
         {
@@ -1349,6 +1351,7 @@ namespace Venus_RT.Modules.PMs
 
             if (ret == RState.End)
             {
+                _lastProcessDone = DateTime.Now;
                 StatsDataManager.Instance.Increase(_statProcessedWafer.Name);
                 _dictRecipeTime[_processRoutine.currentRecipeResult.RecipeName] = fsm.ElapsedTime;
                 return true;

+ 5 - 0
Venus/Venus_RT/Modules/SystemDispatcher.cs

@@ -205,6 +205,10 @@ namespace Venus_RT.Modules
         StartWTWClean,
         WTWClean,
 
+        WaitLongIdleClean,
+        StartLongIdleClean,
+        LongIdleClean,
+
         // Align Status
         WaitAlign,
         StartAlign,
@@ -581,6 +585,7 @@ namespace Venus_RT.Modules
                 {
                     Status = ModuleStatus.WaitPreJobClean;
                 }
+
             }
 
             _wafer = null;

+ 101 - 14
Venus/Venus_RT/Modules/VenusDispatcher.cs

@@ -27,6 +27,7 @@ using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robot;
 using Venus_RT.Modules.TM.VenusEntity;
 using System.Threading.Tasks;
 using Venus_RT.Modules.VCE;
+using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.PMs;
 
 namespace Venus_RT.Modules
 {
@@ -42,10 +43,12 @@ namespace Venus_RT.Modules
     {
         enum CleanType
         {
+            LongIdleClean,
             IdleClean,
             PreJobClean,
             PostJobClean,
             WTWClean,
+
         }
 
         public override int TimeToReady
@@ -84,9 +87,11 @@ namespace Venus_RT.Modules
         private WaferTask _wafer;
         private SchedulerPM _pmScheduler => Scheduler as SchedulerPM;
 
+        private string _longIdleCleanRecipe;
         private string _preJobCleanRecipe;
         private string _postJobCleanRecipe;
         private string _wtwCleanRecipe;
+        private DateTime _lstProcessTime;
         private Queue<CleanType> _pendingCleanTask = new Queue<CleanType>();
 
         public VenusPMTask(ModuleName pm) : base(pm)
@@ -114,6 +119,10 @@ namespace Venus_RT.Modules
                                     {
                                         Status = ModuleStatus.WaitPreJobClean;
                                     }
+                                    else if (cleanTask == CleanType.LongIdleClean && !string.IsNullOrWhiteSpace(_longIdleCleanRecipe))
+                                    {
+                                        Status = ModuleStatus.WaitLongIdleClean;
+                                    }
                                 }
                                 else if (_pmScheduler.RunIdleCleanTask())  // Check Idle Clean
                                 {
@@ -180,6 +189,23 @@ namespace Venus_RT.Modules
                             }
                         }
                         break;
+                    case ModuleStatus.WaitLongIdleClean:
+                        {
+                            if (WaferManager.Instance.CheckNoWafer(Module, 0))
+                            {
+                                if (_pmScheduler.RunJobCleanTask(_longIdleCleanRecipe))
+                                {
+                                    Status = ModuleStatus.StartLongIdleClean;
+                                }
+                                else
+                                {
+                                    LOG.Write(eEvent.WARN_ROUTER, Module, $"Run LongTime clean recipe{_longIdleCleanRecipe} failed");
+                                    Status = ModuleStatus.Idle;
+                                    _longIdleCleanRecipe = string.Empty;
+                                }
+                            }
+                        }
+                        break;
                     case ModuleStatus.Processing:
                         {
                             var wafer = WaferManager.Instance.GetWafer(Module, 0);
@@ -197,6 +223,12 @@ namespace Venus_RT.Modules
                             }
                         }
                         break;
+                    case ModuleStatus.LongIdleClean:
+                        {
+                            _longIdleCleanRecipe = string.Empty;
+                            Status = ModuleStatus.Idle;
+                        }
+                        break;
                     case ModuleStatus.PreJobClean:
                         {
                             _preJobCleanRecipe = string.Empty;
@@ -266,6 +298,9 @@ namespace Venus_RT.Modules
                     case ModuleStatus.StartIdleClean:
                         Status = ModuleStatus.IdleClean;
                         break;
+                    case ModuleStatus.StartLongIdleClean:
+                        Status = ModuleStatus.LongIdleClean;
+                        break;
                     case ModuleStatus.StartPreJobClean:
                         Status = ModuleStatus.PreJobClean;
                         break;
@@ -305,6 +340,10 @@ namespace Venus_RT.Modules
                 {
                     Status = ModuleStatus.WaitPreJobClean;
                 }
+                else if (cleanTask == CleanType.LongIdleClean && !string.IsNullOrWhiteSpace(_longIdleCleanRecipe))
+                {
+                    Status = ModuleStatus.WaitLongIdleClean;
+                }
             }
 
             _wafer = null;
@@ -333,6 +372,12 @@ namespace Venus_RT.Modules
         {
             return !_pendingCleanTask.Contains(CleanType.PostJobClean) && string.IsNullOrWhiteSpace(_postJobCleanRecipe);
         }
+
+        public void InvokeLongIdleClean(string longIdleJobClean)
+        {
+            _longIdleCleanRecipe = longIdleJobClean;
+            _pendingCleanTask.Enqueue(CleanType.LongIdleClean);
+        }
     }
 
     //class VenusPMTask : ModuleTask
@@ -777,6 +822,9 @@ namespace Venus_RT.Modules
         private Dictionary<ModuleName, List<Guid>> _preLotCleanMarks = new Dictionary<ModuleName, List<Guid>>();
         private Dictionary<ModuleName, List<Guid>> _postLotCleanMarks = new Dictionary<ModuleName, List<Guid>>();
 
+        // process => int  => pm 0.PMA 1.PMB 2.PMC 3.PMD 
+        private Dictionary<string, Dictionary<ModuleName, int>> _Sequence2PMWaferCount = new Dictionary<string, Dictionary<ModuleName, int>>();
+
         private bool _isCycleMode;
         private int _cycleSetPoint = 0;
         private int _cycledCount = 0;
@@ -1013,6 +1061,14 @@ namespace Venus_RT.Modules
                 pj.LotName = lotId;
                 pj.SlotWafers = seqSlotWafers[seqs[i]];
                 pj.SetState(EnumProcessJobState.Queued);
+                if (!_Sequence2PMWaferCount.ContainsKey(pj.Sequence.Name))
+                    _Sequence2PMWaferCount.Add(pj.Sequence.Name,new Dictionary<ModuleName, int>()
+                    {
+                        {ModuleName.PMA , 0},
+                        {ModuleName.PMB , 0},
+                        {ModuleName.PMC , 0},
+                        {ModuleName.PMD , 0},
+                    });
 
                 if (!CheckSequencePmReady(pj.Sequence, out reason))
                 {
@@ -1303,6 +1359,7 @@ namespace Venus_RT.Modules
             _curTmAction.Clear();
             _lstControlJobs.Clear();
             _lstProcessJobs.Clear();
+            _Sequence2PMWaferCount.Clear();
             InUseRecipes.Clear();
 
             _lpCycleWafer[ModuleName.LP1] = 0;
@@ -2097,7 +2154,6 @@ namespace Venus_RT.Modules
                         if (pj != null)
                         {
                             //2024-10-31 15:36:19 修改postjob来源
-                            //var postClean = pj.Sequence.GetPostCleanRecipe(pm.Key);
                             var postClean = pj.Sequence.GetPostCleanRecipe(pm.Key);
                             if (!string.IsNullOrWhiteSpace(postClean))
                             {
@@ -2116,8 +2172,13 @@ namespace Venus_RT.Modules
                     var pj = _lstProcessJobs.Find(process => process.InnerId == waitInWafer.lotId);
                     if (pj != null)
                     {
+                        var longIdleClean = pj.Sequence.GetLongIdleCleanRecipe(pm.Key, out int idletime);
+                        if (!string.IsNullOrWhiteSpace(longIdleClean) && idletime >= 0 && Singleton<RouteManager>.Instance.GetPM(pm.Key).LastProcessDone != null && (DateTime.Now - Singleton<RouteManager>.Instance.GetPM(pm.Key).LastProcessDone).TotalSeconds > idletime)
+                        {
+                            pmTask.InvokeLongIdleClean(longIdleClean);
+                        }
+
                         //2024-10-31 15:36:37 修改prejob来源
-                        //var preClean = pj.Sequence.GetPreCleanRecipe(pm.Key);
                         var preClean = pj.Sequence.GetPreCleanRecipe(pm.Key);
                         if (!string.IsNullOrWhiteSpace(preClean))
                         {
@@ -2610,18 +2671,44 @@ namespace Venus_RT.Modules
                 temperature = temp;
             }
 
-            var waferTask = new WaferTask((ModuleName)wafer.OriginStation,
-                                            wafer.OriginSlot,
-                                            pm,
-                                            0,
-                                            temperature,
-                                            wafer.InnerId,
-                                            wafer.ProcessJob.InnerId,
-                                            recipeName,
-                                            wafer.ProcessJob.Sequence.GetWTWCleanRecipe(pm),
-                                            wafer.ProcessJob.Sequence.LLInOutPath,
-                                            wafer.ProcessJob.Sequence.LLDelayTime,
-                                            IsSequenceNeedAlign(wafer.ProcessJob.Sequence));  // post clean
+
+            int interval = wafer.ProcessJob.Sequence.GetWTWCleanInterval(pm);
+
+            WaferTask waferTask;
+
+            ++_Sequence2PMWaferCount[wafer.ProcessJob.Sequence.Name][pm];
+
+            if (interval == 1 || _Sequence2PMWaferCount[wafer.ProcessJob.Sequence.Name][pm] % interval == 0)
+            {
+                waferTask = new WaferTask((ModuleName)wafer.OriginStation,
+                                                wafer.OriginSlot,
+                                                pm,
+                                                0,
+                                                temperature,
+                                                wafer.InnerId,
+                                                wafer.ProcessJob.InnerId,
+                                                recipeName,
+                                                wafer.ProcessJob.Sequence.GetWTWCleanRecipe(pm),
+                                                wafer.ProcessJob.Sequence.LLInOutPath,
+                                                wafer.ProcessJob.Sequence.LLDelayTime,
+                                                IsSequenceNeedAlign(wafer.ProcessJob.Sequence));  // post clean
+            }
+            else
+            {
+                waferTask = new WaferTask((ModuleName)wafer.OriginStation,
+                                                wafer.OriginSlot,
+                                                pm,
+                                                0,
+                                                temperature,
+                                                wafer.InnerId,
+                                                wafer.ProcessJob.InnerId,
+                                                recipeName,
+                                                "",
+                                                wafer.ProcessJob.Sequence.LLInOutPath,
+                                                wafer.ProcessJob.Sequence.LLDelayTime,
+                                                IsSequenceNeedAlign(wafer.ProcessJob.Sequence));  // post clean
+            }
+
 
             waferTask.OnWaferArrived += WaferArrived;
             waferTask.OnWaferLeaved += WaferLeaved;