using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Windows.Media.Imaging; 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.DataCenter; 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 SicRT.Equipments.Schedulers; using SicRT.Modules.Schedulers; using SicRT.Scheduler; namespace SicRT.Modules { public partial class AutoTransfer : SchedulerModuleFactory { public class TrayInfo { public int TrayModule { get; set; } public int TraySlot { get; set; } public int TrayProcessCount { get; set; } } private List _lstNeedMapJob = new List(); private List _lstControlJobs = new List(); private List _lstProcessJobs = new List(); private List _lstProcessedTrayInfo = new List(); //保存石墨盘的进入腔体的信息(最多4次工艺需要换盘) private int _maxTrayCount = 2; //可以同时运行的石墨盘总数 private bool _cassProcessOnebyOne = false; //Cassette是左右交互取片还是一个Cassette取完再取另一个 private R_TRIG NotifyTrayExhausted = new R_TRIG(); private const string LogSource = "Scheduler"; private SchedulerDBCallback _dbCallback; //private const string StatsNameTotalRunningWafer = "TotalRunningWafer"; public bool CassetteFromAToB => SC.GetValue("System.Scheduler.CassetteFromAToB"); private bool _isCycleMode; private int _cycleSetPoint = 0; private int _cycledCount = 0; private int _cycledWafer = 0; private string _curRecipeName = ""; private string _curSequenceName = ""; private bool _isModuleErrorPrevious; private bool[] _isPMErrorPrevious = new bool[2]; private string _timeBuffer1 { get; set; } private string _timeBuffer2 { get; set; } private string _timeBuffer3 { get; set; } private Dictionary _bufferWaferInfo = new Dictionary(); private string _sAutoTransferConditionText; public string AutoTransferConditionText { get { return _sAutoTransferConditionText; } set { _sAutoTransferConditionText = value; } } private string _sWhichCondition; public string WhichCondition { get { return _sWhichCondition; } set { _sWhichCondition = value; } } // public AutoTransfer() { _dbCallback = new SchedulerDBCallback(); DATA.Subscribe("Scheduler.IsCycleMode", () => _isCycleMode); DATA.Subscribe("Scheduler.CycledCount", () => _cycledCount); DATA.Subscribe("Scheduler.CycleSetPoint", () => _cycleSetPoint); DATA.Subscribe("Scheduler.RecipeName", () => _curRecipeName); DATA.Subscribe("Scheduler.SequenceName", () => _curSequenceName); DATA.Subscribe("Scheduler.TimeBuffer1", () => _timeBuffer1); DATA.Subscribe("Scheduler.TimeBuffer2", () => _timeBuffer2); DATA.Subscribe("Scheduler.TimeBuffer3", () => _timeBuffer3); //显示所需条件信息用 DATA.Subscribe("Scheduler.AutoTransferConditionText", () => AutoTransferConditionText); //要显示哪个任务的条件 DATA.Subscribe("Scheduler.WhichCondition", () => WhichCondition); //DATA.Subscribe("CassAL.SlotSequenceList", () => currentSlotSequenceList["CassAL"]); DATA.Subscribe("CassAL.LocalJobName", () => { var jb = _lstControlJobs.FirstOrDefault(x => x.Module == "CassAL"); if (jb != null) return jb.Name; return ""; }); DATA.Subscribe("CassAL.LocalJobStatus", () => { var jb = _lstControlJobs.FirstOrDefault(x => x.Module == "CassAL"); if (jb != null) return jb.State.ToString(); return ""; }); //DATA.Subscribe("CassAR.SlotSequenceList", () => currentSlotSequenceList["CassAR"]); DATA.Subscribe("CassAR.LocalJobName", () => { var jb = _lstControlJobs.FirstOrDefault(x => x.Module == "CassAR"); if (jb != null) return jb.Name; return ""; }); DATA.Subscribe("CassAR.LocalJobStatus", () => { var jb = _lstControlJobs.FirstOrDefault(x => x.Module == "CassAR"); if (jb != null) return jb.State.ToString(); return ""; }); OP.Subscribe($"{ModuleName.TM}.ResetTask", (string cmd, object[] args) => { _tmRobot.ResetTask(); return true; }); OP.Subscribe($"{ModuleName.EFEM}.ResetTask", (string cmd, object[] args) => { _waferRobot.ResetTask(); _trayRobot.ResetTask(); return true; }); OP.Subscribe($"{ModuleName.WaferRobot}.ResetTask", (string cmd, object[] args) => { _waferRobot.ResetTask(); return true; }); OP.Subscribe($"{ModuleName.TrayRobot}.ResetTask", (string cmd, object[] args) => { _trayRobot.ResetTask(); return true; }); } public bool HasJobRunning { get { return _lstControlJobs.Count > 0; } } public void Clear() { _tmRobot.ResetTask(); foreach (var pm in _lstPms) { pm.ResetTask(); } foreach (var cass in _lstCassettes) { cass.ResetTask(); } _load.ResetTask(); _unload.ResetTask(); _buffer.ResetTask(); _cassetteBL.ResetTask(); _lstControlJobs.Clear(); _lstProcessJobs.Clear(); _bufferWaferInfo.Clear(); } public void ResetTask() { if (!_load.IsOnline) { _load.ResetTask(); } if (!_unload.IsOnline) { _unload.ResetTask(); } if (!_buffer.IsOnline) { _buffer.ResetTask(); } if (!_cassetteBL.IsOnline) { _cassetteBL.ResetTask(); } foreach (var pm in _lstPms) { if (!pm.IsOnline) { pm.ResetTask(); } } foreach (var cass in _lstCassettes) { if (!cass.IsOnline) { cass.ResetTask(); } } } public void GetConfig() { _cycledCount = 0; _isCycleMode = SC.GetValue("System.IsCycleMode"); _cycleSetPoint = _isCycleMode ? SC.GetValue("System.CycleCount") : 0; _maxTrayCount = _lstPms.Count * 2; } #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"]; bool autoStart = (bool)param["AutoStart"]; string lotId = jobId; if (param.ContainsKey("LotId")) lotId = (string)param["LotId"]; if (CheckModuleHaveWaferWithNoJob(out reason)) { EV.PostWarningLog(LogSource, $"{reason}"); return false; } if (!ValidateSequence(slotSequence, out reason)) { EV.PostWarningLog(LogSource, $"{reason}"); return false; } if (slotSequence.Length != 25) { reason = $"slot sequence parameter not valid, length is {slotSequence.Length}, should be 25"; EV.PostWarningLog(LogSource, reason); return false; } if (string.IsNullOrEmpty(jobId)) { jobId = "CJ_Local_" + module + DateTime.Now; } if (_lstControlJobs.Exists(x => x.Name == jobId)) { reason = $"LotID : {jobId} already created"; EV.PostWarningLog(LogSource, reason); 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); 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); 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); return false; } if (wafer.ProcessState != EnumWaferProcessStatus.Idle) { reason = $"specifies wafer: {module} slot {i + 1} process state is not idle"; EV.PostWarningLog(LogSource, reason); return false; } if (wafer.ProcessJob != null) { reason = $"specifies wafer: {module} slot {i + 1} ProcessJob is not null"; EV.PostWarningLog(LogSource, reason); return false; } if (wafer.SubstE90Status != EnumE90Status.NeedProcessing) { reason = $"specifies wafer: {module} slot {i + 1} SubstE90Status is not NeedProcessing"; EV.PostWarningLog(LogSource, reason); 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); 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); // return false; //} //if (!CheckSequenceRecipeFileValid(pj.Sequence, out reason)) //{ // reason = $"recipe file not valid in the sequence, {reason}"; // EV.PostWarningLog(LogSource, reason); // return false; //} //if (!CheckSequenceOrderOk(pj.Sequence, out reason)) //{ // reason = $"sequence path not valid, {reason}"; // EV.PostWarningLog(LogSource, reason); // 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++; } } CarrierManager.Instance.DeleteCarrier(cj.Module); CarrierManager.Instance.CreateCarrier(cj.Module); CarrierManager.Instance.UpdateCarrierId(cj.Module, $"{cj.Module} {DateTime.Now}"); 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 CreateJobEx(Dictionary param) { string reason = ""; string[] slotSequence = (string[])param["SlotSequence"]; string jobId = (string)param["JobId"]; string module = (string)param["Module"]; bool autoStart = (bool)param["AutoStart"]; if (slotSequence.Length != 25) { reason = $"slot sequence parameter not valid, slot count is {slotSequence.Length}, should be 25"; EV.PostWarningLog(LogSource, reason); return false; } if (!ValidateSequence(slotSequence, out reason)) { EV.PostWarningLog(LogSource, $"{reason}"); return false; } if (string.IsNullOrEmpty(jobId)) { jobId = "CJ_Local_" + module; } for (int i = 0; i < 25; i++) { if (string.IsNullOrEmpty(slotSequence[i]) || string.IsNullOrEmpty(slotSequence[i].Trim())) { continue; } } if (CheckModuleHaveWaferWithNoJob(out reason)) { return false; } //bool cassAHasWafer = false; //bool cassBHasWafer = false; //for (int i = 0; i < 25; i++) //{ // if (_cassetteAL.HasWafer(i)) // { // cassAHasWafer = true; // break; // } //} //for (int i = 0; i < 25; i++) //{ // if (_cassetteAR.HasWafer(i)) // { // cassBHasWafer = true; // break; // } //} ////从CassetteA出发,运行流程后回到另一个Cassette,需要一个Cassette有片子,一个Cassette没有片子 //if (_cassetteFromAToB) //{ // if (cassAHasWafer && cassBHasWafer) // { // EV.PostWarningLog(LogSource, $"Cassette AL and Cassette AR both have wafer,Can not Run Sequence From CassetteAL to CassetteAR!"); // return; // } //} //for (int i = 0; i < 25; i++) //{ // if (_cassetteAL.HasWafer(i)) // { // WaferInfo wafer = _cassetteAL.GetWaferInfo(i); // if (wafer.ProcessState == EnumWaferProcessStatus.Idle) // { // wafer.NextSequenceStep = 0; // } // } // if (_cassetteAR.HasWafer(i)) // { // WaferInfo wafer = _cassetteAR.GetWaferInfo(i); // if (wafer.ProcessState == EnumWaferProcessStatus.Idle) // { // wafer.NextSequenceStep = 0; // } // } //} Dictionary seqSlot = new Dictionary(); Dictionary> seqSlotWafers = new Dictionary>(); Dictionary indexSequence = new Dictionary(); bool enableGroupBySequence = false; for (int i = 0; i < 25; 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; seqSlotWafers[groupName].Add(i); } if (seqSlotWafers.Count == 0) { reason = $"Can not create job, no wafer assigned"; EV.PostWarningLog(LogSource, reason); return false; } List pjs = new List(); string[] seqs = seqSlot.Keys.ToArray(); List pjIDs = new List(); for (int i = 0; i < seqs.Length; i++) { var name = jobId + "_" + (i + 1); if (!CreateProcessJob(name, indexSequence[seqs[i]], seqSlotWafers[seqs[i]], autoStart)) //ProcessJob创建失败直接返回,不再创建ControlJob { return false; } pjIDs.Add(name); } if (!CreateControlJob(jobId, module, pjIDs, autoStart)) { foreach (var pjName in pjIDs) { var pj = _lstProcessJobs.FirstOrDefault(x => x.Name == pjName); if (pj != null) _lstProcessJobs.Remove(pj); } } return true; } private bool ValidateSequence(string[] seqs, out string reason) { reason = string.Empty; bool isAllSequenceNull = true; for (int i = 0; i < seqs.Length; i++) { if (string.IsNullOrEmpty(seqs[i])) continue; var sequence = SequenceInfoHelper.GetInfo(seqs[i]); if ((sequence == null || sequence.Steps == null || sequence.Steps.Count == 0) && !string.IsNullOrEmpty(sequence.Name)) { reason = $"Invalid sequence {seqs[i]}"; return false; } isAllSequenceNull = false; if (sequence.Steps != null) { int currentIndex = 0; if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.Aligner) { reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Aligner"; return false; } else { if (sequence.Steps[currentIndex].AlignAngle < 0 || sequence.Steps[currentIndex].AlignAngle > 360) { reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Aligner angle parameter is not valid"; return false; } } currentIndex++; if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.Load) { reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Load"; return false; } currentIndex++; if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.Buffer) { reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Buffer"; return false; } else { if (!sequence.Steps[currentIndex].StepParameter.ContainsKey("SlotSelection") || string.IsNullOrEmpty(sequence.Steps[currentIndex].StepParameter["SlotSelection"].ToString()) || sequence.Steps[currentIndex].StepParameter["SlotSelection"].ToString().Contains("3")) { reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Buffer SlotSelection parameter is not valid"; return false; } if (!sequence.Steps[currentIndex].StepParameter.ContainsKey("BufferType") || !sequence.Steps[currentIndex].StepParameter["BufferType"].ToString().Contains("Heat")) { reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Buffer BufferType parameter is not valid"; return false; } } currentIndex++; if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules.Any(pm => !ModuleHelper.IsPm(pm))) { reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be PM"; return false; } if (sequence.Steps.Count == 7) { currentIndex++; if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.Buffer) { reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Buffer"; return false; } else { if (!sequence.Steps[currentIndex].StepParameter.ContainsKey("SlotSelection") || sequence.Steps[currentIndex].StepParameter["SlotSelection"].ToString() != "3") { reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Buffer SlotSelection parameter is not valid"; return false; } if (!sequence.Steps[currentIndex].StepParameter.ContainsKey("BufferType") || !sequence.Steps[currentIndex].StepParameter["BufferType"].ToString().Contains("Cooling")) { reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Buffer BufferType parameter is not valid"; return false; } } } currentIndex++; if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.UnLoad) { reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Unload"; return false; } currentIndex++; if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.Aligner) { reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Load"; return false; } else { if (sequence.Steps[0].AlignAngle < 0 || sequence.Steps[0].AlignAngle > 360) { reason = $"Invalid sequence {seqs[i]}, Aligner angle parameter is not valid"; return false; } } } } if (isAllSequenceNull) { reason = $"Invalid sequence, sequence are all null "; return false; } 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.IsCassette(ModuleHelper.Converter(module))) { EV.PostWarningLog(LogSource, $"{module} should be Cassete"); 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.LotName = jobId; cj.LotInnerId = Guid.NewGuid(); cj.LotWafers = new List(); cj.SetState(EnumControlJobState.WaitingForStart); 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) { var _module = GetModule(module); if (!_module.HasWafer(slotWafer.Item2)) { EV.PostWarningLog(LogSource, $"job wafer: {module} slot {slotWafer.Item2 + 1} not in the carrier"); return false; } if (!_module.CheckWaferStatus(slotWafer.Item2, WaferStatus.Normal)) { EV.PostWarningLog(LogSource, $"job wafer: {module} slot {slotWafer.Item2 + 1} status is {_module.GetWaferInfo(slotWafer.Item2).Status}"); return false; } if (_module.GetWaferInfo(slotWafer.Item2).ProcessState != EnumWaferProcessStatus.Idle) { EV.PostWarningLog(LogSource, $"job wafer: {module} slot {slotWafer.Item2 + 1} process status is {_module.GetWaferInfo(slotWafer.Item2).ProcessState}"); return false; } slotWafers.Add(Tuple.Create(ModuleHelper.Converter(module), slotWafer.Item2)); totalWafer++; } pj.ControlJobName = cj.Name; cj.ProcessJobNameList.Add(pj.Name); pj.SlotWafers = slotWafers; foreach (var pjSlotWafer in pj.SlotWafers) { WaferInfo wafer = GetModule(pjSlotWafer.Item1).GetWaferInfo(pjSlotWafer.Item2); cj.LotWafers.Add(wafer); wafer.ProcessJob = pj; wafer.ProcessJobID = pj.Sequence.Name; 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); } } _lstControlJobs.Add(cj); CarrierManager.Instance.DeleteCarrier(cj.Module); CarrierManager.Instance.CreateCarrier(cj.Module); CarrierManager.Instance.UpdateCarrierId(cj.Module, $"{cj.Module} {DateTime.Now}"); 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/*0 based*/, bool isAutoStart) { var sequenceInfo = SequenceInfoHelper.GetInfo(sequenceName); //模块顺序检查 List lstLoad = new List(); List lstBuffer = new List(); List lstUnLoad = new List(); List lstPM = new List(); for (int i = 0; i < sequenceInfo.Steps.Count; i++) { if (sequenceInfo.Steps[i].StepModules.Count == 0) { return false; } if (sequenceInfo.Steps[i].StepModules.Any(pm => ModuleHelper.IsPm(pm))) { lstPM.Add(i); } if (sequenceInfo.Steps[i].StepModules.Any(load => load == ModuleName.Load || load == ModuleName.LoadLock)) { lstLoad.Add(i); } if (sequenceInfo.Steps[i].StepModules.Any(unload => unload == ModuleName.UnLoad)) { lstUnLoad.Add(i); } if (sequenceInfo.Steps[i].StepModules.Any(buff => buff == ModuleName.Buffer)) { lstBuffer.Add(i); } } if (lstPM.Count <= 0) { EV.PostWarningLog(LogSource, $"Sequence must have pm step info!"); return false; } if (lstLoad.Count > 1) { EV.PostWarningLog(LogSource, $"Sequence can not contain {lstLoad.Count} Load Step!"); return false; } if (lstUnLoad.Count > 1) { EV.PostWarningLog(LogSource, $"Sequence can not contain {lstUnLoad.Count} UnLoad Step!"); return false; } if (lstBuffer.Count > 0) { foreach (int bufferId in lstBuffer) { if (lstLoad.Count == 1) { if (bufferId < lstLoad[0]) { EV.PostWarningLog(LogSource, $"Sequence Load Step Must Before Buffer Step!"); return false; } } if (lstUnLoad.Count == 1) { if (bufferId > lstUnLoad[0]) { EV.PostWarningLog(LogSource, $"Sequence Buffer Step Must Before UnLoad Step!"); return false; } } } } 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; } internal void 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; //} foreach (var cj in _lstControlJobs) { foreach (var pj in _lstProcessJobs) { if (pj.ControlJobName == cj.Name) { pj.SetState(EnumProcessJobState.Stopping); } } if (_cycleSetPoint > 0) { _cycleSetPoint = _cycledCount; } } } internal void 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; } 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); _dbCallback.LotFinished(cj); JobDataRecorder.EndCJ(cj.InnerId.ToString(), aborted_cj, unprocessed_cj); } public void 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; //} foreach (var cj in _lstControlJobs) { if (cj.State == EnumControlJobState.Paused) { cj.SetState(EnumControlJobState.Executing); } } } internal void 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; //} foreach (var cj in _lstControlJobs) { if (cj.State == EnumControlJobState.Executing) { cj.SetState(EnumControlJobState.Paused); } } } internal void StartJob(string jobName) { GetConfig(); //ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName); //if (cj == null) //{ // EV.PostWarningLog(LogSource, $"start job rejected, not found job with id {jobName}"); // return; //} ////StartPreprocess(); //if (_isCycleMode) //{ // if (CheckAllJobDone()) // { // _cycledWafer = 0; // _cycledCount = 0; // } //} foreach (var cj in _lstControlJobs) { if (cj.State == EnumControlJobState.WaitingForStart) { cj.BeginTime = DateTime.Now; cj.LotInnerId = Guid.NewGuid(); _dbCallback.LotCreated(cj); cj.SetState(EnumControlJobState.Executing); } } } #endregion /// /// Start Auto Transfer /// /// /// public Result Start(params object[] objs) { GetConfig(); _cycledWafer = 0; _cycledCount = 0; //_totalWaferWhenStart = StatsDataManager.Instance.GetValue(StatsNameTotalRunningWafer); bool hasPmOnline = false; foreach (var schedulerPm in _lstPms) { if (schedulerPm.IsOnline && !schedulerPm.IsError) { hasPmOnline = true; break; } } if (_pm1.IsError) { EV.PostWarningLog("Scheduler", "can not change to auto mode, at least one process chamber be online and no error"); return Result.FAIL; } if (_pm1.IsService) { EV.PostWarningLog("Scheduler", "can not change to auto mode, PM is Service Mode"); return Result.FAIL; } if (!hasPmOnline) { EV.PostWarningLog("Scheduler", "can not change to auto mode, at least one process chamber be online and no error"); return Result.FAIL; } if (!_tmRobot.IsOnline || _tmRobot.IsError) { EV.PostWarningLog("Scheduler", "can not change to auto mode, TM robot should be online and no error"); return Result.FAIL; } return Result.RUN; } public Result Monitor() { NotifyTrayExhausted.CLK = CheckTrayExhausted(); if (NotifyTrayExhausted.Q) { EV.PostAlarmLog("System", "Tray ProcessCount Exhausted , No Tray for next Process !"); } ControlJobInfo cjActive = _lstControlJobs.Find(x => x.State == EnumControlJobState.Executing); if (cjActive != null) { MonitorModuleTasks(); } MonitorModuleError(); MonitorModuleState(); MonitorJobTasks(); MonitorCleanTasks(); return Result.RUN; } #region Job task public Result MonitorJobTasks() { UpdateProcessJobStatus(); UpdateControlJobStatus(); StartNewJob(); return Result.RUN; } protected bool CheckAllWaferReturned(ProcessJobInfo pj, bool checkAllProcessed) { for (int i = 0; i < pj.SlotWafers.Count; ++i) { WaferInfo wafer = GetModule(GetWaferReturnedCassette(pj.SlotWafers[i].Item1)).GetWaferInfo(pj.SlotWafers[i].Item2); if (wafer.IsEmpty) return false; if (checkAllProcessed && GetModule(GetWaferReturnedCassette(pj.SlotWafers[i].Item1)).CheckWaferNeedProcess(pj.SlotWafers[i].Item2)) return false; if (wafer.ProcessJob == null || wafer.ProcessJob.InnerId != pj.InnerId) { return false; } } return true; } private ModuleName GetWaferReturnedCassette(ModuleName moduleFrom) { if (CassetteFromAToB) { if (moduleFrom == ModuleName.CassAL) { return ModuleName.CassAR; } else if (moduleFrom == ModuleName.CassAR) { return ModuleName.CassAL; } } return moduleFrom; } 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 (GetModule(schedulerPm.Module).CheckNeedRunClean(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()) { //if (CheckWaferSequenceStepDone(ModuleName.LoadLock, 0)) if (_unload.IsAvailable && _buffer.IsAvailable && _tmRobot.IsAvailable && _load.IsAvailable && _waferRobot.IsAvailable && _unload.NoTray(0) && _waferRobot.IsAvailable && _tmRobot.NoTray(0) && _waferRobot.IsAvailable && _load.NoTray(0)) { pj.SetState(EnumProcessJobState.ProcessingComplete); JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0); } } } else if (pj.State == EnumProcessJobState.Stopping) { if (CheckAllWaferReturned(pj, false) && CheckAllPmCleaned(pj) && CheckAllDummyWaferReturned()) { //if (CheckWaferSequenceStepDone(ModuleName.LoadLock, 0)) if (_unload.IsAvailable && _buffer.IsAvailable && _tmRobot.IsAvailable && _load.IsAvailable && _waferRobot.IsAvailable && _unload.NoTray(0) && _waferRobot.IsAvailable && _tmRobot.NoTray(0) && _waferRobot.IsAvailable && _load.NoTray(0)) { pj.SetState(EnumProcessJobState.ProcessingComplete); JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0); } } } } } private void UpdateControlJobStatus() { if (_lstControlJobs.Count == 0) return; bool allControlJobComplete = true; 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.Find(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) { 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); _dbCallback.LotFinished(cj); } } if (cj.State == EnumControlJobState.Completed) { cjRemoveList.Add(cj); } allControlJobComplete = allControlJobComplete && cj.State == EnumControlJobState.Completed; } if (_isCycleMode && _cycledCount < _cycleSetPoint) { int countPerCycle = 0; int countProcessed = 0; foreach (var pj in _lstProcessJobs) { foreach (var pjSlotWafer in pj.SlotWafers) { countPerCycle++; WaferInfo wafer = GetModule(pjSlotWafer.Item1).GetWaferInfo(pjSlotWafer.Item2); if (!wafer.IsEmpty && !GetModule(pjSlotWafer.Item1).CheckWaferNeedProcess(pjSlotWafer.Item2)) countProcessed++; } } _cycledWafer = _cycledCount * countPerCycle + countProcessed; //StatsDataManager.Instance.SetValue(StatsNameTotalRunningWafer, _totalWaferWhenStart + _cycledWafer); if (allControlJobComplete) { _cycledCount++; if (_cycledCount < _cycleSetPoint) { foreach (var cj in _lstControlJobs) { cj.SetState(EnumControlJobState.Executing); } foreach (var pj in _lstProcessJobs) { pj.SetState(EnumProcessJobState.Queued); pj.InnerId = Guid.NewGuid(); foreach (var pjSlotWafer in pj.SlotWafers) { WaferInfo wafer = GetModule(pjSlotWafer.Item1).GetWaferInfo(pjSlotWafer.Item2); wafer.ProcessJob = null; wafer.NextSequenceStep = 0; wafer.ProcessState = EnumWaferProcessStatus.Idle; } } } } } foreach (var cj in cjRemoveList) { List pjRemoveList = new List(); foreach (var pj in _lstProcessJobs) { if (pj.ControlJobName == cj.Name) pjRemoveList.Add(pj); } foreach (var pj in pjRemoveList) { _lstProcessJobs.Remove(pj); } _lstControlJobs.Remove(cj); } ControlJobInfo cjActived = null; foreach (var cj in _lstControlJobs) { if (cj.State == EnumControlJobState.Executing) { cjActived = cj; break; } } } private void StartNewJob() { foreach (var cj in _lstControlJobs) { if (cj.State == EnumControlJobState.Executing) { 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; } if (pj.State == EnumProcessJobState.Queued) { ActiveProcessJob(pj); } } } } } public bool CheckAllJobDone() { foreach (var cj in _lstControlJobs) { if (cj.State == EnumControlJobState.Executing || cj.State == EnumControlJobState.Paused) return false; } if (_lstControlJobs.Count == 0) { return true; } return false; } private bool ActiveProcessJob(ProcessJobInfo pj) { //_lstPms.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) && _lstPms.Exists(x => x.Module == module)) // { // _lstPms.Add(_lstPms.Find(x => x.Module == module)); // } // } //} foreach (var pjSlotWafer in pj.SlotWafers) { WaferInfo wafer = GetModule(pjSlotWafer.Item1).GetWaferInfo(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(), null, cj.InnerId.ToString(), pj.Name, cj.Module, cj.Module, pj.SlotWafers.Count); pj.SetState(EnumProcessJobState.Processing); return true; } #endregion #region Module task public Result MonitorModuleTasks() { //Load和UnLoad不能同时抽气 //System.Diagnostics.Debug.Assert(!((_tmRobot.IsInPumping && _load.IsInPumping) || (_tmRobot.IsInPumping && _unload.IsInPumping) || (_unload.IsInPumping && _load.IsInPumping)),$"检测到 _load.IsInPumping :{_load.IsInPumping}, _unload.IsInPumping :{_unload.IsInPumping}, _tmRobot.IsInPumping :{_tmRobot.IsInPumping}"); if ((_tmRobot.IsInPumping && _load.IsInPumping) || (_tmRobot.IsInPumping && _unload.IsInPumping) || (_unload.IsInPumping && _load.IsInPumping)) EV.PostAlarmLog("Schedule", $"检测到 _load.IsInPumping :{_load.IsInPumping}, _unload.IsInPumping :{_unload.IsInPumping}, _tmRobot.IsInPumping :{_tmRobot.IsInPumping}"); MonitorPMTask(); MonitorBufferTask(); MonitorAlignerTask(); MonitorTmRobotTask(); MonitorWaferRobotTask(); MonitorTrayRobotTask(); MonitorLoadTask(); MonitorUnLoadTask(); return Result.RUN; } private void MonitorBufferTask() { if (!_buffer.IsAvailable) { return; } for (int i = 0; i < 3; i++) { bool canExcute = _buffer.HasWafer(i) && _buffer.CheckWaferNextStepIsThis(_buffer.Module, i); if (canExcute) { WaferInfo bufferWafer = _buffer.GetWaferInfo(i); int bufferSetValue = 0; if (!GetWaferSequenceNextValue(ModuleName.Buffer, i, "BufferType", out string strBufferType)) { continue; } if (!GetWaferSequenceNextValue(ModuleName.Buffer, i, "SetValue", out string strBufferSetValue)) { continue; } if (!Int32.TryParse(strBufferSetValue, out bufferSetValue)) { continue; } WaferInfo wafer = _buffer.GetWaferInfo(i); //分别判断冷却和加热方式温度是否达到 if (strBufferType == "HeatByTemp") { if (_bufferWaferInfo.ContainsKey(bufferWafer.InnerId.ToString())) { DateTime dtStartTime = _bufferWaferInfo[bufferWafer.InnerId.ToString()]; double pastTime = (DateTime.Now - dtStartTime).TotalSeconds; //选择By温度5秒后再判断温度 if (pastTime > 5) { if (_buffer.GetTemperature() >= bufferSetValue) wafer.NextSequenceStep++; _bufferWaferInfo.Remove(bufferWafer.InnerId.ToString()); } } else { _bufferWaferInfo.Add(bufferWafer.InnerId.ToString(), DateTime.Now); } } else if (strBufferType == "HeatByTime") { if (_bufferWaferInfo.ContainsKey(bufferWafer.InnerId.ToString())) { DateTime dtStartTime = _bufferWaferInfo[bufferWafer.InnerId.ToString()]; double pastTime = (DateTime.Now - dtStartTime).TotalSeconds; if (i == 0) { _timeBuffer1 = pastTime > bufferSetValue ? "0" : (bufferSetValue - pastTime).ToString(); } else if (i == 1) { _timeBuffer2 = pastTime > bufferSetValue ? "0" : (bufferSetValue - pastTime).ToString(); } if (i == 2) { _timeBuffer3 = pastTime > bufferSetValue ? "0" : (bufferSetValue - pastTime).ToString(); } if (pastTime > bufferSetValue) { wafer.NextSequenceStep++; _bufferWaferInfo.Remove(bufferWafer.InnerId.ToString()); } } else { _bufferWaferInfo.Add(bufferWafer.InnerId.ToString(), DateTime.Now); } } else if (strBufferType == "CoolingByTime") { if (_bufferWaferInfo.ContainsKey(bufferWafer.InnerId.ToString())) { DateTime dtStartTime = _bufferWaferInfo[bufferWafer.InnerId.ToString()]; double pastTime = (DateTime.Now - dtStartTime).TotalSeconds; if (i == 0) { _timeBuffer1 = pastTime > bufferSetValue ? "0" : (bufferSetValue - pastTime).ToString(); } else if (i == 1) { _timeBuffer2 = pastTime > bufferSetValue ? "0" : (bufferSetValue - pastTime).ToString(); } if (i == 2) { _timeBuffer3 = pastTime > bufferSetValue ? "0" : (bufferSetValue - pastTime).ToString(); } if (pastTime > bufferSetValue) { wafer.NextSequenceStep++; _bufferWaferInfo.Remove(bufferWafer.InnerId.ToString()); } } else { _bufferWaferInfo.Add(bufferWafer.InnerId.ToString(), DateTime.Now); } } return; } } //Place和Pick条件都一样 if (!_buffer.IsReadyForPlace(ModuleName.TMRobot, 0)) { _buffer.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0); } } private void MonitorLoadTask() { if (!_load.IsAvailable) { return; } bool canExcute = _load.HasWafer(0) && _load.HasTrayAndNotExceedProcessCount(0); if (canExcute) { if (!_load.CheckWaferTrayGrouped()) { _load.GroupWaferTray(); return; } else if (_load.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0) && !_unload.IsInPumping && !_tmRobot.IsInPumping) { _load.Purge(_load.GetWaferPurgeCount(0), _load.GetWaferPumpDelayTime(0)); _load.GetWaferInfo(0).NextSequenceStep++; return; } } if (_load.HasWafer(0) && _load.HasTrayAndNotExceedProcessCount(0)) { //有Wafer和石墨盘,等待TM来取,此时Unload必须不在动作 if (!_load.IsReadyForPick(ModuleName.TMRobot, 0) && !_unload.IsInPumping && !_tmRobot.IsInPumping) { _load.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Pick, 0); return; } } else if ((_tmRobot.NoWafer(0) && _tmRobot.HasTrayAndExceedProcessCount(0)) || (_buffer.NoWafer(0) && _buffer.HasTrayAndExceedProcessCount(0)) || (_buffer.NoWafer(1) && _buffer.HasTrayAndExceedProcessCount(1)) || (_buffer.NoWafer(2) && _buffer.HasTrayAndExceedProcessCount(2))) { if (!_load.IsReadyForPlace(ModuleName.TMRobot, 0) && !_unload.IsInPumping && !_tmRobot.IsInPumping) { _load.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0); return; } } else if (_load.NoWafer(0)) { //Load只有石墨盘,要么是WaferRobot来放,要么是TrayRobot来取 if (!_load.IsReadyForPlace(ModuleName.WaferRobot, 0) && !_unload.IsInPumping && !_tmRobot.IsInPumping) { _load.PrepareTransfer(ModuleName.WaferRobot, EnumTransferType.Place, 0); return; } } else if (_load.HasTrayAndExceedProcessCount(0)) { if (!_load.IsReadyForPick(ModuleName.TrayRobot, 0) && !_unload.IsInPumping && !_tmRobot.IsInPumping) { _load.PrepareTransfer(ModuleName.TrayRobot, EnumTransferType.Pick, 0); return; } } else { //啥也没有,要么是等工艺做完TMRobot来放(TM手上有Tray,无Wafer),要么是还没做工艺等TrayRobot来放 if (_tmRobot.HasTray(0) && _tmRobot.NoWafer(0) || _unload.HasTray(0) || (_buffer.HasTray(0) && _buffer.NoWafer(0)) || (_buffer.HasTray(1) && _buffer.NoWafer(1)) || (_buffer.HasTray(2) && _buffer.NoWafer(2))) { if (!_load.IsReadyForPlace(ModuleName.TMRobot, 0) && !_unload.IsInPumping && !_tmRobot.IsInPumping) { _load.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0); return; } } else { if (!_load.IsReadyForPlace(ModuleName.TrayRobot, 0) && !_unload.IsInPumping && !_tmRobot.IsInPumping) { _load.PrepareTransfer(ModuleName.TrayRobot, EnumTransferType.Place, 0); return; } } } } private void MonitorUnLoadTask() { if (!_unload.IsAvailable) { return; } //UnLoad if (_unload.FirstDetectWaferArrive(0) || _unload.FirstDetectWaferLeave(0)) { _unload.ResetPurgedAndSeparatedStatus(); } bool canExcuteUnLoad = _unload.HasWafer(0); //&& _unload.GetWaferInfo(0).ProcessState == EnumWaferProcessStatus.Completed; //并且闸板阀关上 if (canExcuteUnLoad) { if (!_unload.CheckCoolingCompleted()) { GetWaferSequenceCoolingTime(_unload.Module, 0, out int coolingTime); _unload.Cooling(true, coolingTime); return; } if (_unload.CheckCoolingCompleted() && !_unload.CheckWaferTraySeparated()) { _unload.SeparateWaferTray(); return; } if (_unload.CheckWaferNextStepIsThis(ModuleName.UnLoad, 0) && _unload.NoTray(0) && _unload.CheckCoolingCompleted() && _unload.CheckWaferTraySeparated() && !_unload.CheckPurged() && !_load.IsInPumping && !_tmRobot.IsInPumping) { _unload.Purge(_unload.GetWaferPurgeCount(0), _unload.GetWaferPumpDelayTime(0)); _unload.GetWaferInfo(0).NextSequenceStep++; return; } } if (_unload.HasTray(0)) { if (!_unload.CheckPurged() && _unload.CheckWaferTraySeparated() && !_unload.IsReadyForPick(ModuleName.TMRobot, 0) && !_load.IsInPumping && !_tmRobot.IsInPumping) { _unload.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Pick, 0); return; } } else if (_unload.HasWafer(0)) { if (_unload.CheckPurged() && _unload.CheckWaferTraySeparated() && !_unload.IsReadyForPick(ModuleName.WaferRobot, 0) && !_load.IsInPumping && !_tmRobot.IsInPumping) { _unload.PrepareTransfer(ModuleName.WaferRobot, EnumTransferType.Pick, 0); return; } } else { if (!_unload.IsReadyForPlace(ModuleName.TMRobot, 0) && !_load.IsInPumping && !_tmRobot.IsInPumping) { _unload.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0); return; } } } private void MonitorAlignerTask() { if (!_aligner.IsAvailable) { return; } if (_aligner.HasWafer(0) && _aligner.CheckWaferNextStepIsThis(ModuleName.Aligner, 0)) { _aligner.Aligning(); _aligner.GetWaferInfo(0).NextSequenceStep++; } } private void MonitorPMTask() { foreach (var pm in _lstPms) { if (!pm.IsAvailable) continue; if (_pm1.HasWafer(0)) { if (_pm1.CheckNeedRunClean(out bool withWafer, out string recipe) && withWafer && GetModule(pm.Module).GetWaferInfo(0).Status == WaferStatus.Dummy && GetModule(pm.Module).GetWaferInfo(0).ProcessState == EnumWaferProcessStatus.Wait) { pm.Process(recipe, true, withWafer); continue; } if (GetModule(pm.Module).CheckWaferNeedProcess(0, pm.Module)) { WaferInfo wafer = GetModule(pm.Module).GetWaferInfo(0); if (pm.Process(wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].RecipeName, false, true)) { GetModule(pm.Module).GetWaferInfo(0).NextSequenceStep++; continue; } } else { if (!pm.IsReadyForPick(ModuleName.TMRobot, 0)) { pm.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Pick, 0); } } } else { if (GetModule(pm.Module).CheckNeedRunClean(out bool withWafer, out string recipe) && !withWafer) { pm.Process(recipe, true, withWafer); continue; } if (!pm.IsReadyForPlace(ModuleName.TMRobot, 0)) { pm.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0); } } } } private void MonitorTmRobotTask() { if (!_tmRobot.IsAvailable) return; foreach (var pm in _lstPms) { if (pm.IsWaitTransfer(ModuleName.TMRobot)) pm.StopWaitTransfer(ModuleName.TMRobot); } if (_buffer.IsWaitTransfer(ModuleName.TMRobot)) _buffer.StopWaitTransfer(ModuleName.TMRobot); if (_load.IsWaitTransfer(ModuleName.TMRobot)) _load.StopWaitTransfer(ModuleName.TMRobot); if (_unload.IsWaitTransfer(ModuleName.TMRobot)) _unload.StopWaitTransfer(ModuleName.TMRobot); MonitorTmRobotPMTask(); MonitorTmRobotBufferTask(); MonitorTmRobotLoadTask(); MonitorTmRobotUnLoadTask(); } private void MonitorWaferRobotTask() { foreach (var cass in _lstCassettes) { if (cass.IsWaitTransfer(ModuleName.WaferRobot)) cass.StopWaitTransfer(ModuleName.WaferRobot); } if (_aligner.IsWaitTransfer(ModuleName.WaferRobot)) _aligner.StopWaitTransfer(ModuleName.WaferRobot); if (_load.IsWaitTransfer(ModuleName.WaferRobot)) _load.StopWaitTransfer(ModuleName.WaferRobot); if (_unload.IsWaitTransfer(ModuleName.WaferRobot)) _unload.StopWaitTransfer(ModuleName.WaferRobot); MonitorWaferRobotCassetteTask(); MonitorWaferRobotUnLoadTask(); MonitorWaferRobotAligerTask(); MonitorWaferRobotLoadTask(); } private void MonitorTrayRobotTask() { if (_cassetteBL.IsWaitTransfer(ModuleName.TrayRobot)) _cassetteBL.StopWaitTransfer(ModuleName.TrayRobot); if (_load.IsWaitTransfer(ModuleName.TrayRobot)) _load.StopWaitTransfer(ModuleName.TrayRobot); MonitorTrayRobotLoadTask(); MonitorTrayRobotCassetteTask(); } private void MonitorTmRobotLoadTask() { if (!_load.IsAvailable) return; if (!_tmRobot.IsAvailable) return; //place Robot有Tray无Wafer,Load无Tray bool canPlace = _tmRobot.HasTrayAndExceedProcessCount(0) && _tmRobot.NoWafer(0) && _load.NoTray(0); if (canPlace) { if (_load.IsReadyForPlace(ModuleName.TMRobot, 0) && !_unload.IsInPumping) { if (_tmRobot.Place(_load.Module, 0, Hand.Blade1)) { _load.WaitTransfer(ModuleName.TMRobot); return; } } } if (!_load.IsAvailable) return; if (!_tmRobot.IsAvailable) return; //place Robot有Tray无Wafer,Load无Tray canPlace = _tmRobot.HasTray(0) && _tmRobot.NoWafer(0) && _load.NoTray(0) && _load.HasWafer(0); if (canPlace) { if (_load.IsReadyForPlace(ModuleName.TMRobot, 0) && !_unload.IsInPumping) { if (_tmRobot.Place(_load.Module, 0, Hand.Blade1)) { _load.WaitTransfer(ModuleName.TMRobot); return; } } } if (!_load.IsAvailable) return; if (!_tmRobot.IsAvailable) return; //pick TM无Tray,需要Process,下一个位置没有Tray bool canPick = _tmRobot.NoTray(0) && _load.CheckWaferNeedProcess(0) && !_load.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0) && _load.CheckWaferNextStepModuleNoTray(0); if (canPick) { //需要完成组合和Purge if (!_load.CheckWaferTrayGrouped()) { return; } if (_load.IsReadyForPick(ModuleName.TMRobot, 0) && !_unload.IsInPumping) { if (_tmRobot.Pick(_load.Module, 0, Hand.Blade1)) { _load.WaitTransfer(ModuleName.TMRobot); return; } } } } private void MonitorTmRobotUnLoadTask() { if (!_unload.IsAvailable) return; if (!_tmRobot.IsAvailable) return; //UnLoad取盘只关心LoadLock是否有空位 //place Robot有Wafer,UnLoad无Tray无Wafer bool canPlaceUnLoad = _tmRobot.HasWafer(0) && _unload.NoTray(0) && _unload.NoWafer(0) && (_aligner.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0) || _unload.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0) || _tmRobot.CheckWaferSequenceStepDone(0)) ;//&& _tmRobot.GetWaferInfo(0).ProcessState == EnumWaferProcessStatus.Completed; if (canPlaceUnLoad) { if (_unload.IsReadyForPlace(ModuleName.TMRobot, 0) && !_load.IsInPumping) { if (_tmRobot.Place(_unload.Module, 0, Hand.Blade1)) { _unload.WaitTransfer(ModuleName.TMRobot); return; } } } if (!_unload.IsAvailable) return; if (!_tmRobot.IsAvailable) return; //pick UnLoad有Tray,TM无Tray,LoadLock没有Tray,UnLoad分离完成 bool canPickUnLoad = _tmRobot.NoTray(0) && _unload.HasTray(0) && _load.NoTray(0); //&& _unload.GetWaferInfo(0).ProcessState == EnumWaferProcessStatus.Completed; if (canPickUnLoad) { //需要UnLoad把石墨盘和Wafer分离完成 if (!_unload.CheckWaferTraySeparated()) { return; } if (_unload.IsReadyForPick(ModuleName.TMRobot, 0) && !_load.IsInPumping) { if (_tmRobot.Pick(_unload.Module, 0, Hand.Blade1)) { _unload.WaitTransfer(ModuleName.TMRobot); return; } } } } private void MonitorTmRobotBufferTask() { if (!_tmRobot.IsAvailable) return; if (!_buffer.IsAvailable) return; //place Buffer位置没有Tray,Robot有Wafer,下一步骤是Buffer bool canPalce = _tmRobot.HasWafer(0) && _buffer.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0); if (canPalce) { SlotItem bufferEmptySlot = GetEmptyBufferSlot(_tmRobot.GetWaferInfo(0)); if (bufferEmptySlot == null) { return; } if (_buffer.IsReadyForPlace(ModuleName.TMRobot, bufferEmptySlot.Slot)) { if (_tmRobot.Place(_buffer.Module, bufferEmptySlot.Slot, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } return; } if (!_tmRobot.IsAvailable) return; if (!_buffer.IsAvailable) return; //place 最后没有新的wafer需要工艺时,完成工艺后的Tray放入Buffer中 canPalce = _tmRobot.HasTray(0) && _tmRobot.NoWafer(0); if (canPalce) { if (_tmRobot.HasTrayAndExceedProcessCount(0) && _load.NoTray(0) && _load.NoWafer(0)) return; if (!_tmRobot.CheckWaferNeedProcess(0) && GetWaferInJobQueue() == null && !_load.CheckWaferNeedProcess(0) && !_aligner.CheckWaferNeedProcess(0) && !_waferRobot.CheckWaferNeedProcess(0)) { SlotItem bufferEmptySlot = null; for (int i = 0; i < 3; i++) { if (_buffer.NoTray(i) && _buffer.NoWafer(i)) { bufferEmptySlot = new SlotItem(ModuleName.Buffer, i); break; } } if (bufferEmptySlot == null) { return; } if (_buffer.IsReadyForPlace(ModuleName.TMRobot, bufferEmptySlot.Slot)) { if (_tmRobot.Place(_buffer.Module, bufferEmptySlot.Slot, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } } if (!_tmRobot.IsAvailable) return; if (!_buffer.IsAvailable) return; //pick 当前步(UnLoad没有Wafer),Buffer有Tray,机械手没有Tray bool canPick = _tmRobot.NoTray(0); if (canPick) { for (int i = 0; i < 3; i++) { if (_buffer.HasTray(i) && !_buffer.CheckWaferNextStepIsThis(ModuleName.Buffer, i)) { int bufferSetValue = 0; if (!GetWaferSequenceCurrentValue(ModuleName.Buffer, i, "BufferType", out string strBufferType)) { continue; } if (!GetWaferSequenceCurrentValue(ModuleName.Buffer, i, "SetValue", out string strBufferSetValue)) { continue; } if (!Int32.TryParse(strBufferSetValue, out bufferSetValue)) { continue; } //分别判断冷却和加热方式温度是否达到 if (strBufferType == "HeatByTemp" && _buffer.GetTemperature() < bufferSetValue) { continue; } else if (strBufferType == "CoolingByTemp" && _buffer.GetTemperature() > bufferSetValue) { continue; } //如果已经完成所有步骤或者下一步需要经过UnLoad,UnLoad不允许有盘 if (_buffer.CheckWaferSequenceStepDone(i) || _unload.CheckWaferNextStepIsThis(ModuleName.Buffer, i) || _aligner.CheckWaferNextStepIsThis(ModuleName.Buffer, i)) { if (_unload.HasWafer(0) || _unload.HasTray(0)) { continue; } } //下一步如果去PM1,判断PM1是否准备好 if (_pm1.CheckWaferNextStepIsThis(ModuleName.Buffer, i)) { if (!_pm1.IsAvailable || _pm1.HasTray(0) || _pm1.HasWafer(0) || !_pm1.IsReadyForPlace(ModuleName.TMRobot, 0) || !_pm1.CheckBufferToPMTemp()) continue; } if (_buffer.CheckWaferNextStepModuleNoTray(i)) { if (_buffer.IsReadyForPick(ModuleName.TMRobot, i)) { if (_tmRobot.Pick(_buffer.Module, i, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } } } } if (!_tmRobot.IsAvailable) return; if (!_buffer.IsAvailable) return; //pick 工艺开始时,如果Buffer中有Tray时,优先取Buffer中的Tray,而不是Cst中Tray canPick = _tmRobot.NoTray(0) && _load.IsReadyForPlace(ModuleName.TMRobot, 0) && _load.NoTray(0) //&& _load.HasWafer(0) && ((GetWaferInJobQueue() != null || _aligner.CheckWaferNeedProcess(0) || _waferRobot.CheckWaferNeedProcess(0)) || _load.CheckWaferNeedProcess(0)); if (canPick) { //优先取出超过ProcessCount的Tray for (int i = 0; i < 3; i++) { if (_buffer.HasTray(i) && _buffer.NoWafer(i)) { if (_buffer.IsReadyForPick(ModuleName.TMRobot, i) && _buffer.HasTrayAndExceedProcessCount(i)) { if (_tmRobot.Pick(_buffer.Module, i, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } } for (int i = 0; i < 3; i++) { if (_buffer.HasTray(i) && _buffer.NoWafer(i)) { if (_buffer.IsReadyForPick(ModuleName.TMRobot, i) && _load.IsReadyForPlace(ModuleName.TMRobot, 0)) { if (_tmRobot.Pick(_buffer.Module, i, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } } } } private void MonitorTmRobotPMTask() { if (!_tmRobot.IsAvailable) return; //place to pm bool blade0HasWaferAndNeedProcess = _tmRobot.HasWafer(0) && _tmRobot.CheckWaferNeedProcess(0); if (blade0HasWaferAndNeedProcess) { foreach (var pm in _lstPms) { if (!pm.IsAvailable || !GetModule(pm.Module).NoWafer(0) || !pm.IsReadyForPlace(ModuleName.TMRobot, 0) || !pm.CheckTempBelow900()) continue; //bool cleanRequired = CheckNeedRunClean(pm.Module, out bool withWafer, out _); //if (cleanRequired) //{ // if (!withWafer) // continue; // bool blade0DummyPlace = _tmRobot.HasWafer(0) // && CheckWaferNeedProcess(ModuleName.TMRobot, 0, pm.Module) // && WaferManager.Instance.CheckWaferIsDummy(ModuleName.TMRobot, 0); //bool blade1DummyPlace =_tmRobot.HasWafer(1) // && CheckWaferNeedProcess(ModuleName.TMRobot, 1, pm.Module) // && WaferManager.Instance.CheckWaferIsDummy(ModuleName.TMRobot, 1); // if (blade0DummyPlace || blade1DummyPlace) // { // Hand placeBlade = blade0DummyPlace ? Hand.Blade1 : Hand.Blade2; // if (blade0DummyPlace && blade1DummyPlace) // { // if ( _tmRobot.GetWaferInfo(1).OriginSlot < // _tmRobot.GetWaferInfo(0).OriginSlot) // { // placeBlade = Hand.Blade2; // } // } // if (_tmRobot.Place(pm.Module, 0, placeBlade)) // { // pm.WaitTransfer(ModuleName.TMRobot); // return; // } // } // continue; //} bool blade0Place = _tmRobot.HasWafer(0) && _tmRobot.CheckWaferNeedProcess(0, pm.Module); if (blade0Place) { Hand placeBlade = Hand.Blade1; if (_tmRobot.Place(pm.Module, 0, placeBlade)) { pm.WaitTransfer(ModuleName.TMRobot); return; } } } } if (!_tmRobot.IsAvailable) return; //pick from pm if (_tmRobot.NoWafer(0) && _tmRobot.NoTray(0)) { Hand pickBlade = Hand.Blade1; ModuleName pickPm = ModuleName.System; foreach (var schedulerPm in _lstPms) { //增加温度低于900才能Pick的限制 if (!schedulerPm.IsAvailable || GetModule(schedulerPm.Module).NoWafer(0) || GetModule(schedulerPm.Module).CheckWaferNeedProcess(0, schedulerPm.Module) || _tmRobot.HasWafer((int)pickBlade) || !schedulerPm.CheckTempBelow900()) continue; //如果下一步是Buffer if (_buffer.CheckWaferNextStepIsThis(schedulerPm.Module, 0)) { SlotItem bufferEmptySlot = GetEmptyBufferSlot(GetModule(schedulerPm.Module).GetWaferInfo(0)); if (bufferEmptySlot == null) { return; } } else if (_unload.HasWafer(0) || _unload.HasTray(0)) { return; } pickPm = schedulerPm.Module; break; } if (pickPm != ModuleName.System) { SchedulerModule pm = GetModule(pickPm.ToString()); if (pm.IsReadyForPick(ModuleName.TMRobot, 0)) { if (_tmRobot.Pick(pm.Module, 0, pickBlade)) { pm.WaitTransfer(ModuleName.TMRobot); return; } } } } } private void MonitorWaferRobotLoadTask() { if (!_waferRobot.IsAvailable) return; if (!_load.IsAvailable) return; //place Load没有Wafer有Tray,Robot有Wafer,步骤没有完成,下一步不是Aligner (其它:SlitValve都关了,大气) bool canPlace = _waferRobot.HasWafer(0) && _load.NoWafer(0) && _load.NoTray(0) && _waferRobot.GetWaferInfo(0).Status != WaferStatus.Dummy && !_aligner.CheckWaferNextStepIsThis(ModuleName.WaferRobot, 0) && _waferRobot.CheckWaferNeedProcess(0); if (canPlace) { if (_load.IsReadyForPlace(ModuleName.WaferRobot, 0)) { if (_waferRobot.Place(_load.Module, 0, Hand.Blade1)) { _load.WaitTransfer(ModuleName.WaferRobot); return; } } } } private void MonitorWaferRobotUnLoadTask() { if (!_waferRobot.IsAvailable) return; if (!_unload.IsAvailable) return; //pick UnLoad有Wafer没有Tray,Robot没有Wafer,步骤都完成了或者下一步的模块没有片子 (其它:UnLoad 夹爪夹住,顶针下降,SlitValve都关了,大气) bool canPick = _waferRobot.NoWafer(0) && _unload.HasWafer(0) && _unload.NoTray(0) && (_unload.CheckWaferNextStepModuleNoWafer(0) || _unload.CheckWaferSequenceStepDone(0)) && _unload.GetWaferInfo(0).Status != WaferStatus.Dummy; if (canPick) { //下一步是Aligner并且Aligner上不允许有片子 if (_aligner.CheckWaferNextStepIsThis(ModuleName.UnLoad, 0)) { if (_aligner.HasWafer(0)) { return; } } if (_unload.IsReadyForPick(ModuleName.WaferRobot, 0)) { if (_waferRobot.Pick(_unload.Module, 0, Hand.Blade1)) { _unload.WaitTransfer(ModuleName.WaferRobot); return; } } } } private void MonitorWaferRobotAligerTask() { if (!_waferRobot.IsAvailable || !_aligner.IsAvailable) { return; } //place 任务还没完成,下一步是Aligner,Robot有片子,Aligner没片子 bool canPlaceAligner = _aligner.NoWafer(0) && _waferRobot.HasWafer(0) && (_aligner.CheckWaferNextStepIsThis(ModuleName.WaferRobot, 0) || _waferRobot.CheckWaferSequenceStepDone(0)) && _waferRobot.GetWaferInfo(0).Status != WaferStatus.Dummy; if (canPlaceAligner) { if (_aligner.IsReadyForPlace(ModuleName.WaferRobot, 0)) { if (_waferRobot.Place(_aligner.Module, 0, Hand.Blade1)) { _aligner.WaitTransfer(ModuleName.WaferRobot); return; } } } if (!_waferRobot.IsAvailable || !_aligner.IsAvailable) { return; } //pick Robot没片子,Aligner有片子 bool canPickAligner = _aligner.HasWafer(0) && _waferRobot.NoWafer(0) && _aligner.GetWaferInfo(0).Status != WaferStatus.Dummy && !_aligner.CheckWaferNextStepIsThis(ModuleName.Aligner, 0) && _load.CheckWaferNextStepIsThis(ModuleName.Aligner, 0) && _load.IsReadyForPlace(ModuleName.WaferRobot, 0); //pick Aligner wafer to load if (canPickAligner) { //需要运行工艺,Load不能有片子,Load不能有Tray if (_aligner.CheckWaferNeedProcess(0)) { if (_load.HasWafer(0) || _load.HasTray(0) || _tmRobot.HasTrayAndExceedProcessCount(0) || _buffer.HasTrayAndExceedProcessCount(0) || _buffer.HasTrayAndExceedProcessCount(1) || _buffer.HasTrayAndExceedProcessCount(2)) { return; } } if (_aligner.IsReadyForPick(ModuleName.WaferRobot, 0)) { if (_waferRobot.Pick(_aligner.Module, 0, Hand.Blade1)) { _aligner.WaitTransfer(ModuleName.WaferRobot); return; } } } //pick Aligner wafer to cst bool canPick = _aligner.HasWafer(0) && _waferRobot.NoWafer(0) && _aligner.GetWaferInfo(0).Status != WaferStatus.Dummy && !_aligner.CheckWaferNextStepIsThis(ModuleName.Aligner, 0) && _aligner.CheckWaferSequenceStepDone(0); //WaferRobot从Aligner Pick Wafer不应检查Load腔条件 if (canPick) { if (_aligner.IsReadyForPick(ModuleName.WaferRobot, 0)) { if (_waferRobot.Pick(_aligner.Module, 0, Hand.Blade1)) { _aligner.WaitTransfer(ModuleName.WaferRobot); return; } } } } private void MonitorWaferRobotCassetteMapTask() { //if (!_waferRobot.IsAvailable) // return; //if (_waferRobot.HasWafer(0)) //{ // return; //} //else //{ // ControlJobInfo cjActive = _lstNeedMapJob.Find(x => x.State == EnumControlJobState.WaitingForStart); // if (cjActive != null) // { // if (_waferRobot.Map(ModuleHelper.Converter(cjActive.Module))) // { // } // } //} } private void MonitorWaferRobotCassetteTask() { if (!_waferRobot.IsAvailable) return; //place 任务完成了,Robot有片子,Cassette没有片子 bool canPlaceCassette = _waferRobot.HasWafer(0) && _waferRobot.GetWaferInfo(0).Status != WaferStatus.Dummy && _waferRobot.CheckWaferSequenceStepDone(0); if (canPlaceCassette) { WaferInfo wafer = _waferRobot.GetWaferInfo(0); if (GetWaferReturnedCassette((ModuleName)wafer.OriginStation) == ModuleName.CassAL) { if (_cassetteAL.IsAvailable && _cassetteAL.IsReadyForPlace(ModuleName.WaferRobot, wafer.OriginSlot)) { if (_waferRobot.Place(_cassetteAL.Module, wafer.OriginSlot, Hand.Blade1)) { _cassetteAL.WaitTransfer(ModuleName.WaferRobot); return; } } } else if (GetWaferReturnedCassette((ModuleName)wafer.OriginStation) == ModuleName.CassAR) { if (_cassetteAR.IsAvailable && _cassetteAR.IsReadyForPlace(ModuleName.WaferRobot, wafer.OriginSlot)) { if (_waferRobot.Place(_cassetteAR.Module, wafer.OriginSlot, Hand.Blade1)) { _cassetteAR.WaitTransfer(ModuleName.WaferRobot); return; } } } } if (!_waferRobot.IsAvailable) return; //pick Robot没有片子,下一步的模块没有片子 bool canPick = _waferRobot.NoWafer(0); SlotItem position = GetWaferInJobQueue(); if (canPick && position != null) { //下一步是Aligner并且Aligner上不允许有片子 if (_aligner.CheckWaferNextStepIsThis(position.Module, position.Slot)) { if (_aligner.HasWafer(0)) { return; } ////如果UnLoad有Wafer,而且下一步是Aligner,则不能取 //if (CheckWaferNextStepIsAligner(ModuleName.UnLoad, 0)) //{ // return; //} } else if (_load.HasWafer(0) || _load.NoTray(0) || _load.HasTrayAndExceedProcessCount(0) || !_load.IsReadyForPlace(ModuleName.WaferRobot, 0) || _tmRobot.HasTrayAndExceedProcessCount(0) || _buffer.HasTrayAndExceedProcessCount(0) || _buffer.HasTrayAndExceedProcessCount(1) || _buffer.HasTrayAndExceedProcessCount(2)) { return; } if (GetRunWaferCount() >= _maxTrayCount)//超过可以运行的石墨盘最大数 { return; } if (position.Module == ModuleName.CassAR) { if (_cassetteAR.IsAvailable && _cassetteAR.IsReadyForPick(ModuleName.WaferRobot, 0)) { if (_waferRobot.Pick(position.Module, position.Slot, Hand.Blade1)) { _cassetteAR.WaitTransfer(ModuleName.WaferRobot); return; } } } else if (position.Module == ModuleName.CassAL) { if (_cassetteAL.IsAvailable && _cassetteAL.IsReadyForPick(ModuleName.WaferRobot, 0)) { if (_waferRobot.Pick(position.Module, position.Slot, Hand.Blade1)) { _cassetteAL.WaitTransfer(ModuleName.WaferRobot); return; } } } } } private void MonitorTrayRobotLoadTask() { //---------------------------------- string s = ""; if (WhichCondition == "TrayRobotLoad") { s += AddC("_trayRobot.IsAvailable", _trayRobot.IsAvailable.ToString(), "True"); s += AddC("_load.IsAvailable", _load.IsAvailable.ToString(), "True"); s += "canPlace:\r\n"; s += AddC("_load.NoTray(0)", _load.NoTray(0).ToString(), "True"); s += AddC("_trayRobot.HasTray(0)", _trayRobot.HasTray(0).ToString(), "True"); } AutoTransferConditionText = s; //---------------------------------- // if (!_trayRobot.IsAvailable) return; if (!_load.IsAvailable) return; //place UnLoad没有Tray,Load没有Tray,Robot有Tray,Cassette或Aligner有任务未完成 bool canPlace = _load.NoTray(0) && _trayRobot.HasTrayAndNotExceedProcessCount(0) && _unload.NoTray(0) && _load.HasWafer(0) && (GetWaferInJobQueue() != null || (_aligner.HasWafer(0) && _aligner.CheckWaferNeedProcess(0)) || (_waferRobot.HasWafer(0) && _waferRobot.CheckWaferNeedProcess(0)) || (_load.HasWafer(0) && _load.CheckWaferNeedProcess(0))); if (canPlace) { //TMRobot有Tray无Wafer也不能放 if (_tmRobot.NoWafer(0) && _tmRobot.HasTray(0)) { return; } if (_load.IsReadyForPlace(ModuleName.TrayRobot, 0)) { if (_trayRobot.Place(_load.Module, 0, Hand.Blade1)) { _load.WaitTransfer(ModuleName.TrayRobot); return; } } } if (!_trayRobot.IsAvailable) return; if (!_load.IsAvailable) return; //pick Load有Tray,判断CassatteA和Aligner还有片子没有跑PM工艺就不需要Pick bool canPick = _load.HasTrayAndExceedProcessCount(0); if (canPick) { //if (_load.HasTray(0) )// && _load.GetWaferInfo(0).TrayProcessCount < _trayMaxProcessCount) //{ //if (GetWaferInJobQueue() != null) //{ // return; //} //} SlotItem emptyTraySlot = GetTrayOrignSlot(ModuleName.LoadLock, 0);// GetEmptyTraySlot(13); //先取Wafer再取石墨盘 if (emptyTraySlot != null && _load.HasTrayAndExceedProcessCount(0)) { if (_load.IsReadyForPick(ModuleName.TrayRobot, 0)) { if (_trayRobot.Pick(_load.Module, 0, Hand.Blade1)) { _load.WaitTransfer(ModuleName.TrayRobot); return; } } } } } private void MonitorTrayRobotCassetteTask() { if (!_trayRobot.IsAvailable) return; if (!_cassetteBL.IsAvailable) return; //place Robot有盘 其它逻辑跟Load的Pick一致 bool canPlace = _trayRobot.HasTrayAndExceedProcessCount(0) || _load.HasTray(0) || (GetWaferInJobQueue() == null && _aligner.NoWafer(0) && _waferRobot.NoWafer(0) && _load.NoWafer(0)); if (canPlace) { SlotItem slotItem = GetTrayOrignSlot(ModuleName.TrayRobot, 0); //GetEmptyTraySlot(13); if (slotItem != null) { if (_cassetteBL.IsReadyForPlace(ModuleName.TrayRobot, slotItem.Slot)) { if (_trayRobot.Place(slotItem.Module, slotItem.Slot, Hand.Blade1)) { _cassetteBL.WaitTransfer(ModuleName.TrayRobot); return; } } } } //pick Casstte有Tray,UnLoad没有Tray,Load没有Tray(各个腔体运行的石墨盘总数小于设定值) if (GetCurrentTrayCount() >= _maxTrayCount) { return; } if (!_trayRobot.IsAvailable) return; if (!_cassetteBL.IsAvailable) return; if (CheckHasTrayAndNoWafer(new List>() { new Tuple(ModuleName.Buffer,0), new Tuple(ModuleName.Buffer,1), new Tuple(ModuleName.Buffer,2), new Tuple(ModuleName.TMRobot,0), new Tuple(ModuleName.LoadLock,0), })) return; bool canPick = (_aligner.HasWafer(0) && _aligner.CheckWaferNeedProcess(0)) || (_waferRobot.HasWafer(0) && _waferRobot.CheckWaferNeedProcess(0)) || (_load.HasWafer(0) && _load.CheckWaferNeedProcess(0)) || GetWaferInJobQueue() != null; if (canPick) { SlotItem slotItem = GetTraySlot(8); if (slotItem != null && _load.NoTray(0) && _trayRobot.NoTray(0)) { if (_cassetteBL.IsReadyForPick(ModuleName.TrayRobot, slotItem.Slot)) { if (_trayRobot.Pick(slotItem.Module, slotItem.Slot, Hand.Blade1)) { _cassetteBL.WaitTransfer(ModuleName.TrayRobot); return; } } } } } #endregion #region Logic Check /// /// 获得Buffer的方式和数值 /// /// /// /// /// /// private bool GetWaferSequenceNextValue(ModuleName module, int slot, string nodeName, out string nodeValue) { nodeValue = ""; if (!GetModule(module).HasWafer(slot)) return false; WaferInfo wafer = GetModule(module).GetWaferInfo(slot); if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null) return false; if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count) return false; if (!wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(module)) return false; nodeValue = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepParameter[nodeName].ToString(); if (String.IsNullOrEmpty(nodeValue)) { return false; } return true; } private bool GetWaferSequenceCurrentValue(ModuleName module, int slot, string nodeName, out string nodeValue) { nodeValue = ""; if (!GetModule(module).HasWafer(slot)) return false; WaferInfo wafer = GetModule(module).GetWaferInfo(slot); if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null) return false; if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count) return false; if (!wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep - 1].StepModules.Contains(module)) return false; nodeValue = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep - 1].StepParameter[nodeName].ToString(); if (String.IsNullOrEmpty(nodeValue)) { return false; } return true; } private bool GetWaferSequenceCoolingTime(ModuleName module, int slot, out int coolingTime) { coolingTime = 0; if (!WaferManager.Instance.CheckHasWafer(module, slot)) return false; WaferInfo wafer = WaferManager.Instance.GetWafer(module, slot); if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null) return false; if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count) return false; if (!wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(module)) return false; if (!int.TryParse(wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepParameter["CoolingTime"].ToString(), out coolingTime)) { coolingTime = 0; //coolingTime = SC.GetValue("Unload.DefaultCoolingTime"); //EV.PostWarningLog("Scheduler", $"Sequence step Unload cooling time is not valid, instead with the SC default value {coolingTime} seconds"); return false; } return true; } private bool CheckHasTrayAndNoWafer(List> needCheckPositions) { foreach (var positionTuple in needCheckPositions) { var module = GetModule(positionTuple.Item1); if (module.HasTray(positionTuple.Item2) && module.NoWafer(positionTuple.Item2)) { return true; } } return false; } private bool CheckTrayExhausted() { return !(_buffer.HasTrayAndNotExceedProcessCount(0) | _buffer.HasTrayAndNotExceedProcessCount(1) | _buffer.HasTrayAndNotExceedProcessCount(2) | _cassetteBL.HasTrayAndNotExceedProcessCount(0) | _cassetteBL.HasTrayAndNotExceedProcessCount(1) | _cassetteBL.HasTrayAndNotExceedProcessCount(2) | _cassetteBL.HasTrayAndNotExceedProcessCount(3) | _cassetteBL.HasTrayAndNotExceedProcessCount(4) | _cassetteBL.HasTrayAndNotExceedProcessCount(5) | _cassetteBL.HasTrayAndNotExceedProcessCount(6) | _cassetteBL.HasTrayAndNotExceedProcessCount(7) | _load.HasTrayAndNotExceedProcessCount(0) | _unload.HasTrayAndNotExceedProcessCount(0) | _tmRobot.HasTrayAndNotExceedProcessCount(0) | _trayRobot.HasTrayAndNotExceedProcessCount(0) | _pm1.HasTrayAndNotExceedProcessCount(0)); } public bool CheckBufferWaferHasJob() { WaferInfo wafer = _buffer.GetWaferInfo(0); if (wafer.IsEmpty) { return false; } if (wafer.ProcessJob == null) { return false; } ProcessJobInfo pj = _lstProcessJobs.Find(x => x.InnerId == wafer.ProcessJob.InnerId); if (pj == null) { return false; } return true; } public bool CheckWaferProcessModuleIsAvailable(ModuleName waferModule, int waferSlot) { WaferInfo wafer = GetModule(waferModule).GetWaferInfo(waferSlot); if (wafer.IsEmpty) return false; if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null) return false; if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count) return false; //foreach (var module in wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules) //{ //if (GetModule(module).NoWafer(0) // && _lstPms.Find(x => x.Module == module).IsAvailable // && !CheckNeedRunClean(module, out bool _, out string _)) // return true; //} foreach (var step in wafer.ProcessJob.Sequence.Steps) { foreach (var module in step.StepModules) { if (module.ToString().StartsWith("PM") && GetModule(module).NoWafer(0) && _lstPms.Find(x => x.Module == module).IsAvailable && !GetModule(module).CheckNeedRunClean(out bool _, out string _)) return true; } } return false; } private SlotItem GetWaferInJobQueue() { foreach (var cj in _lstControlJobs) { if (cj.State == EnumControlJobState.Executing) { foreach (var pj in _lstProcessJobs) { if (pj.ControlJobName == cj.Name && pj.State == EnumProcessJobState.Processing) { foreach (var pjSlotWafer in pj.SlotWafers) { if (pjSlotWafer.Item1 == ModuleName.CassAL || pjSlotWafer.Item1 == ModuleName.CassAR) { if (GetModule(pjSlotWafer.Item1).CheckWaferNeedProcess(pjSlotWafer.Item2)) return new SlotItem(pjSlotWafer.Item1, pjSlotWafer.Item2); } } } } } } return null; } private SlotItem GetTraySlot(int slotCount) { foreach (var cj in _lstControlJobs) { if (cj.State == EnumControlJobState.Executing) { for (int i = 0; i < slotCount; i++) { if (_cassetteBL.HasTrayAndNotExceedProcessCount(i)) { return new SlotItem(ModuleName.CassBL, i); } } } } return null; } private SlotItem GetTrayOrignSlot(ModuleName module, int slot) { WaferInfo wafer = GetModule(module).GetWaferInfo(slot); if (wafer != null && GetModule(module).HasTray(slot) && _cassetteBL.NoTray(wafer.TrayOriginSlot)) { return new SlotItem(ModuleName.CassBL, wafer.TrayOriginSlot); } return null; } //private SlotItem GetEmptyTraySlot(int slotCount) //{ // foreach (var cj in _lstControlJobs) // { // if (cj.State == EnumControlJobState.Executing) // { // for (int i = 0; i < slotCount; i++) // { //if (_cassetteBL.NoTray(i)) // { // return new SlotItem(ModuleName.CassBL, i); // } // } // } // } // return null; //} /// /// 获取空位置 /// /// /// private SlotItem GetEmptyBufferSlot(WaferInfo wafer) { foreach (var cj in _lstControlJobs) { if (cj.State == EnumControlJobState.Executing) { string strSots = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepParameter["SlotSelection"].ToString(); if (strSots == null) { return null; } string[] slots = strSots.Split(','); for (int i = 0; i < slots.Length; i++) { int slot = 0; if (Int32.TryParse(slots[i], out slot)) { if (_buffer.NoTray(slot - 1)) { return new SlotItem(ModuleName.Buffer, slot - 1); } } } } } return null; } /// /// 获取各个模块的Wafer总数量 /// /// private int GetRunWaferCount() { int waferCount = 0; if (_load.HasWafer(0)) { waferCount++; } if (_unload.HasWafer(0)) { waferCount++; } if (_tmRobot.HasWafer(0)) { waferCount++; } foreach (SchedulerPM pm in _lstPms) { if (GetModule(pm.Module).HasWafer(0)) { waferCount++; } } for (int i = 0; i < 3; i++) { if (_buffer.HasWafer(i)) { waferCount++; } } return waferCount; } /// /// 获取各个模块的石墨盘总数量 /// /// private int GetCurrentTrayCount() { int trayCount = 0; if (_load.HasTray(0)) { trayCount++; } if (_unload.HasTray(0)) { trayCount++; } if (_tmRobot.HasTray(0)) { trayCount++; } foreach (SchedulerPM pm in _lstPms) { if (GetModule(pm.Module).HasTray(0)) { trayCount++; } } for (int i = 0; i < 3; i++) { if (_buffer.HasTray(i)) { trayCount++; } } return trayCount; } /// /// 获取ProcessJob可以同时运行工艺的Wafer总数 /// /// private int GetCurrentWaferCount() { int waferCountDiv = 0; int cassWaferCount = 0; foreach (var cj in _lstControlJobs) { if (cj.State == EnumControlJobState.Executing) { foreach (var pj in _lstProcessJobs) { if (pj.ControlJobName == cj.Name && pj.State == EnumProcessJobState.Processing) { cassWaferCount += pj.SlotWafers.Count; foreach (var pjSlotWafer in pj.SlotWafers) { var module = GetModule(pjSlotWafer.Item1); if (module.HasWafer(pjSlotWafer.Item2) && !module.CheckWaferNeedProcess(pjSlotWafer.Item2)) { waferCountDiv++; } } } } } } return cassWaferCount - waferCountDiv; //int waferCount = 0; //if (_load.HasWafer(0)) //{ // waferCount++; //} //for (int i = 0; i < 3; i++) //{ //if (_buffer.HasWafer(i)) // { // waferCount++; // } //} //if (_waferRobot.CheckWaferNeedProcess(0) ) //{ // waferCount++; //} //if (_aligner.CheckWaferNeedProcess(0) ) //{ // waferCount++; //} //for (int i=0;i<25;i++) //{ // if (CheckWaferNeedProcess(ModuleName.CassAL, i)) // { // waferCount++; // } // if (CheckWaferNeedProcess(ModuleName.CassAR, i)) // { // waferCount++; // } //} //return waferCount; } #endregion #region Module error public Result MonitorModuleError() { bool isModuleError = false; bool[] isPMError = new bool[2]; for (int i = 0; i < isPMError.Length; i++) { isPMError[i] = false; } if (_tmRobot.IsError) isModuleError = true; for (int i = 0; i < _lstPms.Count; i++) // PM出错,不影响其他腔体的传片 { if (_lstPms[i].IsError) isPMError[i] = true; } if (isModuleError && !_isModuleErrorPrevious) { //var jb1 = _lstControlJobs.Find(x => x.Module == "LP1"); //if (jb1 != null) // PauseJob(jb1.Name); //var jb2 = _lstControlJobs.Find(x => x.Module == "LP2"); //if (jb2 != null) // PauseJob(jb2.Name); } else if (!isModuleError && _isModuleErrorPrevious) { Reset(); //CloseDoor(); } for (int i = 0; i < _lstPms.Count; i++) { if (!isPMError[i] && _isPMErrorPrevious[i]) { _lstPms[i].ResetTask(); } _isPMErrorPrevious[i] = isPMError[i]; } _isModuleErrorPrevious = isModuleError; return Result.RUN; } public Result MonitorModuleState() { bool controlJobExecuting = false; bool isModuleBusy = false; foreach (var controlJob in _lstControlJobs) { if (controlJob.State == EnumControlJobState.Executing) controlJobExecuting = true; } //if (!controlJobExecuting) // return Result.RUN; //if (_tmRobot.IsOnline && _tmRobot.Entity.IsBusy) // isModuleBusy = true; //if (_efemRobot.IsOnline && _efemRobot.Entity.IsBusy) // isModuleBusy = true; //foreach (var pm in _lstPms) // PM出错,不影响其他腔体的传片 //{ // if (pm.IsOnline && pm.Entity.IsBusy) // isModuleBusy = true; //} //foreach (var ll in _lstLls) //{ // if (ll.IsOnline && ll.Entity.IsBusy) // isModuleBusy = true; //} //foreach (var lp in _lstLps) //{ // if (lp.IsOnline && lp.Entity.IsBusy) // isModuleBusy = true; //} //if (_aligner.IsOnline && _aligner.Entity.IsBusy) // isModuleBusy = true; //if (isModuleBusy) //{ // _timer.Stop(); // _started = false; //} //else //{ // if (!_started) // { // _timer.Start(_deadLockTimeout * 1000); // _started = true; // } //} //_trigDeadLock.CLK = _timer.IsTimeout(); //if (_trigDeadLock.Q) //{ // EV.PostWarningLog("System", "A deadlock has occurred"); //} return Result.RUN; } public Result MonitorCleanTasks() { //if (!_isInited) //{ // _isInited = true; // InitClean(); //} //foreach (var pm in _lstPms) //{ // pm.MonitorCleanTasks(); //} return Result.RUN; } private bool CheckModuleHaveWaferWithNoJob(out string reason) { reason = ""; if (_lstControlJobs.Count > 0) { reason = "lstControlJobs.Count > 0"; return false; } else { if (_buffer.HasWafer(0) || _buffer.HasWafer(1) || _buffer.HasWafer(2)) { reason = $"Buffer have wafer!"; EV.PostWarningLog(LogSource, reason); return true; } if (_tmRobot.HasWafer(0)) { reason = $"TmRobot have wafer!"; EV.PostWarningLog(LogSource, reason); return true; } if (_aligner.HasWafer(0)) { reason = $"Aligner have wafer!"; EV.PostWarningLog(LogSource, reason); return true; } if (_waferRobot.HasWafer(0)) { reason = $"WaferRobot have wafer!"; EV.PostWarningLog(LogSource, reason); return true; } if (_load.HasWafer(0)) { reason = $"Load have wafer!"; EV.PostWarningLog(LogSource, reason); return true; } if (_load.HasTray(0)) { reason = $"Load have Tray!"; EV.PostWarningLog(LogSource, reason); return true; } if (_unload.HasWafer(0)) { reason = $"UnLoad have wafer!"; EV.PostWarningLog(LogSource, reason); return true; } if (_unload.HasTray(0)) { reason = $"UnLoad have Tray!"; EV.PostWarningLog(LogSource, reason); return true; } return false; } } #endregion /// /// Add condition string /// /// /// /// private string AddC(string s, string v, string sShould) { return (s + ":" + v + ", Should be:" + sShould + "\r\n"); } } }