using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Timers;
using Aitex.Core.Common;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.RecipeCenter;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using Aitex.Sorter.Common;
using MECF.Framework.Common.DBCore;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.Jobs;
using MECF.Framework.Common.Schedulers;
using MECF.Framework.Common.SubstrateTrackings;
using MECF.Framework.RT.ModuleLibrary.PMModules;
using MECF.Framework.RT.ModuleLibrary.SystemModules;
using MECF.Framework.RT.ModuleLibrary.SystemModules.Routines;
using EfemDualSchedulerLib.Schedulers;
using MECF.Framework.Common.DataCenter;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadLocks;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.PMs;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robots;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.TMs;
using JetVirgoPM.PMs.RecipeExecutors;
namespace EfemDualSchedulerLib
{
///
/// 自动传输
///
public partial class AutoTransfer : SchedulerModuleFactory, IAutoTransfer
{
//const Hand Hand_Dual = Hand.Blade1;
//const Hand Hand_Single = Hand.Blade2;
//用于避免两爪都有wafer,放了一片就又去LoadPort Pick
private bool EfemRobotPickAllowable = true;
private bool _isRunningInParallelMode;
private List _mapTarget = new List();
private List _lstControlJobs = new List();
private List _lstProcessJobs = new List();
//private Object _locker = new Object();
private List _lstPms = new List();
private List _lstLps = new List();
private List _lstLls = new List();
private List _lstBuffers = new List();
private List _lstPmsCurrentSequence = new List();
private R_TRIG _trigLp1JobComplete = new R_TRIG();
private R_TRIG _trigLp2JobComplete = new R_TRIG();
private R_TRIG _trigLp3JobComplete = new R_TRIG();
private Dictionary _temperatureSetpointDic = new Dictionary();
private Dictionary _temperatureTrigDic = new Dictionary();
private Dictionary> currentSlotSequenceList = new Dictionary>()
{
{"LP1",Enumerable.Repeat("",25).ToList()},
{"LP2",Enumerable.Repeat("",25).ToList()},
{"LP3",Enumerable.Repeat("",25).ToList()}
};
private const string LogSource = "Scheduler";
public string LPHadCreateJob { get; set; }
//private bool _isCycleMode;
//private int _cycleSetPoint = 0;
//private int _cycledCount = 0;
//private int _cycledWafer = 0;
private SchedulerFACallback _faCallback;
private SchedulerDBCallback _dbCallback;
//private float _throughput;
//private DeviceTimer _throughputTimer = new DeviceTimer();
//private int _processedWaferCountInFinishedCJ;
class CycleData
{
public DateTime StartTime { get; private set; }
public TimeSpan EscapeTime => StartTime == DateTime.MinValue ? TimeSpan.Zero : DateTime.Now.Subtract(StartTime);
public bool IsCycleMode => SC.GetValue("System.IsCycleMode");
public string CycleBy => SC.GetStringValue("System.CycleBy");
public int CycleCountSetPoint => SC.GetValue("System.CycleCount");// 设置的循环次数
public int CycledCount { get; private set; } // 已处理的循环次数
public int CycleWaferCountSetPoint => SC.GetValue("System.CycleWaferCount");// 设置的晶圆片数
public int CycledWaferCount { get; private set; } // 已处理的晶圆片数
public void Start()
{
LOG.Info("Cycle: Start cycle data");
StartTime = DateTime.Now;
}
public void Reset()
{
LOG.Info("Cycle: Reset cycle data");
CycledWaferCount = 0;
CycledCount = 0;
}
//public void BeginOrAddCycle(int setpoint)
//{
// if (IsCycleMode) // add
// {
// CycleWaferCountSetPoint += setpoint;
// LOG.Info($"Cycle: Add {setpoint} wafers, total cycle count = {CycleWaferCountSetPoint}");
// }
// else // begin
// {
// IsCycleMode = true;
// StartTime = DateTime.Now;
// CycleWaferCountSetPoint = setpoint;
// CycledWaferCount = 0;
// LOG.Info($"Cycle: Begin {setpoint} wafers");
// }
//}
public bool IsCycleEnd()
{
if (!IsCycleMode)
return true;
if (CycleBy == "WaferCount" && CycledWaferCount >= CycleWaferCountSetPoint)
{
SC.SetItemValue("System.IsCycleMode", false);
Reset();
return true;
}
else if (CycleBy == "LotCount" && CycledCount >= CycleCountSetPoint)
{
SC.SetItemValue("System.IsCycleMode", false);
Reset();
return true;
}
return false;
}
public void Increase(int waferCount, int count = 1)
{
IncreaseWaferCount(waferCount);
IncreaseCount(count);
}
public void IncreaseWaferCount(int waferCount)
{
CycledWaferCount += waferCount;
LOG.Info($"Cycle: finished {CycledWaferCount} wafer(s)");
}
public void IncreaseCount(int count = 1)
{
CycledCount += count;
LOG.Info($"Cycle: finished {CycledCount} Count(s)");
}
}
class ThroughputData
{
public bool IsCalcing { get; private set; } = false;
public DateTime CacledLastTime { get; private set; } = DateTime.MinValue; // 创建时间或者计算时间
public double CalcedTotalTimeSeconds { get; private set; } = 0; // 总的计算时间
public int CalcedProcessedCount { get; private set; } = 0; // 已计算完的总数(control job)
public double TotalTimeSeconds { get; private set; }
public DateTime CaclingLastTime { get; private set; } = DateTime.MinValue; // 创建时间或者计算时间
public int CalcingProcessedCount { get; private set; } = 0;// 正在计算的总数(control job)
public int ProcessedCount => CalcedProcessedCount + CalcingProcessedCount;
public double Throughput { get; private set; }
public double LiveThroughput { get; private set; }
public void BeginCalc()
{
if (IsCalcing) return;
IsCalcing = true;
CalcedTotalTimeSeconds = 0;
CacledLastTime = DateTime.Now;
CaclingLastTime = DateTime.Now;
LOG.Info("Throughput: Begin");
}
public void Pause()
{
if (!IsCalcing)
{
IsCalcing = false;
LOG.Info("Throughput: Pause");
}
}
public void Reset()
{
CacledLastTime = DateTime.Now;
CalcedTotalTimeSeconds = 0;
CalcedProcessedCount = 0;
CaclingLastTime = DateTime.Now;
CalcedProcessedCount = 0;
CalcingProcessedCount = 0;
Throughput = 0;
LiveThroughput = 0;
LOG.Info("Throughput: Reset");
}
public void UpdateCalced(int calcedCount)
{
CalcedProcessedCount += calcedCount;
CalcingProcessedCount -= calcedCount;
if (CalcingProcessedCount < 0) CalcingProcessedCount = 0;
CalcedTotalTimeSeconds += DateTime.Now.Subtract(CacledLastTime).TotalSeconds;
CacledLastTime = DateTime.Now;
}
public void UpdateCalcing(int calcingCount)
{
DateTime now = DateTime.Now;
double seconds_this = now.Subtract(CaclingLastTime).TotalSeconds;
int calcingCount_this = calcingCount - CalcingProcessedCount;
double count_this = ProcessedCount + calcingCount;
LiveThroughput = 3600 / (seconds_this / calcingCount_this);
TotalTimeSeconds = CalcedTotalTimeSeconds + seconds_this;
Throughput = 3600 * count_this / TotalTimeSeconds;
LOG.Info($"Throughput: {Throughput}, Finished {count_this} wafer(s) in {(int)TotalTimeSeconds} seconds;" +
$" {LiveThroughput} last wafer in {(int)seconds_this} seconds");
CaclingLastTime = now;
CalcingProcessedCount = calcingCount;
}
}
private CycleData _CycleData = new CycleData();
private ThroughputData _throughputData = new ThroughputData();
private bool _isAutoUnloadFoup
{
get
{
return SC.GetValue("EFEM.LoadPort.EnableAutoUnloadFoup");
}
}
private ModuleName _TMRobotBlade1Station = ModuleName.System;
private Dictionary _loadlockCooling = new Dictionary();
Queue tmRobotActions = new Queue() { };
Queue efemRobotActions = new Queue() { };
public AutoTransfer(EquipmentManager equipment)
{
_faCallback = new SchedulerFACallback();
_dbCallback = new SchedulerDBCallback();
if (SC.GetValueOrDefault("System.SetUp.PMA.IsInstalled"))
_lstPms.Add(_pm1);
if (SC.GetValueOrDefault("System.SetUp.PMB.IsInstalled"))
_lstPms.Add(_pm2);
//if (SC.GetValueOrDefault("System.SetUp.PMC.IsInstalled"))
// _lstPms.Add(_pm3);
if (SC.GetValueOrDefault("System.SetUp.LLA.IsInstalled"))
_lstLls.Add(_loadlockA);
if (SC.GetValueOrDefault("System.SetUp.LLB.IsInstalled"))
_lstLls.Add(_loadlockB);
if (SC.GetValueOrDefault("System.SetUp.LP1.IsInstalled"))
_lstLps.Add(_lp1);
if (SC.GetValueOrDefault("System.SetUp.LP2.IsInstalled"))
_lstLps.Add(_lp2);
if (SC.GetValueOrDefault("System.SetUp.LP3.IsInstalled"))
_lstLps.Add(_lp3);
//临时办法,设备异常后进行reset,重新home后reset机械手task
OP.Subscribe($"{ModuleName.TM}.ResetTask", (string cmd, object[] args) =>
{
_tmRobot.ResetTask();
return true;
});
OP.Subscribe($"{ModuleName.EFEM}.ResetTask", (string cmd, object[] args) =>
{
_efem.ResetTask();
return true;
});
DATA.Subscribe("Scheduler.IsCycleMode", () => _CycleData.IsCycleMode);
DATA.Subscribe("Scheduler.CycleBy", () => _CycleData.CycleBy);
DATA.Subscribe("Scheduler.CycleCountSetPoint", () => _CycleData.CycleCountSetPoint);
DATA.Subscribe("Scheduler.CycledCount", () => _CycleData.CycledCount);
DATA.Subscribe("Scheduler.CycleWaferCountSetPoint", () => _CycleData.CycleWaferCountSetPoint);
DATA.Subscribe("Scheduler.CycledWaferCount", () => _CycleData.CycledWaferCount);
DATA.Subscribe("Scheduler.CycleEscapeTime", () => _CycleData.EscapeTime);
DATA.Subscribe("Scheduler.Throughput", () => _throughputData.Throughput);
DATA.Subscribe("Scheduler.LiveThroughput", () => _throughputData.LiveThroughput);
DATA.Subscribe("System.Scheduler.RunningRecipeList", () => _GetRunningRecipeList());
DATA.Subscribe("Scheduler.CjIdList", () => _GetRunningCjIdList());
DATA.Subscribe("LP1.LocalJobName", () =>
{
var jb = _lstControlJobs.Find(x => x.Module == "LP1");
if (jb != null)
return jb.Name;
return "";
});
DATA.Subscribe($"LP1.JobLotName", () =>
{
var cj = _lstControlJobs.FirstOrDefault(x => x.Module == "LP1");
if (cj != null)
return cj.LotName;
return "";
});
DATA.Subscribe("LP1.LocalJobStatus", () =>
{
var jb = _lstControlJobs.Find(x => x.Module == "LP1");
if (jb != null)
return jb.State.ToString();
return "";
});
DATA.Subscribe("LP1.CurrentRecipeList", () =>
{
List result = Enumerable.Repeat("", 25).ToList();
for (int i = 0; i < _lstProcessJobs.Count; i++)
{
foreach (var wafers in _lstProcessJobs[i].SlotWafers)
{
if (wafers.Item1 == ModuleName.LP1)
{
result[wafers.Item2] = _lstProcessJobs[i].Sequence.Name;
}
}
}
return result;
});
DATA.Subscribe("LP2.LocalJobName", () =>
{
var jb = _lstControlJobs.Find(x => x.Module == "LP2");
if (jb != null)
return jb.Name;
return "";
});
DATA.Subscribe($"LP2.JobLotName", () =>
{
var cj = _lstControlJobs.FirstOrDefault(x => x.Module == "LP2");
if (cj != null)
return cj.LotName;
return "";
});
DATA.Subscribe("LP2.LocalJobStatus", () =>
{
var jb = _lstControlJobs.Find(x => x.Module == "LP2");
if (jb != null)
return jb.State.ToString();
return "";
});
DATA.Subscribe("LP2.CurrentRecipeList", () =>
{
List result = Enumerable.Repeat("", 25).ToList();
for (int i = 0; i < _lstProcessJobs.Count; i++)
{
foreach (var wafers in _lstProcessJobs[i].SlotWafers)
{
if (wafers.Item1 == ModuleName.LP2)
{
result[wafers.Item2] = _lstProcessJobs[i].Sequence.Name;
}
}
}
return result;
});
DATA.Subscribe("LP3.LocalJobName", () =>
{
var jb = _lstControlJobs.Find(x => x.Module == "LP3");
if (jb != null)
return jb.Name;
return "";
});
DATA.Subscribe($"LP3.JobLotName", () =>
{
var cj = _lstControlJobs.FirstOrDefault(x => x.Module == "LP3");
if (cj != null)
return cj.LotName;
return "";
});
DATA.Subscribe("LP3.LocalJobStatus", () =>
{
var jb = _lstControlJobs.Find(x => x.Module == "LP3");
if (jb != null)
return jb.State.ToString();
return "";
});
DATA.Subscribe("LP3.CurrentRecipeList", () =>
{
List result = Enumerable.Repeat("", 25).ToList();
for (int i = 0; i < _lstProcessJobs.Count; i++)
{
foreach (var wafers in _lstProcessJobs[i].SlotWafers)
{
if (wafers.Item1 == ModuleName.LP3)
{
result[wafers.Item2] = _lstProcessJobs[i].Sequence.Name;
}
}
}
return result;
});
tmRobotActions.Enqueue(MonitorTmRobotLoadLockPickTask);
tmRobotActions.Enqueue(MonitorTmRobotPMAPlaceTask);
tmRobotActions.Enqueue(MonitorTmRobotPMBPlaceTask);
tmRobotActions.Enqueue(MonitorTmRobotPMAPickTask);
tmRobotActions.Enqueue(MonitorTmRobotPMBPickTask);
tmRobotActions.Enqueue(MonitorTmRobotLoadLockPlaceTask);
tmRobotActions.Enqueue(MonitorTmRobotGoToTask);
efemRobotActions.Enqueue(MonitorEfemRobotAlignerPickTask);
efemRobotActions.Enqueue(MonitorEfemRobotAlignerPlaceTask);
efemRobotActions.Enqueue(MonitorEfemRobotLoadLockPlaceTask);
efemRobotActions.Enqueue(MonitorEfemRobotLoadLockPickTask);
efemRobotActions.Enqueue(MonitorEfemRobotLoadPortPickTask);
efemRobotActions.Enqueue(MonitorEfemRobotLoadPortPlaceTask);
}
private List _GetRunningCjIdList()
{
return _lstControlJobs/*.Where(o => o.State == EnumControlJobState.Executing
|| o.State == EnumControlJobState.Paused)*/.Select(o => o.InnerId.ToString()).ToList();
}
const string StrProcessRecipe = "ProcessRecipe";
const string StrRecipe = "Recipe";
private List _GetRunningRecipeList()
{
var runningCjList = _lstControlJobs.Where(o => o.State == EnumControlJobState.Executing
|| o.State == EnumControlJobState.Paused).Select(o => o.Name).ToList();
return _lstProcessJobs.Where(o => runningCjList.Contains(o.ControlJobName))
.SelectMany(a => a.Sequence.Steps.SelectMany(b => b.StepParameter.Where(c => c.Key == StrProcessRecipe || c.Key == StrRecipe))).Select(d => d.Value as string)
.Where(o => !string.IsNullOrWhiteSpace(o)).ToList();
}
public bool HasJobRunning
{
get { return _lstControlJobs.Count > 0; }
}
public void Clear()
{
_tmRobot.ResetTask();
_efem.ResetTask();
foreach (var pm in _lstPms)
{
pm.ResetTask();
}
//foreach (var lp in _lstLps)
//{
// lp.ResetTask();
//}
_lstControlJobs.Clear();
_lstProcessJobs.Clear();
_temperatureSetpointDic.Clear();
_temperatureTrigDic.Clear();
_CycleData.Reset();
}
#region Job Management
public bool CreateJob(Dictionary param)
{
string reason;
string[] slotSequence = (string[])param["SlotSequence"];
string jobId = (string)param["JobId"];
string module = (string)param["Module"];
LPHadCreateJob = (string)param["Module"];
bool autoStart = (bool)param["AutoStart"];
string lotId = jobId;
if (param.ContainsKey("LotId"))
lotId = (string)param["LotId"];
if (!ValidateSequence(slotSequence, out reason))
{
EV.PostWarningLog(LogSource, $"{reason}");
_faCallback.JobCreateFailed(module, lotId, jobId, "");
return false;
}
if (slotSequence.Length != 25)
{
reason = $"slot sequence parameter not valid, length is {slotSequence.Length}, should be 25";
EV.PostWarningLog(LogSource, reason);
_faCallback.JobCreateFailed(module, lotId, jobId, "");
return false;
}
if (!ModuleHelper.IsLoadPort(ModuleHelper.Converter(module)))
{
reason = $"{module} should be LP";
EV.PostWarningLog(LogSource, reason);
_faCallback.JobCreateFailed(module, lotId, jobId, "");
return false;
}
if (string.IsNullOrEmpty(jobId))
{
jobId = "CJ_Local_" + module;
}
if (_lstControlJobs.Exists(x => x.Name == jobId))
{
reason = $"LotID : {jobId} already created";
EV.PostWarningLog(LogSource, reason);
_faCallback.JobCreateFailed(module, lotId, jobId, "");
return false;
}
SchedulerLoadPort lp = GetModule(module) as SchedulerLoadPort;
if (!lp.CheckReadyRunJob())
{
reason = $"{module} not ready";
EV.PostWarningLog(LogSource, reason);
_faCallback.JobCreateFailed(module, lotId, jobId, "");
return false;
}
ControlJobInfo cj = new ControlJobInfo();
cj.Name = jobId;
cj.Module = module;
cj.LotName = jobId;
cj.LotInnerId = Guid.NewGuid();
cj.LotWafers = new List();
cj.SetState(EnumControlJobState.WaitingForStart);
Dictionary seqSlot = new Dictionary();
Dictionary>> seqSlotWafers = new Dictionary>>();
Dictionary indexSequence = new Dictionary();
bool enableGroupBySequence = SC.GetValue("System.Scheduler.GroupWaferBySequence");
string WaferAssociationInfo = $"WaferAssociationInfo({module}):";
for (int i = 0; i < 25; i++)
{
WaferAssociationInfo = WaferAssociationInfo + string.Format(" slot{0} -- {1};", i + 1, slotSequence[i]);
if (string.IsNullOrEmpty(slotSequence[i]) || string.IsNullOrEmpty(slotSequence[i].Trim()))
continue;
string groupName = enableGroupBySequence ? slotSequence[i].Trim() : i.ToString();
indexSequence[groupName] = slotSequence[i];
if (!seqSlot.ContainsKey(groupName))
{
seqSlot[groupName] = new bool[25];
}
if (!seqSlotWafers.ContainsKey(groupName))
{
seqSlotWafers[groupName] = new List>();
}
seqSlot[groupName][i] = true;
if (!WaferManager.Instance.CheckHasWafer(module, i))
{
reason = $"job wafer: {module} slot {i + 1} not in the carrier";
EV.PostWarningLog(LogSource, reason);
_faCallback.JobCreateFailed(module, lotId, jobId, "");
return false;
}
if (!WaferManager.Instance.CheckWafer(ModuleHelper.Converter(module), i, WaferStatus.Normal))
{
reason = $"job wafer: {module} slot {i + 1} status is {WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).Status}";
EV.PostWarningLog(LogSource, reason);
_faCallback.JobCreateFailed(module, lotId, jobId, "");
return false;
}
var wafer = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i);
if (wafer == null || wafer.IsEmpty)
{
reason = $"specifies wafer: {module} slot {i + 1} not in the carrier";
EV.PostWarningLog(LogSource, reason);
_faCallback.JobCreateFailed(module, lotId, jobId, "");
return false;
}
if (!ModuleHelper.IsLoadPort(ModuleHelper.Converter(wafer.WaferOrigin.Split('.')[0])))
{
reason = $"specifies wafer: {module} slot {i + 1} not origin LP";
EV.PostWarningLog(LogSource, reason);
_faCallback.JobCreateFailed(module, lotId, jobId, "");
return false;
}
if (wafer.ProcessState != EnumWaferProcessStatus.Idle)
{
reason = $"specifies wafer: {module} slot {i + 1} process state is not idle";
EV.PostWarningLog(LogSource, reason);
_faCallback.JobCreateFailed(module, lotId, jobId, "");
return false;
}
seqSlotWafers[groupName].Add(Tuple.Create(ModuleHelper.Converter(module), i));
cj.LotWafers.Add(WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i));
WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).PPID = slotSequence[i];
}
currentSlotSequenceList[module] = slotSequence.Reverse().ToList();
EV.PostInfoLog(LogSource, WaferAssociationInfo);
if (seqSlotWafers.Count == 0)
{
reason = $"Can not create job, no wafer assigned";
EV.PostWarningLog(LogSource, reason);
_faCallback.JobCreateFailed(module, lotId, jobId, "");
return false;
}
List pjs = new List();
string[] seqs = seqSlot.Keys.ToArray();
for (int i = 0; i < seqs.Length; i++)
{
ProcessJobInfo pj = new ProcessJobInfo();
pj.Name = jobId + "_" + (i + 1);
pj.Sequence = SequenceInfoHelper.GetInfo(indexSequence[seqs[i]]);
pj.ControlJobName = cj.Name;
pj.LotName = lotId;
pj.SlotWafers = seqSlotWafers[seqs[i]];
pj.SetState(EnumProcessJobState.Queued);
if (!CheckSequencePmReady(pj.Sequence, null, out _, out string innerReason))
{
reason = $"no valid chamber for the {innerReason}";
EV.PostWarningLog(LogSource, reason);
_faCallback.JobCreateFailed(module, lotId, jobId, "");
return false;
}
if (!CheckSequenceRecipeFileValid(pj.Sequence, out reason))
{
reason = $"recipe file not valid in the sequence, {reason}";
EV.PostWarningLog(LogSource, reason);
_faCallback.JobCreateFailed(module, lotId, jobId, "");
return false;
}
if (!CheckSequenceOrderOk(pj.Sequence, out reason))
{
reason = $"sequence path not valid, {reason}";
EV.PostWarningLog(LogSource, reason);
_faCallback.JobCreateFailed(module, lotId, jobId, "");
return false;
}
if (CheckSequenceNeedDummyWafer(pj.Sequence))
{
reason = $"create job failed, no valid dummy wafer exist";
EV.PostWarningLog(LogSource, reason);
_faCallback.JobCreateFailed(module, lotId, jobId, "");
return false;
}
pjs.Add(pj);
}
foreach (var pj in pjs)
{
cj.ProcessJobNameList.Add(pj.Name);
_lstProcessJobs.Add(pj);
}
_lstControlJobs.Add(cj);
int totalWafer = 0;
foreach (var pj in pjs)
{
foreach (var pjSlotWafer in pj.SlotWafers)
{
WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
wafer.ProcessJob = pj;
WaferDataRecorder.SetCjInfo(wafer.InnerId.ToString(), cj.InnerId.ToString());
WaferDataRecorder.SetWaferSequence(wafer.InnerId.ToString(), pj.Sequence.Name);
WaferDataRecorder.SetWaferLotId(wafer.InnerId.ToString(), jobId);
WaferManager.Instance.UpdateWaferLotId(pjSlotWafer.Item1, pjSlotWafer.Item2, jobId);
totalWafer++;
}
}
_faCallback.JobCreated(cj, GetFirstProcessJob(cj));
if (_CycleData.IsCycleMode)
{
_CycleData.Start();
}
CarrierInfo carrier = CarrierManager.Instance.GetCarrier(cj.Module);
JobDataRecorder.StartCJ(cj.InnerId.ToString(), carrier.InnerId.ToString(), cj.Name, cj.Module, cj.Module, totalWafer);
return true;
}
public bool CreateControlJob(string jobId, string module, List pjIDs, bool isAutoStart)
{
if (_lstControlJobs.Exists(x => x.Name == jobId))
{
EV.PostWarningLog(LogSource, $"{jobId} is already created");
return false;
}
if (!ModuleHelper.IsLoadPort(ModuleHelper.Converter(module)))
{
EV.PostWarningLog(LogSource, $"{module} should be LoadPort");
return false;
}
LoadPort lp = DEVICE.GetDevice($"{module}");
if (!lp.IsIdle)
{
EV.PostWarningLog(LogSource, $"{module} is not idle");
return false;
}
if (!lp.IsMapped)
{
EV.PostWarningLog(LogSource, $"{module} is not mapped");
return false;
}
if (!lp.IsPresent)
{
EV.PostWarningLog(LogSource, $"{module} is not present");
return false;
}
foreach (var _lp in _lstLps)
{
if (_lp.Module.ToString() == module)
{
if (!_lp.IsOnline)
{
EV.PostWarningLog(LogSource, $"{module} is not online");
return false;
}
if (_lp.IsError)
{
EV.PostWarningLog(LogSource, $"{module} is error");
return false;
}
}
}
if (_lstProcessJobs.Count <= 0) //判断上一步ProcessJob是否创建成功
{
EV.PostWarningLog(LogSource, $"process job is not exist");
return false;
}
ControlJobInfo cj = new ControlJobInfo();
cj.Name = jobId;
cj.Module = module;
cj.SetState(EnumControlJobState.WaitingForStart);
cj.LotName = jobId;
cj.LotWafers = new List();
int totalWafer = 0;
foreach (var pjName in pjIDs)
{
var pj = _lstProcessJobs.FirstOrDefault(x => x.Name == pjName);
if (pj == null)
{
LOG.Info($"not find {pjName} while create control job");
continue;
}
var slotWafers = new List>();
foreach (var slotWafer in pj.SlotWafers)
{
if (!WaferManager.Instance.CheckHasWafer(module, slotWafer.Item2))
{
EV.PostWarningLog(LogSource, $"job wafer: {module} slot {slotWafer.Item2 + 1} not in the carrier");
return false;
}
if (!WaferManager.Instance.CheckWafer(ModuleHelper.Converter(module), slotWafer.Item2, WaferStatus.Normal))
{
EV.PostWarningLog(LogSource, $"job wafer: {module} slot {slotWafer.Item2 + 1} status is {WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), slotWafer.Item2).Status}");
return false;
}
if (WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), slotWafer.Item2).ProcessState != EnumWaferProcessStatus.Idle)
{
EV.PostWarningLog(LogSource, $"job wafer: {module} slot {slotWafer.Item2 + 1} process status is {WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), slotWafer.Item2).ProcessState}");
return false;
}
slotWafers.Add(Tuple.Create(ModuleHelper.Converter(module), slotWafer.Item2));
totalWafer++;
}
pj.ControlJobName = jobId;
cj.ProcessJobNameList.Add(pj.Name);
pj.SlotWafers = slotWafers;
foreach (var pjSlotWafer in pj.SlotWafers)
{
WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
cj.LotWafers.Add(wafer);
WaferDataRecorder.SetCjInfo(wafer.InnerId.ToString(), cj.InnerId.ToString());
WaferDataRecorder.SetWaferSequence(wafer.InnerId.ToString(), pj.Sequence.Name);
//WaferDataRecorder.SetWaferLotId(wafer.InnerId.ToString(), jobId);
}
}
_lstControlJobs.Add(cj);
CarrierInfo carrier = CarrierManager.Instance.GetCarrier(cj.Module);
JobDataRecorder.StartCJ(cj.InnerId.ToString(), carrier.InnerId.ToString(), cj.Name, cj.Module, cj.Module, totalWafer);
return true;
}
public bool CreateProcessJob(string jobId, string sequenceName, List slotNumbers, bool isAutoStart)
{
var sequenceInfo = SequenceInfoHelper.GetInfo(sequenceName);
#region 模块检查
if (!CheckSequenceAlignerReady(sequenceInfo, out string reason))
{
EV.PostWarningLog(LogSource, $"Aligner is not ready for the {reason}");
return false;
}
if (!CheckSequencePMReady(sequenceInfo, out reason))
{
EV.PostWarningLog(LogSource, $"PM is not ready for the {reason}");
return false;
}
#endregion
#region Sequence检查
if (!CheckSequenceAlignerOrder(sequenceInfo, out reason))
{
EV.PostWarningLog(LogSource, $"Aligner order is not valid for the {reason}");
return false;
}
if (!CheckSequencePMOrder(sequenceInfo, out reason))
{
EV.PostWarningLog(LogSource, $"PM order is not valid, {reason}");
return false;
}
#endregion
var slotWafers = new List>();
foreach (var slot in slotNumbers)
{
slotWafers.Add(Tuple.Create(ModuleName.System, slot));
}
ProcessJobInfo pj = new ProcessJobInfo();
pj.Name = jobId;
pj.Sequence = sequenceInfo;
pj.SlotWafers = slotWafers;
pj.SetState(EnumProcessJobState.Queued);
_lstProcessJobs.Add(pj);
return true;
}
private bool CheckSequenceAlignerReady(SequenceInfo seq, out string reason)
{
for (int i = 0; i < seq.Steps.Count; i++)
{
SequenceStepInfo stepInfo = seq.Steps[i];
foreach (var module in stepInfo.StepModules)
{
if (ModuleHelper.IsAligner(module))
{
if (!_aligner.IsOnline)
{
reason = $"Step {i + 1}, {module} is not online";
return false;
}
//if (!_aligner.IsIdle)
//{
// reason = $"Step {i + 1}, {module} is not idle";
// return false;
//}
if (_aligner.IsError)
{
reason = $"Step {i + 1}, {module} is error";
return false;
}
}
}
}
reason = string.Empty;
return true;
}
private bool CheckSequenceAlignerOrder(SequenceInfo seq, out string reason)
{
int alignerCount = 0;
int alignerIndex = -1;
int llIndex = -1;
int pmIndex = -1;
for (int i = 0; i < seq.Steps.Count; i++)
{
SequenceStepInfo stepInfo = seq.Steps[i];
foreach (var module in stepInfo.StepModules)
{
if (ModuleHelper.IsAligner(module))
{
alignerCount++;
alignerIndex = i;
if (i == seq.Steps.Count - 1)
{
reason = $"Step {i + 1}, {module} can not be the last step";
return false;
}
}
if (ModuleHelper.IsLoadLock(module))
{
if (llIndex == -1 || llIndex > i)
llIndex = i;
}
if (ModuleHelper.IsPm(module))
{
pmIndex = i;
}
}
}
if (alignerCount >= 2)
{
reason = $"Step {alignerIndex + 1}, Aligner step can appear once at most in sequence";
return false;
}
else if (alignerCount == 1)
{
if (llIndex != -1 && alignerIndex > llIndex)
{
reason = $"Step {alignerIndex + 1}, Aligner step should be in front of LoadLock step";
return false;
}
if (pmIndex != -1 && alignerIndex > pmIndex)
{
reason = $"Step {alignerIndex + 1}, Aligner step should be in front of PM step";
return false;
}
}
reason = string.Empty;
return true;
}
private bool CheckSequencePMReady(SequenceInfo seq, out string reason)
{
for (int i = 0; i < seq.Steps.Count; i++)
{
SequenceStepInfo stepInfo = seq.Steps[i];
if (stepInfo.StepModules.Count == 0)
{
reason = $"Step {i + 1}, no PM is selected";
return false;
}
foreach (var module in stepInfo.StepModules)
{
if (ModuleHelper.IsPm(module))
{
foreach (var pm in _lstPms)
{
if (pm.Module == module)
{
if (!pm.IsOnline)
{
reason = $"Step {i + 1}, selected {module} is not online";
return false;
}
//if (!pm.IsIdle)
//{
// reason = $"Step {i + 1}, selected {module} is not idle";
// return false;
//}
if (pm.IsError)
{
reason = $"Step {i + 1}, selected {module} is error";
return false;
}
#region Check Recipe File Valid
var recipeContent = RecipeFileManager.Instance.LoadRecipe("", stepInfo.StepParameter[$"{module}Recipe"].ToString(), false);
if (string.IsNullOrEmpty(recipeContent))
{
reason = $"Step {i + 1}, can not find recipe file {stepInfo.RecipeName}";
return false;
}
#endregion
}
}
}
}
}
reason = "";
return true;
}
private bool CheckSequencePMOrder(SequenceInfo seq, out string reason)
{
int pmCount = 0;
for (int i = 0; i < seq.Steps.Count; i++)
{
SequenceStepInfo stepInfo = seq.Steps[i];
foreach (var module in stepInfo.StepModules)
{
if (ModuleHelper.IsPm(module))
{
pmCount++;
break;
}
}
}
if (pmCount == 0)
{
reason = $"Sequence must contains PM step";
return false;
}
if (pmCount >= 2)
{
reason = $"PM step only can appear once in sequence";
return false;
}
reason = string.Empty;
return true;
}
internal ProcessJobInfo GetFirstProcessJob(ControlJobInfo cj)
{
foreach (var pj in _lstProcessJobs)
{
if (pj.ControlJobName == cj.Name)
return pj;
}
return null;
}
public bool StopJob(string jobName)
{
ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
if (cj == null)
{
EV.PostWarningLog(LogSource, $"stop job rejected, not found job with id {jobName}");
return false;
}
foreach (var pj in _lstProcessJobs)
{
if (pj.ControlJobName == cj.Name)
{
pj.SetState(EnumProcessJobState.Stopping);
}
}
_faCallback.JobStopped(cj, GetFirstProcessJob(cj));
_dbCallback.LotFinished(cj);
return true;
}
public bool AbortJob(string jobName)
{
ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
if (cj == null)
{
EV.PostWarningLog(LogSource, $"abort job rejected, not found job with id {jobName}");
return false;
}
int unprocessed_cj = 0;
int aborted_cj = 0;
List pjAbortList = new List();
foreach (var pj in _lstProcessJobs)
{
if (pj.ControlJobName == cj.Name)
{
pj.SetState(EnumProcessJobState.Aborting);
pjAbortList.Add(pj);
int unprocessed = 0;
int aborted = 0;
WaferInfo[] wafers = WaferManager.Instance.GetWaferByProcessJob(pj.Name);
foreach (var waferInfo in wafers)
{
waferInfo.ProcessJob = null;
waferInfo.NextSequenceStep = 0;
if (waferInfo.ProcessState != EnumWaferProcessStatus.Completed)
{
unprocessed++;
unprocessed_cj++;
}
}
JobDataRecorder.EndPJ(pj.InnerId.ToString(), aborted, unprocessed);
}
}
foreach (var pj in pjAbortList)
{
_lstProcessJobs.Remove(pj);
}
_lstControlJobs.Remove(cj);
JobDataRecorder.EndCJ(cj.InnerId.ToString(), aborted_cj, unprocessed_cj);
_faCallback.JobAborted(cj, GetFirstProcessJob(cj));
_dbCallback.LotFinished(cj);
_temperatureSetpointDic.Clear();
_temperatureTrigDic.Clear();
return true;
}
public bool ResumeJob(string jobName)
{
ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
if (cj == null)
{
EV.PostWarningLog(LogSource, $"resume job rejected, not found job with id {jobName}");
return false;
}
if (cj.State == EnumControlJobState.Paused)
{
cj.SetState(EnumControlJobState.Executing);
}
_faCallback.JobResumed(cj, GetFirstProcessJob(cj));
return true;
}
public bool StartJob(string jobName)
{
ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
if (cj == null)
{
EV.PostWarningLog(LogSource, $"start job rejected, not found job with id {jobName}");
return false;
}
if (cj.State == EnumControlJobState.WaitingForStart)
{
cj.SetState(EnumControlJobState.Executing);
(GetModule(cj.Module) as SchedulerLoadPort).NoteJobStart();
//if (cj.IsCycleMode)
//{
// _CycleData.BeginOrAddCycle(cj.CycleWaferCountSP);
//}
cj.BeginTime = DateTime.Now;
cj.LotInnerId = Guid.NewGuid();
_dbCallback.LotCreated(cj);
_faCallback.JobStarted(cj, GetFirstProcessJob(cj));
//foreach (var pj in _lstProcessJobs)
//{
// if (pj.ControlJobName == cj.Name)
// {
// pj.SetState(EnumProcessJobState.Processing);
// }
//}
}
return true;
}
public bool PauseJob(string jobName)
{
ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
if (cj == null)
{
EV.PostWarningLog(LogSource, $"pause job rejected, not found job with id {jobName}");
return false;
}
if (cj.State == EnumControlJobState.Executing)
{
cj.SetState(EnumControlJobState.Paused);
}
_faCallback.JobPaused(cj, GetFirstProcessJob(cj));
return true;
}
public void Abort()
{
}
public bool IsCJExisted(string CJID)
{
return _lstControlJobs.Exists(x => x.Name == CJID);
}
public void ModuleError(string moduleName)
{
GetModule(moduleName).ResetTask();
PauseJob(string.Empty);
}
public void Map(string moduleName)
{
ModuleName target = ModuleHelper.Converter(moduleName);
if (!ModuleHelper.IsLoadPort(target))
{
EV.PostWarningLog(LogSource, $"Invalid map target {target}");
return;
}
if (!_mapTarget.Contains(target))
{
_mapTarget.Add(target);
}
}
#endregion
public Result Start(params object[] objs)
{
_ValueDict.Clear();
_CycleData.Reset();
var waferInfo = "";
bool hasPmOnline = false;
foreach (var schedulerPm in _lstPms)
{
if (schedulerPm.IsAvailable)
{
hasPmOnline = true;
if (WaferManager.Instance.CheckHasWafer(schedulerPm.Module, 0))
waferInfo += $"{(waferInfo == "" ? "" : ", ")}{schedulerPm.Module}";
}
}
bool hasTMOnline = false;
if (_tmRobot.IsAvailable)
hasTMOnline = true;
if (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 0))
waferInfo += $"{(waferInfo == "" ? "" : ", ")}{ModuleName.TMRobot} primary arm";
if (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 1))
waferInfo += $"{(waferInfo == "" ? "" : ", ")}{ModuleName.TMRobot} secondly arm";
if (!hasPmOnline || !hasTMOnline)
{
var content = hasPmOnline ? "" : "both process chamber";
content += hasTMOnline ? "" : $"{(content == "" ? "" : ", ")}TM";
EV.PostWarningLog("Scheduler", $"can not change to auto mode, {content} is busy or offline");
return Result.FAIL;
}
if (waferInfo != "")
{
EV.PostWarningLog("Scheduler", $"can not change to auto mode, {waferInfo} wafer presence.");
return Result.FAIL;
}
if (!_efem.IsOnline)
{
EV.PostWarningLog("Scheduler", $"can not change to auto mode, EFEM is offline");
return Result.FAIL;
}
return Result.RUN;
}
public Result Monitor()
{
for (int i = 0; i < 25; i++)
{
ProcessJobInfo pj = WaferManager.Instance.GetWafer(_lp1.Module, i).ProcessJob;
if (pj == null)
break;
ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == pj.ControlJobName);
if (cj == null)
break;
if (_lp1.FirstDetectWaferArrive(i))
{
_faCallback.JobWaferEnd(cj, pj, _lp1.Module.ToString(), i);
}
}
for (int i = 0; i < 25; i++)
{
ProcessJobInfo pj = WaferManager.Instance.GetWafer(_lp2.Module, i).ProcessJob;
if (pj == null)
break;
ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == pj.ControlJobName);
if (cj == null)
break;
if (_lp2.FirstDetectWaferArrive(i))
{
_faCallback.JobWaferEnd(cj, pj, _lp2.Module.ToString(), i);
}
}
MonitorJobTasks();
MonitorCleanTasks();
ControlJobInfo cjActive = _lstControlJobs.Find(x => x.State == EnumControlJobState.Executing);
if (cjActive != null)
{
MonitorModuleTasks();
}
return Result.RUN;
}
#region Job task
public Result MonitorJobTasks()
{
UpdateParallelMode();
CalcingThroughput();
UpdateProcessJobStatus();
UpdateControlJobStatus();
//if (GetUnprocessedWaferCount() < SC.GetValue("System.Scheduler.WaferCountBelowWhichStartNewProcessJob"))
{
StartNewJob();
}
return Result.RUN;
}
//only for pj in process
protected int GetUnprocessedWaferCount()
{
int count = 0;
foreach (ProcessJobInfo pj in _lstProcessJobs)
{
if (pj.State == EnumProcessJobState.Processing || pj.State == EnumProcessJobState.Paused)
count += GetUnprocessedWaferCount(pj);
}
if (CheckWaferNeedProcess(WaferManager.Instance.GetWafer(ModuleName.EfemRobot, 0)))
count++;
if (CheckWaferNeedProcess(WaferManager.Instance.GetWafer(ModuleName.EfemRobot, 1)))
count++;
if (CheckWaferNeedProcess(WaferManager.Instance.GetWafer(ModuleName.Aligner, 0)))
count++;
return count;
}
protected int GetUnprocessedWaferCount(ProcessJobInfo pj)
{
int count = 0;
for (int i = 0; i < pj.SlotWafers.Count; ++i)
{
WaferInfo wafer = WaferManager.Instance.GetWafer(pj.SlotWafers[i].Item1, pj.SlotWafers[i].Item2);
if (wafer.IsEmpty)
continue;
if (CheckWaferNeedProcess(pj.SlotWafers[i].Item1, pj.SlotWafers[i].Item2))
count++;
}
return count;
}
protected bool CheckAllWaferReturned(ProcessJobInfo pj, bool checkAllProcessed)
{
for (int i = 0; i < pj.SlotWafers.Count; ++i)
{
WaferInfo wafer = WaferManager.Instance.GetWafer(pj.SlotWafers[i].Item1, pj.SlotWafers[i].Item2);
if (wafer.IsEmpty)
return false;
if (checkAllProcessed && CheckWaferNeedProcess(pj.SlotWafers[i].Item1, pj.SlotWafers[i].Item2))
return false;
}
return true;
}
protected bool CheckAllDummyWaferReturned()
{
foreach (var schedulerPm in _lstPms)
{
if (WaferManager.Instance.CheckWaferIsDummy(schedulerPm.Module, 0))
return false;
}
if (WaferManager.Instance.CheckWaferIsDummy(_tmRobot.Module, 0))
return false;
if (WaferManager.Instance.CheckWaferIsDummy(_tmRobot.Module, 1))
return false;
return true;
}
protected bool CheckAllPmCleaned(ProcessJobInfo pj)
{
foreach (var schedulerPm in _lstPms)
{
if (CheckNeedRunClean(schedulerPm.Module, out _, out _))
{
foreach (var sequenceStepInfo in pj.Sequence.Steps)
{
if (sequenceStepInfo.StepModules.Contains(schedulerPm.Module))
return false;
}
}
}
return true;
}
private void UpdateProcessJobStatus()
{
foreach (var pj in _lstProcessJobs)
{
if (pj.State == EnumProcessJobState.Processing)
{
if (CheckAllWaferReturned(pj, true) && CheckAllPmCleaned(pj) && CheckAllDummyWaferReturned())
{
pj.SetState(EnumProcessJobState.ProcessingComplete);
JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0);
}
}
else if (pj.State == EnumProcessJobState.Stopping)
{
if (CheckAllWaferReturned(pj, false) && CheckAllPmCleaned(pj) && CheckAllDummyWaferReturned())
{
pj.SetState(EnumProcessJobState.ProcessingComplete);
JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0);
}
}
}
}
private void UpdateParallelMode()
{
bool enableParallel = SC.GetValue("System.Scheduler.IsRunInParallelMode");
int hasJobLpCount = 0;
_isRunningInParallelMode = enableParallel;
List pmUsed = new List();
foreach (var lp in _lstLps)
{
var cj = _lstControlJobs.Find(x => x.Module == lp.Module.ToString());
if (cj != null)
{
hasJobLpCount++;
var pj = _lstProcessJobs.FirstOrDefault(x => x.ControlJobName == cj.Name);
if (pj != null)
{
var seq = pj.Sequence;
for (int i = 0; i < seq.Steps.Count; i++)
{
SequenceStepInfo stepInfo = seq.Steps[i];
foreach (var module in stepInfo.StepModules)
{
if (ModuleHelper.IsPm(module) && !pmUsed.Contains(module))
pmUsed.Add(module);
}
}
}
}
}
_isRunningInParallelMode = enableParallel && hasJobLpCount > 1 && pmUsed.Count > 1;
}
private void UpdateControlJobStatus()
{
if (_lstControlJobs.Count == 0)
return;
List cjRemoveList = new List();
foreach (var cj in _lstControlJobs)
{
if (cj.State == EnumControlJobState.Executing)
{
bool allPjCompleted = true;
foreach (var pjName in cj.ProcessJobNameList)
{
var pj = _lstProcessJobs.FirstOrDefault(x => x.Name == pjName);
if (pj == null) { LOG.Error($"Not find pj named {pjName} in {cj.Name}"); continue; }
if (pj.State != EnumProcessJobState.Complete &&
pj.State != EnumProcessJobState.ProcessingComplete)
{
allPjCompleted = false; break;
}
}
if (allPjCompleted)
{
if (!_CycleData.IsCycleMode || (_CycleData.IsCycleMode && _CycleData.IsCycleEnd()))
CompleteJobClean(cj);
_FinishCJ(cj);
cj.EndTime = DateTime.Now;
string strInfo = $"{cj.Module} has finished: \r\n\r\nProcessed wafer number: {cj.LotWafers.Count} \r\nStart time: {cj.BeginTime} \r\nEnd time: {cj.EndTime} \r\nDuration: {(cj.EndTime - cj.BeginTime).TotalSeconds:F0} sec";
EV.PostInfoLog("Scheduler", strInfo);
if (SC.GetValue("System.Job.EnablePopDialogWhenJobDone"))
{
EV.PostPopDialogMessage(EventLevel.Information, "System Information", strInfo);
}
}
}
}
if (_lstControlJobs.Any(cj => cj.State == EnumControlJobState.Completed) && _CycleData.IsCycleMode && !_CycleData.IsCycleEnd())
{
var completeCJs = from cj in _lstControlJobs
where cj.State == EnumControlJobState.Completed
select cj;
var otherCJs = from cj in _lstControlJobs
where cj.State != EnumControlJobState.Completed
select cj;
_lstControlJobs = otherCJs.Concat(completeCJs).ToList();
_lstControlJobs.ForEach(cj =>
{
if (cj.State == EnumControlJobState.Completed)
{
_CycleData.IncreaseCount();
if (_CycleData.IsCycleEnd())
return;
cj.SetState(EnumControlJobState.Executing);
cj.BeginTime = DateTime.Now;
cj.LotWafers.ForEach(x =>
{
x.NextSequenceStep = 0;
x.ProcessState = EnumWaferProcessStatus.Idle;
});
foreach (var pjName in cj.ProcessJobNameList)
{
var pj = _lstProcessJobs.Find(x => x.Name == pjName);
if (pj == null)
{
LOG.Error($"Not find pj named {pjName} in {cj.Name}");
continue;
}
pj.SetState(EnumProcessJobState.Queued);
}
}
});
}
foreach (var cj in _lstControlJobs)
{
if (cj.State == EnumControlJobState.Completed
&& (!_CycleData.IsCycleMode || _CycleData.IsCycleMode && _CycleData.IsCycleEnd())
&& (!_isAutoUnloadFoup || (_isAutoUnloadFoup && (GetModule(cj.Module.ToString()) as SchedulerLoadPort).IsUnloaded)))
{
(GetModule(cj.Module) as SchedulerLoadPort).NoteJobComplete();
cjRemoveList.Add(cj);
}
}
foreach (var cj in cjRemoveList)
{
List pjRemoveList = _lstProcessJobs.Where(o => o.ControlJobName == cj.Name).ToList();
pjRemoveList.ForEach(o => _lstProcessJobs.Remove(o));
_lstControlJobs.Remove(cj);
CalcedThroughput(pjRemoveList);
}
ControlJobInfo cjActived = null;
foreach (var cj in _lstControlJobs)
{
if (cj.State == EnumControlJobState.Executing)
{
cjActived = cj;
break;
}
}
if (cjActived != null)
{
bool allPjResouceOk = true;
string reason = string.Empty;
foreach (var pjName in cjActived.ProcessJobNameList)
{
var pj = _lstProcessJobs.Find(x => x.Name == pjName);
if (pj == null)
{
LOG.Error($"Not find pj named {pjName} in {cjActived.Name}");
continue;
}
if (pj.State != EnumProcessJobState.Complete && pj.State != EnumProcessJobState.ProcessingComplete)
{
if (!CheckSequencePmReady(pj.Sequence, null, out _, out reason))
{
allPjResouceOk = false;
break;
}
}
}
if (!allPjResouceOk)
{
cjActived.SetState(EnumControlJobState.Paused);
EV.PostWarningLog(LogSource, $"{cjActived.Module} paused, {reason}");
}
}
}
private void _FinishCJ(ControlJobInfo cj)
{
cj.SetState(EnumControlJobState.Completed);
int unprocessed_cj = 0;
int aborted_cj = 0;
foreach (var pj in _lstProcessJobs)
{
if (pj.ControlJobName == cj.Name)
{
int unprocessed = 0;
int aborted = 0;
WaferInfo[] wafers = WaferManager.Instance.GetWaferByProcessJob(pj.Name);
foreach (var waferInfo in wafers)
{
waferInfo.ProcessJob = null;
waferInfo.NextSequenceStep = 0;
if (waferInfo.ProcessState != EnumWaferProcessStatus.Completed)
{
unprocessed++;
unprocessed_cj++;
}
}
JobDataRecorder.EndPJ(pj.InnerId.ToString(), aborted, unprocessed);
}
}
JobDataRecorder.EndCJ(cj.InnerId.ToString(), aborted_cj, unprocessed_cj);
_faCallback.JobFinished(cj, GetFirstProcessJob(cj));
_dbCallback.LotFinished(cj);
}
//private bool _HandleFinishedCycleCJ(ControlJobInfo cj)
//{
// //if (!cj.IsCycleMode) return false;
// int countProcessed = 0;
// foreach (var pjName in cj.ProcessJobNameList)
// {
// var pj = _lstProcessJobs.FirstOrDefault(x => x.Name == pjName);
// if (pj == null) { LOG.Error($"Not find pj named {pjName} in {cj.Name}"); continue; }
// if (pj.State == EnumProcessJobState.Complete || pj.State == EnumProcessJobState.ProcessingComplete)
// {
// foreach (var pjSlotWafer in pj.SlotWafers)
// {
// WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
// if (!wafer.IsEmpty && !CheckWaferNeedProcess(pjSlotWafer.Item1, pjSlotWafer.Item2))
// countProcessed++;
// }
// }
// }
// _CycleData.Increase(countProcessed);
// int leftCount = _CycleData.CycleWaferCountSetPoint - _CycleData.CycledWaferCount;
// // finished cycle
// if (leftCount <= 0) return false;
// // 移除老的cj
// var pjList = _lstProcessJobs.Where(o => o.ControlJobName == cj.Name).ToList();
// CalcedThroughput(pjList);
// pjList.ForEach(o => _lstProcessJobs.Remove(o));
// _lstControlJobs.Remove(cj);
// // 模拟 LP unload / load
// {
// ModuleName mName = ModuleHelper.Converter(cj.Module);
// var wafers_old = WaferManager.Instance.GetWafers(mName).ToList();
// WaferManager.Instance.DeleteWafer(mName, 0, SC.GetValue($"EFEM.LoadPort.CassetteSlotNumber"));
// CarrierManager.Instance.DeleteCarrier(cj.Module);
// CarrierManager.Instance.CreateCarrier(cj.Module);
// foreach (var wafer in wafers_old)
// {
// if (wafer.Status != WaferStatus.Normal) continue;
// var newWafer = WaferManager.Instance.CreateWafer(mName, wafer.Slot, wafer.Status);
// newWafer.PPID = wafer.PPID;
// CarrierManager.Instance.RegisterCarrierWafer(cj.Module, wafer.Slot, newWafer);
// }
// }
// // 产生新的cj
// ControlJobInfo newCj = new ControlJobInfo();
// newCj.Name = cj.Name;
// newCj.Module = cj.Module;
// newCj.LotName = cj.LotName;
// //newCj.IsCycleMode = cj.IsCycleMode;
// //newCj.CycleWaferCountSP = cj.CycleWaferCountSP;
// //newCj.CycledWaferCount = _CycleData.CycledWaferCount;
// newCj.LotInnerId = Guid.NewGuid();
// newCj.LotWafers = cj.LotWafers.Take(leftCount).ToList();
// int addedCount = 0;
// List newPjList = new List();
// //int toAddCount = Math.Min(leftCount, cj.LotWafers.Count);
// for (int ii = 0; ii < cj.ProcessJobNameList.Count; ii++)
// {
// string pjName = cj.ProcessJobNameList[ii];
// var pj = pjList.FirstOrDefault(o => o.ControlJobName == cj.Name && o.Name == pjName);
// if (pj == null) continue;
// int toAddCount = Math.Min(leftCount - addedCount, cj.LotWafers.Count);
// if (toAddCount <= 0) break;
// addedCount += toAddCount;
// ProcessJobInfo newPj = new ProcessJobInfo();
// newPj.Name = pj.Name;
// newPj.Sequence = pj.Sequence;
// newPj.ControlJobName = pj.ControlJobName;
// newPj.SlotWafers = pj.SlotWafers.Take(toAddCount).ToList();
// newPj.SetState(EnumProcessJobState.Queued);
// _lstProcessJobs.Add(newPj);
// newCj.ProcessJobNameList.Add(pj.Name);
// newPjList.Add(newPj);
// }
// _lstControlJobs.Add(newCj);
// // 开始新的cj
// newCj.SetState(EnumControlJobState.Executing);
// newCj.LotInnerId = Guid.NewGuid();
// newCj.BeginTime = DateTime.Now;
// _dbCallback.LotCreated(newCj);
// newPjList.ForEach(o => ActiveProcessJob(o));
// return true;
//}
public bool CheckAllJobDone()
{
if (_lp1.IsAvailable)
{
_trigLp1JobComplete.CLK = CheckJobComplete(ModuleName.LP1.ToString());
if (_trigLp1JobComplete.Q)
{
if (_isAutoUnloadFoup)
{
_lp1.Unload();
}
EV.Notify("CARRIER_PROCESS_COMPLETE", new SerializableDictionary()
{
{ "PortID", 1},
{ "PORT_ID", 1},
{ "CarrierID", CarrierManager.Instance.GetCarrier(_lp1.Module.ToString()).CarrierId},
{ "CAR_ID", CarrierManager.Instance.GetCarrier(_lp1.Module.ToString()).CarrierId}
});
}
}
if (_lp2.IsAvailable)
{
_trigLp2JobComplete.CLK = CheckJobComplete(ModuleName.LP2.ToString());
if (_trigLp2JobComplete.Q)
{
if (_isAutoUnloadFoup)
{
_lp2.Unload();
}
EV.Notify("CARRIER_PROCESS_COMPLETE", new SerializableDictionary()
{
{ "PortID", 2},
{ "PORT_ID", 2},
{ "CarrierID", CarrierManager.Instance.GetCarrier(_lp2.Module.ToString()).CarrierId},
{ "CAR_ID", CarrierManager.Instance.GetCarrier(_lp2.Module.ToString()).CarrierId}
});
}
}
if (_lp3.IsAvailable)
{
_trigLp3JobComplete.CLK = CheckJobComplete(ModuleName.LP3.ToString());
if (_trigLp3JobComplete.Q)
{
if (_isAutoUnloadFoup)
{
_lp3.Unload();
}
EV.Notify("CARRIER_PROCESS_COMPLETE", new SerializableDictionary()
{
{ "PortID", 3 },
{ "PORT_ID", 3 },
{ "CarrierID", CarrierManager.Instance.GetCarrier(_lp3.Module.ToString()).CarrierId },
{ "CAR_ID", CarrierManager.Instance.GetCarrier(_lp3.Module.ToString()).CarrierId }
});
}
}
foreach (var cj in _lstControlJobs)
{
if (cj.State == EnumControlJobState.Executing || cj.State == EnumControlJobState.Paused)
return false;
}
if (!_lp1.IsAvailable || !_lp2.IsAvailable || !_lp3.IsAvailable)
return false;
return true;
}
private bool CheckJobComplete(string lp = null)
{
if (_lstProcessJobs.Count == 0)
return false;
if (_lstControlJobs.Count == 0)
return false;
if (_CycleData.IsCycleMode && !_CycleData.IsCycleEnd())
return false;
if (lp != null)
{
var cj = _lstControlJobs.Find(x => x.Module == lp);
if (cj == null)
return false;
}
foreach (var pj in _lstProcessJobs)
{
if (lp == null)
{
if (pj.State != EnumProcessJobState.ProcessingComplete)
{
return false;
}
}
}
foreach (var cj in _lstControlJobs)
{
if (lp == null)
{
if (cj.State != EnumControlJobState.Completed)
{
return false;
}
}
else
{
if (cj.Module == lp && cj.State != EnumControlJobState.Completed)
{
return false;
}
}
}
return true;
}
private void StartNewJob()
{
ControlJobInfo cjActived = null;
bool enableParallel = SC.GetValue("System.Scheduler.IsRunInParallelMode");
List pmOccupied = GetPmUsedInRunningPj();
var orderedLstCJs = _lstControlJobs.OrderBy(x => x.BeginTime);
foreach (var cj in orderedLstCJs)
{
if (cj.State != EnumControlJobState.Executing)
continue;
cjActived = cj;
foreach (var pjName in cjActived.ProcessJobNameList)
{
var pj = _lstProcessJobs.Find(x => x.Name == pjName);
if (pj == null)
{
LOG.Error($"Not find pj named {pjName} in {cjActived.Name}");
continue;
}
if (pj.State == EnumProcessJobState.Queued)
{
var pmIsReady = CheckSequencePmReady(pj.Sequence, pmOccupied, out var pmUsed, out string reason);
if (pmUsed.Count > 0)
{
var needPreClean = pmUsed.Any(x =>
{
return SC.GetValue($"{x.ToString()}.JobClean.IsEnabled") && SC.GetValue($"{x.ToString()}.JobClean.EnablePreJobClean");
});
if (needPreClean && !pmIsReady)
break;
ActiveProcessJob(pj);
foreach (var moduleName in pmUsed)
{
if (!pmOccupied.Contains(moduleName))
pmOccupied.Add(moduleName);
}
break;
}
}
}
if (!_isRunningInParallelMode)
break;
}
}
private List GetPmUsedInRunningPj()
{
var pmUsed = new List();
foreach (var cj in _lstControlJobs)
{
if (cj.State != EnumControlJobState.Executing && cj.State != EnumControlJobState.Paused)
continue;
foreach (var pj in _lstProcessJobs)
{
if (pj.ControlJobName == cj.Name && (pj.State == EnumProcessJobState.Processing || pj.State == EnumProcessJobState.Paused))
{
for (int i = 0; i < pj.Sequence.Steps.Count; i++)
{
SequenceStepInfo stepInfo = pj.Sequence.Steps[i];
foreach (var module in stepInfo.StepModules)
{
if (ModuleHelper.IsPm(module) && !pmUsed.Contains(module))
pmUsed.Add(module);
}
}
}
}
}
return pmUsed;
}
//private bool CheckSequencePmReady(SequenceInfo seq, out string reason)
//{
// for (int i = 0; i < seq.Steps.Count; i++)
// {
// SequenceStepInfo stepInfo = seq.Steps[i];
// bool hasPm = false;
// foreach (var module in stepInfo.StepModules)
// {
// if (ModuleHelper.IsPm(module))
// {
// PM pm = DEVICE.GetDevice(module.ToString());
// if (pm.IsInstalled && !pm.IsError)
// {
// hasPm = true;
// break;
// }
// }
// else
// {
// hasPm = true; // other modules default ok
// }
// }
// if (!hasPm)
// {
// reason = $"Step {i + 1} no valid PM, " + string.Join("|", stepInfo.StepModules);
// return false;
// }
// }
// reason = "";
// return true;
//}
private bool CheckSequencePmReady(SequenceInfo seq, List pmOccupied, out List pmUsed, out string reason)
{
pmUsed = new List();
reason = "";
bool pmIsReady = true;
for (int i = 0; i < seq.Steps.Count; i++)
{
SequenceStepInfo stepInfo = seq.Steps[i];
bool hasPm = false;
foreach (var module in stepInfo.StepModules)
{
if (!ModuleHelper.IsPm(module))
{
hasPm = true;
break;
}
PMModuleBase pm = EquipmentManager.Modules[module] as PMModuleBase;
if (pm.IsInstalled && (pmOccupied == null || !pmOccupied.Contains(module)))
{
hasPm = true;
}
if (!pmUsed.Contains(module))
pmUsed.Add(module);
}
if (pmIsReady && !hasPm)
{
reason = $"Step {i + 1} no valid PM, " + string.Join("|", stepInfo.StepModules);
pmIsReady = false;
}
}
return pmIsReady;
}
private bool CheckSequenceRecipeFileValidTobedone(SequenceInfo seq, out string reason)
{
for (int i = 0; i < seq.Steps.Count; i++)
{
SequenceStepInfo stepInfo = seq.Steps[i];
foreach (var module in stepInfo.StepModules)
{
if (ModuleHelper.IsPm(module))
{
var recipeContent =
RecipeFileManager.Instance.LoadRecipe($"{module}\\", stepInfo.RecipeName, false);
if (string.IsNullOrEmpty(recipeContent))
{
reason = $"Can not find recipe file {module}\\{stepInfo.RecipeName}";
return false;
}
string cleanRecipeName = "";
if (stepInfo.CleanInterval > 0
&& stepInfo.StepParameter.ContainsKey("CleanRecipeNoWafer")
&& !string.IsNullOrEmpty((string)stepInfo.StepParameter["CleanRecipeNoWafer"]))
{
cleanRecipeName = (string)stepInfo.StepParameter["CleanRecipeNoWafer"];
if (!string.IsNullOrEmpty(cleanRecipeName))
{
recipeContent =
RecipeFileManager.Instance.LoadRecipe($"{module}\\", cleanRecipeName, false);
if (string.IsNullOrEmpty(recipeContent))
{
reason = $"Can not find recipe file {module}\\{cleanRecipeName}";
return false;
}
}
}
if (stepInfo.CleanInterval > 0
&& stepInfo.StepParameter.ContainsKey("CleanRecipeWafer")
&& !string.IsNullOrEmpty((string)stepInfo.StepParameter["CleanRecipeWafer"]))
{
cleanRecipeName = (string)stepInfo.StepParameter["CleanRecipeWafer"];
if (!string.IsNullOrEmpty(cleanRecipeName))
{
recipeContent =
RecipeFileManager.Instance.LoadRecipe($"{module}\\", cleanRecipeName, false);
if (string.IsNullOrEmpty(recipeContent))
{
reason = $"Can not find recipe file {module}\\{cleanRecipeName}";
return false;
}
}
}
}
}
}
reason = "";
return true;
}
private bool CheckSequenceRecipeFileValid(SequenceInfo seq, out string reason)
{
for (int i = 0; i < seq.Steps.Count; i++)
{
SequenceStepInfo stepInfo = seq.Steps[i];
foreach (var module in stepInfo.StepModules)
{
if (ModuleHelper.IsPm(module))
{
var recipeContent =
RecipeFileManager.Instance.LoadRecipe("", stepInfo.StepParameter[$"{module}Recipe"].ToString(), false);
if (string.IsNullOrEmpty(recipeContent))
{
reason = $"Can not find recipe file {stepInfo.StepParameter[$"{module}Recipe"].ToString()}";
return false;
}
}
}
}
reason = "";
return true;
}
private bool CheckSequenceOrderOk(SequenceInfo seq, out string reason)
{
reason = "";
bool foundPm = false;
bool isLLBeforePm = false;
bool isLLAfterPm = false;
bool isAlignerAfterLL = false;
for (int i = 0; i < seq.Steps.Count; i++)
{
SequenceStepInfo stepInfo = seq.Steps[i];
foreach (var module in stepInfo.StepModules)
{
if (ModuleHelper.IsPm(module))
{
foundPm = true;
}
if (!foundPm && ModuleHelper.IsLoadLock(module))
{
isLLBeforePm = true;
}
if (foundPm && ModuleHelper.IsLoadLock(module))
{
isLLAfterPm = true;
}
if (ModuleHelper.IsAligner(module) && (isLLBeforePm || foundPm))
{
isAlignerAfterLL = true;
}
}
}
if (!isLLBeforePm)
{
reason = $"not found LL before PM;";
return false;
}
if (!isLLAfterPm)
{
reason = $"not found LL after PM;";
return false;
}
if (!foundPm)
{
reason = $"not found PM in the sequence file;";
return false;
}
if (isAlignerAfterLL)
{
reason = "Aligner after LL not support";
return false;
}
return true;
}
private bool CheckSequenceNeedDummyWafer(SequenceInfo seq)
{
bool needDummyWafer = false;
for (int i = 0; i < seq.Steps.Count; i++)
{
SequenceStepInfo stepInfo = seq.Steps[i];
foreach (var module in stepInfo.StepModules)
{
if (ModuleHelper.IsPm(module))
{
if (stepInfo.CleanInterval > 0
&& stepInfo.StepParameter.ContainsKey("CleanRecipeWafer")
&& !string.IsNullOrEmpty((string)stepInfo.StepParameter["CleanRecipeWafer"]))
{
needDummyWafer = true;
break;
}
}
}
if (needDummyWafer)
break;
}
return needDummyWafer;
}
private bool ActiveProcessJob(ProcessJobInfo pj)
{
//pm is ok
if (!CheckSequencePmReady(pj.Sequence, null, out _, out string reason))
{
EV.PostWarningLog(LogSource, $"can not active {pj.Name}, {reason}");
return false;
}
_lstPmsCurrentSequence.Clear();
for (int i = 0; i < pj.Sequence.Steps.Count; i++)
{
SequenceStepInfo stepInfo = pj.Sequence.Steps[i];
foreach (var module in stepInfo.StepModules)
{
if (ModuleHelper.IsPm(module))
{
var pm = _lstPms.Find(x => x.Module == module);
if (pm != null)
_lstPmsCurrentSequence.Add(pm);
}
}
}
foreach (var pjSlotWafer in pj.SlotWafers)
{
WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
wafer.ProcessJob = pj;
wafer.NextSequenceStep = 0;
WaferDataRecorder.SetPjInfo(wafer.InnerId.ToString(), pj.InnerId.ToString());
}
ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == pj.ControlJobName);
CarrierInfo carrier = CarrierManager.Instance.GetCarrier(cj.Module);
JobDataRecorder.StartPJ(pj.InnerId.ToString(), carrier.InnerId.ToString(), cj.InnerId.ToString(), pj.Name, cj.Module, cj.Module, pj.SlotWafers.Count);
pj.SetState(EnumProcessJobState.Processing);
PreJobClean(cj);
return true;
}
#endregion
#region Module task
public Result MonitorModuleTasks()
{
MonitorPMTask();
MonitorEfemRobotTask();
for (int i = 0; i < tmRobotActions.Count; i++)
{
MonitorTmRobotTask();
}
//MonitorLoadLockTask();
MonitorInterlockTask();
MonitorAlignerTask();
return Result.RUN;
}
private void MonitorInterlockTask()
{
foreach (var cj in _lstControlJobs)
{
if (cj.State == EnumControlJobState.Executing || cj.State == EnumControlJobState.Paused ||
cj.State == EnumControlJobState.WaitingForStart)
{
var lp = GetModule(cj.Module);
if (CarrierManager.Instance.CheckNoCarrier(lp.Module, 0))
{
EV.PostAlarmLog("System", "Cassette removed while job not finished.");
//Singleton.Instance.PostMsg(RouteManager.MSG.ERROR);
}
}
}
}
private void MonitorAlignerTask()
{
if (!_aligner.IsAvailable)
return;
if (CheckWaferNextStepIsAlign(_aligner.Module, 0))
{
WaferInfo wafer = WaferManager.Instance.GetWafer(_aligner.Module, 0);
GetWaferSequenceAlignAngle(_aligner.Module, 0, out double angle);
if (_aligner.Align(angle))
{
wafer.NextSequenceStep++;
}
WaferDataRecorder.SetWaferNotchAngle(wafer.InnerId.ToString(), (float)angle);
}
}
//private void MonitorBufferTask()
//{
// foreach (var buffer in _lstBuffers)
// {
// if (!buffer.IsAvailable)
// continue;
// }
//}
private void MonitorLoadLockTask()
{
// bool isPrepareTransferForEfemobotPlace = GetWaferCountInJobQueue() > 0;
// foreach (var ll in _lstLls)
// {
// if (ll.Entity.IsPrepareTransfer)
// {
// return;
// }
// var deviceLL = DEVICE.GetDevice(ll.Module.ToString());
// //if (ll.CheckAtAtm() && (ll.Entity.IsCooling || deviceLL.CheckDoorOpen()))
// if (deviceLL.CheckDoorOpen())
// {
// var wafers = WaferManager.Instance.GetWafers(ll.Module).ToList();
// int emptySlot = 0;
// foreach (var wafer in wafers)
// {
// if (wafer.IsEmpty || wafer.ProcessState != EnumWaferProcessStatus.Idle)
// emptySlot++;
// }
// if (emptySlot >= GetWaferCountInJobQueue())
// {
// isPrepareTransferForEfemobotPlace = false;
// break;
// }
// }
// }
// foreach (var ll in _lstLls)
// {
// if (!ll.IsAvailable)
// continue;
// var deviceLL = DEVICE.GetDevice(ll.Module.ToString());
// var wafers = WaferManager.Instance.GetWafers(ll.Module).ToList();
// var isEmptyLL = true;
// bool isPrepareTransferForEfemobotPick = true;
// for (int i = 0; i <= 5;)
// {
// var wafer0 = WaferManager.Instance.GetWafer(ll.Module, i);
// var wafer1 = WaferManager.Instance.GetWafer(ll.Module, i + 1);
// if (!wafer0.IsEmpty || !wafer1.IsEmpty)
// isEmptyLL = false;
// if (wafer0.IsEmpty && wafer1.IsEmpty && GetVacuumWafer() > 0)
// isPrepareTransferForEfemobotPick = false;
// if ((!wafer0.IsEmpty && wafer0.ProcessState == EnumWaferProcessStatus.Idle) ||
// (!wafer1.IsEmpty && wafer1.ProcessState == EnumWaferProcessStatus.Idle))
// isPrepareTransferForEfemobotPick = false;
// i += 2;
// }
// if (isEmptyLL)
// isPrepareTransferForEfemobotPick = false;
// if (isPrepareTransferForEfemobotPlace && isEmptyLL && (_tmDevice.CheckSlitValveClose(ll.Module) || GetVacuumWafer() == 0) &&
// !ll.Entity.IsPrepareTransferReady(ModuleName.EfemRobot, EnumTransferType.Place))
// {
// ll.PrepareTransfer(ModuleName.EfemRobot, EnumTransferType.Place, 0);
// return;
// }
// if (isPrepareTransferForEfemobotPick)
// {
// if (!ll.Entity.IsPrepareTransferReady(ModuleName.EfemRobot, EnumTransferType.Pick))
// {
// if (!_loadlockCooling.ContainsKey(ll.Module))
// _loadlockCooling.Add(ll.Module, false);
// _loadlockCooling[ll.Module] = false;
// ll.PrepareTransfer(ModuleName.EfemRobot, EnumTransferType.Pick, 0);
// return;
// }
// //TODO, cooling 要在 Open ATM door 之前做,PrepareTransfer 需要分开 [2021/7/3 TerryLu]
// if (ll.Entity.IsPreCoolingDone())
// {
// foreach (var wafer in wafers)
// {
// if (wafer != null && !wafer.IsEmpty && GetWaferSequenceLoadLockCoolingTime(ll.Module, wafer.Slot, out int coolingTime))
// {
// _loadlockCooling[ll.Module] = true;
// ll.Cooling(coolingTime);
// break;
// }
// }
// if (_loadlockCooling[ll.Module])
// {
// foreach (var wafer in wafers)
// {
// if (wafer != null && !wafer.IsEmpty)
// {
// wafer.NextSequenceStep++;
// }
// }
// }
// }
// }
// bool isPrepareTransferForTMRobot = true;
// bool isAllEmpty = true;
// foreach (var wafer in wafers)
// {
// if (!wafer.IsEmpty)
// isAllEmpty = false;
// if (wafer.IsEmpty && GetATMWafer() > 0)
// {
// isPrepareTransferForTMRobot = false;
// break;
// }
// if (wafer.ProcessState != EnumWaferProcessStatus.Idle)
// {
// isPrepareTransferForTMRobot = false;
// break;
// }
// }
// if (isAllEmpty)
// {
// if (GetVacuumWafer() == 0)
// {
// isPrepareTransferForTMRobot = false;
// }
// else
// {
// foreach (var anotherLL in _lstLls)
// {
// if (!anotherLL.IsOnline || anotherLL == ll)
// continue;
// var anotherLLWafers = WaferManager.Instance.GetWafers(anotherLL.Module).ToList();
// int count = 0;
// for (int i = 0; i <= 5;)
// {
// if (WaferManager.Instance.CheckNoWafer(anotherLL.Module, i) && WaferManager.Instance.CheckNoWafer(anotherLL.Module, i + 1))
// {
// count++;
// }
// i += 2;
// }
// if (count >= GetVacuumWafer())
// {
// isPrepareTransferForTMRobot = false;
// break;
// }
// }
// }
// }
// if (isPrepareTransferForTMRobot && !ll.Entity.IsPrepareTransferReady(ModuleName.TMRobot, EnumTransferType.Pick))
// {
// ll.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Pick, 0);
// continue;
// }
// }
}
private void MonitorPMTask()
{
foreach (var pm in _lstPms)
{
if (!pm.IsAvailable)
continue;
if (WaferManager.Instance.CheckHasWafer(pm.Module, 0) || WaferManager.Instance.CheckHasWafer(pm.Module, 1))
{
if (CheckNeedRunClean(pm.Module, out bool withWafer, out string recipe) && withWafer
&& WaferManager.Instance.GetWafer(pm.Module, 0).Status == WaferStatus.Dummy
&& WaferManager.Instance.GetWafer(pm.Module, 0).ProcessState == EnumWaferProcessStatus.Wait
&& WaferManager.Instance.GetWafer(pm.Module, 1).Status == WaferStatus.Dummy
&& WaferManager.Instance.GetWafer(pm.Module, 1).ProcessState == EnumWaferProcessStatus.Wait)
{
pm.Process(recipe, true, withWafer);
continue;
}
var wafer0 = WaferManager.Instance.GetWafer(pm.Module, 0);
var wafer1 = WaferManager.Instance.GetWafer(pm.Module, 1);
if (CheckCanProcess(pm.Module))
{
WaferInfo wafer = wafer0.Status != WaferStatus.Empty ? wafer0 : wafer1;
if (pm.Process(wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepParameter[$"{pm.Module}Recipe"].ToString(), false, true))
{
if (wafer0.Status != WaferStatus.Empty)
wafer0.NextSequenceStep++;
if (wafer1.Status != WaferStatus.Empty)
wafer1.NextSequenceStep++;
continue;
}
}
}
else
{
if (CheckNeedRunClean(pm.Module, out bool withWafer, out string recipe) && !withWafer)
{
pm.Process(recipe, true, withWafer);
continue;
}
if (WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 0)
&& WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 1)
)
{
var _moduleName = ModuleName.LP1;
if (LPHadCreateJob != "LP1")
{
_moduleName = ModuleName.LP2;
}
SlotItem item = GetNextWaferInJobQueue(_moduleName);
if (item != null && CheckWaferNeedProcessPre(item.Module, item.Slot, pm.Module))
{
if (GetWaferTemperatureSetInRecipe(item.Module, item.Slot, pm.Module, out double temp1, out double temp2) && !pm.CheckTempReady(temp1, temp2))
{
if (temp1 != 0 && temp2 != 0)
{
pm.Preheating(temp1, temp2);
continue;
}
}
}
}
}
//if (!pm.IsAvailable)
// continue;
//var wafers = FindAllLoadLockSlotForTMRobotPick();
//if (wafers.Count > 0)
//{
// if (wafers.Any(x => CheckWaferNeedProcess(x.Item1.Module, x.Item2, pm.Module)))
// {
// for (int i = 0; i < WaferManager.Instance.GetWafers(pm.Module).Length; i++)
// {
// if (WaferManager.Instance.CheckNoWafer(pm.Module, i) && !pm.IsReadyForPlace(ModuleName.TMRobot, Hand.Blade1, i))
// {
// pm.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, i);
// return;
// }
// }
// }
//}
//else
//{
// if (WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 0)
// && WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 1)
// && WaferManager.Instance.CheckNoWafer(pm.Module, 0)
// && WaferManager.Instance.CheckNoWafer(pm.Module, 1)
// && _tmRobot.IsAvailable
// && !pm.CheckSlitValveClose())
// {
// pm.CloseSlitValve();
// return;
// }
//}
}
}
private void MonitorTmRobotTask()
{
if (!_tmRobot.IsAvailable)
return;
//TM robot is idle, release all the target
foreach (var ll in _lstLls)
{
if (ll.IsWaitTransfer(ModuleName.TMRobot))
ll.StopWaitTransfer(ModuleName.TMRobot);
}
foreach (var pm in _lstPms)
{
if (pm.IsWaitTransfer(ModuleName.TMRobot))
pm.StopWaitTransfer(ModuleName.TMRobot);
}
//MonitorTmRobotDummyWaferBufferTask();
//if (!_tmRobot.IsAvailable)
// return;
if (!_tmRobot.IsAvailable)
return;
var act = tmRobotActions.Peek();
act.Invoke();
if (!_tmRobot.IsAvailable)
return;
if (act == MonitorTmRobotLoadLockPickTask)
{
List> availableLoadLockSlots = FindAllLoadLockSlotForTMRobotPick();
if (availableLoadLockSlots.Count > 0)
{
Tuple firstSlot = GetWaferOrderInJobQueue(availableLoadLockSlots);
if (firstSlot != null)
{
SchedulerLoadLock ll = firstSlot.Item1;
int pickSlot = firstSlot.Item2;
if (!ll.IsAvailable)
return;
}
}
}
if (act == MonitorTmRobotLoadLockPlaceTask && _lstLls.All(x => !x.IsAvailable))
return;
tmRobotActions.Enqueue(tmRobotActions.Dequeue());
//MonitorTmRobotLoadLockPickTask();
//if (!_tmRobot.IsAvailable)
// return;
//MonitorTmRobotPMPickTask();
//if (!_tmRobot.IsAvailable)
// return;
//MonitorTmRobotLoadLockPlaceTask();
//if (!_tmRobot.IsAvailable)
// return;
//MonitorTmRobotPMPlaceTask();
//if (!_tmRobot.IsAvailable)
// return;
//MonitorTmRobotGoToTask();
}
private void MonitorTmRobotLoadLockPlaceTask()
{
if (!_tmRobot.IsAvailable)
return;
//place to ll
bool blade0HasWaferAndProcessed = _tmRobot.Blade1Enable && WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 0) && CheckWaferNextStepIsLoadLock(ModuleName.TMRobot, 0);
bool blade1HasWaferAndProcessed = _tmRobot.Blade2Enable && WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 1) && CheckWaferNextStepIsLoadLock(ModuleName.TMRobot, 1);
if (blade0HasWaferAndProcessed || blade1HasWaferAndProcessed)
{
Hand placeBlade = blade0HasWaferAndProcessed ? Hand.Blade1 : Hand.Blade2;
foreach (var ll in _lstLls)
{
if (!ll.IsAvailable)
continue;
if (!CheckWaferNextStepIsLoadLock(ModuleName.TMRobot, (int)placeBlade, ll.Module))
continue;
int? placeSlot = GetAvilableLoadLockSlotForTMRobotPlace(ll);
if (placeSlot != null)
{
if (_tmRobot.Place(ll.Module, (int)placeSlot, placeBlade, 0, 0, false))
{
WaferManager.Instance.GetWafer(ModuleName.TMRobot, (int)placeBlade).NextSequenceStep++;
ll.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
if (GetEmptySlotInPM() < 1)
return;
}
private void MonitorTmRobotLoadLockPickTask()
{
if (!_tmRobot.IsAvailable)
return;
if (!CanTmRobotLoadLockPick())
return;
//pick from ll
if (WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 0) || WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 1))
{
Hand pickBlade;
if (_tmRobot.Blade1Enable && WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 0))
{
pickBlade = Hand.Blade1;
}
else if (_tmRobot.Blade2Enable && WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 1))
{
pickBlade = Hand.Blade2;
}
else
{
return;
}
//if (_lstLls.All(x => !x.IsAvailable))
// return;
List> availableLoadLockSlots = FindAllLoadLockSlotForTMRobotPick();
if (availableLoadLockSlots.Count > 0)
{
Tuple firstSlot = GetWaferOrderInJobQueue(availableLoadLockSlots);
if (firstSlot != null)
{
SchedulerLoadLock ll = firstSlot.Item1;
int pickSlot = firstSlot.Item2;
if (!ll.IsAvailable)
return;
if (_tmRobot.Pick(ll.Module, (int)pickSlot, pickBlade, 0, 0, false))
{
ll.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
}
private R_TRIG tmRobotGotoLoadLockTrig = new R_TRIG();
private R_TRIG tmRobotGotoPMTrig = new R_TRIG();
SchedulerPM gotoPm = null;
private void MonitorTmRobotGoToTask()
{
if (!_tmRobot.IsAvailable)
return;
//int gotoSlot = Int32.MaxValue;
//int gotoModule = -1;
//int waferOriginSlot = int.MaxValue;
if (WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 0) && WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 1))
{
//PMA、PMB都为空,ll中有需要跑的wafer时,准备tmRobot到ll
var llWafers = FindAllLoadLockSlotForTMRobotPick();
tmRobotGotoLoadLockTrig.CLK = llWafers.Count > 0 && !CanTmRobotLoadLockPick() && GetEmptySlotInPMA() == 2 && GetEmptySlotInPMB() == 2;
if (tmRobotGotoLoadLockTrig.Q)
{
if (_tmRobot.Goto(llWafers[0].Item1.Module, llWafers[0].Item2, Hand.Blade1))
{
llWafers[0].Item1.WaitTransfer(ModuleName.TMRobot);
return;
}
}
//PMA、PMB都在工艺过程中,tmRobot移动到先开始工艺的腔体位置
bool PMAInProcess = _pm1.CheckInProcess();
bool PMBInProcess = _pm2.CheckInProcess();
if (PMAInProcess ^ PMBInProcess)
{
gotoPm = PMAInProcess ? _pm1 : _pm2;
}
if (!PMAInProcess && !PMBInProcess)
{
gotoPm = null;
}
tmRobotGotoPMTrig.CLK = PMAInProcess && PMBInProcess && gotoPm != null;
if (tmRobotGotoPMTrig.Q)
{
if (_tmRobot.Goto(gotoPm.Module, 0, Hand.Blade1))
{
gotoPm.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
private bool CanTmRobotLoadLockPick()
{
if (FindAllLoadLockSlotForTMRobotPick().Count <= 1
&& GetUnprocessedWaferCount() >= 1
&& WaferManager.Instance.GetWafers(ModuleName.TMRobot).All(x => x.IsEmpty))
//&& (CheckWaferNeedProcess(ModuleName.EfemRobot, 0) || CheckWaferNeedProcess(ModuleName.EfemRobot, 1) || CheckWaferNeedProcess(ModuleName.Aligner, 0)))
return false;
var tmWafers = WaferManager.Instance.GetWafers(ModuleName.TMRobot);
for (int i = 0; i < tmWafers.Length; i++)
{
if (!tmWafers[i].IsEmpty && !CheckWaferNeedProcess(tmWafers[i]))
return false;
}
foreach (var pm in _lstPms)
{
var pmWafer0 = WaferManager.Instance.GetWafer(pm.Module, 0);
var pmWafer1 = WaferManager.Instance.GetWafer(pm.Module, 1);
//如果腔体中两片都满了,则跳过
if (!pmWafer0.IsEmpty && !pmWafer1.IsEmpty)
continue;
//如果腔体中一片为空,则取一片相同recipeName的放入
if (!pmWafer0.IsEmpty || !pmWafer1.IsEmpty)
{
var wafer = !pmWafer0.IsEmpty ? pmWafer0 : pmWafer1;
if (!CheckWaferNeedProcess(wafer))
continue;
//判断TMRobot是否已经存在相同recipeName的wafer
for (int i = 0; i < tmWafers.Length; i++)
{
if (CheckWaferNeedProcess(tmWafers[i])
&& tmWafers[i].ProcessJob.Sequence.Name == wafer.ProcessJob.Sequence.Name)
return false;
}
}
}
return true;
}
//private void MonitorTmRobotDummyWaferBufferTask()
//{
// if (!_tmRobot.IsAvailable)
// return;
// //place to buffer
// bool blade0HasWaferAndProcessedDummy = WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 0) &&
// WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0).Status == WaferStatus.Dummy &&
// WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0).ProcessState == EnumWaferProcessStatus.Completed;
// bool blade1HasWaferAndProcessedDummy = WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 1) &&
// WaferManager.Instance.GetWafer(ModuleName.TMRobot, 1).Status == WaferStatus.Dummy &&
// WaferManager.Instance.GetWafer(ModuleName.TMRobot, 1).ProcessState == EnumWaferProcessStatus.Completed;
// if (blade0HasWaferAndProcessedDummy || blade1HasWaferAndProcessedDummy)
// {
// Hand placeBlade = blade0HasWaferAndProcessedDummy ? Hand.Blade1 : Hand.Blade2;
// if (blade0HasWaferAndProcessedDummy && blade1HasWaferAndProcessedDummy)
// {
// if (WaferManager.Instance.GetWafer(ModuleName.TMRobot, 1).OriginSlot <
// WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0).OriginSlot)
// {
// placeBlade = Hand.Blade2;
// }
// }
// int placeSlot = WaferManager.Instance.GetWafer(ModuleName.TMRobot, (int)placeBlade).OriginSlot;
// if (WaferManager.Instance.CheckNoWafer(_pm1.Module, placeSlot) && _pm1.IsReadyForPlace(ModuleName.TMRobot, placeBlade, placeSlot))
// {
// if (_tmRobot.Place(_pm1.Module, placeSlot, placeBlade))
// {
// _pm1.WaitTransfer(ModuleName.TMRobot);
// return;
// }
// }
// }
// if (!_tmRobot.IsAvailable)
// return;
// //pick from buffer
// foreach (var schedulerPm in _lstPms)
// {
// if (!CheckNeedRunClean(schedulerPm.Module, out bool withWafer, out string _) || !withWafer)
// continue;
// if (WaferManager.Instance.CheckHasWafer(schedulerPm.Module, 0))
// continue;
// if (WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 0) ||
// WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 1))
// {
// Hand pickBlade = WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 0)
// ? Hand.Blade1
// : Hand.Blade2;
// for (int i = 0; i < 2; i++)
// {
// if ((WaferManager.Instance.GetWafer(_pm1.Module, i).ProcessState == EnumWaferProcessStatus.Wait)
// && _pm1.IsReadyForPick(ModuleName.TMRobot, pickBlade, i))
// {
// if (_tmRobot.Pick(_pm1.Module, i, pickBlade))
// {
// _pm1.WaitTransfer(ModuleName.TMRobot);
// return;
// }
// }
// }
// }
// }
//}
private void MonitorTmRobotPMAPlaceTask()
{
//if (!_pm1.IsAvailable)
// return;
//if (_tmRobot.HasWafer(0) && CheckWaferNeedProcess(ModuleName.TMRobot, 0, _pm1.Module))
//{
// if (WaferManager.Instance.CheckNoWafer(_pm1.Module, 0) && !_pm1.IsReadyForPlace(ModuleName.TMRobot, Hand.Blade1, 0))
// {
// _pm1.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0);
// return;
// }
// if (WaferManager.Instance.CheckNoWafer(_pm1.Module, 1) && !_pm1.IsReadyForPlace(ModuleName.TMRobot, Hand.Blade1, 1))
// {
// _pm1.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 1);
// return;
// }
//}
//if (_tmRobot.HasWafer(1) && CheckWaferNeedProcess(ModuleName.TMRobot, 1, _pm1.Module))
//{
// if (WaferManager.Instance.CheckNoWafer(_pm1.Module, 0) && !_pm1.IsReadyForPlace(ModuleName.TMRobot, Hand.Blade1, 0))
// {
// _pm1.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0);
// return;
// }
// if (WaferManager.Instance.CheckNoWafer(_pm1.Module, 1) && !_pm1.IsReadyForPlace(ModuleName.TMRobot, Hand.Blade1, 1))
// {
// _pm1.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 1);
// return;
// }
//}
if (!_tmRobot.IsAvailable)
return;
//place
bool blade0HasWaferAndNeedProcesse = _tmRobot.Blade1Enable && WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 0) && CheckWaferNeedProcess(ModuleName.TMRobot, 0);
bool blade1HasWaferAndNeedProcesse = _tmRobot.Blade2Enable && WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 1) && CheckWaferNeedProcess(ModuleName.TMRobot, 1);
if (blade0HasWaferAndNeedProcesse || blade1HasWaferAndNeedProcesse)
{
Hand placeBlade = blade0HasWaferAndNeedProcesse ? Hand.Blade1 : Hand.Blade2;
var wafer = WaferManager.Instance.GetWafer(ModuleName.TMRobot, (int)placeBlade);
//foreach (var schedulerPm in _lstPms)
{
var schedulerPm = _pm1;
if (!schedulerPm.IsAvailable)
return;
var pmWafer0 = WaferManager.Instance.GetWafer(schedulerPm.Module, 0);
var pmWafer1 = WaferManager.Instance.GetWafer(schedulerPm.Module, 1);
//如果腔体中两片都满了,则不允许放入
if (!pmWafer0.IsEmpty && !pmWafer1.IsEmpty)
return;
//如果腔体中两片都为空,则取一片放入
if (pmWafer0.IsEmpty && pmWafer1.IsEmpty)
{
if (WaferManager.Instance.CheckNoWafer(schedulerPm.Module, 0)
&& CheckCanPlaceWaferToPM(schedulerPm.Module, wafer))
{
if (GetWaferTemperatureSetInRecipe(ModuleName.TMRobot, (int)placeBlade, ModuleName.PMA, out double temp1, out double temp2))
{
if (_tmRobot.Place(schedulerPm.Module, 0, placeBlade, temp1, temp2, true))
{
schedulerPm.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
//如果腔体中一片为空,则取一片相同recipeName的放入
if (!pmWafer0.IsEmpty || !pmWafer1.IsEmpty)
{
var pmWafer = !pmWafer0.IsEmpty ? pmWafer0 : pmWafer1;
if (!CheckWaferNeedProcess(pmWafer))
return;
int placeSlot = pmWafer0.IsEmpty ? 0 : 1;
if (WaferManager.Instance.CheckNoWafer(schedulerPm.Module, placeSlot)
&& CheckCanPlaceWaferToPM(schedulerPm.Module, wafer))
{
if (GetWaferTemperatureSetInRecipe(ModuleName.TMRobot, (int)placeBlade, ModuleName.PMA, out double temp1, out double temp2))
{
if (_tmRobot.Place(schedulerPm.Module, placeSlot, placeBlade, temp1, temp2, true))
{
schedulerPm.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
}
}
}
private void MonitorTmRobotPMBPlaceTask()
{
//if (!_pm2.IsAvailable)
// return;
//if (_tmRobot.HasWafer(0) && CheckWaferNeedProcess(ModuleName.TMRobot, 0, _pm2.Module))
//{
// if (WaferManager.Instance.CheckNoWafer(_pm2.Module, 0) && !_pm2.IsReadyForPlace(ModuleName.TMRobot, Hand.Blade1, 0))
// {
// _pm2.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0);
// return;
// }
// if (WaferManager.Instance.CheckNoWafer(_pm2.Module, 1) && !_pm2.IsReadyForPlace(ModuleName.TMRobot, Hand.Blade1, 1))
// {
// _pm2.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 1);
// return;
// }
//}
//if (_tmRobot.HasWafer(1) && CheckWaferNeedProcess(ModuleName.TMRobot, 1, _pm2.Module))
//{
// if (WaferManager.Instance.CheckNoWafer(_pm2.Module, 0) && !_pm2.IsReadyForPlace(ModuleName.TMRobot, Hand.Blade1, 0))
// {
// _pm2.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0);
// return;
// }
// if (WaferManager.Instance.CheckNoWafer(_pm2.Module, 1) && !_pm2.IsReadyForPlace(ModuleName.TMRobot, Hand.Blade1, 1))
// {
// _pm2.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 1);
// return;
// }
//}
if (!_tmRobot.IsAvailable)
return;
//place
bool blade0HasWaferAndNeedProcesse = _tmRobot.Blade1Enable && WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 0) && CheckWaferNeedProcess(ModuleName.TMRobot, 0);
bool blade1HasWaferAndNeedProcesse = _tmRobot.Blade2Enable && WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 1) && CheckWaferNeedProcess(ModuleName.TMRobot, 1);
if (blade0HasWaferAndNeedProcesse || blade1HasWaferAndNeedProcesse)
{
Hand placeBlade = blade0HasWaferAndNeedProcesse ? Hand.Blade1 : Hand.Blade2;
var wafer = WaferManager.Instance.GetWafer(ModuleName.TMRobot, (int)placeBlade);
//foreach (var schedulerPm in _lstPms)
{
var schedulerPm = _pm2;
if (!schedulerPm.IsAvailable)
return;
var pmWafer0 = WaferManager.Instance.GetWafer(schedulerPm.Module, 0);
var pmWafer1 = WaferManager.Instance.GetWafer(schedulerPm.Module, 1);
//如果腔体中两片都满了,则不允许放入
if (!pmWafer0.IsEmpty && !pmWafer1.IsEmpty)
return;
//如果腔体中两片都为空,则取一片放入
if (pmWafer0.IsEmpty && pmWafer1.IsEmpty)
{
if (WaferManager.Instance.CheckNoWafer(schedulerPm.Module, 0)
&& CheckCanPlaceWaferToPM(schedulerPm.Module, wafer))
{
if (GetWaferTemperatureSetInRecipe(ModuleName.TMRobot, (int)placeBlade, ModuleName.PMB, out double temp1, out double temp2))
{
if (_tmRobot.Place(schedulerPm.Module, 0, placeBlade, temp1, temp2, true))
{
schedulerPm.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
//如果腔体中一片为空,则取一片相同recipeName的放入
if (!pmWafer0.IsEmpty || !pmWafer1.IsEmpty)
{
var pmWafer = !pmWafer0.IsEmpty ? pmWafer0 : pmWafer1;
if (!CheckWaferNeedProcess(pmWafer))
return;
int placeSlot = pmWafer0.IsEmpty ? 0 : 1;
if (WaferManager.Instance.CheckNoWafer(schedulerPm.Module, placeSlot)
&& CheckCanPlaceWaferToPM(schedulerPm.Module, wafer))
{
if (GetWaferTemperatureSetInRecipe(ModuleName.TMRobot, (int)placeBlade, ModuleName.PMB, out double temp1, out double temp2))
{
if (_tmRobot.Place(schedulerPm.Module, placeSlot, placeBlade, temp1, temp2, true))
{
schedulerPm.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
}
}
}
private void MonitorTmRobotPMAPickTask()
{
if (!_tmRobot.IsAvailable)
return;
// pick
if ((WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 0) || WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 1)))
{
Hand pickBlade;
if (_tmRobot.Blade1Enable && WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 0))
{
pickBlade = Hand.Blade1;
}
else if (_tmRobot.Blade2Enable && WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 1))
{
pickBlade = Hand.Blade2;
}
else
{
return;
}
//foreach (var schedulerPm in _lstPms)
{
var schedulerPm = _pm1;
if (!schedulerPm.IsAvailable)
return;
if (CheckCanPickWaferFromPM(schedulerPm.Module, 0))
{
if (GetWaferTemperatureSetInRecipe(schedulerPm.Module, 0, ModuleName.PMA, out double temp1, out double temp2))
{
if (_tmRobot.Pick(schedulerPm.Module, 0, pickBlade, temp1, temp2, true))
{
schedulerPm.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
if (CheckCanPickWaferFromPM(schedulerPm.Module, 1))
{
if (GetWaferTemperatureSetInRecipe(schedulerPm.Module, 1, ModuleName.PMA, out double temp1, out double temp2))
{
if (_tmRobot.Pick(schedulerPm.Module, 1, pickBlade, temp1, temp2, true))
{
schedulerPm.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
}
}
private void MonitorTmRobotPMBPickTask()
{
if (!_tmRobot.IsAvailable)
return;
// pick
if ((WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 0) || WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 1)))
{
Hand pickBlade;
if (_tmRobot.Blade1Enable && WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 0))
{
pickBlade = Hand.Blade1;
}
else if (_tmRobot.Blade2Enable && WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 1))
{
pickBlade = Hand.Blade2;
}
else
{
return;
}
//foreach (var schedulerPm in _lstPms)
{
var schedulerPm = _pm2;
if (!schedulerPm.IsAvailable)
return;
if (CheckCanPickWaferFromPM(schedulerPm.Module, 0))
{
if (GetWaferTemperatureSetInRecipe(schedulerPm.Module, 0, ModuleName.PMB, out double temp1, out double temp2))
{
if (_tmRobot.Pick(schedulerPm.Module, 0, pickBlade, temp1, temp2, true))
{
schedulerPm.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
if (CheckCanPickWaferFromPM(schedulerPm.Module, 1))
{
if (GetWaferTemperatureSetInRecipe(schedulerPm.Module, 1, ModuleName.PMB, out double temp1, out double temp2))
{
if (_tmRobot.Pick(schedulerPm.Module, 1, pickBlade, temp1, temp2, true))
{
schedulerPm.WaitTransfer(ModuleName.TMRobot);
return;
}
}
}
}
}
}
static readonly List llNameList = new List()
{ "IsAvailable", "Task", "IsOnline", "IsError" , "IsIdle", "IsBusy", "IsPrepareTransfer", "IsCooling", "IsAtm", "IsVacuum", "Cooling", "WaitTransfer"
, "Wafer0", "Wafer1", "Wafer2", "Wafer3", "Wafer4", "Wafer5"
, "NextStep0", "NextStep1", "NextStep2", "NextStep3", "NextStep4", "NextStep5"
, "need0", "need1", "need2", "need3", "need4", "need5"};
static readonly List efemNameList = new List()
{ "IsAvailable","IsOnline","IsReady","Task","IsError"," WaitTransfer"
, "Wafer0", "Wafer1", "Wafer2"
, "NextStep0", "NextStep1", "NextStep2"
, "need0", "need1", "need2"};
static readonly List tmRobotNameList = new List()
{ "IsAvailable","IsOnline","IsError","Task","IsError"," WaitTransfer"
, "Wafer0", "Wafer1", "Wafer2", "Wafer3"
, "NextStep0", "NextStep1", "NextStep2", "NextStep3"
, "need0", "need1", "need2", "need3"};
static readonly List pmNameList = new List()
{ "IsAvailable","IsOnline","IsError","TaskDone","IsError"," WaitTransfer"
, "Wafer0", "Wafer1", "Wafer2", "Wafer3"
, "NextStep0", "NextStep1", "NextStep2", "NextStep3"
, "need0", "need1", "need2", "need3"};
static readonly List lpNameList = new List()
{ "IsAvailable","Task","IsOnline","IsError","IsReady"};
private int _GetWaferNextStepId(ModuleName module, int slotId)
{
if (!WaferManager.Instance.IsWaferSlotLocationValid(module, slotId)) return -1;
var wafer = WaferManager.Instance.GetWafer(module, slotId);
return wafer.NextSequenceStep;
}
private string _GetWaferOrigin(ModuleName module, int slotId)
{
if (!WaferManager.Instance.IsWaferSlotLocationValid(module, slotId)) return "";
var wafer = WaferManager.Instance.GetWafer(module, slotId);
return wafer.WaferOrigin;
}
private void MonitorEfemRobotTask()
{
if (!_efem.IsAvailable)
return;
////efem robot is idle, release all the target
foreach (var ll in _lstLls)
{
if (ll.IsWaitTransfer(ModuleName.EfemRobot))
ll.StopWaitTransfer(ModuleName.EfemRobot);
}
if (_aligner.IsWaitTransfer(ModuleName.EfemRobot))
_aligner.StopWaitTransfer(ModuleName.EfemRobot);
foreach (var lp in _lstLps)
{
if (lp.IsWaitTransfer(ModuleName.EfemRobot))
lp.StopWaitTransfer(ModuleName.EfemRobot);
}
if (!_efem.IsAvailable)
return;
var act = efemRobotActions.Peek();
act.Invoke();
if (!_efem.IsAvailable)
return;
efemRobotActions.Enqueue(efemRobotActions.Dequeue());
//if (!_efem.IsAvailable)
// return;
//MonitorEfemRobotAlignerTask();
//if (!_efem.IsAvailable)
// return;
//MonitorEfemRobotLoadLockTask();
//if (_aligner.HasWafer(0) && (!_efem.Blade1Enable || !_efem.Blade2Enable))
// return;
//if (_aligner.HasWafer(0) && (_efem.HasWafer(0) || _efem.HasWafer(1)))
// return;
//if (!_efem.IsAvailable)
// return;
//MonitorEfemRobotLoadPortTask();
//MonitorEfemRobotGoToTask();
}
private void MonitorEfemRobotLoadPortPlaceTask()
{
if (!_efem.IsAvailable)
return;
//place
bool blade0HasWaferAndProcessed = _efem.Blade1Enable && WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 0) &&
!CheckWaferNeedProcess(ModuleName.EfemRobot, 0);
bool blade1HasWaferAndProcessed = _efem.Blade2Enable && WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 1) &&
!CheckWaferNeedProcess(ModuleName.EfemRobot, 1);
if (blade0HasWaferAndProcessed || blade1HasWaferAndProcessed)
{
Hand placeBlade = blade0HasWaferAndProcessed ? Hand.Blade1 : Hand.Blade2;
if (blade0HasWaferAndProcessed && blade1HasWaferAndProcessed)
{
if (WaferManager.Instance.GetWafer(ModuleName.EfemRobot, 1).OriginSlot <
WaferManager.Instance.GetWafer(ModuleName.EfemRobot, 0).OriginSlot)
{
placeBlade = Hand.Blade2;
}
}
SlotItem destination = GetWaferReturnLoadPort(ModuleName.EfemRobot, (int)placeBlade);
if (destination != null && ModuleHelper.IsLoadPort(destination.Module))
{
SchedulerLoadPort lp = (SchedulerLoadPort)GetModule(destination.Module.ToString());
if (lp.IsReadyForPlace(ModuleName.EfemRobot, placeBlade, destination.Slot))
{
if (_efem.Place(destination.Module, destination.Slot, placeBlade))
{
lp.WaitTransfer(ModuleName.EfemRobot);
if (_CycleData.IsCycleMode)
_CycleData.IncreaseWaferCount(1);
//_cycledTotalWafer++;
//if (SC.ContainsItem("System.TotalCycledWafer"))
// SC.SetItemValue("System.TotalCycledWafer", _cycledTotalWafer);
return;
}
}
}
}
}
private void MonitorEfemRobotLoadPortPickTask()
{
if (!_efem.IsAvailable)
return;
if (_aligner.HasWafer(0) && (!_efem.Blade1Enable || !_efem.Blade2Enable))
return;
if (_aligner.HasWafer(0) && (_efem.HasWafer(0) || _efem.HasWafer(1)))
return;
if (_lstLls.Any(x => GetEmptySlotInLoadLock(x) < 4))
return;
//pick
bool isBlade0Empty = _efem.Blade1Enable && WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 0);
bool isBlade1Empty = _efem.Blade2Enable && WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 1);
if (GetWaferCountInJobQueue() > 0 && (isBlade0Empty || isBlade1Empty) && EfemRobotPickAllowable)
{
Hand pickBlade = isBlade1Empty ? Hand.Blade2 : Hand.Blade1;
SlotItem position = GetWaferInJobQueue();
if (position != null)
{
SchedulerLoadPort lp = GetModule(position.Module.ToString()) as SchedulerLoadPort;
if (lp != null && lp.IsReadyForPick(ModuleName.EfemRobot, pickBlade, position.Slot))
{
//WaferManager.Instance.GetWafer(position.Module, position.Slot).NextSequenceStep++;
if (_efem.Pick(position.Module, position.Slot, pickBlade))
{
lp.WaitTransfer(ModuleName.EfemRobot);
return;
}
}
}
}
}
private bool GetWaferProcessAccess(WaferInfo wafer)
{
if (wafer.ProcessJob == null || string.IsNullOrEmpty(wafer.ProcessJob.Name))
return false;
return GetPMOccupiedCount(wafer.ProcessJob.Name) > GetWaitingProcessWaferCount(wafer.ProcessJob.Name);
}
private int GetPMOccupiedCount(string pjName)
{
List location = new List();
foreach (var pj in _lstProcessJobs)
{
if (pj.Name != pjName)
continue;
if (pj.State != EnumProcessJobState.Processing)
continue;
foreach (var step in pj.Sequence.Steps)
{
foreach (var module in step.StepModules)
{
if (ModuleHelper.IsPm(module) && !location.Exists(x => x == module))
location.Add(module);
}
}
}
return location.Count;
}
private int GetWaitingProcessWaferCount(string pjName)
{
List> location = new List>()
{
Tuple.Create(ModuleName.TMRobot, 0),
Tuple.Create(ModuleName.TMRobot, 1),
Tuple.Create(ModuleName.LLA, 0),
Tuple.Create(ModuleName.LLB, 0),
Tuple.Create(ModuleName.AlignerB, 0),
Tuple.Create(ModuleName.PMA, 0),
Tuple.Create(ModuleName.PMB, 0),
Tuple.Create(ModuleName.PMC, 0),
};
int count = 0;
foreach (var tuple in location)
{
WaferInfo wafer = WaferManager.Instance.GetWafer(tuple.Item1, tuple.Item2);
if (wafer.IsEmpty)
continue;
if (wafer.ProcessJob != null && wafer.ProcessJob.Name == pjName)
count++;
}
return count;
}
Dictionary>> _ValueDict = new Dictionary>>();
//private void PrintVariables(string key, List names, params object[] values)
//{
// StackTrace trace = new StackTrace(true);
// var frames = trace.GetFrames();//1代表上级,2代表上上级,以此类推
// if (frames.Length < 2) return;
// var frame1 = frames[1];
// var method1 = frame1.GetMethod();
// if (method1 == null) return;
// string methodName = method1.Name;
// var newList = values.ToList();
// if (!_ValueDict.ContainsKey(methodName))
// {
// _ValueDict[methodName] = new Dictionary>() { { key, newList } };
// LOG.Debug($"{methodName} Key={key} Values({_ToString(names, newList)})");
// }
// else
// {
// var dict = _ValueDict[methodName];
// if (dict.ContainsKey(key))
// {
// var list = dict[key];
// StringBuilder builder = new StringBuilder();
// for (int ii = 0; ii < names.Count; ii++)
// {
// if (list[ii].Equals(newList[ii])) continue;
// builder.Append($",{names[ii]}({list[ii]} --> {newList[ii]})");
// list[ii] = newList[ii];
// }
// if (builder.Length > 0)
// {
// LOG.Debug($"{methodName} Key={key} {builder.ToString()}");
// }
// }
// else
// {
// _ValueDict[methodName].Add(key, newList);
// LOG.Debug($"{methodName} Key={key} Values({_ToString(names, newList)})");
// }
// }
//}
private string _ToString(List names, List