using System; using System.Collections.Generic; using System.Linq; using Aitex.Core.Common; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Event; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using Aitex.Sorter.Common; using MECF.Framework.Common.DBCore; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.Jobs; using MECF.Framework.Common.Schedulers; using MECF.Framework.Common.SubstrateTrackings; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.UnLoad; using SicRT.Equipments.Schedulers; using SicRT.Modules.Schedulers; namespace SicRT.Modules { public partial class ManualAutoTransfer : SchedulerModuleFactory { public class TrayInfo { public int TrayModule { get; set; } public int TraySlot { get; set; } public int TrayProcessCount { get; set; } } private List _lstNeedMapJob = new(); private List _lstControlJobs = new(); private List _lstProcessJobs = new(); private List _lstProcessedTrayInfo = new(); //保存石墨盘的进入腔体的信息(最多4次工艺需要换盘) private int _maxTrayCount = 4; //可以同时运行的石墨盘总数 private bool _cassProcessOnebyOne = false; //Cassette是左右交互取片还是一个Cassette取完再取另一个 private R_TRIG NotifyTrayExhausted = new(); 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 double _timeBuffer1 { get; set; } private double _timeBuffer2 { get; set; } private double _timeBuffer3 { get; set; } private double _timeLoad { get; set; } private const int _bufferFloors = 1; private Dictionary _loadWaferInfo = new(); private Dictionary _bufferWaferInfo = new(); private Queue waferRobotActions = new() { }; private Queue trayRobotActions = new() { }; private Queue tmRobotActions = new() { }; private R_TRIG _updateAutoJobLocation = new(); //需要向数据库更新Wafer位置 public ManualAutoTransfer() { _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.TimeLoad", () => _timeLoad); DATA.Subscribe("LoadLock.LocalJobName", () => { var jb = _lstControlJobs.Find(x => x.Module == "LoadLock"); if (jb != null) return jb.Name; return ""; }); DATA.Subscribe("LoadLock.LocalJobStatus", () => { var jb = _lstControlJobs.Find(x => x.Module == "LoadLock"); 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; }); tmRobotActions.Enqueue(MonitorTmRobotLoadPlaceTask); tmRobotActions.Enqueue(MonitorTmRobotLoadPickTask); tmRobotActions.Enqueue(MonitorTmRobotPMPlaceTask); tmRobotActions.Enqueue(MonitorTmRobotPMPickTask); tmRobotActions.Enqueue(MonitorTmRobotBufferPlaceTask); tmRobotActions.Enqueue(MonitorTmRobotBufferPickTask); } public bool HasJobRunning { get { return _lstControlJobs.Count > 0; } } public void Clear() { _tmRobot.ResetTask(); foreach (var pm in _lstPms) { pm.ResetTask(); } _load.ResetTask(); _buffer.ResetTask(); _lstControlJobs.Clear(); _lstProcessJobs.Clear(); _loadWaferInfo.Clear(); } public void ResetTask() { if (!_load.IsOnline) { _load.ResetTask(); } if (!_buffer.IsOnline) { _buffer.ResetTask(); } foreach (var pm in _lstPms) { if (!pm.IsOnline) { pm.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) { var reason = ""; var slotSequence = (string[])param["SlotSequence"]; var jobId = (string)param["JobId"]; var module = (string)param["Module"]; var lotId = (string)param["LotId"]; var autoStart = (bool)param["AutoStart"]; ////检查Load腔Lock是否锁定 //if(!_load.CheckLocked()) //{ // EV.PostWarningLog(LogSource, $"The Load is Unlocked,do not start"); // return false; //} //检查所有Module里Tray的数量 if (GetCurrentTrayCount() >= _maxTrayCount) { EV.PostWarningLog(LogSource, $"The machine has more than {_maxTrayCount} Tray"); return false; } //拿到Recipe和ModuleName var recipeName = ""; var moduleName = ModuleName.System; var seq = SequenceInfoHelper.GetInfo(slotSequence[0]); for (var i = 0; i < seq.Steps.Count; i++) { var stepInfo = seq.Steps[i]; foreach (var m in stepInfo.StepModules) { if (ModuleHelper.IsPm(m)) { recipeName = seq.Steps[i].RecipeName; moduleName = m; } } } //每个PM腔不能超过2个对应Wafer if (moduleName != ModuleName.System) { if (GetRunWaferCount(moduleName) >= _maxTrayCount / 2) { EV.PostWarningLog(LogSource, $"Creating the job failed . There are already {_maxTrayCount / 2} job of the same pm in the system."); return false; } } if (CheckModuleHaveWaferWithNoJob(out reason)) { EV.PostWarningLog(LogSource, $"{reason}"); return false; } if (!ValidateSequence(slotSequence, out reason)) { EV.PostWarningLog(LogSource, $"{reason}"); return false; } if (slotSequence.Length != 1) { reason = $"slot sequence parameter not valid, length is {slotSequence.Length}, should be 1"; EV.PostWarningLog(LogSource, reason); return false; } if (string.IsNullOrEmpty(jobId)) { jobId = "CJ_Local_Load" + DateTime.Now; } if (_lstControlJobs.Exists(x => x.Name == jobId)) { reason = $"JobID : {jobId} already created"; EV.PostWarningLog(LogSource, reason); return false; } //检查Sequence对应的PM腔状态 if (!CheckPMState(slotSequence[0])) { return false; } var cj = new ControlJobInfo(); cj.Name = jobId; cj.Module = module; cj.LotName = lotId; cj.LotInnerId = Guid.NewGuid(); cj.LotWafers = new List(); cj.SetState(EnumControlJobState.WaitingForStart); var seqSlot = new Dictionary(); var seqSlotWafers = new Dictionary>>(); var indexSequence = new Dictionary(); var enableGroupBySequence = SC.GetValue("System.Scheduler.GroupWaferBySequence"); var WaferAssociationInfo = $"WaferAssociationInfo({module}):"; for (var i = 0; i < 1; i++) { WaferAssociationInfo = WaferAssociationInfo + string.Format(" slot{0} -- {1};", i + 1, slotSequence[i]); if (string.IsNullOrEmpty(slotSequence[i]) || string.IsNullOrEmpty(slotSequence[i].Trim())) continue; var 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).WaferStatus}"; EV.PostWarningLog(LogSource, reason); return false; } var wafer = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i); if (wafer == null || wafer.IsWaferEmpty) { reason = $"specifies wafer: {module} slot {i + 1} not in the carrier"; EV.PostWarningLog(LogSource, reason); return false; } if (wafer.ProcessState != WaferProcessStatus.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; } var pjs = new List(); var seqs = seqSlot.Keys.ToArray(); for (var i = 0; i < seqs.Length; i++) { var 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); pjs.Add(pj); } foreach (var pj in pjs) { cj.ProcessJobNameList.Add(pj.Name); _lstProcessJobs.Add(pj); } _lstControlJobs.Add(cj); var 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; wafer.NextSequenceStep = 0; wafer.WaferOrigin = lotId; wafer.LotId = lotId; WaferDataRecorder.SetCjInfo(wafer.WaferInnerID.ToString(), cj.InnerId.ToString()); WaferDataRecorder.SetWaferSequence(wafer.WaferInnerID.ToString(), pj.Sequence.Name); WaferDataRecorder.SetWaferLotId(wafer.WaferInnerID.ToString(), lotId); WaferManager.Instance.UpdateWaferLotId(pjSlotWafer.Item1, pjSlotWafer.Item2, lotId); 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); JobDataRecorder.StartCJ(cj.InnerId.ToString(), null, cj.Name, cj.Module, cj.Module, totalWafer); //保存信息 var waferInfo = WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0); if (waferInfo != null) { if (waferInfo.ProcessState == WaferProcessStatus.Idle) { WaferManager.Instance.GetWafer(_load.Module, 0).NextSequenceStep = 0; } waferInfo.LotId = cj.LotName; if (recipeName.IndexOf(@"\") > 0) { recipeName = recipeName.Substring(recipeName.LastIndexOf(@"\") + 1); } AutoJobRecorder.Add(waferInfo.WaferID.ToString(), recipeName, cj.LotName, ModuleName.LoadLock.ToString(), GetWaferStatue(waferInfo)); } return true; } private string GetWaferStatue(WaferInfoRt wafer) { if (wafer.ProcessState == WaferProcessStatus.InProcess) { return "InProcess"; } else if (wafer.ProcessState == WaferProcessStatus.Completed) { return "Completed"; } else { return "Idle"; } } 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 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; } var cj = new ControlJobInfo(); cj.Name = jobId; cj.Module = module; cj.LotName = jobId; cj.LotInnerId = Guid.NewGuid(); cj.LotWafers = new List(); cj.SetState(EnumControlJobState.WaitingForStart); var 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).WaferStatus}"); return false; } if (_module.GetWaferInfo(slotWafer.Item2).ProcessState != WaferProcessStatus.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) { WaferInfoRt wafer = GetModule(pjSlotWafer.Item1).GetWaferInfo(pjSlotWafer.Item2); cj.LotWafers.Add(wafer); wafer.ProcessJob = pj; wafer.ProcessJobID = pj.Sequence.Name; WaferDataRecorder.SetCjInfo(wafer.WaferInnerID.ToString(), cj.InnerId.ToString()); WaferDataRecorder.SetWaferSequence(wafer.WaferInnerID.ToString(), pj.Sequence.Name); WaferDataRecorder.SetWaferLotId(wafer.WaferInnerID.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}"); var 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); //模块顺序检查 var lstLoad = new List(); var lstBuffer = new List(); var lstUnLoad = new List(); var lstPM = new List(); for (var 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 (var 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)); } var 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; } } } public void Abort() { var wafer = WaferManager.Instance.GetWafer(ModuleName.PM1, 0); if (wafer?.WaferID != null) { AutoJobRecorder.UpdatePosition(wafer.WaferID.ToString(), ModuleName.PM1.ToString(), "Abort"); } var wafer1 = WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0); if (wafer1?.WaferID != null) { AutoJobRecorder.UpdatePosition(wafer1.WaferID.ToString(), ModuleName.TM.ToString(), "Abort"); } var wafer2 = WaferManager.Instance.GetWafer(ModuleName.Buffer, 0); if (wafer2?.WaferID != null) { AutoJobRecorder.UpdatePosition(wafer2.WaferID.ToString(), ModuleName.Buffer.ToString(), "Abort"); } var wafer3 = WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0); if (wafer3?.WaferID != null) { AutoJobRecorder.UpdatePosition(wafer3.WaferID.ToString(), ModuleName.LoadLock.ToString(), "Abort"); } } internal void AbortJob(string jobName) { var cj = _lstControlJobs.Find(x => x.Name == jobName); if (cj == null) { EV.PostWarningLog(LogSource, $"abort job rejected, not found job with id {jobName}"); return; } var unprocessed_cj = 0; var aborted_cj = 0; var pjAbortList = new List(); foreach (var pj in _lstProcessJobs) { if (pj.ControlJobName == cj.Name) { pj.SetState(EnumProcessJobState.Aborting); pjAbortList.Add(pj); var unprocessed = 0; var aborted = 0; var wafers = WaferManager.Instance.GetWaferByProcessJob(pj.Name); foreach (var waferInfo in wafers) { waferInfo.ProcessJob = null; waferInfo.NextSequenceStep = 0; if (waferInfo.ProcessState != WaferProcessStatus.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 CheckPMState(string sequence) { var seqInfo = SequenceInfoHelper.GetInfo(sequence); 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", $"{moduleName} is not be error"); return false; } if (!module.IsOnline) { EV.PostWarningLog("Scheduler", $"{moduleName} is not be Online"); return false; } if (!module.IsLineHeaterEnable) { EV.PostWarningLog("Scheduler", $"{moduleName} LineHeater is not be Open"); 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(); var 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 cj in _lstControlJobs) { if (cj.State == EnumControlJobState.WaitingForStart) { cj.BeginTime = DateTime.Now; cj.LotInnerId = Guid.NewGuid(); //_dbCallback.LotCreated(cj); cj.SetState(EnumControlJobState.Executing); } } } #endregion Job Management /// /// Start Auto Transfer /// /// /// public Result Start(params object[] objs) { GetConfig(); _cycledWafer = 0; _cycledCount = 0; //_totalWaferWhenStart = StatsDataManager.Instance.GetValue(StatsNameTotalRunningWafer); 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() { var cjActive = _lstControlJobs.Find(x => x.State == EnumControlJobState.Executing); if (cjActive != null) { MonitorModuleTasks(); MonitorAutoJobStatus(); } MonitorModuleError(); MonitorModuleState(); MonitorJobTasks(); MonitorCleanTasks(); return Result.RUN; } #region Job task public Result MonitorJobTasks() { UpdateProcessJobStatus(); UpdateControlJobStatus(); StartNewJob(); return Result.RUN; } /// /// 检查PJ中的Wafer信息是否被清空。 /// 如果被清空,则说明中间过程中Wafer被人工删除,此时返回true,通知相关Monitor可以改PJ。 /// /// /// protected bool CheckAllWaferDeleted(ProcessJobInfo pj) { var wi = WaferManager.Instance.GetWaferByProcessJob(pj.Name); return wi == null || wi.Length <= 0; } protected bool CheckAllWaferReturned(ProcessJobInfo pj, bool checkAllProcessed) { for (var i = 0; i < pj.SlotWafers.Count; ++i) { WaferInfoRt wafer = WaferManager.Instance.GetWafer(pj.SlotWafers[i].Item1, pj.SlotWafers[i].Item2); if (wafer.IsWaferEmpty) return false; if (checkAllProcessed && CheckWaferNeedProcess(pj.SlotWafers[i].Item1, 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 ((CheckAllWaferDeleted(pj) || CheckAllWaferReturned(pj, true)) // 当前PJ的Wafer信息均被删除,或者Wafer全部返回Cass && CheckAllPmCleaned(pj) && CheckAllDummyWaferReturned() && _load.IsAvailable && _tmRobot.IsAvailable && _buffer.IsAvailable && _tmRobot.NoTray(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)) if (CheckWaferSequenceStepDone(ModuleName.LoadLock, 0)) { _load.SetJobStatue(); pj.SetState(EnumProcessJobState.ProcessingComplete); JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0); AutoJobRecorder.EndJob(WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0).WaferID.ToString()); } } } else if (pj.State == EnumProcessJobState.Stopping) { if (CheckAllWaferReturned(pj, false) && CheckAllPmCleaned(pj) && CheckAllDummyWaferReturned() && _load.IsAvailable && _tmRobot.IsAvailable && _buffer.IsAvailable && _tmRobot.NoTray(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)) if (CheckWaferSequenceStepDone(ModuleName.LoadLock, 0)) { _load.SetJobStatue(); pj.SetState(EnumProcessJobState.ProcessingComplete); JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0); AutoJobRecorder.EndJob(WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0).WaferID.ToString()); } } } } } private void UpdateControlJobStatus() { if (_lstControlJobs.Count == 0) return; var allControlJobComplete = true; var cjRemoveList = new List(); foreach (var cj in _lstControlJobs) { if (cj.State == EnumControlJobState.Executing) { var 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); var unprocessed_cj = 0; var aborted_cj = 0; foreach (var pj in _lstProcessJobs) { if (pj.ControlJobName == cj.Name) { var unprocessed = 0; var aborted = 0; var wafers = WaferManager.Instance.GetWaferByProcessJob(pj.Name); foreach (var waferInfo in wafers) { waferInfo.ProcessJob = null; waferInfo.NextSequenceStep = 0; if (waferInfo.ProcessState != WaferProcessStatus.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) { var countPerCycle = 0; var countProcessed = 0; foreach (var pj in _lstProcessJobs) { foreach (var pjSlotWafer in pj.SlotWafers) { countPerCycle++; WaferInfoRt wafer = GetModule(pjSlotWafer.Item1).GetWaferInfo(pjSlotWafer.Item2); if (!wafer.IsWaferEmpty && !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) { WaferInfoRt wafer = GetModule(pjSlotWafer.Item1).GetWaferInfo(pjSlotWafer.Item2); wafer.ProcessJob = null; wafer.NextSequenceStep = 0; wafer.ProcessState = WaferProcessStatus.Idle; } } } } } foreach (var cj in cjRemoveList) { var 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 void MonitorAutoJobStatus() { _updateAutoJobLocation.CLK = _tmRobot.IsAvailable; if (_updateAutoJobLocation.Q) { WaferInfoRt wafer = WaferManager.Instance.GetWafer(ModuleName.PM1, 0); if (wafer?.WaferID != null) { AutoJobRecorder.UpdatePosition(wafer.WaferID.ToString(), ModuleName.PM1.ToString(), GetWaferStatue(wafer)); } WaferInfoRt wafer1 = WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0); if (wafer1?.WaferID != null) { AutoJobRecorder.UpdatePosition(wafer1.WaferID.ToString(), ModuleName.TM.ToString(), GetWaferStatue(wafer1)); } WaferInfoRt wafer2 = WaferManager.Instance.GetWafer(ModuleName.Buffer, 0); if (wafer2?.WaferID != null) { AutoJobRecorder.UpdatePosition(wafer2.WaferID.ToString(), ModuleName.Buffer.ToString(), GetWaferStatue(wafer2)); } WaferInfoRt wafer3 = WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0); if (wafer3?.WaferID != null) { AutoJobRecorder.UpdatePosition(wafer3.WaferID.ToString(), ModuleName.LoadLock.ToString(), GetWaferStatue(wafer3)); } } } public bool CheckAllJobDone() { foreach (var cj in _lstControlJobs) { if (cj.State == EnumControlJobState.Executing || cj.State == EnumControlJobState.Paused) return false; } if (_lstControlJobs.Count == 0) { //EV.PostWarningLog("Scheduler", "ControlJob Finished!"); 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) { WaferInfoRt wafer = GetModule(pjSlotWafer.Item1).GetWaferInfo(pjSlotWafer.Item2); wafer.ProcessJob = pj; //wafer.NextSequenceStep = 0; WaferDataRecorder.SetPjInfo(wafer.WaferInnerID.ToString(), pj.InnerId.ToString()); } var cj = _lstControlJobs.Find(x => x.Name == pj.ControlJobName); var 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 Job task #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(); MonitorTmRobotTask(); MonitorLoadTask(); return Result.RUN; } #region SIC多片机报错 private void MonitorBufferTask() { if (!_buffer.IsAvailable) { return; } for (var i = 0; i < _bufferFloors; i++) { var canExcute = _buffer.HasWafer(i) && _buffer.CheckWaferNextStepIsThis(_buffer.Module, i); if (canExcute) { WaferInfoRt bufferWafer = _buffer.GetWaferInfo(i); if (i == 2 || i == 1) { bufferWafer.NextSequenceStep++; return; } var bufferSetValue = 0; if (!GetWaferSequenceNextValue(ModuleName.Buffer, i, "SetValue", out var strBufferSetValue)) { continue; } if (!Int32.TryParse(strBufferSetValue, out bufferSetValue)) { continue; } if (_bufferWaferInfo.ContainsKey(bufferWafer.WaferInnerID.ToString())) { var dtStartTime = _bufferWaferInfo[bufferWafer.WaferInnerID.ToString()]; var pastTime = (DateTime.Now - dtStartTime).TotalSeconds; if (i == 0) { _timeBuffer1 = pastTime > bufferSetValue ? 0 : (bufferSetValue - pastTime); } else if (i == 1) { _timeBuffer2 = pastTime > bufferSetValue ? 0 : (bufferSetValue - pastTime); } else if (i == 2) { _timeBuffer3 = pastTime > bufferSetValue ? 0 : (bufferSetValue - pastTime); } if (pastTime > bufferSetValue) { bufferWafer.NextSequenceStep++; _bufferWaferInfo.Remove(bufferWafer.WaferInnerID.ToString()); } } else { _bufferWaferInfo.Add(bufferWafer.WaferInnerID.ToString(), DateTime.Now); } return; } } //Place和Pick条件都一样 if (!_buffer.IsReadyForPlace(ModuleName.TMRobot, 0)) { _buffer.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0); } } #endregion SIC多片机报错 /// /// 检测到LL中的Wafer已完成Job。 /// //private readonly R_TRIG _trigLLPjDone = new(); private void MonitorLoadTask() { if (!_load.IsAvailable) { return; } if (_load.FirstDetectWaferArrive(0) || _load.FirstDetectWaferLeave(0)) { _load.ResetPurged(); //_trigLLPjDone.RST = true; } var canExcute = _load.HasWafer(0); if (canExcute) { if (_load.GetWaferInfo(0).ProcessJob != null) { if (_load.GetWaferInfo(0).ProcessJob.State != EnumProcessJobState.Processing) { return; } } else { return; } if (!_load.CheckWaferSequenceStepDone(0)) { if (_load.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0)) { if (_load.CheckWaferNeedProcess(0)) { //添加夹爪动作和边缘对位 _load.TrayHome(); _load.Purge(_load.GetWaferPurgeCount(0), _load.GetWaferPumpDelayTime(0)); _load.GetWaferInfo(0).NextSequenceStep++; return; } else { if (!GetWaferSequenceNextValue(ModuleName.Load, 0, "SetValue", out var strSetValue)) { return; } if (!Int32.TryParse(strSetValue, out var setValue)) { return; } if (_loadWaferInfo.ContainsKey(_load.GetWaferInfo(0).WaferInnerID.ToString())) { var dtStartTime = _loadWaferInfo[_load.GetWaferInfo(0).WaferInnerID.ToString()]; var pastTime = (DateTime.Now - dtStartTime).TotalSeconds; _timeLoad = pastTime > setValue ? 0 : (setValue - pastTime); if (pastTime > setValue) { if (!_load.CheckPurged()) { _load.Purge(_load.GetWaferPurgeCount(0), _load.GetWaferPumpDelayTime(0)); return; } _load.ResetPurged(); _load.Vent(); _load.GetWaferInfo(0).NextSequenceStep++; _loadWaferInfo.Remove(_load.GetWaferInfo(0).WaferInnerID.ToString()); return; } } else { _loadWaferInfo.Add(_load.GetWaferInfo(0).WaferInnerID.ToString(), DateTime.Now); return; } } } else if (!_load.IsReadyForPick(ModuleName.TMRobot, 0) && !_tmRobot.IsInPumping) { _load.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Pick, 0); return; } } /*else { // Job Done, 响蜂鸣器 _trigLLPjDone.CLK = true; if (_trigLLPjDone.Q) { OP.DoOperation("System.AlertJobDone", ModuleName.LoadLock.ToString(), 0); } }*/ } else { if (_load.NoTray(0)) { if (!_load.IsReadyForPlace(ModuleName.TMRobot, 0) && !_tmRobot.IsInPumping) { _load.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0); return; } } } } private void MonitorPMTask() { //if (_pm1.FirstDetectTrayArrive(0)) //{ // _pm1.GetWaferInfo(0).TrayUsedForWhichPM = (int)_pm1.Module; //} //if (_pm2.FirstDetectTrayArrive(1)) //{ // _pm2.GetWaferInfo(0).TrayUsedForWhichPM = (int)_pm2.Module; //} foreach (var pm in _lstPms) { if (!pm.IsAvailable) continue; if (pm.HasWafer(0)) { if (pm.CheckNeedRunClean(out var withWafer, out var recipe) && withWafer && GetModule(pm.Module).GetWaferInfo(0).WaferStatus == WaferStatus.Dummy && GetModule(pm.Module).GetWaferInfo(0).ProcessState == WaferProcessStatus.Wait) { pm.Process(recipe, true, withWafer); continue; } if (GetModule(pm.Module).CheckWaferNeedProcess(0, pm.Module)) { WaferInfoRt 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 var withWafer, out var recipe) && !withWafer) { pm.Process(recipe, true, withWafer); continue; } if (!pm.IsReadyForPlace(ModuleName.TMRobot, 0)) { pm.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0); } } } } #region TmRobotTask private void MonitorTmRobotLoadPlaceTask() { if (!_load.IsAvailable || !_tmRobot.IsAvailable) { return; } //place Robot有Tray有Wafer,Load无Tray,无Wafer var canPlace = _tmRobot.HasTray(0) && _load.NoTray(0) && _load.NoWafer(0) && !_load.CheckTrayPlaced(); if (canPlace) { if (!_tmRobot.CheckWaferNeedProcess(0) || _tmRobot.CheckWaferSequenceStepDone(0) || _load.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0)) { if (_load.IsReadyForPlace(ModuleName.TMRobot, 0)) { if (_tmRobot.Place(_load.Module, 0, Hand.Blade1)) { _load.WaitTransfer(ModuleName.TMRobot, false, 0); return; } } } } } private void MonitorTmRobotLoadPickTask() { if (!_load.IsAvailable || !_tmRobot.IsAvailable) { return; } //pick TM无Tray,需要Process var canPick = _tmRobot.NoTray(0) && _tmRobot.NoWafer(0) && _load.HasTray(0) && _load.HasWafer(0) && _load.CheckWaferNeedProcess(0) && !_load.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0) && _load.CheckWaferNextStepModuleNoTray(0); if (canPick) { //下一步如果去PM1,判断PM1是否准备好 if (_pm1.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0)) { if (!_pm1.IsAvailable || _pm1.HasTray(0) || _pm1.HasWafer(0) || !_pm1.IsReadyForPlace(ModuleName.TMRobot, 0)) { return; } if (!_pm1.CheckBufferToPMTemp()) { return; } } //下一步如果去PM2,判断PM2是否准备好 if (_pm2.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0)) { if (!_pm2.IsAvailable || _pm2.HasTray(0) || _pm2.HasWafer(0) || !_pm2.IsReadyForPlace(ModuleName.TMRobot, 0)) { return; } if (!_pm2.CheckBufferToPMTemp()) { return; } } if (_load.IsReadyForPick(ModuleName.TMRobot, 0)) { if (_tmRobot.Pick(_load.Module, 0, Hand.Blade1)) { _load.WaitTransfer(ModuleName.TMRobot, true, 0); return; } } } } private void MonitorTmRobotBufferPlaceTask() { if (!_tmRobot.IsAvailable || !_buffer.IsAvailable) { return; } //place Buffer位置没有Tray,Robot有Wafer,下一步骤是Buffer var canPalce = _tmRobot.HasTray(0); if (canPalce) { SlotItem bufferEmptySlot = null; if (_tmRobot.CheckWaferNeedProcess(0) && _buffer.NoTray(0) && _buffer.NoWafer(0) && _buffer.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0)) { bufferEmptySlot = new SlotItem(ModuleName.Buffer, 0); } //TMRobot的下一步是Buffer3 else if (!_tmRobot.CheckWaferNeedProcess(0) && _buffer.NoTray(0) && _buffer.NoWafer(0) && _buffer.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0)) { bufferEmptySlot = new SlotItem(ModuleName.Buffer, 0); } //Load里有Tray else if (!_tmRobot.CheckWaferNeedProcess(0) && _buffer.NoTray(0) && _buffer.NoWafer(0) && _load.HasTray(0)) { bufferEmptySlot = new SlotItem(ModuleName.Buffer, 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; } } private void MonitorTmRobotTask() { // TMRobot Idle或者Error时,清除被传盘对象的等待状态 if (_tmRobot.CheckTaskDone()) { foreach (var pm in _lstPms.Where( pm => pm.IsWaitTransfer(ModuleName.TMRobot) && _tmRobot.CheckTaskDone())) { pm.StopWaitTransfer(ModuleName.TMRobot); } if (_buffer.IsWaitTransfer(ModuleName.TMRobot) && _tmRobot.CheckTaskDone()) _buffer.StopWaitTransfer(ModuleName.TMRobot); if (_load.IsWaitTransfer(ModuleName.TMRobot) && _tmRobot.CheckTaskDone()) _load.StopWaitTransfer(ModuleName.TMRobot); //if (_unload.IsWaitTransfer(ModuleName.TMRobot)) // _unload.StopWaitTransfer(ModuleName.TMRobot); } if (!_tmRobot.IsAvailable) { return; } if (!_tmRobot.IsAvailable) return; var act = tmRobotActions.Peek(); act.Invoke(); tmRobotActions.Enqueue(tmRobotActions.Dequeue()); } private void MonitorTmRobotBufferPickTask() { if (!_tmRobot.IsAvailable || !_buffer.IsAvailable) { return; } //pick,Buffer有Tray,机械手没有Tray MonitorTmRobotBuffer1PickTask(); MonitorTmRobotBuffer2PickTask(); MonitorTmRobotBuffer3PickTask(); } private void MonitorTmRobotBuffer3PickTask() { if (!_tmRobot.IsAvailable || !_buffer.IsAvailable) { return; } //pick,Buffer有Tray,机械手没有Tray var canPick = _tmRobot.NoTray(0); if (canPick) { if (_buffer.HasTray(0) && _buffer.HasWafer(0)) { if (_buffer.CheckWaferNextStepIsThis(ModuleName.Buffer, 0)) { return; } //下一步如果去PM1,判断PM1是否准备好 if (_pm1.CheckWaferNextStepIsThis(ModuleName.Buffer, 0)) { if (!_pm1.IsAvailable || _pm1.HasTray(0) || _pm1.HasWafer(0) || !_pm1.IsReadyForPlace(ModuleName.TMRobot, 0)) { return; } if (!_pm1.CheckBufferToPMTemp()) { 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; } //pick,Buffer有Tray,机械手没有Tray var canPick = _tmRobot.NoTray(0); if (canPick) { if (_buffer.HasTray(0) && _buffer.HasWafer(0)) { if (_buffer.CheckWaferNextStepIsThis(ModuleName.Buffer, 0)) { return; } //下一步如果去PM2,判断PM2是否准备好 if (_pm2.CheckWaferNextStepIsThis(ModuleName.Buffer, 0)) { if (!_pm2.IsAvailable || _pm2.HasTray(0) || _pm2.HasWafer(0) || !_pm2.IsReadyForPlace(ModuleName.TMRobot, 0)) { return; } if (!_pm2.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; } } } } } } private void MonitorTmRobotBuffer1PickTask() { if (!_tmRobot.IsAvailable || !_buffer.IsAvailable) { return; } var canPick = _tmRobot.NoTray(0) && _tmRobot.NoWafer(0); if (canPick) { if (_buffer.HasTray(0) && _load.NoTray(0) && _load.NoWafer(0) && !_buffer.CheckWaferNextStepIsThis(ModuleName.Buffer, 0) && _load.IsReadyForPlace(ModuleName.TMRobot, 0) && _load.IsAvailable && _load.IsOnline) { if (!_buffer.CheckWaferNeedProcess(0)) { if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0)) { if (_tmRobot.Pick(_buffer.Module, 0, Hand.Blade1)) { _buffer.WaitTransfer(ModuleName.TMRobot); return; } } } } } } private void MonitorTmRobotPMPlaceTask() { if (!_tmRobot.IsAvailable) return; //place to pm var blade0HasWaferAndNeedProcess = _tmRobot.HasWafer(0) && _tmRobot.HasTray(0) && _tmRobot.CheckWaferNeedProcess(0); if (blade0HasWaferAndNeedProcess) { foreach (var pm in _lstPms) { if (!pm.IsAvailable || !GetModule(pm.Module).NoWafer(0) || !GetModule(pm.Module).NoTray(0) || !pm.IsReadyForPlace(ModuleName.TMRobot, 0)) continue; var blade0Place = _tmRobot.HasWafer(0) && _tmRobot.CheckWaferNeedProcess(0, pm.Module) && pm.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0); if (blade0Place) { if (!pm.CheckBufferToPMTemp()) { continue; } if (_tmRobot.Place(pm.Module, 0, Hand.Blade1)) { pm.WaitTransfer(ModuleName.TMRobot); return; } } } } } private void MonitorTmRobotPMPickTask() { if (!_tmRobot.IsAvailable) return; //TMRobot从PM取Wafer,Buffer1中不能有Tray,否则先去Buffer1中的Tray if (_tmRobot.NoWafer(0) && _tmRobot.NoTray(0)) { var pickBlade = Hand.Blade1; var pickPm = ModuleName.System; foreach (var schedulerPm in _lstPms) { //增加温度低于900才能Pick的限制 if (!schedulerPm.IsAvailable || GetModule(schedulerPm.Module).NoTray(0) || GetModule(schedulerPm.Module).CheckWaferNeedProcess(0, schedulerPm.Module) || _tmRobot.HasWafer((int)pickBlade) || _tmRobot.HasTray((int)pickBlade)) continue; if (!schedulerPm.CheckPMToTMRobotTemp()) { continue; } //如果下一步是Buffer,只能取出放Buffer1 if (_buffer.CheckWaferNextStepIsThis(schedulerPm.Module, 0)) { if (_buffer.NoTray(0) && _buffer.NoWafer(0)) { pickPm = schedulerPm.Module; break; } } else if ((_buffer.NoTray(0) && _buffer.NoWafer(0)) || (_load.NoTray(0) && _load.NoWafer(0))) { pickPm = schedulerPm.Module; break; } } if (pickPm != ModuleName.System) { var pm = GetModule(pickPm.ToString()); if (pm.IsReadyForPick(ModuleName.TMRobot, 0)) { if (_tmRobot.Pick(pm.Module, 0, pickBlade)) { pm.WaitTransfer(ModuleName.TMRobot); return; } } } } } #endregion TmRobotTask #endregion Module task #region Logic Check /// /// 获得Buffer的方式和数值 /// /// /// /// /// /// private bool GetWaferSequenceNextValue(ModuleName module, int slot, string nodeName, out string nodeValue) { nodeValue = ""; if (!GetModule(module).HasWafer(slot)) return false; WaferInfoRt 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; WaferInfoRt 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; WaferInfoRt 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) | _pm2.HasTrayAndNotExceedProcessCount(0)); } public bool CheckBufferWaferHasJob() { WaferInfoRt wafer = _buffer.GetWaferInfo(0); if (wafer.IsWaferEmpty) { return false; } if (wafer.ProcessJob == null) { return false; } var 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.IsWaferEmpty) 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 var _, out var _)) return true; } } return false; } public bool CheckWaferSequenceStepDone(ModuleName waferModule, int waferSlot) { var wafer = WaferManager.Instance.GetWafer(waferModule, waferSlot); if (wafer.IsWaferEmpty) { return false; } if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null) { return false; } if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count && wafer.ProcessJob.Sequence.Steps.Count > 0) { return true; } return false; } private SlotItem GetWaferInJobQueue() { var 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 (var i = 0; i < slotCount; i++) { if (_cassetteBL.HasTrayAndNotExceedProcessCount(i) && _cassetteBL.GetWaferInfo(i).TrayUsedForWhichPM == usedForWhichPM) { return new SlotItem(ModuleName.CassBL, i); } } } } return null; } private SlotItem GetTrayOrignSlot(ModuleName module, int slot) { WaferInfoRt 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(WaferInfoRt 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() { var waferCount = 0; if (_load.HasWafer(0)) { waferCount++; } if (_unload.HasWafer(0)) { waferCount++; } if (_tmRobot.HasWafer(0)) { waferCount++; } foreach (var pm in _lstPms) { if (GetModule(pm.Module).HasWafer(0)) { waferCount++; } } for (var i = 0; i < _bufferFloors; i++) { if (_buffer.HasWafer(i)) { waferCount++; } } return waferCount; } private int GetRunWaferCount(ModuleName processIn) { var waferCount = 0; 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 (var i = 0; i < _bufferFloors; 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() { var trayCount = 0; if (_tmRobot.HasTray(0)) { trayCount++; } foreach (var pm in _lstPms) { if (GetModule(pm.Module).HasTray(0)) { trayCount++; } } for (var i = 0; i < _bufferFloors; i++) { if (_buffer.HasTray(i)) { trayCount++; } } return trayCount; } /// /// 获取ProcessJob可以同时运行工艺的Wafer总数 /// /// private int GetCurrentWaferCount() { var waferCountDiv = 0; var 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 Logic Check #region Module error public Result MonitorModuleError() { var isModuleError = false; var isPMError = new bool[2]; for (var i = 0; i < isPMError.Length; i++) { isPMError[i] = false; } if (_tmRobot.IsError) isModuleError = true; for (var i = 0; i < _lstPms.Count; i++) // PM出错,不影响其他腔体的传片 { if (_lstPms[i].IsError) isPMError[i] = true; } if (isModuleError && !_isModuleErrorPrevious) { } else if (!isModuleError && _isModuleErrorPrevious) { Reset(); } for (var 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() { var controlJobExecuting = false; var 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)) if (_buffer.HasWafer(0)) { 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 (!_load.HasWafer(0)) { reason = $"Load have no wafer!"; EV.PostWarningLog(LogSource, reason); return true; } if (!_load.HasTray(0)) { reason = $"Load have no Tray!"; EV.PostWarningLog(LogSource, reason); return true; } return false; } } private bool CheckWaferNeedProcess(ModuleName module, int waferSlot, ModuleName processIn = ModuleName.System) { WaferInfoRt wafer = WaferManager.Instance.GetWafer(module, waferSlot); if (wafer.IsWaferEmpty) 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; var hasPm = 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)) { hasPm = true; break; } } if (hasPm) break; } if (processIn == ModuleName.System && !hasPm) return false; return true; } #endregion Module error } }