|
@@ -848,6 +848,12 @@ namespace Venus_RT.Modules
|
|
|
LowerInUpperOut,
|
|
|
}
|
|
|
|
|
|
+ enum SpecialRoutingPattern
|
|
|
+ {
|
|
|
+ Disable,
|
|
|
+ LongTimeRecipe,
|
|
|
+ }
|
|
|
+
|
|
|
class SystemDispatcher : ICycle
|
|
|
{
|
|
|
private List<ControlJobInfo> _lstControlJobs = new List<ControlJobInfo>();
|
|
@@ -882,9 +888,12 @@ 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 Stopwatch _cycleWatch = new Stopwatch();
|
|
|
|
|
|
private SequenceLLInOutPath _LLInOutPath = SequenceLLInOutPath.DInDOut;
|
|
|
+ private SpecialRoutingPattern _specialRoutingPattern = SpecialRoutingPattern.Disable;
|
|
|
|
|
|
public SequenceLLInOutPath LLInOutPath => _LLInOutPath;
|
|
|
|
|
@@ -953,6 +962,7 @@ namespace Venus_RT.Modules
|
|
|
_efemRobotSingleArmOption = SC.GetValue<int>("EFEM.SingleArmOption");
|
|
|
_tmRobotSingleArmOption = SC.GetValue<int>("TM.SingleArmOption");
|
|
|
_LLSlotInOutOption = (LLSlotInOutOpt)SC.GetValue<int>("System.LoadlockSlotInOutOption");
|
|
|
+ _specialRoutingPattern = (SpecialRoutingPattern)SC.GetValue<int>("System.SpecialRoutingPattern");
|
|
|
|
|
|
// rounding TM robot single arm option
|
|
|
if(_tmRobotSingleArmOption > 2 && _LLSlotInOutOption == LLSlotInOutOpt.AllInAllOut)
|
|
@@ -968,6 +978,7 @@ namespace Venus_RT.Modules
|
|
|
_lpCycleCount = new Dictionary<ModuleName, int> { { ModuleName.LP1, 0 }, { ModuleName.LP2, 0 }, { ModuleName.LP3, 0 } };
|
|
|
_lpCycleSP = new Dictionary<ModuleName, int> { { ModuleName.LP1, 1 }, { ModuleName.LP2, 1 }, { ModuleName.LP3, 1 } };
|
|
|
_lpThroughput = new Dictionary<ModuleName, float> { { ModuleName.LP1, 0 }, { ModuleName.LP2, 0 }, { ModuleName.LP3, 0 } };
|
|
|
+ _lpCycleWatch = new Dictionary<ModuleName, Stopwatch> { { ModuleName.LP1, new Stopwatch() }, { ModuleName.LP2, new Stopwatch() }, { ModuleName.LP3, new Stopwatch() } };
|
|
|
|
|
|
return RState.Running;
|
|
|
}
|
|
@@ -1004,7 +1015,7 @@ namespace Venus_RT.Modules
|
|
|
{
|
|
|
jobId = "CJ_Local_" + module;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
foreach (var item in _loadportControlJobDic.Values)
|
|
|
{
|
|
|
if (item?.Name == jobId)
|
|
@@ -1016,7 +1027,7 @@ namespace Venus_RT.Modules
|
|
|
}
|
|
|
string lotId = (string)param["LotId"];
|
|
|
if (string.IsNullOrEmpty(lotId))
|
|
|
- {
|
|
|
+ {
|
|
|
lotId = "CJ_Local_" + module;
|
|
|
}
|
|
|
|
|
@@ -1172,7 +1183,6 @@ namespace Venus_RT.Modules
|
|
|
//AssociatedPMWithLP(cj);
|
|
|
_loadportControlJobDic[cj.Module] = cj;
|
|
|
|
|
|
-
|
|
|
_faCallback.JobCreated(cj, GetFirstProcessJob(cj));
|
|
|
return true;
|
|
|
}
|
|
@@ -1966,7 +1976,7 @@ namespace Venus_RT.Modules
|
|
|
var lp = ModuleHelper.Converter(cj.Module);
|
|
|
if (_lpCycleCount[lp] > 0)
|
|
|
{
|
|
|
- _lpThroughput[lp] = (float)(_lpCycleWafer[lp] / (DateTime.Now - cj.StartTime).TotalHours);
|
|
|
+ _lpThroughput[lp] = (float)((_lpCycleWafer[lp] - 2) / _lpCycleWatch[lp].Elapsed.TotalHours);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -2099,6 +2109,12 @@ namespace Venus_RT.Modules
|
|
|
_faCallback.JobWaferEnd(currentControlJob, item.SourceSlot);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ if(ModuleHelper.IsLoadPort(item.DestinationModule))
|
|
|
+ {
|
|
|
+ if (!_lpCycleWatch[wafer.sourceMod].IsRunning)
|
|
|
+ _lpCycleWatch[wafer.sourceMod].Start();
|
|
|
+ }
|
|
|
//--2024-03-21 增加了PortJobWaferEnd 上报事件 end--
|
|
|
}
|
|
|
|
|
@@ -2209,6 +2225,9 @@ namespace Venus_RT.Modules
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (_tmRobotStatus == RState.Running)
|
|
|
+ return;
|
|
|
+
|
|
|
// keep two raw atm wafer, try match a double place to LL
|
|
|
var atmWaferCount = _lstWaferTasks.Count(wt => ModuleHelper.IsPm(wt.destMod) && (ModuleHelper.IsLoadPort(wt.currentMod) || ModuleHelper.IsAligner(wt.currentMod) || ModuleHelper.IsEFEMRobot(wt.currentMod) || ModuleHelper.IsLoadLock(wt.currentMod)));
|
|
|
if (atmWaferCount < 2)
|
|
@@ -2217,6 +2236,22 @@ namespace Venus_RT.Modules
|
|
|
if (busyPMs.Count() == 0)
|
|
|
return;
|
|
|
|
|
|
+ ModuleName nextPM = busyPMs.First().Key;
|
|
|
+ if (_lpCycleWafer.Sum(kv => kv.Value) == 0)
|
|
|
+ {
|
|
|
+ if (busyPMs.ToList().Exists(kv => _dictModuleTask[kv.Key].TimeToReady > 36000) && busyPMs.ToList().Exists(pv => _dictModuleTask[pv.Key].TimeToReady < 3600))
|
|
|
+ {
|
|
|
+ foreach (var pm in busyPMs)
|
|
|
+ {
|
|
|
+ if (_dictModuleTask[pm.Key].TimeToReady > 36000)
|
|
|
+ {
|
|
|
+ nextPM = pm.Key;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
foreach (var runningJob in runningJobs)
|
|
|
{
|
|
|
if (_qePollingJobs.Contains(runningJob) && _qePollingJobs.First() != runningJob)
|
|
@@ -2227,9 +2262,9 @@ namespace Venus_RT.Modules
|
|
|
if (wafer.IsEmpty || wafer.ProcessJob == null)
|
|
|
continue;
|
|
|
|
|
|
- if (wafer.ProcessJob.Sequence.PMs.Contains(busyPMs.First().Key) && wafer.NextSequenceStep == 0 && !_lstWaferTasks.Exists(task => task.sourceMod == (ModuleName)wafer.OriginStation && task.sourceSlot == wafer.OriginSlot))
|
|
|
+ if (wafer.ProcessJob.Sequence.PMs.Contains(nextPM) && wafer.NextSequenceStep == 0 && !_lstWaferTasks.Exists(task => task.sourceMod == (ModuleName)wafer.OriginStation && task.sourceSlot == wafer.OriginSlot))
|
|
|
{
|
|
|
- CreateWaferTasks(wafer, busyPMs.First().Key);
|
|
|
+ CreateWaferTasks(wafer, nextPM);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
@@ -3282,7 +3317,44 @@ namespace Venus_RT.Modules
|
|
|
|
|
|
if(robotWafers.Count == 0)
|
|
|
{
|
|
|
- if(_dictModuleTask.Count(mod => ModuleHelper.IsPm(mod.Key) && mod.Value.HasWafer && mod.Value.TimeToReady < 5) > 0 && outLLModule.ReayForTMInTime(30) && outLLWaferStatus.emptySlot.Count > 0)
|
|
|
+ #region special routing pattern
|
|
|
+ if (_specialRoutingPattern != SpecialRoutingPattern.Disable)
|
|
|
+ {
|
|
|
+ if(_specialRoutingPattern == SpecialRoutingPattern.LongTimeRecipe && freeHands.Count == 2)
|
|
|
+ {
|
|
|
+ if(_dictModuleTask.Where(mod => ModuleHelper.IsPm(mod.Key) && !mod.Value.HasWafer).Count() == 0)
|
|
|
+ {
|
|
|
+ var readyOutPMs = _dictModuleTask.Where(mod => ModuleHelper.IsPm(mod.Key) && mod.Value.HasWafer && mod.Value.TimeToReady < 25).OrderBy(mod => mod.Value.TimeToReady).ToList();
|
|
|
+ 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)
|
|
|
+ {
|
|
|
+ _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(inLL, llWafer.currentSlot, ModuleName.TMRobot, (int)freeHands[0], freeHands[0]) });
|
|
|
+
|
|
|
+ var pmSwap = new List<MoveItem>
|
|
|
+ { new MoveItem(readyOutPMs.First().Key, 0, ModuleName.TMRobot, (int)freeHands[1], freeHands[1]),
|
|
|
+ new MoveItem(ModuleName.TMRobot, (int)freeHands[0], readyOutPMs.First().Key, 0, freeHands[0])
|
|
|
+ };
|
|
|
+
|
|
|
+ _tmSchdActions.Enqueue(pmSwap);
|
|
|
+
|
|
|
+ if(outLLModule.ReayForTMInTime(25) && outLLWaferStatus.emptySlot.Count > 0)
|
|
|
+ {
|
|
|
+ _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, (int)freeHands[1], outLL, outLLWaferStatus.emptySlot[0], freeHands[1]) });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+
|
|
|
+ if (_dictModuleTask.Count(mod => ModuleHelper.IsPm(mod.Key) && mod.Value.HasWafer && mod.Value.TimeToReady < 5) > 0 && outLLModule.ReayForTMInTime(30) && outLLWaferStatus.emptySlot.Count > 0)
|
|
|
{
|
|
|
var readyOutPMs = _dictModuleTask.Where(mod => ModuleHelper.IsPm(mod.Key) && mod.Value.HasWafer && mod.Value.TimeToReady < 25).OrderBy(mod => mod.Value.TimeToReady).ToList();
|
|
|
var placeActions = new List<MoveItem>();
|
|
@@ -3330,7 +3402,29 @@ namespace Venus_RT.Modules
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- foreach(var robotWafer in robotWafers)
|
|
|
+ #region special routing pattern
|
|
|
+ if (_specialRoutingPattern != SpecialRoutingPattern.Disable)
|
|
|
+ {
|
|
|
+ if (_specialRoutingPattern == SpecialRoutingPattern.LongTimeRecipe && _tmRobotSingleArmOption == 0)
|
|
|
+ {
|
|
|
+ if(_dictModuleTask.Where(mod => ModuleHelper.IsPm(mod.Key) && !mod.Value.HasWafer).Count() == 0)
|
|
|
+ {
|
|
|
+ if (ModuleHelper.IsLoadPort(robotWafers[0].destMod))
|
|
|
+ {
|
|
|
+ if (outLLModule.ReayForTMInTime(10) && outLLWaferStatus.emptySlot.Count > 0)
|
|
|
+ {
|
|
|
+ _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, robotWafers[0].currentSlot, outLL, outLLWaferStatus.emptySlot[0], (Hand)(robotWafers[0].currentSlot)) });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ foreach (var robotWafer in robotWafers)
|
|
|
{
|
|
|
if (ModuleHelper.IsPm(robotWafer.destMod))
|
|
|
{
|