|
@@ -473,7 +473,7 @@ namespace Venus_RT.Modules
|
|
|
private Dictionary<ModuleName, int> _lpCycleWafer = new Dictionary<ModuleName, int>();
|
|
|
private Dictionary<ModuleName, int> _lpCycleCount = new Dictionary<ModuleName, int>();
|
|
|
private Dictionary<ModuleName, int> _lpCycleSP = new Dictionary<ModuleName, int>();
|
|
|
- private Dictionary<ModuleName, int> _lpThroughput = new Dictionary<ModuleName, int>();
|
|
|
+ private Dictionary<ModuleName, float> _lpThroughput = new Dictionary<ModuleName, float>();
|
|
|
private Stopwatch _cycleWatch = new Stopwatch();
|
|
|
|
|
|
private SchedulerFACallback _faCallback;
|
|
@@ -605,10 +605,11 @@ namespace Venus_RT.Modules
|
|
|
cj.LotInnerId = Guid.NewGuid();
|
|
|
cj.LotWafers = new List<WaferInfo>();
|
|
|
cj.SetState(EnumControlJobState.WaitingForStart);
|
|
|
- cj.JetState = EnumJetCtrlJobState.Created;
|
|
|
+ cj.JetState = EnumJetCtrlJobState.Quequed;
|
|
|
cj.PreJobClean = preCleanRecipe;
|
|
|
cj.PostJobClean = postCleanRecipe;
|
|
|
cj.SequenceNameList = slotSequence;
|
|
|
+ cj.CycleNumber = SC.GetValue<int>("System.CycleCount"); // only for temperary debug
|
|
|
|
|
|
Dictionary<string, bool[]> seqSlot = new Dictionary<string, bool[]>();
|
|
|
Dictionary<string, List<Tuple<ModuleName, int>>> seqSlotWafers = new Dictionary<string, List<Tuple<ModuleName, int>>>();
|
|
@@ -1204,7 +1205,7 @@ namespace Venus_RT.Modules
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- if(emptyAndReadyIn20sPMs.Count >= 2 && waitInWafers.Count >= 2)
|
|
|
+ if(emptyAndReadyIn20sPMs.Count >= 2 && waitInWafers.Count >= 2 && waitInWafers[0].currentMod == waitInWafers[1].currentMod)
|
|
|
{
|
|
|
var doublePickActions = new List<MoveItem>()
|
|
|
{
|
|
@@ -1621,146 +1622,191 @@ namespace Venus_RT.Modules
|
|
|
if (_lstControlJobs.Count == 0 || _tmRobotStatus == RState.Running)
|
|
|
return;
|
|
|
|
|
|
- bool allControlJobComplete = true;
|
|
|
- List<ControlJobInfo> cjRemoveList = new List<ControlJobInfo>();
|
|
|
-
|
|
|
- var runingJobs = _lstControlJobs.FindAll(cj => cj.State == EnumControlJobState.Executing);
|
|
|
- foreach(var runingjob in runingJobs)
|
|
|
+ var runningJobs = _lstControlJobs.FindAll(cj => cj.State == EnumControlJobState.Executing);
|
|
|
+ var queueJobs = _lstControlJobs.FindAll(cj => cj.State == EnumControlJobState.Queued).OrderBy(cj => cj.StartTime);
|
|
|
+ if (runningJobs.Count == 0)
|
|
|
{
|
|
|
- int countProcessed = 0;
|
|
|
- foreach (var pjName in runingjob.ProcessJobNameList)
|
|
|
+ if (queueJobs.Count() > 0)
|
|
|
{
|
|
|
- var pj = _lstProcessJobs.Find(x => x.Name == pjName);
|
|
|
- if (pj == null)
|
|
|
- {
|
|
|
- LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Not find pj named {pjName} in {runingjob.Name}");
|
|
|
- continue;
|
|
|
- }
|
|
|
+ // start the first waiting job
|
|
|
+ RunControlJob(queueJobs.First());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ foreach (var runningjob in runningJobs)
|
|
|
+ {
|
|
|
+ // update the running job
|
|
|
+ RunControlJob(runningjob);
|
|
|
+ }
|
|
|
|
|
|
- // caculate process wafer by process
|
|
|
- if (_isCycleMode && _cycledCount < (_isCycleMode ? _cycleSetPoint : 0))
|
|
|
+ foreach (var queueJob in queueJobs)
|
|
|
+ {
|
|
|
+ if (!runningJobs.Exists(cj => IsControlJobIntersect(cj, queueJob)))
|
|
|
{
|
|
|
- foreach (var pjSlotWafer in pj.SlotWafers)
|
|
|
- {
|
|
|
- WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
|
|
|
- if (!wafer.IsEmpty && wafer.ProcessState == EnumWaferProcessStatus.Completed)
|
|
|
- countProcessed++;
|
|
|
- }
|
|
|
+ // parallelly start the not intersect job
|
|
|
+ RunControlJob(queueJob);
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- int lpCycleWafer = _lpCycleCount[ModuleHelper.Converter(runingjob.Module)] * runingjob.LotWafers.Count + (runingjob.State == EnumControlJobState.Completed&& runingjob.LotWafers.Count == countProcessed ? 0 : countProcessed);
|
|
|
- if (_lpCycleCount[ModuleHelper.Converter(runingjob.Module)] != _cycledCount || lpCycleWafer != _lpCycleWafer[ModuleHelper.Converter(runingjob.Module)])
|
|
|
+ // update system cycle status
|
|
|
+ if (_lstControlJobs.All(cj => cj.State == EnumControlJobState.Completed))
|
|
|
+ _cycleState = RState.End;
|
|
|
+
|
|
|
+ List<ControlJobInfo> cjRemoveList = new List<ControlJobInfo>();
|
|
|
+ foreach (var cj in _lstControlJobs)
|
|
|
+ {
|
|
|
+ LoadportCassetteState state = (LoadportCassetteState)DATA.Poll($"{cj.Module}.CassetteState");
|
|
|
+ if (cj.State == EnumControlJobState.Completed && state != LoadportCassetteState.Normal)
|
|
|
{
|
|
|
- _lpCycleWafer[ModuleHelper.Converter(runingjob.Module)] = lpCycleWafer;
|
|
|
+ cjRemoveList.Add(cj);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- if (IsAllProcessJobComplete(runingjob))
|
|
|
+ foreach (var cj in cjRemoveList)
|
|
|
+ {
|
|
|
+ List<ProcessJobInfo> pjRemoveList = new List<ProcessJobInfo>();
|
|
|
+ foreach (var pj in _lstProcessJobs)
|
|
|
{
|
|
|
- var PMs = GetWaitPreCleanPMsByCtrlJob(runingjob);
|
|
|
- if (runingjob.JetState == EnumJetCtrlJobState.Processing)
|
|
|
+ if (pj.ControlJobName == cj.Name)
|
|
|
+ pjRemoveList.Add(pj);
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach (var pj in pjRemoveList)
|
|
|
+ {
|
|
|
+ _lstProcessJobs.Remove(pj);
|
|
|
+ }
|
|
|
+
|
|
|
+ _lstControlJobs.Remove(cj);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool RunControlJob(ControlJobInfo cj)
|
|
|
+ {
|
|
|
+ switch (cj.JetState)
|
|
|
+ {
|
|
|
+ case EnumJetCtrlJobState.Quequed:
|
|
|
{
|
|
|
- // subscribe clean task
|
|
|
- foreach (var pm in PMs)
|
|
|
+ if (IsCtrlJobNeedPreClean(cj))
|
|
|
{
|
|
|
- var pmTask = _dictModuleTask[pm] as VenusPMTask;
|
|
|
- if (pmTask != null && pmTask.Scheduler.IsOnline)
|
|
|
+ cj.JetState = EnumJetCtrlJobState.PreJobClean;
|
|
|
+
|
|
|
+ var PMs = GetWaitPreCleanPMsByCtrlJob(cj);
|
|
|
+ foreach (var pm in PMs)
|
|
|
{
|
|
|
- pmTask.SubscribeLotCleanTask(runingjob, VenusPMTask.RecipeJobType.PostClean);
|
|
|
+ var pmTask = _dictModuleTask[pm] as VenusPMTask;
|
|
|
+ if (pmTask != null && pmTask.Scheduler.IsOnline)
|
|
|
+ {
|
|
|
+ pmTask.SubscribeLotCleanTask(cj, VenusPMTask.RecipeJobType.PreClean);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ActiveControlJob(cj);
|
|
|
+ }
|
|
|
|
|
|
- runingjob.JetState = EnumJetCtrlJobState.PostJobClean;
|
|
|
+ cj.SetState(EnumControlJobState.Executing);
|
|
|
}
|
|
|
- else if (runingjob.JetState == EnumJetCtrlJobState.PostJobClean)
|
|
|
+ break;
|
|
|
+ case EnumJetCtrlJobState.PreJobClean:
|
|
|
{
|
|
|
- foreach (var pm in PMs)
|
|
|
+ if (IsPreJobCleanDone(cj))
|
|
|
{
|
|
|
- var pmTask = _dictModuleTask[pm] as VenusPMTask;
|
|
|
- if (pmTask != null && pmTask.Scheduler.IsOnline && !pmTask.IsAllJobCompleted())
|
|
|
- return;
|
|
|
+ ActiveControlJob(cj);
|
|
|
}
|
|
|
-
|
|
|
- runingjob.JetState = EnumJetCtrlJobState.Completed;
|
|
|
- runingjob.SetState(EnumControlJobState.Completed);
|
|
|
- runingjob.EndTime = DateTime.Now;
|
|
|
-
|
|
|
- _faCallback.JobFinished(runingjob, GetFirstProcessJob(runingjob));
|
|
|
- _dbCallback.LotFinished(runingjob);
|
|
|
-
|
|
|
- if (!(_isCycleMode && _cycledCount < _cycleSetPoint))
|
|
|
- (Singleton<TransferModule>.Instance.GetScheduler(ModuleHelper.Converter(runingjob.Module)) as SchedulerLoadPort).NoteJobComplete();
|
|
|
-
|
|
|
- _lpCycleCount[ModuleHelper.Converter(runingjob.Module)]++;
|
|
|
}
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- var pendingJobs = _lstControlJobs.FindAll(cj => cj.State == EnumControlJobState.Queued).OrderBy(cj => cj.StartTime);
|
|
|
- if(pendingJobs.Count() > 0)
|
|
|
- {
|
|
|
- if (runingJobs.Count == 0)
|
|
|
- {
|
|
|
- pendingJobs.First().JetState = EnumJetCtrlJobState.Processing;
|
|
|
- ActiveControlJob(pendingJobs.First());
|
|
|
-
|
|
|
- // subscribe clean task
|
|
|
- var PMs = GetWaitPreCleanPMsByCtrlJob(pendingJobs.First());
|
|
|
- foreach (var pm in PMs)
|
|
|
+ break;
|
|
|
+ case EnumJetCtrlJobState.Processing:
|
|
|
{
|
|
|
- var pmTask = _dictModuleTask[pm] as VenusPMTask;
|
|
|
- if (pmTask != null && pmTask.Scheduler.IsOnline)
|
|
|
+ if (IsCtrlJobNeedPostClean(cj))
|
|
|
{
|
|
|
- pmTask.SubscribeLotCleanTask(pendingJobs.First(), VenusPMTask.RecipeJobType.PreClean);
|
|
|
+ if (IsAllJobWaferProcessedOrProcessing(cj))
|
|
|
+ {
|
|
|
+ cj.JetState = EnumJetCtrlJobState.PostJobClean;
|
|
|
+ var PMs = GetWaitPreCleanPMsByCtrlJob(cj);
|
|
|
+ foreach (var pm in PMs)
|
|
|
+ {
|
|
|
+ var pmTask = _dictModuleTask[pm] as VenusPMTask;
|
|
|
+ if (pmTask != null && pmTask.Scheduler.IsOnline)
|
|
|
+ {
|
|
|
+ pmTask.SubscribeLotCleanTask(cj, VenusPMTask.RecipeJobType.PostClean);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (IsAllProcessJobComplete(cj))
|
|
|
+ {
|
|
|
+ cj.JetState = EnumJetCtrlJobState.Completed;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
+ break;
|
|
|
+ case EnumJetCtrlJobState.PostJobClean:
|
|
|
+ {
|
|
|
+ if (IsPostJobCleanDone(cj))
|
|
|
+ {
|
|
|
+ cj.JetState = EnumJetCtrlJobState.Completed;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
- foreach(var cj in _lstControlJobs)
|
|
|
+ // caculate processed wafer by control job
|
|
|
+ var lp = ModuleHelper.Converter(cj.Module);
|
|
|
+ int countProcessed = 0;
|
|
|
+ foreach (var pjName in cj.ProcessJobNameList)
|
|
|
{
|
|
|
- LoadportCassetteState state = (LoadportCassetteState)DATA.Poll($"{cj.Module}.CassetteState");
|
|
|
- if (cj.State == EnumControlJobState.Completed && state != LoadportCassetteState.Normal)
|
|
|
+ var pj = _lstProcessJobs.Find(x => x.Name == pjName);
|
|
|
+ if (pj == null)
|
|
|
{
|
|
|
- cjRemoveList.Add(cj);
|
|
|
+ LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Not find pj named {pjName} in {cj.Name}");
|
|
|
+ continue;
|
|
|
}
|
|
|
|
|
|
- allControlJobComplete = allControlJobComplete && cj.State == EnumControlJobState.Completed;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- if (_isCycleMode && _cycledCount < (_isCycleMode ? _cycleSetPoint : 0))
|
|
|
- {
|
|
|
- int totolCycleWafer = _lpCycleWafer.Sum(item => item.Value);
|
|
|
- if (totolCycleWafer != _cycledWafer || _lpCycleCount.Sum(item => item.Value) > 0 && _throughput < 0.01) // refresh _throughput in time
|
|
|
+ // caculate process wafer by process
|
|
|
+ if (_lpCycleCount[lp] < cj.CycleNumber)
|
|
|
{
|
|
|
- _cycledWafer = totolCycleWafer;
|
|
|
- if (_cycledCount > 0 || allControlJobComplete)
|
|
|
+ foreach (var pjSlotWafer in pj.SlotWafers)
|
|
|
{
|
|
|
- _throughput = (float)(_cycledWafer / _cycleWatch.Elapsed.TotalHours);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- _throughput = 0;
|
|
|
+ WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
|
|
|
+ if (!wafer.IsEmpty && wafer.ProcessState == EnumWaferProcessStatus.Completed)
|
|
|
+ countProcessed++;
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ int lpCycleWafer = 0;
|
|
|
+ if (cj.JetState == EnumJetCtrlJobState.Completed)
|
|
|
+ {
|
|
|
+ cj.EndTime = DateTime.Now;
|
|
|
+
|
|
|
+ _faCallback.JobFinished(cj, GetFirstProcessJob(cj));
|
|
|
+ _dbCallback.LotFinished(cj);
|
|
|
+
|
|
|
+ if (_lpCycleCount[lp] >= cj.CycleNumber)
|
|
|
+ (Singleton<TransferModule>.Instance.GetScheduler(lp) as SchedulerLoadPort).NoteJobComplete();
|
|
|
|
|
|
- if (allControlJobComplete)
|
|
|
+ _lpCycleCount[lp]++;
|
|
|
+ lpCycleWafer = _lpCycleCount[lp] * cj.LotWafers.Count;
|
|
|
+ _lpThroughput[lp] = (float)(lpCycleWafer / (DateTime.Now - cj.StartTime).TotalHours);
|
|
|
+ LOG.Write(eEvent.EV_ROUTER, lp, $"Cycle Count: {_lpCycleCount[lp]}, Total Processed Wafer: {lpCycleWafer}, Throughput: {_lpThroughput[lp]}");
|
|
|
+
|
|
|
+ if (_lpCycleCount[lp] < cj.CycleNumber)
|
|
|
{
|
|
|
- _cycledCount++;
|
|
|
+ cj.SetState(EnumControlJobState.Executing);
|
|
|
+ cj.JetState = EnumJetCtrlJobState.Quequed;
|
|
|
|
|
|
- LOG.Write(eEvent.EV_ROUTER, ModuleName.System, $"Cycle Count: {_cycledCount}, Total Processed Wafer: {_cycledWafer}, Throughput: {_throughput}");
|
|
|
- if (_cycledCount < _cycleSetPoint)
|
|
|
- {
|
|
|
- foreach (var cj in _lstControlJobs)
|
|
|
- {
|
|
|
- cj.SetState(EnumControlJobState.Queued);
|
|
|
+ cj.LotInnerId = Guid.NewGuid();
|
|
|
|
|
|
- cj.LotInnerId = Guid.NewGuid();
|
|
|
+ _dbCallback.LotCreated(cj);
|
|
|
|
|
|
- _dbCallback.LotCreated(cj);
|
|
|
- }
|
|
|
- foreach (var pj in _lstProcessJobs)
|
|
|
+ foreach (var pj in _lstProcessJobs)
|
|
|
+ {
|
|
|
+ if (pj.ControlJobName == cj.Name)
|
|
|
{
|
|
|
pj.SetState(EnumProcessJobState.Queued);
|
|
|
pj.InnerId = Guid.NewGuid();
|
|
@@ -1773,33 +1819,73 @@ namespace Venus_RT.Modules
|
|
|
wafer.ProcessState = EnumWaferProcessStatus.Idle;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- _lstWaferTasks.Clear();
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- _cycleState = RState.End;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ _lstWaferTasks.RemoveAll(wt => wt.currentMod == lp);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ cj.SetState(EnumControlJobState.Completed);
|
|
|
}
|
|
|
}
|
|
|
+ else
|
|
|
+ {
|
|
|
+ lpCycleWafer = _lpCycleCount[lp] * cj.LotWafers.Count + countProcessed;
|
|
|
+ }
|
|
|
|
|
|
- foreach (var cj in cjRemoveList)
|
|
|
+ if (lpCycleWafer != _lpCycleWafer[lp])
|
|
|
{
|
|
|
- List<ProcessJobInfo> pjRemoveList = new List<ProcessJobInfo>();
|
|
|
- foreach (var pj in _lstProcessJobs)
|
|
|
+ _lpCycleWafer[lp] = lpCycleWafer;
|
|
|
+ if (_lpCycleCount[lp] > 0)
|
|
|
{
|
|
|
- if (pj.ControlJobName == cj.Name)
|
|
|
- pjRemoveList.Add(pj);
|
|
|
+ _lpThroughput[lp] = (float)(lpCycleWafer / (DateTime.Now - cj.StartTime).TotalHours);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- foreach (var pj in pjRemoveList)
|
|
|
- {
|
|
|
- _lstProcessJobs.Remove(pj);
|
|
|
- }
|
|
|
+ return cj.State == EnumControlJobState.Completed;
|
|
|
+ }
|
|
|
|
|
|
- _lstControlJobs.Remove(cj);
|
|
|
+ private bool IsControlJobIntersect(ControlJobInfo cj1, ControlJobInfo cj2)
|
|
|
+ {
|
|
|
+ var cj1Pms = GetWaitPreCleanPMsByCtrlJob(cj1);
|
|
|
+ var cj2Pms = GetWaitPreCleanPMsByCtrlJob(cj2);
|
|
|
+
|
|
|
+ return cj1Pms.Intersect(cj2Pms).Count() > 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool IsCtrlJobNeedPreClean(ControlJobInfo cj)
|
|
|
+ {
|
|
|
+ return !string.IsNullOrWhiteSpace(cj.PreJobClean);
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool IsCtrlJobNeedPostClean(ControlJobInfo cj)
|
|
|
+ {
|
|
|
+ return !string.IsNullOrWhiteSpace(cj.PostJobClean.Trim());
|
|
|
+ }
|
|
|
+ private bool IsPreJobCleanDone(ControlJobInfo cj)
|
|
|
+ {
|
|
|
+ var pms = GetWaitPreCleanPMsByCtrlJob(cj);
|
|
|
+ foreach (var pm in pms)
|
|
|
+ {
|
|
|
+ var pmTask = _dictModuleTask[pm] as PMTask;
|
|
|
+ if (pmTask.Scheduler.IsOnline && !pmTask.IsPreJobCleanDone())
|
|
|
+ return false;
|
|
|
}
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool IsPostJobCleanDone(ControlJobInfo cj)
|
|
|
+ {
|
|
|
+ var pms = GetWaitPreCleanPMsByCtrlJob(cj);
|
|
|
+ foreach (var pm in pms)
|
|
|
+ {
|
|
|
+ var pmTask = _dictModuleTask[pm] as PMTask;
|
|
|
+ if (pmTask.Scheduler.IsOnline && !pmTask.IsPostJobCleanDone())
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
private bool ActiveProcessJob(ProcessJobInfo pj)
|
|
@@ -1826,7 +1912,7 @@ namespace Venus_RT.Modules
|
|
|
|
|
|
private bool ActiveControlJob(ControlJobInfo cj)
|
|
|
{
|
|
|
- cj.SetState(EnumControlJobState.Executing);
|
|
|
+ cj.JetState = EnumJetCtrlJobState.Processing;
|
|
|
foreach (var pjName in cj.ProcessJobNameList)
|
|
|
{
|
|
|
var pj = _lstProcessJobs.Find(x => x.Name == pjName);
|
|
@@ -1923,20 +2009,36 @@ namespace Venus_RT.Modules
|
|
|
|
|
|
private void CreateNewWaferTask()
|
|
|
{
|
|
|
- var cj = _lstControlJobs.Find(job => job.State == EnumControlJobState.Executing);
|
|
|
- if (cj != null)
|
|
|
+ var runningJobs = _lstControlJobs.FindAll(cj => cj.JetState == EnumJetCtrlJobState.PreJobClean || cj.JetState == EnumJetCtrlJobState.Processing);
|
|
|
+ var onDutyPms = new Dictionary<ModuleName, int>();
|
|
|
+ foreach (var job in runningJobs)
|
|
|
+ {
|
|
|
+ var pms = GetWaitPreCleanPMsByCtrlJob(job);
|
|
|
+ foreach (var pm in pms)
|
|
|
+ {
|
|
|
+ if (_dictModuleTask[pm].Scheduler.IsOnline && !onDutyPms.ContainsKey(pm))
|
|
|
+ {
|
|
|
+ onDutyPms[pm] = _lstWaferTasks.Where(wt => wt.destMod == pm).Count();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (runningJobs.Count == 0 || onDutyPms.Count == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ var oderedPMs = onDutyPms.OrderBy(kv => kv.Value).OrderBy(kv => _dictModuleTask[kv.Key].TimeToReady);
|
|
|
+ if (oderedPMs.First().Value < 1)
|
|
|
{
|
|
|
- var pm = GetComingAvailablePM(cj);
|
|
|
- if (pm != ModuleName.System)
|
|
|
+ foreach (var runningJob in runningJobs)
|
|
|
{
|
|
|
- foreach (var wafer in cj.LotWafers)
|
|
|
+ foreach (var wafer in runningJob.LotWafers)
|
|
|
{
|
|
|
if (wafer.IsEmpty || wafer.ProcessJob == null)
|
|
|
continue;
|
|
|
|
|
|
- if (wafer.ProcessJob.Sequence.PMs.Contains(pm) && wafer.NextSequenceStep == 0 && !_lstWaferTasks.Exists(task => task.sourceMod == (ModuleName)wafer.OriginStation && task.sourceSlot == wafer.OriginSlot))
|
|
|
+ if (wafer.ProcessJob.Sequence.PMs.Contains(oderedPMs.First().Key) && wafer.NextSequenceStep == 0 && !_lstWaferTasks.Exists(task => task.sourceMod == (ModuleName)wafer.OriginStation && task.sourceSlot == wafer.OriginSlot))
|
|
|
{
|
|
|
- CreateWaferTasks(wafer, pm);
|
|
|
+ CreateWaferTasks(wafer, oderedPMs.First().Key);
|
|
|
return;
|
|
|
}
|
|
|
}
|