|
@@ -24,6 +24,8 @@ using Venus_Core;
|
|
|
using Venus_RT.Modules.Schedulers;
|
|
|
using Venus_RT.Scheduler;
|
|
|
using Venus_Unity;
|
|
|
+using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.PMs;
|
|
|
+using System.Linq.Expressions;
|
|
|
|
|
|
namespace Venus_RT.Modules
|
|
|
{
|
|
@@ -786,6 +788,8 @@ namespace Venus_RT.Modules
|
|
|
private LLSlotInOutOpt _LLSlotInOutOption = 0;
|
|
|
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 Stopwatch _cycleWatch = new Stopwatch();
|
|
|
|
|
|
private SequenceLLInOutPath _LLInOutPath = SequenceLLInOutPath.DInDOut;
|
|
@@ -812,20 +816,19 @@ namespace Venus_RT.Modules
|
|
|
|
|
|
InitModules();
|
|
|
|
|
|
- DATA.Subscribe("Scheduler.CycledCount", () => _cycledCount, SubscriptionAttribute.FLAG.IgnoreSaveDB);
|
|
|
- DATA.Subscribe("Scheduler.CycledWafer", () => _cycledWafer, SubscriptionAttribute.FLAG.IgnoreSaveDB);
|
|
|
- DATA.Subscribe("Scheduler.CycleSetPoint", () => _cycleSetPoint, SubscriptionAttribute.FLAG.IgnoreSaveDB);
|
|
|
- DATA.Subscribe("Scheduler.Throughput", () => _throughput, SubscriptionAttribute.FLAG.IgnoreSaveDB);
|
|
|
-
|
|
|
-
|
|
|
DATA.Subscribe("Scheduler.PjIdList", () => Array.ConvertAll(_lstProcessJobs.ToArray(), x => x.InnerId.ToString()).ToList());
|
|
|
DATA.Subscribe("Scheduler.PjNameList", () => Array.ConvertAll(_lstProcessJobs.ToArray(), x => x.LotName.ToString()).ToList());
|
|
|
DATA.Subscribe("Scheduler.InUsingRecipe", () => InUseRecipes);
|
|
|
- for (int i = 1; i <= 3; i++)
|
|
|
+
|
|
|
+ foreach(var lp in new List<ModuleName> { ModuleName.LP1, ModuleName.LP2, ModuleName.LP3})
|
|
|
{
|
|
|
- _loadportControlJobDic[$"LP{i}"] = null;
|
|
|
- string lp = $"LP{i}";
|
|
|
- DATA.Subscribe($"{lp}.CurrentControlJob", () => _loadportControlJobDic[lp], SubscriptionAttribute.FLAG.IgnoreSaveDB);
|
|
|
+ _loadportControlJobDic[lp.ToString()] = null;
|
|
|
+ DATA.Subscribe($"{lp}.CurrentControlJob", () => _loadportControlJobDic[lp.ToString()], SubscriptionAttribute.FLAG.IgnoreSaveDB);
|
|
|
+
|
|
|
+ DATA.Subscribe($"{lp}.CycledCount", () => _lpCycleCount[lp], SubscriptionAttribute.FLAG.IgnoreSaveDB);
|
|
|
+ DATA.Subscribe($"{lp}.CycledWafer", () => _lpCycleWafer[lp], SubscriptionAttribute.FLAG.IgnoreSaveDB);
|
|
|
+ DATA.Subscribe($"{lp}.CycleSetPoint", () => _lpCycleSP[lp], SubscriptionAttribute.FLAG.IgnoreSaveDB);
|
|
|
+ DATA.Subscribe($"{lp}.Throughput", () => _lpThroughput[lp], SubscriptionAttribute.FLAG.IgnoreSaveDB);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -952,6 +955,7 @@ namespace Venus_RT.Modules
|
|
|
cj.PreJobClean = preCleanRecipe;
|
|
|
cj.PostJobClean = postCleanRecipe;
|
|
|
cj.SequenceNameList = slotSequence;
|
|
|
+ cj.CycleNumber = _cycleSetPoint;
|
|
|
|
|
|
Dictionary<string, bool[]> seqSlot = new Dictionary<string, bool[]>();
|
|
|
Dictionary<string, List<Tuple<ModuleName, int>>> seqSlotWafers = new Dictionary<string, List<Tuple<ModuleName, int>>>();
|
|
@@ -1528,132 +1532,51 @@ namespace Venus_RT.Modules
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private bool IsControlJobIntersect(ControlJobInfo cj1, ControlJobInfo cj2)
|
|
|
+ {
|
|
|
+ var cj1Pms = GetWaitPreCleanPMsByCtrlJob(cj1);
|
|
|
+ var cj2Pms = GetWaitPreCleanPMsByCtrlJob(cj2);
|
|
|
+
|
|
|
+ return cj1Pms.Intersect(cj2Pms).Count() > 0;
|
|
|
+ }
|
|
|
+
|
|
|
private void UpdateControlJobStatus()
|
|
|
{
|
|
|
if (_lstControlJobs.Count == 0 || _efemRobotStatus == RState.Running || _tmRobotStatus == RState.Running)
|
|
|
return;
|
|
|
|
|
|
- bool allControlJobComplete = true;
|
|
|
- List<ControlJobInfo> cjRemoveList = new List<ControlJobInfo>();
|
|
|
- foreach (var cj in _lstControlJobs)
|
|
|
+ var runningJobs = _lstControlJobs.FindAll(cj => IsCtrlJobRuning(cj));
|
|
|
+ var queueJobs = _lstControlJobs.FindAll(cj => cj.JetState == EnumJetCtrlJobState.Quequed).OrderBy(cj => cj.StartTime);
|
|
|
+ if (runningJobs.Count == 0)
|
|
|
{
|
|
|
- if (cj.JetState == EnumJetCtrlJobState.Quequed) // active quequed control job: need prejob clean or don need prejob clean
|
|
|
+ if(queueJobs.Count() > 0)
|
|
|
{
|
|
|
- var runingJobs = _lstControlJobs.FindAll(job => IsCtrlJobRuning(job));
|
|
|
- if (runingJobs.Count == 0 || (runingJobs.Count == 1 && IsCtrlJobEndingState(runingJobs.First())))
|
|
|
- {
|
|
|
- var quequedJobs = _lstControlJobs.FindAll(job => job.JetState == EnumJetCtrlJobState.Quequed);
|
|
|
- var firstQuequeJob = quequedJobs.OrderBy(job => job.StartTime).First();
|
|
|
- if (firstQuequeJob.InnerId == cj.InnerId)
|
|
|
- {
|
|
|
- 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);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ // start the first waiting job
|
|
|
+ RunControlJob(queueJobs.First());
|
|
|
}
|
|
|
- else if (IsCtrlJobRuning(cj))
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ foreach(var runningjob in runningJobs)
|
|
|
{
|
|
|
- if (cj.JetState == EnumJetCtrlJobState.PreJobClean)
|
|
|
- {
|
|
|
- if (IsPreJobCleanDone(cj))
|
|
|
- {
|
|
|
- ActiveControlJob(cj);
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- if (cj.JetState == EnumJetCtrlJobState.Processing && IsCtrlJobNeedPostClean(cj)) // active post job clean
|
|
|
- {
|
|
|
- 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);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // control job complete
|
|
|
- if (IsAllProcessJobComplete(cj) && (!IsCtrlJobNeedPostClean(cj) || cj.JetState == EnumJetCtrlJobState.PostJobClean && IsPostJobCleanDone(cj)))
|
|
|
- {
|
|
|
- cj.JetState = EnumJetCtrlJobState.Completed;
|
|
|
-
|
|
|
- cj.SetState(EnumControlJobState.Completed);
|
|
|
- cj.EndTime = DateTime.Now;
|
|
|
-
|
|
|
- _faCallback.JobFinished(cj, GetFirstProcessJob(cj));
|
|
|
- _dbCallback.LotFinished(cj);
|
|
|
-
|
|
|
- if (!(_isCycleMode && _cycledCount < _cycleSetPoint))
|
|
|
- (Singleton<TransferModule>.Instance.GetScheduler(ModuleHelper.Converter(cj.Module)) as SchedulerLoadPort).NoteJobComplete();
|
|
|
-
|
|
|
- _lpCycleCount[ModuleHelper.Converter(cj.Module)]++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- int countProcessed = 0;
|
|
|
- foreach (var pjName in cj.ProcessJobNameList)
|
|
|
- {
|
|
|
- var pj = _lstProcessJobs.Find(x => x.Name == pjName);
|
|
|
- if (pj == null)
|
|
|
- {
|
|
|
- LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Not find pj named {pjName} in {cj.Name}");
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- // caculate process wafer by process
|
|
|
- if (_isCycleMode && _cycledCount < (_isCycleMode ? _cycleSetPoint : 0))
|
|
|
- {
|
|
|
- foreach (var pjSlotWafer in pj.SlotWafers)
|
|
|
- {
|
|
|
- WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
|
|
|
- if (!wafer.IsEmpty && wafer.ProcessState == EnumWaferProcessStatus.Completed)
|
|
|
- countProcessed++;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- int lpCycleWafer = _lpCycleCount[ModuleHelper.Converter(cj.Module)] * cj.LotWafers.Count + (cj.JetState == EnumJetCtrlJobState.Completed && cj.LotWafers.Count == countProcessed ? 0 : countProcessed);
|
|
|
- if (_lpCycleCount[ModuleHelper.Converter(cj.Module)] != _cycledCount || lpCycleWafer != _lpCycleWafer[ModuleHelper.Converter(cj.Module)])
|
|
|
- {
|
|
|
- _lpCycleWafer[ModuleHelper.Converter(cj.Module)] = lpCycleWafer;
|
|
|
- }
|
|
|
-
|
|
|
+ // update the running job
|
|
|
+ RunControlJob(runningjob);
|
|
|
}
|
|
|
|
|
|
- LoadportCassetteState state = (LoadportCassetteState)DATA.Poll($"{cj.Module}.CassetteState");
|
|
|
- if (cj.State == EnumControlJobState.Completed && state != LoadportCassetteState.Normal && cj.JetState == EnumJetCtrlJobState.Completed)
|
|
|
+ foreach(var queueJob in queueJobs)
|
|
|
{
|
|
|
- cjRemoveList.Add(cj);
|
|
|
+ if(!runningJobs.Exists(cj => IsControlJobIntersect(cj, queueJob)))
|
|
|
+ {
|
|
|
+ // parallelly start the not intersect job
|
|
|
+ RunControlJob(queueJob);
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- allControlJobComplete = allControlJobComplete && cj.State == EnumControlJobState.Completed;
|
|
|
}
|
|
|
|
|
|
- if (_isCycleMode && _cycledCount < (_isCycleMode ? _cycleSetPoint : 0))
|
|
|
+
|
|
|
+ if (true)
|
|
|
{
|
|
|
+ bool allControlJobComplete = _lstControlJobs.All(cj => cj.State == EnumControlJobState.Completed);
|
|
|
int totolCycleWafer = _lpCycleWafer.Sum(item => item.Value);
|
|
|
if (totolCycleWafer != _cycledWafer || _lpCycleCount.Sum(item => item.Value) > 0 && _throughput < 0.01) // refresh _throughput in time
|
|
|
{
|
|
@@ -1673,39 +1596,22 @@ namespace Venus_RT.Modules
|
|
|
_cycledCount++;
|
|
|
|
|
|
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.Executing);
|
|
|
- cj.JetState = EnumJetCtrlJobState.Quequed;
|
|
|
-
|
|
|
- cj.LotInnerId = Guid.NewGuid();
|
|
|
-
|
|
|
- _dbCallback.LotCreated(cj);
|
|
|
- }
|
|
|
- foreach (var pj in _lstProcessJobs)
|
|
|
- {
|
|
|
- pj.SetState(EnumProcessJobState.Queued);
|
|
|
- pj.InnerId = Guid.NewGuid();
|
|
|
- foreach (var pjSlotWafer in pj.SlotWafers)
|
|
|
- {
|
|
|
- WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
|
|
|
-
|
|
|
- wafer.ProcessJob = null;
|
|
|
- wafer.NextSequenceStep = 0;
|
|
|
- wafer.ProcessState = EnumWaferProcessStatus.Idle;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- _lstWaferTasks.Clear();
|
|
|
- }
|
|
|
- else
|
|
|
+ if (_cycledCount >= _cycleSetPoint)
|
|
|
_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)
|
|
|
+ {
|
|
|
+ cjRemoveList.Add(cj);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
foreach (var cj in cjRemoveList)
|
|
|
{
|
|
|
List<ProcessJobInfo> pjRemoveList = new List<ProcessJobInfo>();
|
|
@@ -1767,6 +1673,161 @@ namespace Venus_RT.Modules
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ private bool RunControlJob(ControlJobInfo cj)
|
|
|
+ {
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ 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))
|
|
|
+ {
|
|
|
+ cj.JetState = EnumJetCtrlJobState.Completed;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // caculate processed wafer by control job
|
|
|
+ int countProcessed = 0;
|
|
|
+ foreach (var pjName in cj.ProcessJobNameList)
|
|
|
+ {
|
|
|
+ var pj = _lstProcessJobs.Find(x => x.Name == pjName);
|
|
|
+ if (pj == null)
|
|
|
+ {
|
|
|
+ LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Not find pj named {pjName} in {cj.Name}");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // caculate process wafer by process
|
|
|
+ if (_isCycleMode && _cycledCount < (_isCycleMode ? _cycleSetPoint : 0))
|
|
|
+ {
|
|
|
+ foreach (var pjSlotWafer in pj.SlotWafers)
|
|
|
+ {
|
|
|
+ WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
|
|
|
+ if (!wafer.IsEmpty && wafer.ProcessState == EnumWaferProcessStatus.Completed)
|
|
|
+ countProcessed++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ int lpCycleWafer = 0;
|
|
|
+ var lp = ModuleHelper.Converter(cj.Module);
|
|
|
+ if (cj.JetState == EnumJetCtrlJobState.Completed)
|
|
|
+ {
|
|
|
+ cj.EndTime = DateTime.Now;
|
|
|
+
|
|
|
+ _faCallback.JobFinished(cj, GetFirstProcessJob(cj));
|
|
|
+ _dbCallback.LotFinished(cj);
|
|
|
+
|
|
|
+ if (!(_isCycleMode && _cycledCount < _cycleSetPoint))
|
|
|
+ (Singleton<TransferModule>.Instance.GetScheduler(lp) as SchedulerLoadPort).NoteJobComplete();
|
|
|
+
|
|
|
+ _lpCycleCount[lp]++;
|
|
|
+ lpCycleWafer = _lpCycleCount[lp] * cj.LotWafers.Count;
|
|
|
+
|
|
|
+ if (_lpCycleCount[lp] < cj.CycleNumber)
|
|
|
+ {
|
|
|
+ cj.SetState(EnumControlJobState.Executing);
|
|
|
+ cj.JetState = EnumJetCtrlJobState.Quequed;
|
|
|
+
|
|
|
+ cj.LotInnerId = Guid.NewGuid();
|
|
|
+
|
|
|
+ _dbCallback.LotCreated(cj);
|
|
|
+
|
|
|
+ foreach (var pj in _lstProcessJobs)
|
|
|
+ {
|
|
|
+ if(pj.ControlJobName == cj.Name)
|
|
|
+ {
|
|
|
+ pj.SetState(EnumProcessJobState.Queued);
|
|
|
+ pj.InnerId = Guid.NewGuid();
|
|
|
+ foreach (var pjSlotWafer in pj.SlotWafers)
|
|
|
+ {
|
|
|
+ WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
|
|
|
+
|
|
|
+ wafer.ProcessJob = null;
|
|
|
+ wafer.NextSequenceStep = 0;
|
|
|
+ wafer.ProcessState = EnumWaferProcessStatus.Idle;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ _lstWaferTasks.RemoveAll(wt => wt.currentMod == lp);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ cj.SetState(EnumControlJobState.Completed);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ lpCycleWafer = _lpCycleCount[ModuleHelper.Converter(cj.Module)] * cj.LotWafers.Count + countProcessed;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_lpCycleCount[ModuleHelper.Converter(cj.Module)] != _cycledCount || lpCycleWafer != _lpCycleWafer[ModuleHelper.Converter(cj.Module)])
|
|
|
+ {
|
|
|
+ _lpCycleWafer[ModuleHelper.Converter(cj.Module)] = lpCycleWafer;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
private bool IsAllJobWaferProcessedOrProcessing(ControlJobInfo cj)
|
|
|
{
|
|
|
List<ModuleName> allModules = _dictModuleTask.Keys.ToList();
|
|
@@ -1965,20 +2026,36 @@ namespace Venus_RT.Modules
|
|
|
|
|
|
private void CreateNewWaferTask()
|
|
|
{
|
|
|
- var cj = _lstControlJobs.Find(c => (c.JetState == EnumJetCtrlJobState.PreJobClean || c.JetState == EnumJetCtrlJobState.Processing) && c.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;
|
|
|
}
|
|
|
}
|