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.Key; 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 Kxware.Common; using MECF.Framework.Common.DBCore; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.Gem; using MECF.Framework.Common.Jobs; using MECF.Framework.Common.Schedulers; using MECF.Framework.Common.SubstrateTrackings; using SicRT.Equipments.Schedulers; using SicRT.Modules.Schedulers; namespace SicRT.Modules { public partial class AutoTransfer : SchedulerModuleFactory { private List _controlJobList = new(); private List _processJobList = new(); private int _maxTrayCount = 4; //可以同时运行的石墨盘总数 private const string LogSource = "Scheduler"; private SchedulerDBCallback _dbCallback = new(); private bool _isCycleMode; private bool _isATMMode; 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 Dictionary _loadWaferInfo = new(); private Dictionary _bufferWaferInfo = new(); private Queue tmRobotActions = new() { }; private R_TRIG _updateAutoJobLocation = new(); //需要向数据库更新Wafer位置 public AutoTransfer() { 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 = _controlJobList.Find(x => x.Module == "LoadLock"); if (jb != null) return jb.Name; return ""; }); DATA.Subscribe("LoadLock.LocalJobStatus", () => { var jb = _controlJobList.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 _controlJobList.Count > 0; } } public void Clear() { _tmRobot.ResetTask(); foreach (var pm in _lstPms) { pm.ResetTask(); } _load.ResetTask(); _buffer.ResetTask(); _controlJobList.Clear(); _processJobList.Clear(); _loadWaferInfo.Clear(); } public void ResetTask() { if (!_load.IsOnline) { _load.ResetTask(); } if (!_buffer.IsOnline) { _buffer.ResetTask(); } if (!_tmRobot.IsOnline) { _tmRobot.ResetTask(); } foreach (var pm in _lstPms) { if (!pm.IsOnline) { pm.ResetTask(); } } } #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"]; ////检查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; } if (slotSequence.Length != 1) { reason = $"slot sequence parameter not valid, length is {slotSequence.Length}, should be 1"; EV.PostWarningLog(LogSource, reason); return false; } //拿到Recipe和ModuleName var recipeName = ""; var pmModule = 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; pmModule = m; } } } //每个PM腔不能超过2个对应Wafer if(pmModule != ModuleName.System) { if (GetRunWaferCount(pmModule) >= _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 (string.IsNullOrEmpty(jobId)) { jobId = "CJ_Local_Load_" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); } if (!string.IsNullOrEmpty(lotId)) { if (_controlJobList.Exists(x => x.LotName == lotId)) { reason = $"LotID : {lotId} already created"; EV.PostWarningLog(LogSource, reason); 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); List sequenceNameList = new List(); string WaferAssociationInfo = $"WaferAssociationInfo({module}):"; for (int i = 0; i < 1; i++) { //检查是否设置Sequence string sequenceName = slotSequence[i]; if (string.IsNullOrEmpty(sequenceName)) { reason = $"sequence name is empty"; EV.PostWarningLog(LogSource, reason); return false; } //检查是否有Normal Wafer if (!WaferManager.Instance.CheckWafer(ModuleHelper.Converter(module), i, WaferStatus.Normal)) { reason = $"{module} has no normal wafer"; EV.PostWarningLog(LogSource, reason); return false; } WaferInfoRt wafer = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i); 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 = $"{module} wafer has processJob"; EV.PostWarningLog(LogSource, reason); return false; } WaferAssociationInfo = WaferAssociationInfo + string.Format(" slot{0} -- {1};", i + 1, slotSequence[i]); wafer.NextSequenceStep = 0; wafer.PPID = sequenceName; wafer.LotId = lotId; cj.LotWafers.Add(wafer); _isATMMode = SC.GetValue("System.IsATMMode"); _isCycleMode = SC.GetValue("System.IsCycleMode"); //没有包含sequenceName,需新建 if (!sequenceNameList.Exists(s => s == sequenceName)) { sequenceNameList.Add(sequenceName); ProcessJobInfo pj = new ProcessJobInfo(); pj.Name = jobId + "_" + (i + 1); pj.ControlJobName = cj.Name; pj.Sequence = SequenceInfoHelper.GetInfo(sequenceName); pj.SetState(EnumProcessJobState.Queued); pj.SlotWafers = [Tuple.Create(ModuleHelper.Converter(module), i)]; //不是CycleMode模式,则CycleCount设为1 pj.CycleCount = _isATMMode && _isCycleMode ? SC.GetValue("System.CycleCount") : 1; pj.CycleTime = 0; //检查Sequence对应的PM腔状态 if (!CheckPMState(sequenceName)) { return false; } wafer.ProcessJob = pj; _processJobList.Add(pj); cj.ProcessJobNameList.Add(pj.Name); } //已包含sequenceName else { ProcessJobInfo pj = _processJobList.Find(p => p.Sequence.Name == sequenceName); wafer.ProcessJob = pj; pj.SlotWafers.Add(Tuple.Create(ModuleHelper.Converter(module), i)); } } _controlJobList.Add(cj); int totalWafer = 0; foreach (string pjName in cj.ProcessJobNameList) { ProcessJobInfo tempPJ = _processJobList.First(p => p.Name == pjName); foreach (var pjSlotWafer in tempPJ.SlotWafers) { var wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2); WaferDataRecorder.SetCjInfo(wafer.WaferInnerID.ToString(), cj.InnerId.ToString()); WaferDataRecorder.SetWaferSequence(wafer.WaferInnerID.ToString(), tempPJ.Sequence.Name); WaferDataRecorder.SetWaferLotId(wafer.WaferInnerID.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}"); //此carrier为null CarrierInfo carrier = CarrierManager.Instance.GetCarrier(cj.Module); JobDataRecorder.StartCJ(cj.InnerId.ToString(), "", cj.Name, cj.Module, cj.Module, totalWafer); EV.PostInfoLog(LogSource, WaferAssociationInfo); //保存信息 var waferInfo = WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0); if (waferInfo != null) { 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; } public void StartJob(string jobName) { _maxTrayCount = _lstPms.Count * 2; var cj = _controlJobList.Find(x => x.Name == jobName); if (cj == null) { EV.PostWarningLog(LogSource, $"start job rejected, not found job with id {jobName}"); return; } if (cj.State == EnumControlJobState.WaitingForStart) { cj.BeginTime = DateTime.Now; cj.LotInnerId = Guid.NewGuid(); //_dbCallback.LotCreated(cj); foreach (var pjName in cj.ProcessJobNameList) { var pj = _processJobList.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); } } cj.SetState(EnumControlJobState.Executing); string squenceID = cj.LotWafers != null ? cj.LotWafers[0].PPID : string.Empty; //补全路径 squenceID = $"Sequence\\{squenceID}.seq"; GemManager.Instance.Equipment?.TriggerEvent("JobStart", new string[] { "LotID", "SequenceID" }, new object[] { cj.LotName, squenceID }); } } 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; } 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 _controlJobList) { foreach (var pj in _processJobList) { if (pj.ControlJobName == cj.Name) { pj.SetState(EnumProcessJobState.Stopping); } } if (_cycleSetPoint > 0) { _cycleSetPoint = _cycledCount; } } } public void Abort() { try { var wafer = WaferManager.Instance.GetWafer(ModuleName.PM1, 0); if (wafer != null && !string.IsNullOrEmpty(wafer.WaferID)) { AutoJobRecorder.UpdatePosition(wafer.WaferID.ToString(), ModuleName.PM1.ToString(), "Abort"); } var wafer1 = WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0); if (wafer1 != null && !string.IsNullOrEmpty(wafer1.WaferID)) { AutoJobRecorder.UpdatePosition(wafer1.WaferID.ToString(), ModuleName.TM.ToString(), "Abort"); } var wafer2 = WaferManager.Instance.GetWafer(ModuleName.Buffer, 0); if (wafer2 != null && !string.IsNullOrEmpty(wafer2.WaferID)) { AutoJobRecorder.UpdatePosition(wafer2.WaferID.ToString(), ModuleName.Buffer.ToString(), "Abort"); } var wafer3 = WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0); if (wafer3 != null && !string.IsNullOrEmpty(wafer3.WaferID)) { AutoJobRecorder.UpdatePosition(wafer3.WaferID.ToString(), ModuleName.LoadLock.ToString(), "Abort"); } var cjList = _controlJobList.FindAll(c => c.State == EnumControlJobState.Executing); if (cjList != null) { foreach (var cj in cjList) { string squenceID = cj.LotWafers != null ? cj.LotWafers[0].PPID : string.Empty; //补全路径 squenceID = $"Sequence\\{squenceID}.seq"; GemManager.Instance.Equipment?.TriggerEvent("JobAbort", new string[] { "LotID", "SequenceID" }, new object[] { cj.LotName, squenceID }); } } } catch (Exception ex) { LOG.Error(ex.Message, ex); } } internal void AbortJob(string jobName) { var cj = _controlJobList.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 _processJobList) { 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) { _processJobList.Remove(pj); } _controlJobList.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 _controlJobList) { 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 _controlJobList) { 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; } #endregion /// /// Start Auto Transfer /// /// /// public Result CheckAutoMode(params object[] objs) { 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() { MonitorModuleTasks(); MonitorAutoJobStatus(); MonitorModuleError(); MonitorJobTasks(); return Result.RUN; } #region Job task public Result MonitorJobTasks() { UpdateProcessJobStatus(); UpdateControlJobStatus(); 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; } 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 _processJobList) { if (pj.State == EnumProcessJobState.Processing) { if (CheckAllWaferReturned(pj, true)) { if (CheckWaferSequenceStepDone(ModuleName.LoadLock, 0)) { pj.CycleTime++; if (pj.CycleTime < pj.CycleCount) { //重新设置wafer for (int i = 0; i < pj.SlotWafers.Count; ++i) { var wafer = GetModule(pj.SlotWafers[i].Item1).GetWaferInfo(pj.SlotWafers[i].Item2); wafer.NextSequenceStep = 0; wafer.WaferStatus = WaferStatus.Normal; wafer.ProcessState = WaferProcessStatus.Idle; } } else { _load.SetJobStatue(); pj.SetState(EnumProcessJobState.ProcessingComplete); JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0); AutoJobRecorder.EndJob(WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0).WaferID.ToString()); } } } if (CheckAllWaferDeleted(pj)) { _load.SetJobStatue(); pj.SetState(EnumProcessJobState.Complete); 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)) { if (CheckWaferSequenceStepDone(ModuleName.LoadLock, 0)) { _load.SetJobStatue(); pj.SetState(EnumProcessJobState.Complete); JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0); AutoJobRecorder.EndJob(WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0).WaferID.ToString()); } } } } } private void UpdateControlJobStatus() { try { if (_controlJobList.Count == 0) { return; } foreach (var cj in _controlJobList) { if (cj.State == EnumControlJobState.Executing) { bool allPjCompleted = true; foreach (var pjName in cj.ProcessJobNameList) { var pj = _processJobList.Find(x => x.Name == pjName); if (pj != null) { if (pj.State != EnumProcessJobState.ProcessingComplete && pj.State != EnumProcessJobState.Complete) { allPjCompleted = false; break; } } } if (allPjCompleted) { cj.SetState(EnumControlJobState.Completed); foreach (var pjName in cj.ProcessJobNameList) { var pj = _processJobList.Find(x => x.Name == pjName); if (pj != null) { _processJobList.Remove(pj); } } JobDataRecorder.EndCJ(cj.InnerId.ToString(), 0, 0); _dbCallback.LotFinished(cj); } } } for (int i = 0; i < _controlJobList.Count; i++) { if (_controlJobList[i].State == EnumControlJobState.Completed) { _controlJobList.RemoveAt(i); } } } catch (Exception ex) { LOG.Error(ex.Message,ex); } } public void MonitorAutoJobStatus() { try { _updateAutoJobLocation.CLK = _tmRobot.IsAvailable; if (_updateAutoJobLocation.Q) { WaferInfoRt wafer = WaferManager.Instance.GetWafer(ModuleName.PM1, 0); if (wafer != null && !string.IsNullOrEmpty(wafer.WaferID)) { AutoJobRecorder.UpdatePosition(wafer.WaferID.ToString(), ModuleName.PM1.ToString(), GetWaferStatue(wafer)); } WaferInfoRt wafer1 = WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0); if (wafer1 != null && !string.IsNullOrEmpty(wafer1.WaferID)) { AutoJobRecorder.UpdatePosition(wafer1.WaferID.ToString(), ModuleName.TM.ToString(), GetWaferStatue(wafer1)); } WaferInfoRt wafer2 = WaferManager.Instance.GetWafer(ModuleName.Buffer, 0); if (wafer2 != null && !string.IsNullOrEmpty(wafer2.WaferID)) { AutoJobRecorder.UpdatePosition(wafer2.WaferID.ToString(), ModuleName.Buffer.ToString(), GetWaferStatue(wafer2)); } WaferInfoRt wafer3 = WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0); if (wafer3 != null && !string.IsNullOrEmpty(wafer3.WaferID)) { AutoJobRecorder.UpdatePosition(wafer3.WaferID.ToString(), ModuleName.LoadLock.ToString(), GetWaferStatue(wafer3)); } } } catch (Exception ex) { LOG.Error(ex.Message, ex); } } public bool CheckAllJobDone() { //条件满足状态由AutoRunning切换到AutoIdle状态 if (_load.IsAvailable && _tmRobot.IsAvailable && _tmRobot.NoWafer(0) && _tmRobot.NoTray(0) && _buffer.NoWafer(0) && _buffer.NoTray(0) && _buffer.NoWafer(1) && _buffer.NoTray(1) && _buffer.NoWafer(2) && _buffer.NoTray(2) && _pm1.NoWafer(0) && _pm1.NoTray(0) && _pm2.NoWafer(0) && _pm2.NoTray(0) && !_controlJobList.Exists(c => c.State == EnumControlJobState.Executing)) { return true; } return false; } private bool ActiveProcessJob(ProcessJobInfo pj) { 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 = _controlJobList.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 #region Module task public Result MonitorModuleTasks() { MonitorPMTask(); MonitorBufferTask(); MonitorTmRobotTask(); MonitorLoadTask(); return Result.RUN; } private void MonitorBufferTask() { if (!_buffer.IsAvailable) { return; } for (var i = 0; i < 3; 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, "Type", out var strBufferType)) { continue; } if (!GetWaferSequenceNextValue(ModuleName.Buffer, i, "SetValue", out var strBufferSetValue)) { continue; } if (!Int32.TryParse(strBufferSetValue, out bufferSetValue)) { continue; } //分别判断冷却和加热方式温度是否达到 if (strBufferType == "HeatByTemp") { if (_bufferWaferInfo.ContainsKey(bufferWafer.WaferInnerID.ToString())) { var dtStartTime = _bufferWaferInfo[bufferWafer.WaferInnerID.ToString()]; var pastTime = (DateTime.Now - dtStartTime).TotalSeconds; //选择By温度5秒后再判断温度 if (pastTime > 5) { if (_buffer.GetTemperature() >= bufferSetValue) bufferWafer.NextSequenceStep++; _bufferWaferInfo.Remove(bufferWafer.WaferInnerID.ToString()); } } else { _bufferWaferInfo.Add(bufferWafer.WaferInnerID.ToString(), DateTime.Now); } } else if (strBufferType == "HeatByTime") { 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); } } else if (strBufferType == "CoolingByTime") { 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); } } /// /// 检测到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.Purge(_load.GetWaferPurgeCount(0), _load.GetWaferPumpDelayTime(0)); _load.GetWaferInfo(0).NextSequenceStep++; return; } else { if (!GetWaferSequenceNextValue(ModuleName.Load, 0, "Type", out var strType)) { return; } if (!GetWaferSequenceNextValue(ModuleName.Load, 0, "SetValue", out var strSetValue)) { return; } if (!Int32.TryParse(strSetValue, out var setValue)) { return; } //Load腔没有测温 //if (strType == "CoolingByTemp") //{ // if (_load.GetTemperature() <= setValue) // { // _load.Purge(_load.GetWaferPurgeCount(0), _load.GetWaferPumpDelayTime(0)); // _load.Vent(); // _load.GetWaferInfo(0).NextSequenceStep++; // } //} if (strType == "CoolingByTime") { 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()); //补全路径 string squenceID = $"Sequence\\{_load.GetWaferInfo(0).PPID}.seq"; GemManager.Instance.Equipment?.TriggerEvent("JobComplete", new string[] { "LotID", "SequenceID" }, new object[] { _load.GetWaferInfo(0).LotId, squenceID }); 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); } } } } 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()); } #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, _pm1.Module) && _buffer.NoTray(2) && _buffer.NoWafer(2) && _buffer.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0)) { bufferEmptySlot = new SlotItem(ModuleName.Buffer, 2); } else if (_tmRobot.CheckWaferNeedProcess(0, _pm2.Module) && _buffer.NoTray(1) && _buffer.NoWafer(1) && _buffer.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0)) { bufferEmptySlot = new SlotItem(ModuleName.Buffer, 1); } //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 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(2) && _buffer.HasWafer(2)) { if (_buffer.CheckWaferNextStepIsThis(ModuleName.Buffer, 2)) { return; } //下一步如果去PM1,判断PM1是否准备好 if (_pm1.CheckWaferNextStepIsThis(ModuleName.Buffer, 2)) { 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, 2, 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(1) && _buffer.HasWafer(1)) { if (_buffer.CheckWaferNextStepIsThis(ModuleName.Buffer, 1)) { return; } //下一步如果去PM2,判断PM2是否准备好 if (_pm2.CheckWaferNextStepIsThis(ModuleName.Buffer, 1)) { if (!_pm2.IsAvailable || _pm2.HasTray(0) || _pm2.HasWafer(0) || !_pm2.IsReadyForPlace(ModuleName.TMRobot, 0)) { return; } if(!_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; } } } } } } 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 #endregion #region Logic Check /// /// 获得Buffer的方式和数值 /// /// /// /// /// /// private bool GetWaferSequenceNextValue(ModuleName module, int slot, string nodeName, out string nodeValue) { nodeValue = ""; if (!GetModule(module).HasWafer(slot)) return false; 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; } public bool CheckBufferWaferHasJob() { WaferInfoRt wafer = _buffer.GetWaferInfo(0); if (wafer.IsWaferEmpty) { return false; } if (wafer.ProcessJob == null) { return false; } var pj = _processJobList.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 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); } /// /// 获取各个模块的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 < 3; 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 < 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() { 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 < 3; i++) { if (_buffer.HasTray(i)) { trayCount++; } } return trayCount; } /// /// 获取ProcessJob可以同时运行工艺的Wafer总数 /// /// private int GetCurrentWaferCount() { var waferCountDiv = 0; var cassWaferCount = 0; foreach (var cj in _controlJobList) { if (cj.State == EnumControlJobState.Executing) { foreach (var pj in _processJobList) { if (pj.ControlJobName == cj.Name && pj.State == EnumProcessJobState.Processing) { cassWaferCount += pj.SlotWafers.Count; foreach (var pjSlotWafer in pj.SlotWafers) { var module = GetModule(pjSlotWafer.Item1); if (module.HasWafer(pjSlotWafer.Item2) && !module.CheckWaferNeedProcess(pjSlotWafer.Item2)) { waferCountDiv++; } } } } } } return cassWaferCount - waferCountDiv; //int waferCount = 0; //if (_load.HasWafer(0)) //{ // waferCount++; //} //for (int i = 0; i < 3; i++) //{ //if (_buffer.HasWafer(i)) // { // waferCount++; // } //} //if (_waferRobot.CheckWaferNeedProcess(0) ) //{ // waferCount++; //} //if (_aligner.CheckWaferNeedProcess(0) ) //{ // waferCount++; //} //for (int i=0;i<25;i++) //{ // if (CheckWaferNeedProcess(ModuleName.CassAL, i)) // { // waferCount++; // } // if (CheckWaferNeedProcess(ModuleName.CassAR, i)) // { // waferCount++; // } //} //return waferCount; } #endregion #region Module error public Result MonitorModuleError() { 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; } private bool CheckModuleHaveWaferWithNoJob(out string reason) { reason = ""; if (_controlJobList.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 (!_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 } }