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 = 4; //可以同时运行的石墨盘总数 private bool _cassProcessOnebyOne = false; //Cassette是左右交互取片还是一个Cassette取完再取另一个 private R_TRIG NotifyTrayExhausted = new R_TRIG(); private R_TRIG _trigIsPumping = new R_TRIG(); private const string LogSource = "Scheduler"; private SchedulerDBCallback _dbCallback; 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(); Queue waferRobotActions = new Queue() { }; Queue trayRobotActions = new Queue() { }; Queue tmRobotActions = new Queue() { }; 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("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.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; }); waferRobotActions.Enqueue(MonitorWaferRobotCassettePlaceTask); waferRobotActions.Enqueue(MonitorWaferRobotCassettePickTask); waferRobotActions.Enqueue(MonitorWaferRobotUnLoadPickTask); waferRobotActions.Enqueue(MonitorWaferRobotAlignerPlaceTask); waferRobotActions.Enqueue(MonitorWaferRobotAlignerPickTask); waferRobotActions.Enqueue(MonitorWaferRobotLoadPlaceTask); trayRobotActions.Enqueue(MonitorTrayRobotLoadPlaceTask); trayRobotActions.Enqueue(MonitorTrayRobotLoadPickTask); trayRobotActions.Enqueue(MonitorTrayRobotCassettePlaceTask); trayRobotActions.Enqueue(MonitorTrayRobotCassettePickTask); tmRobotActions.Enqueue(MonitorTmRobotPMPlaceTask); tmRobotActions.Enqueue(MonitorTmRobotPMPickTask); tmRobotActions.Enqueue(MonitorTmRobotBufferPlaceTask); tmRobotActions.Enqueue(MonitorTmRobotBufferPickTask); tmRobotActions.Enqueue(MonitorTmRobotLoadPlaceTask); tmRobotActions.Enqueue(MonitorTmRobotLoadPickTask); tmRobotActions.Enqueue(MonitorTmRobotUnLoadPlaceTask); tmRobotActions.Enqueue(MonitorTmRobotUnLoadPickTask); } public bool HasJobRunning { get { return _lstControlJobs.Count > 0; } } public void Clear() { _tmRobot.ResetTask(); _waferRobot.ResetTask(); _trayRobot.ResetTask(); foreach (var pm in _lstPms) { pm.ResetTask(); } foreach (var cass in _lstWaferCassettes) { cass.ResetTask(); } _cassetteBL.ResetTask(); _load.ResetTask(); _unload.ResetTask(); _buffer.ResetTask(); _lstControlJobs.Clear(); _lstProcessJobs.Clear(); _bufferWaferInfo.Clear(); } public void ResetTask() { if(!_tmRobot.IsOnline) { _tmRobot.ResetTask(); } if(!_waferRobot.IsOnline) { _waferRobot.ResetTask(); } if(!_trayRobot.IsOnline) { _trayRobot.ResetTask(); } if (!_load.IsOnline) { _load.ResetTask(); } if (!_unload.IsOnline) { _unload.ResetTask(); } if (!_buffer.IsOnline) { _buffer.ResetTask(); } foreach (var pm in _lstPms) { if (!pm.IsOnline) { pm.ResetTask(); } } foreach (var cass in _lstWaferCassettes) { if (!cass.IsOnline) { cass.ResetTask(); } } if (!_cassetteBL.IsOnline) { _cassetteBL.ResetTask(); } } public void GetConfig() { _cycledCount = 0; _isCycleMode = SC.GetValue("System.IsCycleMode"); _cycleSetPoint = _isCycleMode ? SC.GetValue("System.CycleCount") : 0; _maxTrayCount = _lstPms.Count * 2; } 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); //检查PM的状态 if (!CheckSequencePmReady(pj.Sequence)) { 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) { var 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; } 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("PurgeCount") || !sequence.Steps[currentIndex].StepParameter.ContainsKey("PumpDelayTime")) { reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Buffer PurgeCount or PumpDelayTime 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 Aligner"; 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) { var 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; var 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 bool CheckSequencePmReady(SequenceInfo seqInfo) { if (seqInfo.Name != "") { foreach (var step in seqInfo.Steps) { foreach (var moduleName in step.StepModules) { if (ModuleHelper.IsPm(moduleName)) { var module = _lstPms.Find(x => x.Module == moduleName); if (module != null) { if (module.IsError) { EV.PostWarningLog("Scheduler", $"can not start job, {moduleName} is not be error"); return false; } if (!module.IsOnline) { EV.PostWarningLog("Scheduler", $"can not start job, {moduleName} is not be online"); return false; } //if (module.IsService) //{ // EV.PostWarningLog("Scheduler", $"can not start job, {moduleName} is Service Mode"); // return false; //} } else { EV.PostWarningLog("Scheduler", "Sequence PM can not be null!"); return false; } } } } } else { EV.PostWarningLog("Scheduler", "Sequence can not be null!"); return false; } return true; } 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; } foreach (var needProcessWafer in cj.LotWafers) { if (CheckWaferNeedProcess((ModuleName)needProcessWafer.OriginStation, needProcessWafer.OriginSlot, ModuleName.PM1)) { if (_pm1.IsError) { EV.PostWarningLog("Scheduler", "can not start job, pm1 is in error"); return; } if (_pm1.IsService) { EV.PostWarningLog("Scheduler", "can no tstart job, PM1 is Service Mode"); return; } } else if (CheckWaferNeedProcess((ModuleName)needProcessWafer.OriginStation, needProcessWafer.OriginSlot, ModuleName.PM2)) { if (_pm2.IsError) { EV.PostWarningLog("Scheduler", "can not start job, pm2 is in error"); return; } if (_pm2.IsService) { EV.PostWarningLog("Scheduler", "can no tstart job, PM2 is Service Mode"); return; } } } //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); } } } /// /// Start Auto Transfer /// /// /// public Result Start(params object[] objs) { GetConfig(); _cycledWafer = 0; _cycledCount = 0; bool hasPmOnline = false; foreach (var schedulerPm in _lstPms) { if (schedulerPm.IsOnline && !schedulerPm.IsError) { hasPmOnline = true; break; } } 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; } //Exhaust 耗尽 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(); MonitorJobTasks(); return Result.RUN; } 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) { var 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 (_unload.IsAvailable && _buffer.IsAvailable && _tmRobot.IsAvailable && _load.IsAvailable && _waferRobot.IsAvailable && _unload.NoTray(0) && _trayRobot.IsAvailable && _tmRobot.NoTray(0) && _load.NoTray(0) && _waferRobot.NoWafer(0) && _trayRobot.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 (_unload.IsAvailable && _buffer.IsAvailable && _tmRobot.IsAvailable && _load.IsAvailable && _waferRobot.IsAvailable && _unload.NoTray(0) && _trayRobot.IsAvailable && _tmRobot.NoTray(0) && _load.NoTray(0) && _waferRobot.NoWafer(0) && _trayRobot.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; var 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) { foreach (var pjSlotWafer in pj.SlotWafers) { var 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; } public Result MonitorModuleTasks() { //TMRobot和UnLoad不能同时抽气 _trigIsPumping.CLK = _unload.IsInPumping && _tmRobot.IsInPumping; if (_trigIsPumping.Q) { EV.PostAlarmLog("System", $"检测到 TM.IsInPumping,current Task is {_tmRobot.GetTask()}, _unload.IsInPumping,current Task is {_unload.GetTask()}"); } MonitorPMTask(); MonitorBufferTask(); MonitorAlignerTask(); MonitorTmRobotTask(); MonitorWaferRobotTask(); MonitorTrayRobotTask(); MonitorLoadTask(); MonitorUnLoadTask(); return Result.RUN; } private void MonitorBufferTask() { if (!_buffer.IsAvailable) { return; } if (_buffer.FirstDetectTrayArrive(0) || _buffer.FirstDetectTrayArrive(1) || _buffer.FirstDetectTrayArrive(2)) { _buffer.ResetPurgeStatus(); } for (int i = 0; i < 3; i++) { bool canExcute = _buffer.HasWafer(i) && _buffer.CheckWaferNextStepIsThis(_buffer.Module, i); if (canExcute) { var 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 (!GetWaferSequenceNextValue(ModuleName.Buffer, i, "PurgeCount", out var strPurgeLoopCount)) { continue; } if (!GetWaferSequenceNextValue(ModuleName.Buffer, i, "PumpDelayTime", out var strPurgePumpDelay)) { continue; } //if (!Int32.TryParse(strBufferSetValue, out bufferSetValue) // || !int.TryParse(strPurgeLoopCount, out var purgeLoopCount) // || !int.TryParse(strPurgePumpDelay, out var purgePumpDelay)) //{ // continue; //} if (!int.TryParse(strPurgeLoopCount, out var purgeLoopCount) || !int.TryParse(strPurgePumpDelay, out var purgePumpDelay)) { continue; } var 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温度1秒后再判断温度 // if (pastTime > 1) // { // 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); // } //} // 如果TMRobot空闲,并且Buffer收到新盘,则根据Sequence配置进行Purge。 if (_tmRobot.IsAvailable && !_buffer.HasPurged) { _tmRobot.Purge(purgeLoopCount, purgePumpDelay); _buffer.HasPurged = true; wafer.NextSequenceStep++; } return; } } } private void MonitorLoadTask() { if (!_load.IsAvailable) return; if (!_tmRobot.IsAvailable && _tmRobot.Target == ModuleName.LoadLock) // 如果TMRobot正在操作LoadLock return; if (!_waferRobot.IsAvailable && _waferRobot.Target == ModuleName.LoadLock) // 如果WaferRobot正在操作LoadLock return; if (!_trayRobot.IsAvailable && _trayRobot.Target == ModuleName.LoadLock) // 如果TrayRobot正在操作LoadLock return; //第一种情况 : 有Wafer有Tray且Load Sequence还未执行 if (_load.HasWafer(0) && _load.HasTrayAndNotExceedProcessCount(0) && _load.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0)) { if (!_load.CheckWaferTrayGrouped()) { _load.GroupWaferTray(); return; } _load.Purge(_load.GetWaferPurgeCount(0), _load.GetWaferPumpDelayTime(0)); _load.GetWaferInfo(0).NextSequenceStep++; return; } //第二种情况:有Wafer有Tray且Load Sequence已执行 else if (_load.HasWafer(0) && _load.HasTrayAndNotExceedProcessCount(0) && !_load.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0)) { if (!_load.IsReadyForPick(ModuleName.TMRobot, 0)) { _load.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Pick, 0); return; } } //第三种情况 : Load腔没盘,TMRobot/Buffer1/2/3中有次数用完的盘 else if (_load.NoTray(0) && ((_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)) { _load.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0); return; } } //第四种情况 :Load腔没有Wafer且没有Tray else if (_load.NoWafer(0) && _load.NoTray(0)) { if (!_load.IsReadyForPlace(ModuleName.WaferRobot, 0)) { _load.PrepareTransfer(ModuleName.WaferRobot, EnumTransferType.Place, 0); return; } } //第五种情况 :Load腔有次数用完的盘 else if (_load.HasTrayAndExceedProcessCount(0)) { if (!_load.IsReadyForPick(ModuleName.TrayRobot, 0)) { _load.PrepareTransfer(ModuleName.TrayRobot, EnumTransferType.Pick, 0); return; } } else { bool IsTrayRobotPlace = false; foreach (var pm in _lstPms) { if (_load.HasWafer(0) && _load.CheckWaferNeedProcess(0, pm.Module) && _load.NoTray(0)) { if (CheckLoadWaferNeedCassetteTray(pm.Module)) { IsTrayRobotPlace = true; break; } } } if(IsTrayRobotPlace) { //第六种情况 : 还没做工艺等TrayRobot来放 if (!_load.IsReadyForPlace(ModuleName.TrayRobot, 0)) { _load.PrepareTransfer(ModuleName.TrayRobot, EnumTransferType.Place, 0); return; } } else { //第七种情况 : 准备TMRobot来放Tray if (!_load.IsReadyForPlace(ModuleName.TMRobot, 0)) { _load.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0); return; } } } } private void MonitorUnLoadTask() { if (!_unload.IsAvailable) { return; } if (!_waferRobot.IsAvailable && _waferRobot.Target == ModuleName.UnLoad) // 如果WaferRobot正在操作UnLoad return; if (!_tmRobot.IsAvailable && _tmRobot.Target == ModuleName.UnLoad) // 如果TMRobot正在操作UnLoad return; // 重置UnLoad Purge和分离状态 if (_unload.FirstDetectWaferArrive(0) || _unload.FirstDetectWaferLeave(0)) { _unload.ResetPurgedAndSeparatedStatus(); } // TM把Wafer和Tray放如UnLoad后,先冷却,再分离,然后取Tray前Purge if (_unload.HasWafer(0) && _unload.HasTray(0)) { // 取Tray前Purge if (!_unload.CheckPurgedBeforeTrayPicking()) { if (_tmRobot.IsInPumping) return; _unload.PurgeBeforeTrayPicking( _unload.GetWaferPurgeCount(0), _unload.GetWaferPumpDelayTime(0)); return; } // Cooling if (!_unload.CheckCoolingCompleted()) { GetWaferSequenceCoolingTime(_unload.Module, 0, out var coolingTime); _unload.Cooling(true, coolingTime); return; } // 如果没分离,先分离 if (!_unload.CheckWaferTraySeparated()) { _unload.SeparateWaferTray(); return; } } if (_unload.HasTray(0)) // UnLoad有Tray,先让TMRobot取Tray { if (_unload.CheckWaferTraySeparated()) { // 如果Sequence下一步是UnLoad,并且W&T已冷却和分离 if (!_unload.CheckPurgedBeforeTrayPicking()) { if(_tmRobot.IsInPumping) { return; } _unload.PurgeBeforeTrayPicking( _unload.GetWaferPurgeCount(0), _unload.GetWaferPumpDelayTime(0)); return; } // 如果Tray拿走以前还没Purge,先Purge,在让TMRobot取Tray if (!_unload.CheckPurgedBeforeTrayPicking()) return; if (!_unload.IsReadyForPick(ModuleName.TMRobot, 0)) { if (_tmRobot.IsInPumping) { return; } // UnLoad中有Tray,则准备好让TMRobot来取 _unload.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Pick, 0); return; } } } else if (_unload.HasWafer(0)) // 如果没Tray,下一步让WaferRobot取Wafer { if (_unload.CheckWaferTraySeparated()) { // 如果取Wafer前还未Purge,先Purge if (!_unload.CheckPurgedBeforeWaferPicking() && _unload.CheckWaferNextStepIsThis(ModuleName.UnLoad, 0)) { if (_tmRobot.IsInPumping) { return; } var cycle = _unload.GetWaferPurgeCount(0, "PurgeCountBeforeWaferPicking"); var pumpDelay = _unload.GetWaferPumpDelayTime(0, "PumpDelayTimeBeforeWaferPicking"); _unload.PurgeBeforeWaferPicking(cycle, pumpDelay); _unload.GetWaferInfo(0).NextSequenceStep++; return; } if (_unload.CheckPurgedBeforeWaferPicking() && !_unload.IsReadyForPick(ModuleName.WaferRobot, 0)) { if (_tmRobot.IsInPumping) { return; } // 准备好让WaferRobot来取 _unload.PrepareTransfer(ModuleName.WaferRobot, EnumTransferType.Pick, 0); } } return; } else // 如果UnLoad里啥也没有,则准备好下次TMRobot喂 W&T { // 如果Wafer取完后还没有Purge,先Purge if (!_unload.CheckPurgedAfterWaferPicked()) { if (_tmRobot.IsInPumping) { return; } var cycle = _unload.GetWaferPurgeCount(0, "PurgeCountAfterWaferPicking"); var pumpDelay = _unload.GetWaferPumpDelayTime(0, "PumpDelayTimeAfterWaferPicking"); _unload.PurgeAfterWaferPicked(cycle, pumpDelay); } // 如果Wafer取完后还没有Purge,则终止后去操作。 if (!_unload.CheckPurgedAfterWaferPicked()) return; if (!_unload.IsReadyForPlace(ModuleName.TMRobot, 0)) { if (_tmRobot.IsInPumping) { return; } _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 (pm.HasWafer(0)) { //if (pm.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)) { var 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); if (!_tmRobot.IsAvailable) return; var act = tmRobotActions.Peek(); act.Invoke(); tmRobotActions.Enqueue(tmRobotActions.Dequeue()); } private void MonitorWaferRobotTask() { foreach (var cass in _lstWaferCassettes) { 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); if (!_waferRobot.IsAvailable) return; var act = waferRobotActions.Peek(); act.Invoke(); waferRobotActions.Enqueue(waferRobotActions.Dequeue()); } private void MonitorTrayRobotTask() { if (_cassetteBL.IsWaitTransfer(ModuleName.TrayRobot)) _cassetteBL.StopWaitTransfer(ModuleName.TrayRobot); if (_load.IsWaitTransfer(ModuleName.TrayRobot)) _load.StopWaitTransfer(ModuleName.TrayRobot); if (!_trayRobot.IsAvailable) { return; } var act = trayRobotActions.Peek(); act.Invoke(); trayRobotActions.Enqueue(trayRobotActions.Dequeue()); } private void MonitorTmRobotLoadPlaceTask() { if (!_load.IsAvailable || !_tmRobot.IsAvailable) { return; } //第二种情况 : Load腔无Tray,TMRobot上有使用次数用完的Tray bool canPlace = _tmRobot.HasTrayAndExceedProcessCount(0) && _tmRobot.NoWafer(0) && _load.NoTray(0); if (canPlace) { if (_load.IsReadyForPlace(ModuleName.TMRobot, 0)) { if(_unload.IsInPumping) { return; } if (_tmRobot.Place(_load.Module, 0, Hand.Blade1)) { _load.WaitTransfer(ModuleName.TMRobot); return; } } } if (!_load.IsAvailable || !_tmRobot.IsAvailable) { return; } //第一种情况 : Load腔有Wafer需要Process,TMRobot上有使用次数未超的Tray canPlace = _tmRobot.HasTrayAndNotExceedProcessCount(0) && _tmRobot.NoWafer(0) && _load.NoTray(0) && _load.HasWafer(0) && _load.CheckWaferNeedProcess(0); if (canPlace) { if (_load.CheckWaferNeedProcess(0, _pm1.Module) && _tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 1) { return; } if (_load.CheckWaferNeedProcess(0, _pm2.Module) && _tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 0) { return; } if (_load.IsReadyForPlace(ModuleName.TMRobot, 0)) { if (_unload.IsInPumping) { return; } if (_tmRobot.Place(_load.Module, 0, Hand.Blade1)) { _load.WaitTransfer(ModuleName.TMRobot); return; } } } } private void MonitorTmRobotLoadPickTask() { if (!_load.IsAvailable || !_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)) { if (_unload.IsInPumping) { return; } if (_tmRobot.Pick(_load.Module, 0, Hand.Blade1)) { _load.WaitTransfer(ModuleName.TMRobot); return; } } } } private void MonitorTmRobotUnLoadPlaceTask() { if (!_unload.IsAvailable || !_tmRobot.IsAvailable) { return; } //place Robot有Wafer,UnLoad无Tray无Wafer bool canPlaceUnLoad = _tmRobot.HasWafer(0) && _tmRobot.HasTray(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)) { if (_tmRobot.Place(_unload.Module, 0, Hand.Blade1)) { _unload.WaitTransfer(ModuleName.TMRobot); return; } } } } private void MonitorTmRobotUnLoadPickTask() { if (!_unload.IsAvailable || !_tmRobot.IsAvailable) { return; } //pick UnLoad有Tray,TM无Tray,LoadLock没有Tray,UnLoad分离完成 bool canPickUnLoad = _tmRobot.NoTray(0) && _tmRobot.NoWafer(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)) { if (_tmRobot.Pick(_unload.Module, 0, Hand.Blade1)) { _unload.WaitTransfer(ModuleName.TMRobot); return; } } } } private void MonitorTmRobotBufferPlaceTask() { if (!_tmRobot.IsAvailable || !_buffer.IsAvailable) { return; } //place Buffer位置没有Tray,Robot有Wafer,下一步骤是Buffer bool canPalce = _tmRobot.HasWafer(0) && _tmRobot.HasTray(0) && _buffer.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0); if (canPalce) { SlotItem bufferEmptySlot = null; if ((_tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 0) && _tmRobot.CheckWaferNeedProcess(0, _pm1.Module) && _buffer.NoTray(0) && _buffer.NoWafer(0)) { bufferEmptySlot = new SlotItem(ModuleName.Buffer, 0); } else if ((_tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 1) && _tmRobot.CheckWaferNeedProcess(0, _pm2.Module) && _buffer.NoTray(1) && _buffer.NoWafer(1)) { bufferEmptySlot = new SlotItem(ModuleName.Buffer, 1); } if (bufferEmptySlot != null) { if (_buffer.IsReadyForPlace(ModuleName.TMRobot, bufferEmptySlot.Slot)) { if (_tmRobot.Place(_buffer.Module, bufferEmptySlot.Slot, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } } if (!_tmRobot.IsAvailable || !_buffer.IsAvailable) { return; } //place 完成工艺后的Tray放入Buffer中 canPalce = _tmRobot.HasTray(0) && _tmRobot.NoWafer(0); if (canPalce) { if (_tmRobot.HasTrayAndExceedProcessCount(0) && _load.NoTray(0)) return; SlotItem bufferEmptySlot = null; if (_tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 0 && _buffer.NoTray(0) && _buffer.NoWafer(0) && !_load.CheckWaferNeedProcess(0, _pm1.Module) && !_waferRobot.CheckWaferNeedProcess(0, _pm1.Module) && !_aligner.CheckWaferNeedProcess(0, _pm1.Module)) { bufferEmptySlot = new SlotItem(ModuleName.Buffer, 0); } else if (_tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 1 && _buffer.NoTray(1) && _buffer.NoWafer(1) && !_load.CheckWaferNeedProcess(0, _pm2.Module) && !_waferRobot.CheckWaferNeedProcess(0, _pm2.Module) && !_aligner.CheckWaferNeedProcess(0, _pm2.Module)) { bufferEmptySlot = new SlotItem(ModuleName.Buffer, 1); } if (bufferEmptySlot != null) { if (_buffer.IsReadyForPlace(ModuleName.TMRobot, bufferEmptySlot.Slot)) { if (_tmRobot.Place(_buffer.Module, bufferEmptySlot.Slot, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } } if (!_tmRobot.IsAvailable || !_buffer.IsAvailable) { return; } //place load有wafer有tray要process,需放到buffer3进行躲避 canPalce = _tmRobot.HasTray(0) && _tmRobot.NoWafer(0) && _buffer.NoTray(2) && _buffer.NoWafer(2); if (canPalce) { if (_tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 0 && ((_load.HasTray(0) && _load.HasWafer(0) && _load.CheckWaferNeedProcess(0, _pm1.Module)) || (_buffer.HasTray(0) && _buffer.HasWafer(0)) )) { if (_buffer.IsReadyForPlace(ModuleName.TMRobot, 2)) { if (_tmRobot.Place(_buffer.Module, 2, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } else if (_tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 1 && ((_load.HasTray(0) && _load.HasWafer(0) && _load.CheckWaferNeedProcess(0, _pm2.Module)) || (_buffer.HasTray(1) && _buffer.HasWafer(1)) )) { if (_buffer.IsReadyForPlace(ModuleName.TMRobot, 2)) { if (_tmRobot.Place(_buffer.Module, 2, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } } } private void MonitorTmRobotBufferPickTask() { if (!_tmRobot.IsAvailable || !_buffer.IsAvailable) { return; } MonitorTmRobotBuffer1PickTask(); MonitorTmRobotBuffer2PickTask(); MonitorTmRobotBuffer3PickTask(); } private void MonitorTmRobotBuffer1PickTask() { if (!_tmRobot.IsAvailable || !_buffer.IsAvailable) { return; } //第一种情况:Buffer1的Wafer需要去PM1腔工艺 bool canPick = _tmRobot.NoTray(0) && _buffer.HasTray(0) && _buffer.HasWafer(0) && !_buffer.CheckWaferNextStepIsThis(ModuleName.Buffer, 0); if (canPick) { if (_pm1.CheckWaferNextStepIsThis(ModuleName.Buffer, 0)) { if (!_pm1.IsAvailable || _pm1.HasTray(0) || _pm1.HasWafer(0) || !_pm1.IsReadyForPlace(ModuleName.TMRobot, 0) || !_pm1.CheckBufferToPMTemp()) return; if (_buffer.CheckWaferNextStepModuleNoTray(0)) { if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0)) { if (_tmRobot.Pick(_buffer.Module, 0, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } } } if (!_tmRobot.IsAvailable || !_buffer.IsAvailable) { return; } //第二种情况:工艺开始时,如果Buffer中有Tray时,优先取Buffer中的Tray,而不是Cassette中Tray canPick = _tmRobot.NoTray(0) && _load.IsAvailable && _load.IsReadyForPlace(ModuleName.TMRobot, 0) && _load.NoTray(0) && _load.HasWafer(0) && _load.CheckWaferNeedProcess(0,ModuleName.PM1); if (canPick) { //取Tray前判断Unload是否IsInPumping,否则就会发生TMRobot有Tray //在等Unload Pumping完成的情况 if(_unload.IsInPumping) { return; } if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0)) { if (_tmRobot.Pick(_buffer.Module, 0, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } } private void MonitorTmRobotBuffer2PickTask() { if (!_tmRobot.IsAvailable || !_buffer.IsAvailable) { return; } //第一种情况:Buffer2的Wafer需要去PM2腔工艺 bool canPick = _tmRobot.NoTray(0) && _buffer.HasTray(1) && _buffer.HasWafer(1) && !_buffer.CheckWaferNextStepIsThis(ModuleName.Buffer, 1); if (canPick) { if (_pm2.CheckWaferNextStepIsThis(ModuleName.Buffer, 1)) { if (!_pm2.IsAvailable || _pm2.HasTray(0) || _pm2.HasWafer(0) || !_pm2.IsReadyForPlace(ModuleName.TMRobot, 0) || !_pm2.CheckBufferToPMTemp()) return; if (_buffer.CheckWaferNextStepModuleNoTray(1)) { if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0)) { if (_tmRobot.Pick(_buffer.Module, 1, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } } } if (!_tmRobot.IsAvailable || !_buffer.IsAvailable) { return; } //第二种情况:工艺开始时,如果Buffer中有Tray时,优先取Buffer中的Tray,而不是Cassette中Tray canPick = _tmRobot.NoTray(0) && _buffer.HasTray(1) && _buffer.NoWafer(1) && _load.IsAvailable && _load.IsReadyForPlace(ModuleName.TMRobot, 0) && _load.NoTray(0) && _load.HasWafer(0) && _load.CheckWaferNeedProcess(0, ModuleName.PM2); if (canPick) { //取Tray前判断Unload是否IsInPumping,否则就会发生TMRobot有Tray //在等Unload Pumping完成的情况 if (_unload.IsInPumping) { return; } if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0)) { if (_tmRobot.Pick(_buffer.Module, 1, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } } private void MonitorTmRobotBuffer3PickTask() { if (!_tmRobot.IsAvailable || !_buffer.IsAvailable) { return; } bool canPick = _tmRobot.NoTray(0) && _buffer.HasTray(2); if (canPick) { if (_buffer.GetWaferInfo(2).TrayOriginSlot % 2 == 0) { //第一种情况 : buffer0位置没有tray,load有tray但不是去PM1的 if (_buffer.NoTray(0) && _load.HasTray(0) && !_load.CheckWaferNeedProcess(0, _pm1.Module)) { if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0)) { if (_tmRobot.Pick(_buffer.Module, 2, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } //第二种情况 : buffer0位置没有tray,load也没有tray,并且没有wafer,或者有wafer但是去PM1的 else if (_buffer.NoTray(0) && _load.NoTray(0) && (_load.CheckWaferNeedProcess(0, _pm1.Module) || _load.NoWafer(0))) { if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0)) { if (_tmRobot.Pick(_buffer.Module, 2, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } //第三种情况 :buffer0位置有tray,但是pm1没有tray else if (_buffer.HasTray(0) && !_buffer.CheckWaferNeedProcess(0, _pm1.Module) && _pm1.NoTray(0) && _pm1.NoWafer(0)) { if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0)) { if (_tmRobot.Pick(_buffer.Module, 2, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } } if (_buffer.GetWaferInfo(2).TrayOriginSlot % 2 == 1) { //第一种情况 : buffer1位置没有tray,load有tray但不是去PM2的 if (_buffer.NoTray(1) && _load.HasTray(0) && !_load.CheckWaferNeedProcess(0, _pm2.Module)) { if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0)) { if (_tmRobot.Pick(_buffer.Module, 2, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } //第二种情况 : buffer1位置没有tray,load也没有tray,没有wafer,或者有wafer但是去PM2的 else if (_buffer.NoTray(1) && _load.NoTray(0) && (_load.CheckWaferNeedProcess(0, _pm2.Module) || _load.NoWafer(0))) { if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0)) { if (_tmRobot.Pick(_buffer.Module, 2, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } //第三种情况 : buffer1位置有tray,但是pm2没有tray else if (_buffer.HasTray(1) && !_buffer.CheckWaferNeedProcess(1, _pm2.Module) && _pm2.NoTray(0) && _pm2.NoWafer(0)) { if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0)) { if (_tmRobot.Pick(_buffer.Module, 2, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } } } } private void MonitorTmRobotPMPlaceTask() { if (!_tmRobot.IsAvailable) { return; } //第二种情况 : TMRobot有Tray,没有Wafer,对应Buffer有Tray,需放PM存盘 bool canPlaceNoProcess = _tmRobot.NoWafer(0) && _tmRobot.HasTrayAndNotExceedProcessCount(0); if (canPlaceNoProcess) { foreach (var pm in _lstPms) { int bufferIndex = 0; if (pm == _pm2) { bufferIndex = 1; } if (_tmRobot.GetWaferInfo(0).TrayOriginSlot % 2 == bufferIndex && _buffer.HasTray(bufferIndex) && _buffer.NoWafer(bufferIndex) && !_buffer.CheckWaferNeedProcess(bufferIndex, pm.Module) && pm.IsAvailable && pm.NoTray(0) && pm.NoWafer(0) && pm.CheckTempBelow900() && pm.IsReadyForPlace(ModuleName.TMRobot, 0)) { if (_tmRobot.Place(pm.Module, 0, Hand.Blade1)) { pm.WaitTransfer(ModuleName.TMRobot); return; } } } } if (!_tmRobot.IsAvailable) { return; } //第一种情况 : TMRobot有Wafer并且需要Process bool canPlace = _tmRobot.HasWafer(0) && _tmRobot.HasTray(0) && _tmRobot.CheckWaferNeedProcess(0); if (canPlace) { foreach (var pm in _lstPms) { if (!pm.IsAvailable || !GetModule(pm.Module).NoWafer(0) || !pm.IsReadyForPlace(ModuleName.TMRobot, 0) || !pm.CheckTempBelow900()) continue; bool blade0Place = _tmRobot.HasWafer(0) && _tmRobot.CheckWaferNeedProcess(0, pm.Module) && pm.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0); if (blade0Place) { Hand placeBlade = Hand.Blade1; if (_tmRobot.Place(pm.Module, 0, placeBlade)) { pm.WaitTransfer(ModuleName.TMRobot); return; } } } } } private void MonitorTmRobotPMPickTask() { if (!_tmRobot.IsAvailable) { return; } //第一种情况 : Wafer工艺结束后需取出 if (_tmRobot.NoWafer(0) && _tmRobot.NoTray(0)) { //Wafer取出后只能去Unload冷却,Buffer3有其他用途,冷却取消 if (_unload.HasWafer(0) || _unload.HasTray(0) || !_unload.IsReadyForPlace(ModuleName.TMRobot, 0) || !_unload.IsAvailable) { return; } Hand pickBlade = Hand.Blade1; ModuleName pickPm = ModuleName.System; bool canPickPM1 = false; bool canPickPM2 = false; if(_pm1.IsAvailable && _pm1.HasWafer(0) && _pm1.HasTray(0) && !_pm1.CheckWaferNeedProcess(0) && _pm1.CheckPMToTMRobotTemp()) { canPickPM1 = true; } if (_pm2.IsAvailable && _pm2.HasWafer(0) && _pm2.HasTray(0) && !_pm2.CheckWaferNeedProcess(0) && _pm2.CheckPMToTMRobotTemp()) { canPickPM2 = true; } if (canPickPM1 && !canPickPM2) { pickPm = ModuleName.PM1; } else if (!canPickPM1 && canPickPM2) { pickPm = ModuleName.PM2; } else if (canPickPM1 && canPickPM2) { string pm1ProcessTime = SC.GetStringValue("PM.PM1.PostProcessEndTime"); string pm2ProcessTime = SC.GetStringValue("PM.PM2.PostProcessEndTime"); if (DateTime.TryParse(pm1ProcessTime, out DateTime dtPM1) && DateTime.TryParse(pm2ProcessTime, out DateTime dtPM2)) { pickPm = dtPM1.CompareTo(dtPM2) <= 0 ? ModuleName.PM1 : ModuleName.PM2; } else { pickPm = ModuleName.PM1; } } 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; } } } } if (!_tmRobot.IsAvailable) { return; } //第二种情况 : PM腔有Tray没Wafer,需取出到Buffer3 if (_tmRobot.NoWafer(0) && _tmRobot.NoTray(0)) { Hand pickBlade = Hand.Blade1; foreach (var pm in _lstPms) { //增加温度低于900才能Pick的限制 if (!pm.IsAvailable || pm.HasWafer(0) || pm.NoTray(0) || GetModule(pm.Module).CheckWaferNeedProcess(0, pm.Module) || !pm.CheckTempBelow900() || _buffer.HasTray(2) || _buffer.HasWafer(2)) continue; //如果对应的Buffer1/2有没超次数的Tray和无Wafer,则不取 int bufferIndex = 0; if (pm == _pm2) { bufferIndex = 1; } if (_buffer.NoWafer(bufferIndex) && _buffer.HasTrayAndNotExceedProcessCount(bufferIndex)) { return; } if (pm.IsReadyForPick(ModuleName.TMRobot, 0)) { if (_tmRobot.Pick(pm.Module, 0, pickBlade)) { pm.WaitTransfer(ModuleName.TMRobot); return; } } } } } private void MonitorWaferRobotLoadPlaceTask() { if (!_waferRobot.IsAvailable || !_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 MonitorWaferRobotUnLoadPickTask() { if (!_waferRobot.IsAvailable || !_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 MonitorWaferRobotAlignerPlaceTask() { 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; } } } } private void MonitorWaferRobotAlignerPickTask() { if (!_waferRobot.IsAvailable || !_aligner.IsAvailable) { return; } //pick Aligner wafer to Load 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) && _load.IsAvailable; 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 Cassette bool canPick = _aligner.HasWafer(0) && _waferRobot.NoWafer(0) && _aligner.GetWaferInfo(0).Status != WaferStatus.Dummy && !_aligner.CheckWaferNextStepIsThis(ModuleName.Aligner, 0) && _aligner.CheckWaferSequenceStepDone(0); if (canPick) { if (_aligner.IsReadyForPick(ModuleName.WaferRobot, 0)) { if (_waferRobot.Pick(_aligner.Module, 0, Hand.Blade1)) { _aligner.WaitTransfer(ModuleName.WaferRobot); return; } } } } private void MonitorWaferRobotCassettePlaceTask() { if (!_waferRobot.IsAvailable) { return; } //place 任务完成了,Robot有片子,Cassette没有片子 bool canPlaceCassette = _waferRobot.HasWafer(0) && _waferRobot.GetWaferInfo(0).Status != WaferStatus.Dummy && _waferRobot.CheckWaferSequenceStepDone(0); if (canPlaceCassette) { var 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; } } } } } private void MonitorWaferRobotCassettePickTask() { 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) && _aligner.HasWafer(0)) { return; } //如果Load腔有Wafer或者Load/TMRobot/Buffer有已用完次数的Tray, //则WaferRobot不能从Cassette取Wafer else if ( _load.HasWafer(0) || !_load.IsAvailable || !_load.IsReadyForPlace(ModuleName.WaferRobot,0) || _load.HasTrayAndExceedProcessCount(0) || _tmRobot.HasTrayAndExceedProcessCount(0)) { return; } //超过可以运行的石墨盘最大数 if (GetRunWaferCount() >= _maxTrayCount) { return; } //每个腔超过2个Wafer则不在取Wafer if(CheckWaferNeedProcess(position.Module,position.Slot,_pm1.Module)) { if (GetRunWaferCount(_pm1.Module) >= 2) { return; } } if(CheckWaferNeedProcess(position.Module, position.Slot, _pm2.Module)) { if (GetRunWaferCount(_pm2.Module) >= 2) { return; } } 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; } } } else 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; } } } } } private void MonitorTrayRobotLoadPlaceTask() { if (!_trayRobot.IsAvailable || !_load.IsAvailable) { return; } if (GetCurrentTrayCount() >= _maxTrayCount) { return; } //place Load没有Tray,有Wafer未完成 bool canPlace = _load.NoTray(0) && _trayRobot.HasTrayAndNotExceedProcessCount(0) && _load.HasWafer(0) && _load.CheckWaferNeedProcess(0); if (canPlace) { if ( _trayRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 0 && _load.CheckWaferNeedProcess(0,_pm2.Module)) { return; } if ( _trayRobot.GetWaferInfo(0).TrayOriginSlot % 2 == 1 && _load.CheckWaferNeedProcess(0,_pm1.Module)) { return; } //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; } } } } private void MonitorTrayRobotLoadPickTask() { if (!_trayRobot.IsAvailable || !_load.IsAvailable) { return; } //pick Load有Tray,且Tray次数已使用完 bool canPick = _load.HasTrayAndExceedProcessCount(0); if (canPick) { 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 MonitorTrayRobotCassettePlaceTask() { if (!_trayRobot.IsAvailable || !_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); if (slotItem != null) { if (_cassetteBL.IsReadyForPlace(ModuleName.TrayRobot, slotItem.Slot)) { if (_trayRobot.Place(slotItem.Module, slotItem.Slot, Hand.Blade1)) { _cassetteBL.WaitTransfer(ModuleName.TrayRobot); return; } } } } } private void MonitorTrayRobotCassettePickTask() { if (!_trayRobot.IsAvailable || !_cassetteBL.IsAvailable) { return; } //各个腔体运行的石墨盘总数小于设定值 if (GetCurrentTrayCount() >= _maxTrayCount) { return; } foreach (var pm in _lstPms) { if(_load.HasWafer(0) && _load.CheckWaferNeedProcess(0, pm.Module) && _load.NoTray(0) && _trayRobot.NoTray(0)) { if(CheckLoadWaferNeedCassetteTray(pm.Module)) { int usedForWhichPM = 0; if(pm == _pm2) { usedForWhichPM = 1; } SlotItem slotItem = GetTraySlot(8, usedForWhichPM); if (slotItem != null) { if (_cassetteBL.IsReadyForPick(ModuleName.TrayRobot, slotItem.Slot)) { if (_trayRobot.Pick(slotItem.Module, slotItem.Slot, Hand.Blade1)) { _cassetteBL.WaitTransfer(ModuleName.TrayRobot); return; } } } } } } } private bool CheckLoadWaferNeedCassetteTray(ModuleName pm) { if (pm == ModuleName.PM1) { if ((_buffer.HasTray(0) && _buffer.NoWafer(0)) || (_pm1.HasTray(0) && _pm1.NoWafer(0))) { return false; } } if (pm == ModuleName.PM2) { if ((_buffer.HasTray(1) && _buffer.NoWafer(1)) || (_pm2.HasTray(0) && _pm2.NoWafer(0))) { return false; } } List> modules = 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.PM1,0), new Tuple(ModuleName.PM2,0), }; foreach (var module in modules) { if (CheckHasTrayAndNoWaferByModule(module.Item1, module.Item2, pm)) { return false; } } return true; } /// /// 获得Buffer的方式和数值 /// /// /// /// /// /// private bool GetWaferSequenceNextValue(ModuleName module, int slot, string nodeName, out string nodeValue) { nodeValue = ""; if (!GetModule(module).HasWafer(slot)) return false; var 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; var 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; var 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 CheckHasTrayAndNoWaferByModule(ModuleName moduleName, int slot,ModuleName pmModule) { var module = GetModule(moduleName); if((module.GetWaferInfo(slot).TrayOriginSlot % 2 == 0 && pmModule == ModuleName.PM1) || (module.GetWaferInfo(slot).TrayOriginSlot % 2 == 1 && pmModule == ModuleName.PM2)) { if (module.HasTray(slot) && module.NoWafer(slot)) { 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) | _pm2.HasTrayAndNotExceedProcessCount(0)); } public bool CheckBufferWaferHasJob() { var 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) { var 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() { List> processingWafers = new List>(); 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) { processingWafers.Add(pjSlotWafer); } } } } } } if (processingWafers.Count > 0) { processingWafers = processingWafers.OrderBy(x => x.Item1).ThenBy(x => x.Item2).ToList(); if (SC.GetValue("System.Scheduler.IsRunInParallelMode")) { return SortByParallelMode(processingWafers); } else { return SortBySerialMode(processingWafers); } } return null; } private SlotItem SortBySerialMode(List> processingWafers) { foreach (var pjSlotWafer in processingWafers) { if (pjSlotWafer.Item1 == ModuleName.CassAL || pjSlotWafer.Item1 == ModuleName.CassAR) { if (GetModule(pjSlotWafer.Item1).CheckWaferNeedProcess(pjSlotWafer.Item2, _pm1.Module)) { if (GetRunWaferCount(_pm1.Module) < 2) { return new SlotItem(pjSlotWafer.Item1, pjSlotWafer.Item2); } else { return null; } } else if (GetModule(pjSlotWafer.Item1).CheckWaferNeedProcess(pjSlotWafer.Item2, _pm2.Module)) { if (GetRunWaferCount(_pm2.Module) < 2) { return new SlotItem(pjSlotWafer.Item1, pjSlotWafer.Item2); } else { return null; } } } } return null; } private SlotItem SortByParallelMode(List> processingWafers) { foreach (var pjSlotWafer in processingWafers) { if (pjSlotWafer.Item1 == ModuleName.CassAL || pjSlotWafer.Item1 == ModuleName.CassAR) { if (GetModule(pjSlotWafer.Item1).CheckWaferNeedProcess(pjSlotWafer.Item2, _pm1.Module)) { if (GetRunWaferCount(_pm1.Module) < 2 && GetRunWaferCount(_pm1.Module) <= GetRunWaferCount(_pm2.Module)) { return new SlotItem(pjSlotWafer.Item1, pjSlotWafer.Item2); } } else if (GetModule(pjSlotWafer.Item1).CheckWaferNeedProcess(pjSlotWafer.Item2, _pm2.Module)) { if (GetRunWaferCount(_pm2.Module) < 2 && GetRunWaferCount(_pm2.Module) <= GetRunWaferCount(_pm1.Module)) { return new SlotItem(pjSlotWafer.Item1, pjSlotWafer.Item2); } } } } return SortBySerialMode(processingWafers); } private SlotItem GetTraySlot(int slotCount, int usedForWhichPM) { foreach (var cj in _lstControlJobs) { if (cj.State == EnumControlJobState.Executing) { for (int i = 0; i < slotCount; i++) { if (_cassetteBL.HasTrayAndNotExceedProcessCount(i) && i % 2 == usedForWhichPM) { return new SlotItem(ModuleName.CassBL, i); } } } } return null; } private SlotItem GetTrayOrignSlot(ModuleName module, int slot) { var 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 GetRunWaferCount(ModuleName processIn) { int waferCount = 0; if (_load.HasWafer(0) && (_load.CheckWaferNeedProcess(0, processIn) || _load.GetWaferInfo(0).SubstHists.Select(x => x.locationID).Contains(processIn.ToString()))) { waferCount++; } if (_unload.HasWafer(0) && (_unload.CheckWaferNeedProcess(0, processIn) || _unload.GetWaferInfo(0).SubstHists.Select(x => x.locationID).Contains(processIn.ToString()))) { waferCount++; } if (_tmRobot.HasWafer(0) && (_tmRobot.CheckWaferNeedProcess(0, processIn) || _tmRobot.GetWaferInfo(0).SubstHists.Select(x => x.locationID).Contains(processIn.ToString()))) { waferCount++; } if (GetModule(processIn).HasWafer(0) && (GetModule(processIn).CheckWaferNeedProcess(0, processIn) || GetModule(processIn).GetWaferInfo(0).SubstHists.Select(x => x.locationID).Contains(processIn.ToString()))) { waferCount++; } for (int i = 0; i < 3; i++) { if (_buffer.HasWafer(i) && (_buffer.CheckWaferNeedProcess(i, processIn) || _buffer.GetWaferInfo(i).SubstHists.Select(x => x.locationID).Contains(processIn.ToString()))) { 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; } 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; } 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) { } else if (!isModuleError && _isModuleErrorPrevious) { Reset(); } 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; } 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; } } private bool CheckWaferNeedProcess(ModuleName module, int waferSlot, ModuleName processIn = ModuleName.System) { var wafer = WaferManager.Instance.GetWafer(module, waferSlot); if(wafer == null) { return false; } if (wafer.IsEmpty) return false; if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null || wafer.ProcessJob.Sequence.Steps == null) return false; if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count || wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules == null) return false; //if (processIn != ModuleName.System && !wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(processIn)) // return false; for (int i = wafer.NextSequenceStep; i < wafer.ProcessJob.Sequence.Steps.Count; i++) { foreach (var stepModule in wafer.ProcessJob.Sequence.Steps[i].StepModules) { if (ModuleHelper.IsPm(stepModule)) { if (processIn != ModuleName.System) { return stepModule == processIn ? true : false; } else { return true; } } } } return false; } } }