using System; using System.Collections.Generic; using System.Linq; using System.Diagnostics; using Aitex.Core.Common; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Aitex.Sorter.Common; using Aitex.Core.RT.Log; using Aitex.Core.Util; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.RecipeCenter; using Aitex.Core.RT.Fsm; using MECF.Framework.Common.Jobs; using MECF.Framework.Common.Routine; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.SubstrateTrackings; using MECF.Framework.Common.Schedulers; using MECF.Framework.Common.DBCore; using Venus_Core; using Venus_RT.Modules.Schedulers; using Venus_RT.Scheduler; using Venus_Unity; namespace Venus_RT.Modules { public class WaferTask { public ModuleName sourceMod { get; } public int sourceSlot { get; } public ModuleName destMod { get; private set; } public int destSlot { get; private set; } public ModuleName currentMod { get; private set; } public int currentSlot { get; private set; } public ModuleName nextMod { get; private set; } public int nextSlot { get; private set; } public ModuleName routedMod { get; private set; } public int routedSlot { get; private set; } public Hand hand { get; private set; } public SequenceLLInOutPath llInOutPath { get; } public string processRecipe { get; } public string wtwCleanRecipe { get; } public float temperature { get; } public Guid waferId { get; } public int elapseTime { get { return (int)(DateTime.Now - _scheduledTime).TotalSeconds; } } public int llDelayTime { get; } public RState pressureStatus { get; private set; } public RState temperatureStatus { get; private set; } public RState movingStatus { get; private set; } public bool IsCompleted { get { return movingStatus == RState.End && currentMod == destMod && currentSlot == destSlot; } } public bool IsTimeout { get { return elapseTime > 600; } } public bool IsAligned { get; set; } public bool IsWaitingAtmMoving { get { if (movingStatus != RState.Init) return false; return !IsWaitingVacMoving; } } public bool IsWaitingVacMoving { get { if ( movingStatus == RState.Init && (ModuleHelper.IsPm(nextMod) || ModuleHelper.IsTMRobot(nextMod) || ModuleHelper.IsPm(currentMod) || ModuleHelper.IsTMRobot(currentMod))) return true; return false; } } public delegate void WaferMoveHandler(WaferTask wafer, MoveItem item); public event WaferMoveHandler OnWaferArrived; public event WaferMoveHandler OnWaferLeaved; private DateTime _scheduledTime; public WaferTask(ModuleName source, int srcSlot, ModuleName dest, int dstSlot, float temp, Guid waferID, string recipeName, string wtwClean, SequenceLLInOutPath inOutPath, int LLDelay) { sourceMod = currentMod = nextMod = routedMod = source; sourceSlot = currentSlot = nextSlot = routedSlot = srcSlot; destMod = dest; destSlot = dstSlot; hand = Hand.None; temperature = temp; waferId = waferID; processRecipe = recipeName; wtwCleanRecipe = wtwClean; llInOutPath = inOutPath; llDelayTime = LLDelay; IsAligned = false; pressureStatus = RState.Init; temperatureStatus = RState.Init; movingStatus = RState.Init; _scheduledTime = DateTime.Now; } public RState Run() { if (movingStatus == RState.Running) { var wafer = WaferManager.Instance.GetWafer(nextMod, nextSlot); if (!wafer.IsEmpty && wafer.InnerId == waferId) { LOG.Write(eEvent.EV_ROUTER, ModuleName.System, $"Wafer {wafer.WaferOrigin} from {currentMod}.{currentSlot + 1} move to {nextMod}.{nextSlot + 1}"); if (!ModuleHelper.IsTMRobot(currentMod) && !ModuleHelper.IsEFEMRobot(currentMod)) { OnWaferLeaved(this, new MoveItem(currentMod, currentSlot, nextMod, nextSlot, hand)); } if (!ModuleHelper.IsTMRobot(nextMod) && !ModuleHelper.IsEFEMRobot(nextMod)) { wafer.NextSequenceStep++; OnWaferArrived(this, new MoveItem(currentMod, currentSlot, nextMod, nextSlot, hand)); } currentMod = nextMod; currentSlot = nextSlot; movingStatus = RState.End; } } if (ModuleHelper.IsPm(destMod) && temperatureStatus == RState.Init) { var pmScheduler = Singleton.Instance.GetScheduler(destMod) as SchedulerPM; if (pmScheduler != null && pmScheduler.IsAvailable) { pmScheduler.Preheating(temperature); temperatureStatus = RState.Running; } } return RState.Running; } public void RouteTo(ModuleName mod, int slot) { routedMod = mod; routedSlot = slot; movingStatus = RState.Init; } public void MoveTo(ModuleName mod, int slot) { nextMod = mod; nextSlot = slot; movingStatus = RState.Running; } public void Return() { destMod = sourceMod; destSlot = sourceSlot; movingStatus = RState.End; pressureStatus = RState.End; temperatureStatus = RState.End; } } public enum ModuleStatus { Idle, WaitMove, Moving, NotReady, // PM Status WaitProcess, StartProcess, Processing, StartIdleClean, IdleClean, WaitPreJobClean, StartPreJobClean, PreJobClean, WaitPostJobClean, StartPostJobClean, PostJobClean, WaitWTWClean, StartWTWClean, WTWClean, // Align Status WaitAlign, StartAlign, Aligning, // Loadlock Status ExchangeWaferWithEFEM, ExchangeWaferWithTM, } public class ModuleTask { public ModuleName Module { get; } public ModuleStatus Status { get; set; } public SchedulerModule Scheduler { get; } public virtual int SlotNum { get; protected set; } public virtual bool IsIdle { get { return Status == ModuleStatus.Idle; } } private int _currentActionTime = 0; public virtual int IdleTime { get { if (Status != ModuleStatus.Idle) return 0; return (int)(DateTime.Now - _moduleTimer).TotalSeconds; } } public virtual int BusyTime { get { if (Status == ModuleStatus.Idle) return 0; return (int)(DateTime.Now - _moduleTimer).TotalSeconds; } } public virtual int BusyLastTime { get { if (Status == ModuleStatus.Idle) return 0; return _currentActionTime - BusyTime; } } public virtual int TimeToReady { get { if(Scheduler.IsAvailable) return 0; return int.MaxValue; } } protected DateTime _moduleTimer; public ModuleTask(ModuleName mod) { Module = mod; Scheduler = Singleton.Instance.GetScheduler(mod); SlotNum = 1; _moduleTimer = DateTime.Now; } public virtual RState Run() { Status = Scheduler.IsAvailable ? ModuleStatus.Idle : ModuleStatus.NotReady; return RState.Running; } public virtual void WaferArrived(WaferTask wafer, int slot) { } public virtual void WaferLeaved(WaferTask wafer, int slot) { } } public class PMTask : ModuleTask { enum CleanType { IdleClean, PreJobClean, PostJobClean, WTWClean, } public override int TimeToReady { get { switch(Status) { case ModuleStatus.Idle: case ModuleStatus.Processing: case ModuleStatus.IdleClean: case ModuleStatus.PreJobClean: { return Scheduler.IsAvailable ? 0 : (Scheduler.TimeToReady + 500) / 1000; } case ModuleStatus.PostJobClean: case ModuleStatus.WTWClean: { if(_pendingCleanTask.Count == 0) { return Scheduler.IsAvailable ? 0 : (Scheduler.TimeToReady + 500) / 1000; } } break; } return int.MaxValue; } } private WaferTask _wafer; private SchedulerPM _pmScheduler => Scheduler as SchedulerPM; private string _preJobCleanRecipe; private string _postJobCleanRecipe; private string _wtwCleanRecipe; private Queue _pendingCleanTask = new Queue(); public PMTask(ModuleName pm) : base(pm) { } public override RState Run() { if(Scheduler.IsAvailable) { switch (Status) { case ModuleStatus.Idle: { if(WaferManager.Instance.CheckNoWafer(Module, 0)) { if (_pendingCleanTask.Count > 0) { var cleanTask = _pendingCleanTask.Dequeue(); if (cleanTask == CleanType.PostJobClean && !string.IsNullOrWhiteSpace(_postJobCleanRecipe)) { Status = ModuleStatus.WaitPostJobClean; } else if (cleanTask == CleanType.PreJobClean && !string.IsNullOrWhiteSpace(_preJobCleanRecipe)) { Status = ModuleStatus.WaitPreJobClean; } } else if (_pmScheduler.RunIdleCleanTask()) // Check Idle Clean { Status = ModuleStatus.StartIdleClean; } } } break; case ModuleStatus.WaitProcess: { Scheduler.EventWaferArrived?.Invoke(this, new WaferMoveArgs(ModuleName.TMRobot, 0, Module, 0)); Status = ModuleStatus.StartProcess; } break; case ModuleStatus.WaitPreJobClean: { if(WaferManager.Instance.CheckNoWafer(Module, 0)) { if (_pmScheduler.RunJobCleanTask(_preJobCleanRecipe)) { Status = ModuleStatus.StartPreJobClean; } else { LOG.Write(eEvent.WARN_ROUTER, Module, $"Run Prejob clean recipe{_preJobCleanRecipe} failed"); Status = ModuleStatus.Idle; _preJobCleanRecipe = string.Empty; } } } break; case ModuleStatus.WaitPostJobClean: { if (WaferManager.Instance.CheckNoWafer(Module, 0)) { if (_pmScheduler.RunJobCleanTask(_postJobCleanRecipe)) { Status = ModuleStatus.StartPostJobClean; } else { LOG.Write(eEvent.WARN_ROUTER, Module, $"Run Postjob clean recipe{_postJobCleanRecipe} failed"); Status = ModuleStatus.Idle; _postJobCleanRecipe = string.Empty; } } } break; case ModuleStatus.WaitWTWClean: { if (WaferManager.Instance.CheckNoWafer(Module, 0)) {if (_pmScheduler.RunJobCleanTask(_wtwCleanRecipe)) { Status = ModuleStatus.StartWTWClean; } else { LOG.Write(eEvent.WARN_ROUTER, Module, $"Run WTW Wafer clean recipe{_wtwCleanRecipe} failed"); Status = ModuleStatus.Idle; _wtwCleanRecipe = string.Empty; } } } break; case ModuleStatus.Processing: { var wafer = WaferManager.Instance.GetWafer(Module, 0); if(!wafer.IsEmpty && wafer.ProcessState == EnumWaferProcessStatus.Completed) { _wafer.Return(); Status = ModuleStatus.Idle; } } break; case ModuleStatus.PreJobClean: { _preJobCleanRecipe = string.Empty; Status = ModuleStatus.Idle; } break; case ModuleStatus.PostJobClean: { _postJobCleanRecipe = string.Empty; if (_pendingCleanTask.Count > 0) { var cleanTask = _pendingCleanTask.Dequeue(); if(cleanTask == CleanType.PreJobClean && !string.IsNullOrWhiteSpace(_preJobCleanRecipe)) { Status = ModuleStatus.WaitPreJobClean; break; } } Status = ModuleStatus.Idle; } break; case ModuleStatus.WTWClean: { if(_pendingCleanTask.Count > 0) { var cleanTask = _pendingCleanTask.Dequeue(); if (cleanTask == CleanType.PostJobClean && !string.IsNullOrWhiteSpace(_postJobCleanRecipe)) { Status = ModuleStatus.WaitPostJobClean; } else if (cleanTask == CleanType.PreJobClean && !string.IsNullOrWhiteSpace(_preJobCleanRecipe)) { Status = ModuleStatus.WaitPreJobClean; } } else { Status = ModuleStatus.Idle; } _wtwCleanRecipe = string.Empty; } break; case ModuleStatus.IdleClean: { Status = ModuleStatus.Idle; } break; } } else { switch(Status) { case ModuleStatus.StartProcess: Status = ModuleStatus.Processing; break; case ModuleStatus.StartIdleClean: Status = ModuleStatus.IdleClean; break; case ModuleStatus.StartPreJobClean: Status = ModuleStatus.PreJobClean; break; case ModuleStatus.StartPostJobClean: Status = ModuleStatus.PostJobClean; break; case ModuleStatus.StartWTWClean: Status = ModuleStatus.WTWClean; break; } } return RState.Running; } public override void WaferArrived(WaferTask wafer, int slot) { _wafer = wafer; Status = ModuleStatus.WaitProcess; } public override void WaferLeaved(WaferTask wafer, int slot) { if(!string.IsNullOrWhiteSpace(_wafer.wtwCleanRecipe.Trim())) { Status = ModuleStatus.WaitWTWClean; _wtwCleanRecipe = _wafer.wtwCleanRecipe; } else if(_pendingCleanTask.Count > 0) { var cleanTask = _pendingCleanTask.Dequeue(); if (cleanTask == CleanType.PostJobClean && !string.IsNullOrWhiteSpace(_postJobCleanRecipe)) { Status = ModuleStatus.WaitPostJobClean; } else if (cleanTask == CleanType.PreJobClean && !string.IsNullOrWhiteSpace(_preJobCleanRecipe)) { Status = ModuleStatus.WaitPreJobClean; } } _wafer = null; } public void InvokePreJobClean(string preJobClean) { _preJobCleanRecipe = preJobClean; _pendingCleanTask.Enqueue(CleanType.PreJobClean); } public bool IsPreJobCleanDone() { return !_pendingCleanTask.Contains(CleanType.PreJobClean) && string.IsNullOrWhiteSpace(_preJobCleanRecipe); } public void InvokePostJobClean(string postJobClean) { _postJobCleanRecipe = postJobClean; _pendingCleanTask.Enqueue(CleanType.PostJobClean); } public bool IsPostJobCleanDone() { return !_pendingCleanTask.Contains(CleanType.PostJobClean) && string.IsNullOrWhiteSpace(_postJobCleanRecipe); } } public class AlignerTask : ModuleTask { private WaferTask _wafer; public AlignerTask(ModuleName aligner) : base(aligner) { } public override RState Run() { var efemRobot = Singleton.Instance.GetScheduler(ModuleName.EfemRobot) as SchedulerEfemRobot; if (efemRobot == null || !efemRobot.IsAvailable) return RState.Running; switch (Status) { case ModuleStatus.WaitAlign: { efemRobot.Align(0); Status = ModuleStatus.Aligning; } break; case ModuleStatus.Aligning: { _wafer.IsAligned = true; Status = ModuleStatus.Idle; } break; } return RState.Running; } public override void WaferArrived(WaferTask wafer, int slot) { _wafer = wafer; Status = ModuleStatus.WaitAlign; } public override void WaferLeaved(WaferTask wafer, int slot) { _wafer = null; } } public class LoadPortTask : ModuleTask { public LoadPortTask(ModuleName lp) : base(lp) { SlotNum = SC.GetValue($"EFEM.LoadPort.SlotNumber"); } public override RState Run() { return base.Run(); } } public class TMRobotTask : ModuleTask { public TMRobotTask(ModuleName tmRobot) : base(tmRobot) { SlotNum = 2; } public override RState Run() { return base.Run(); } } public class EFEMRobotTask : ModuleTask { public EFEMRobotTask(ModuleName efemRobot) : base(efemRobot) { SlotNum = 2; } public override RState Run() { return base.Run(); } public bool PostMoveItems(MoveItem[] items) { Status = ModuleStatus.Moving; return (Scheduler as SchedulerEfemRobot).PostMoveItems(items); } } public class LoadlockTask : ModuleTask { public LoadlockTask(ModuleName ll) : base(ll) { SlotNum = SC.GetValue($"{ll}.SlotNumber"); } public override int TimeToReady { get { return Scheduler.IsAvailable ? 0 : (Scheduler.TimeToReady + 500) / 1000; } } public override void WaferArrived(WaferTask wafer, int slot) { Scheduler.WaferArrived(slot); } public bool PreVent() { if (Scheduler.IsAvailable && Scheduler.IsVac) { return (Scheduler as SchedulerLoadLock).PreVent(); } return false; } public bool PrePump() { if (Scheduler.IsAvailable && Scheduler.IsAtm) { return (Scheduler as SchedulerLoadLock).PrePump(); } return false; } } class SystemDispatcher : ICycle { private List _lstControlJobs = new List(); private List _lstProcessJobs = new List(); private List _lstWaferTasks = new List(); private Dictionary _dictModuleTask = new Dictionary(); private Queue _qeReturnWafers = new Queue(); private Queue> _efemSchdActions = new Queue>(); private Queue> _tmSchdActions = new Queue>(); private List _curEfemAction = new List(); private List _curTmAction = new List(); private RState _efemRobotStatus { get { return (_dictModuleTask[ModuleName.EfemRobot].Scheduler as SchedulerEfemRobot).RobotStatus; } } private RState _tmRobotStatus { get { return (_dictModuleTask[ModuleName.TMRobot].Scheduler as SchedulerTMRobot).RobotStatus; } } private SchedulerFACallback _faCallback; private SchedulerDBCallback _dbCallback; private bool _isCycleMode; private int _cycleSetPoint = 0; private int _cycledCount = 0; private int _cycledWafer = 0; private float _throughput = 0.0f; private readonly int _LLASlotNumber = 4; private readonly int _LLBSlotNumber = 4; private int _efemRobotSingleArmOption = 0; private int _tmRobotSingleArmOption = 0; private Dictionary _lpCycleWafer = new Dictionary(); private Dictionary _lpCycleCount = new Dictionary(); private Stopwatch _cycleWatch = new Stopwatch(); private SequenceLLInOutPath _LLInOutPath = SequenceLLInOutPath.DInDOut; public SequenceLLInOutPath LLInOutPath => _LLInOutPath; public bool HasJobRunning => _lstControlJobs.Count > 0; private RState _cycleState = RState.Init; public RState CycleState => _cycleState; private Dictionary _loadportControlJobDic = new Dictionary(); #region public interface public SystemDispatcher() { _faCallback = new SchedulerFACallback(); _dbCallback = new SchedulerDBCallback(); _efemRobotSingleArmOption = SC.GetValue("EFEM.SingleArmOption"); _tmRobotSingleArmOption = SC.GetValue("TM.SingleArmOption"); _LLASlotNumber = SC.GetValue("LLA.SlotNumber"); _LLBSlotNumber = SC.GetValue("LLB.SlotNumber"); InitModules(); DATA.Subscribe("Scheduler.CycledCount", () => _cycledCount, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe("Scheduler.CycledWafer", () => _cycledWafer, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe("Scheduler.CycleSetPoint", () => _cycleSetPoint, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe("Scheduler.Throughput", () => _throughput, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe("Scheduler.PjIdList", () => Array.ConvertAll(_lstProcessJobs.ToArray(), x => x.InnerId.ToString()).ToList()); DATA.Subscribe("Scheduler.PjNameList", () => Array.ConvertAll(_lstProcessJobs.ToArray(), x => x.LotName.ToString()).ToList()); for (int i = 1; i <= 3; i++) { _loadportControlJobDic[$"LP{i}"] = null; string lp = $"LP{i}"; DATA.Subscribe($"{lp}.CurrentControlJob", () => _loadportControlJobDic[lp], SubscriptionAttribute.FLAG.IgnoreSaveDB); } } /// /// 获取lp当前的ControlJob /// /// /// public ControlJobInfo GetLoadPortCurrentControlJob(ModuleName lp) { if(ModuleHelper.IsLoadPort(lp)) { return _loadportControlJobDic.ContainsKey(lp.ToString()) ? _loadportControlJobDic[lp.ToString()] : null; } else { return null; } } public RState Start(params object[] objs) { _efemRobotSingleArmOption = SC.GetValue("EFEM.SingleArmOption"); _tmRobotSingleArmOption = SC.GetValue("TM.SingleArmOption"); _isCycleMode = SC.GetValue("System.IsCycleMode"); _cycleSetPoint = _isCycleMode ? SC.GetValue("System.CycleCount") : 0; _cycledWafer = 0; _cycledCount = 0; _throughput = 0; _cycleWatch.Stop(); _lpCycleWafer.Clear(); _lpCycleCount.Clear(); return RState.Running; } public RState Monitor() { prelude(); RunWaferTask(); RunModuleTasks(); RoutingATMWafers(); RoutingVacWafers(); epilogue(); return _cycleState; } public void Abort() { } public bool CreateJob(Dictionary param, out string reason) { reason = ""; _isCycleMode = SC.GetValue("System.IsCycleMode"); _cycleSetPoint = _isCycleMode ? SC.GetValue("System.CycleCount") : 0; string[] slotSequence = (string[])param["SlotSequence"]; string jobId = (string)param["JobId"]; string module = (string)param["Module"]; if (string.IsNullOrEmpty(jobId)) { jobId = "CJ_Local_" + module; } //bool autoStart = (bool)param["AutoStart"]; string lotId = jobId; if (param.ContainsKey("LotId")) lotId = (string)param["LotId"]; string preCleanRecipe = param.ContainsKey("PreCleanRecipeName") ? (string)param["PreCleanRecipeName"] : string.Empty; string postCleanRecipe = param.ContainsKey("PostCleanRecipeName") ? (string)param["PostCleanRecipeName"] : string.Empty; if (slotSequence.Length != SC.GetValue("EFEM.LoadPort.SlotNumber")) { reason = $"slot sequence parameter not valid, length is {slotSequence.Length}, should be {SC.GetValue("EFEM.LoadPort.SlotNumber")}"; LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason); _faCallback.JobCreateFailed(module, lotId, jobId, ""); return false; } if (!ModuleHelper.IsLoadPort(ModuleHelper.Converter(module))) { reason = $"{module} should be LoadPort"; LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason); _faCallback.JobCreateFailed(module, lotId, jobId, ""); return false; } if (_lstControlJobs.Exists(x => x.Name == jobId)) { reason = $"{jobId} already created"; LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason); _faCallback.JobCreateFailed(module, lotId, jobId, ""); return false; } ControlJobInfo cj = new ControlJobInfo(); cj.Name = jobId; cj.Module = module; cj.LotName = lotId; cj.LotInnerId = Guid.NewGuid(); cj.LotWafers = new List(); cj.SetState(EnumControlJobState.WaitingForStart); cj.JetState = EnumJetCtrlJobState.Created; cj.PreJobClean = preCleanRecipe; cj.PostJobClean = postCleanRecipe; cj.SequenceNameList = slotSequence; Dictionary seqSlot = new Dictionary(); Dictionary>> seqSlotWafers = new Dictionary>>(); Dictionary indexSequence = new Dictionary(); bool enableGroupBySequence = SC.GetValue("Scheduler.GroupWaferBySequence"); for (int i = 0; i < SC.GetValue("EFEM.LoadPort.SlotNumber"); i++) { if (string.IsNullOrEmpty(slotSequence[i]) || string.IsNullOrEmpty(slotSequence[i].Trim())) continue; string groupName = enableGroupBySequence ? slotSequence[i].Trim() : i.ToString(); indexSequence[groupName] = slotSequence[i]; if (!seqSlot.ContainsKey(groupName)) { seqSlot[groupName] = new bool[SC.GetValue("EFEM.LoadPort.SlotNumber")]; } if (!seqSlotWafers.ContainsKey(groupName)) { seqSlotWafers[groupName] = new List>(); } seqSlot[groupName][i] = true; if (!WaferManager.Instance.CheckHasWafer(module, i)) { LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"job wafer: {module} slot {i + 1} not in the carrier"); return false; } if (!WaferManager.Instance.CheckWafer(ModuleHelper.Converter(module), i, WaferStatus.Normal)) { reason = $"job wafer: {module} slot {i + 1} status is {WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).Status}"; LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason); _faCallback.JobCreateFailed(module, lotId, jobId, ""); return false; } if (WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).ProcessState != EnumWaferProcessStatus.Idle) { reason = $"job wafer: {module} slot {i + 1} process status is {WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).ProcessState}"; LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason); _faCallback.JobCreateFailed(module, lotId, jobId, ""); return false; } //--- 2024-03-21 增加了waferinfo 相应的lotId信息 start--- WaferInfo waferInfo = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i); cj.LotWafers.Add(waferInfo); waferInfo.SequenceName = slotSequence[i]; waferInfo.LotId = lotId; //--- 2024-03-21 增加了waferinfo 相应的lotId信息 end--- seqSlotWafers[groupName].Add(Tuple.Create(ModuleHelper.Converter(module), i)); cj.JobWaferSize = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).Size; LOG.Write(eEvent.EV_ROUTER, ModuleName.System, $"Assigned wafer job, wafer {module}.{i + 1}, sequence: {slotSequence[i]}"); } if (seqSlotWafers.Count == 0) { reason = $"job has not assign wafer"; LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason); _faCallback.JobCreateFailed(module, lotId, jobId, ""); return false; } List pjs = new List(); string[] seqs = seqSlot.Keys.ToArray(); for (int i = 0; i < seqs.Length; i++) { ProcessJobInfo pj = new ProcessJobInfo(); pj.Name = jobId + "_" + (i + 1); pj.Sequence = SequenceInfoHelper.GetInfo(indexSequence[seqs[i]]); if (pj.Sequence == null) { reason = $"invalid sequence[{indexSequence[seqs[i]]}]"; return false; } pj.ControlJobName = cj.Name; pj.LotName = lotId; pj.SlotWafers = seqSlotWafers[seqs[i]]; pj.SetState(EnumProcessJobState.Queued); if (!CheckSequencePmReady(pj.Sequence, out reason)) { LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"no valid chamber for the {reason}"); _faCallback.JobCreateFailed(module, lotId, jobId, ""); return false; } if (!RouteManager.IsATMMode && !CheckSequenceRecipeFileValid(pj.Sequence, out reason)) { LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"recipe file not valid in the sequence, {reason}"); _faCallback.JobCreateFailed(module, lotId, jobId, ""); return false; } pjs.Add(pj); } _dbCallback.LotUpdate(cj); foreach (var pj in pjs) { cj.ProcessJobNameList.Add(pj.Name); _lstProcessJobs.Add(pj); } _lstControlJobs.Add(cj); //AssociatedPMWithLP(cj); _loadportControlJobDic[cj.Module] = cj; _faCallback.JobCreated(cj, GetFirstProcessJob(cj)); return true; } public bool CheckAllJobDone() { foreach (var cj in _lstControlJobs) { if (cj.State == EnumControlJobState.Executing || cj.State == EnumControlJobState.Paused) return false; } return true; } public bool CheckJobJustDone(out string sJobName) { foreach (var cj in _lstControlJobs) { if (cj.State == EnumControlJobState.Completed && !cj.BeenPosted) { //LP;WaferSize;Lot;Number;Start;End; sJobName = $"{cj.Module};{cj.JobWaferSize};{cj.LotName};{cj.LotWafers.Count};{cj.StartTime:T};{cj.EndTime:T}"; cj.BeenPosted = true; return true; } } sJobName = "NULL"; return false; } public ProcessJobInfo GetFirstProcessJob(ControlJobInfo cj) { foreach (var pj in _lstProcessJobs) { if (pj.ControlJobName == cj.Name) return pj; } return null; } public bool AbortJob(string jobName, out string reason) { reason = ""; ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName); if (cj == null) { reason = $"abort job rejected, not found job with id {jobName}"; LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason); return false; } List pjAbortList = new List(); foreach (var pj in _lstProcessJobs) { if (pj.ControlJobName == cj.Name) { pj.SetState(EnumProcessJobState.Aborting); pjAbortList.Add(pj); int unprocessed = 0; int aborted = 0; WaferInfo[] wafers = WaferManager.Instance.GetWaferByProcessJob(pj.Name); foreach (var waferInfo in wafers) { waferInfo.ProcessJob = null; waferInfo.NextSequenceStep = 0; if (waferInfo.ProcessState != EnumWaferProcessStatus.Completed) unprocessed++; } JobDataRecorder.EndPJ(pj.InnerId.ToString(), aborted, unprocessed); } } _faCallback.JobAborted(cj, GetFirstProcessJob(cj)); _dbCallback.LotFinished(cj); foreach (var pj in pjAbortList) { _lstProcessJobs.Remove(pj); } _lstControlJobs.Remove(cj); if (_loadportControlJobDic.ContainsKey(cj.Module)) { _loadportControlJobDic[cj.Module] = null; } return true; } public bool StopJob(string jobName, out string reason) { reason = ""; ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName); if (cj == null) { reason = $"stop job rejected, not found job with id {jobName}"; LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason); return false; } foreach (var pj in _lstProcessJobs) { if (pj.ControlJobName == cj.Name) { pj.SetState(EnumProcessJobState.Stopping); } } _faCallback.JobStopped(cj, GetFirstProcessJob(cj)); _dbCallback.LotFinished(cj); if (_loadportControlJobDic.ContainsKey(cj.Module)) { _loadportControlJobDic[cj.Module] = null; } return true; } public bool ResumeJob(string jobName, out string reason) { reason = ""; ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName); if (cj == null) { reason = $"resume job rejected, not found job with id {jobName}"; //LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"resume job rejected, not found job with id {jobName}"); return false; } if (cj.State == EnumControlJobState.Paused) { cj.SetState(EnumControlJobState.Executing); } _faCallback.JobResumed(cj, GetFirstProcessJob(cj)); _cycleState = RState.Running; return true; } public bool PauseJob(string jobName, out string reason) { reason = ""; ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName); if (cj == null) { reason = $"pause job rejected, not found job with id {jobName}"; //LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"pause job rejected, not found job with id {jobName}"); return false; } if (cj.State == EnumControlJobState.Executing) { cj.SetState(EnumControlJobState.Paused); } _faCallback.JobPaused(cj, GetFirstProcessJob(cj)); if (!_lstControlJobs.Exists(job => job.State == EnumControlJobState.Executing)) _cycleState = RState.Paused; return true; } public bool StartJob(string jobName, out string reason) { reason = ""; ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName); if (cj == null) { reason = $"start job rejected, not found job with id {jobName}"; LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason); return false; } if (RtInstance.ConfigType == ConfigType.Kepler2200) { if (!CheckSequenceKepler2200TemperatureReady(GetFirstProcessJob(cj).Sequence)) { return false; } } if (cj.State == EnumControlJobState.WaitingForStart) { cj.SetState(EnumControlJobState.Executing); //PreJobClean(cj); cj.JetState = EnumJetCtrlJobState.Quequed; cj.StartTime = DateTime.Now; _dbCallback.LotCreated(cj); _faCallback.JobStarted(cj, GetFirstProcessJob(cj)); //if (!_blockingWatcher.IsRunning) // _blockingWatcher.Restart(); //ResetTraceFlag(); } if (!_cycleWatch.IsRunning) { _cycleWatch.Restart(); } if (!_lpCycleWafer.Keys.Contains(ModuleHelper.Converter(cj.Module))) { _lpCycleCount.Add(ModuleHelper.Converter(cj.Module), 0); _lpCycleWafer.Add(ModuleHelper.Converter(cj.Module), 0); } _cycleState = RState.Running; return true; } public void Clear() { foreach (var module in _dictModuleTask) { module.Value.Status = ModuleStatus.Idle; module.Value.Scheduler.ResetTask(); } List keys = _loadportControlJobDic.Keys.ToList(); foreach (var key in keys) { _loadportControlJobDic[key] = null; } _lstWaferTasks.Clear(); _tmSchdActions.Clear(); _curTmAction.Clear(); _efemSchdActions.Clear(); _curEfemAction.Clear(); _lstControlJobs.Clear(); _lstProcessJobs.Clear(); _cycleState = RState.End; } // manual return one wafer while system is auto running public bool ManualReturnWafer(object[] objs) { ModuleName SourceModule = (ModuleName)objs[0]; int SourceSlot = (int)objs[1]; if (!_dictModuleTask.Keys.Contains(SourceModule)) { LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"Invalid source module {SourceModule} for manual return wafer"); return false; } if (WaferManager.Instance.CheckNoWafer(SourceModule, SourceSlot)) { LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"Can not return wafer as {SourceModule} {SourceSlot} has no wafer"); return false; } if (!_dictModuleTask[SourceModule].Scheduler.IsIdle) { LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"The module: {SourceModule} is not ready for return wafer"); return false; } var wafer = WaferManager.Instance.GetWafer(SourceModule, SourceSlot); LOG.Write(eEvent.EV_ROUTER, ModuleName.System, $"Manual return wafer: {wafer.WaferOrigin} at {SourceModule} {SourceSlot} while system is auto running"); _qeReturnWafers.Enqueue(wafer); return true; } public RState CheckManualReturnWafer() { var pmWaferCount = _dictModuleTask.Where(mod => ModuleHelper.IsPm(mod.Key) && WaferManager.Instance.CheckHasWafer(mod.Key, 0)).Count(); var tmRobotWaferCount = (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 0) ? 1 : 0) + (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 1) ? 1 : 0); if (!_dictModuleTask[ModuleName.TMRobot].Scheduler.IsIdle && (pmWaferCount > 0 || tmRobotWaferCount > 0)) { LOG.Write(eEvent.ERR_ROUTER, ModuleName.TMRobot, $"The TM Robot is not ready for return wafer."); return RState.Failed; } if (!_dictModuleTask[ModuleName.EfemRobot].Scheduler.IsIdle) { LOG.Write(eEvent.ERR_ROUTER, ModuleName.EfemRobot, $"The EFEM Robot is not ready for return wafer."); return RState.Failed; } foreach (var mod in _dictModuleTask) { if (ModuleHelper.IsLoadPort(mod.Key)) continue; if (!mod.Value.Scheduler.IsIdle) { LOG.Write(eEvent.ERR_ROUTER, mod.Key, $"{mod.Key} is not ready for return wafer."); return RState.Failed; } int nSlotNumber = ModuleHelper.IsLoadLock(mod.Key) ? (mod.Key == ModuleName.LLA ? _LLASlotNumber : _LLBSlotNumber) : (ModuleHelper.IsTMRobot(mod.Key) || ModuleHelper.IsEFEMRobot(mod.Key) ? 2 : 1); for (int slot = 0; slot < nSlotNumber; slot++) { var wafer = WaferManager.Instance.GetWafer(mod.Key, slot); if (wafer.IsEmpty) continue; var destLP = (ModuleName)wafer.OriginStation; if (!_dictModuleTask[destLP].Scheduler.IsAvailable) { LOG.Write(eEvent.ERR_ROUTER, destLP, $"The destination Loadport {destLP} is not ready for return wafer."); return RState.Failed; } } } Clear(); return RState.Running; } public RState ReturnAllWafers() { int systemWaferCount = 0; foreach (var mod in _dictModuleTask) { if (ModuleHelper.IsLoadPort(mod.Key)) continue; int nSlotNumber = ModuleHelper.IsLoadLock(mod.Key) ? (mod.Key == ModuleName.LLA ? _LLASlotNumber : _LLBSlotNumber) : (ModuleHelper.IsTMRobot(mod.Key) || ModuleHelper.IsEFEMRobot(mod.Key) ? 2 : 1); for (int slot = 0; slot < nSlotNumber; slot++) { var wafer = WaferManager.Instance.GetWafer(mod.Key, slot); if (!wafer.IsEmpty) systemWaferCount++; } } if (systemWaferCount == 0) return RState.End; ReturnVacWafers(); ReturnAtmWafers(); return RState.Running; } #endregion #region internal implementation private void InitModules() { foreach (var module in ModuleHelper.InstalledModules) { if (ModuleHelper.IsInstalled(module)) { if(ModuleHelper.IsPm(module)) { _dictModuleTask[module] = new PMTask(module); } else if (ModuleHelper.IsLoadLock(module)) { _dictModuleTask[module] = new LoadlockTask(module); } else if(ModuleHelper.IsLoadPort(module)) { _dictModuleTask[module] = new LoadPortTask(module); } else if(ModuleHelper.IsTMRobot(module)) { _dictModuleTask[module] = new TMRobotTask(module); } else if(ModuleHelper.IsEFEMRobot(module)) { _dictModuleTask[module] = new EFEMRobotTask(module); } else if(ModuleHelper.IsAligner(module)) { _dictModuleTask[module] = new AlignerTask(module); } } } } private void prelude() { } private void epilogue() { UpdateProcessJobStatus(); UpdateControlJobStatus(); UpdateLLInOutPathProperty(); PrepareLLPressure(); CreateNewWaferTask(); _lstWaferTasks.RemoveAll(item => ModuleHelper.IsLoadPort(item.destMod) && ModuleHelper.IsLoadPort(item.currentMod) && item.pressureStatus == RState.End); } private void RunWaferTask() { foreach (var task in _lstWaferTasks) { task.Run(); } } private void RunModuleTasks() { foreach (var task in _dictModuleTask) { task.Value.Run(); } } private bool CheckAllWaferReturned(ProcessJobInfo pj, bool checkAllProcessed) { bool allWaferReturn = true; foreach (var slot in pj.SlotWafers) { var wafer = WaferManager.Instance.GetWafer(slot.Item1, slot.Item2); if(wafer.IsEmpty || (wafer.ProcessState != EnumWaferProcessStatus.Completed && checkAllProcessed)) { allWaferReturn = false; break; } } return allWaferReturn; } private void UpdateProcessJobStatus() { if (_efemRobotStatus == RState.Running || _tmRobotStatus == RState.Running) return; foreach (var pj in _lstProcessJobs) { if (CheckAllWaferReturned(pj, pj.State != EnumProcessJobState.Stopping)) { pj.SetState(EnumProcessJobState.ProcessingComplete); JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0); } } } private void UpdateControlJobStatus() { if (_lstControlJobs.Count == 0 || _efemRobotStatus == RState.Running || _tmRobotStatus == RState.Running) return; bool allControlJobComplete = true; List cjRemoveList = new List(); foreach (var cj in _lstControlJobs) { if (cj.JetState == EnumJetCtrlJobState.Quequed) // active quequed control job: need prejob clean or don need prejob clean { var runingJobs = _lstControlJobs.FindAll(job => IsCtrlJobRuning(job)); if (runingJobs.Count == 0 || (runingJobs.Count == 1 && IsCtrlJobEndingState(runingJobs.First()))) { var quequedJobs = _lstControlJobs.FindAll(job => job.JetState == EnumJetCtrlJobState.Quequed); var firstQuequeJob = quequedJobs.OrderBy(job => job.StartTime).First(); if (firstQuequeJob.InnerId == cj.InnerId) { if (IsCtrlJobNeedPreClean(cj)) { cj.JetState = EnumJetCtrlJobState.PreJobClean; var PMs = GetWaitPreCleanPMsByCtrlJob(cj); foreach (var pm in PMs) { var pmTask = _dictModuleTask[pm] as PMTask; if(pmTask != null && pmTask.Scheduler.IsOnline) { pmTask.InvokePreJobClean(cj.PreJobClean); } } } else { ActiveControlJob(cj); } } } } else if (IsCtrlJobRuning(cj)) { if (cj.JetState == EnumJetCtrlJobState.PreJobClean) { if (IsPreJobCleanDone(cj)) { ActiveControlJob(cj); } } else { if (cj.JetState == EnumJetCtrlJobState.Processing && IsCtrlJobNeedPostClean(cj)) // active post job clean { if (IsAllJobWaferProcessedOrProcessing(cj)) { cj.JetState = EnumJetCtrlJobState.PostJobClean; var PMs = GetWaitPreCleanPMsByCtrlJob(cj); foreach (var pm in PMs) { var pmTask = _dictModuleTask[pm] as PMTask; if (pmTask != null && pmTask.Scheduler.IsOnline) { pmTask.InvokePostJobClean(cj.PostJobClean); } } } } // control job complete if (IsAllProcessJobComplete(cj) && (!IsCtrlJobNeedPostClean(cj) || cj.JetState == EnumJetCtrlJobState.PostJobClean && IsPostJobCleanDone(cj))) { cj.JetState = EnumJetCtrlJobState.Completed; cj.SetState(EnumControlJobState.Completed); cj.EndTime = DateTime.Now; _faCallback.JobFinished(cj, GetFirstProcessJob(cj)); _dbCallback.LotFinished(cj); if (!(_isCycleMode && _cycledCount < _cycleSetPoint)) (Singleton.Instance.GetScheduler(ModuleHelper.Converter(cj.Module)) as SchedulerLoadPort).NoteJobComplete(); _lpCycleCount[ModuleHelper.Converter(cj.Module)]++; } } int countProcessed = 0; foreach (var pjName in cj.ProcessJobNameList) { var pj = _lstProcessJobs.Find(x => x.Name == pjName); if (pj == null) { LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Not find pj named {pjName} in {cj.Name}"); continue; } // caculate process wafer by process if (_isCycleMode && _cycledCount < (_isCycleMode ? _cycleSetPoint : 0)) { foreach (var pjSlotWafer in pj.SlotWafers) { WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2); if (!wafer.IsEmpty && wafer.ProcessState == EnumWaferProcessStatus.Completed) countProcessed++; } } } int lpCycleWafer = _lpCycleCount[ModuleHelper.Converter(cj.Module)] * cj.LotWafers.Count + (cj.JetState == EnumJetCtrlJobState.Completed && cj.LotWafers.Count == countProcessed ? 0 : countProcessed); if (_lpCycleCount[ModuleHelper.Converter(cj.Module)] != _cycledCount || lpCycleWafer != _lpCycleWafer[ModuleHelper.Converter(cj.Module)]) { _lpCycleWafer[ModuleHelper.Converter(cj.Module)] = lpCycleWafer; } } LoadportCassetteState state = (LoadportCassetteState)DATA.Poll($"{cj.Module}.CassetteState"); if (cj.State == EnumControlJobState.Completed && state != LoadportCassetteState.Normal && cj.JetState == EnumJetCtrlJobState.Completed) { cjRemoveList.Add(cj); } allControlJobComplete = allControlJobComplete && cj.State == EnumControlJobState.Completed; } if (_isCycleMode && _cycledCount < (_isCycleMode ? _cycleSetPoint : 0)) { int totolCycleWafer = _lpCycleWafer.Sum(item => item.Value); if (totolCycleWafer != _cycledWafer || _lpCycleCount.Sum(item => item.Value) > 0 && _throughput < 0.01) // refresh _throughput in time { _cycledWafer = totolCycleWafer; if (_cycledCount > 0 || allControlJobComplete) { _throughput = (float)(_cycledWafer / _cycleWatch.Elapsed.TotalHours); } else { _throughput = 0; } } if (allControlJobComplete) { _cycledCount++; LOG.Write(eEvent.EV_ROUTER, ModuleName.System, $"Cycle Count: {_cycledCount}, Total Processed Wafer: {_cycledWafer}, Throughput: {_throughput}"); if (_cycledCount < _cycleSetPoint) { foreach (var cj in _lstControlJobs) { cj.SetState(EnumControlJobState.Executing); cj.JetState = EnumJetCtrlJobState.Quequed; cj.LotInnerId = Guid.NewGuid(); _dbCallback.LotCreated(cj); } foreach (var pj in _lstProcessJobs) { pj.SetState(EnumProcessJobState.Queued); pj.InnerId = Guid.NewGuid(); foreach (var pjSlotWafer in pj.SlotWafers) { WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2); wafer.ProcessJob = null; wafer.NextSequenceStep = 0; wafer.ProcessState = EnumWaferProcessStatus.Idle; } } _lstWaferTasks.Clear(); } else _cycleState = RState.End; } } foreach (var cj in cjRemoveList) { List pjRemoveList = new List(); foreach (var pj in _lstProcessJobs) { if (pj.ControlJobName == cj.Name) pjRemoveList.Add(pj); } foreach (var pj in pjRemoveList) { _lstProcessJobs.Remove(pj); } _lstControlJobs.Remove(cj); } } private bool ActiveProcessJob(ProcessJobInfo pj) { foreach (var pjSlotWafer in pj.SlotWafers) { WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2); wafer.ProcessJob = pj; wafer.NextSequenceStep = 0; WaferDataRecorder.SetPjInfo(wafer.InnerId.ToString(), pj.InnerId.ToString()); } ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == pj.ControlJobName); CarrierInfo carrier = CarrierManager.Instance.GetCarrier(cj.Module); JobDataRecorder.StartPJ(pj.InnerId.ToString(), carrier.InnerId.ToString(), cj.InnerId.ToString(), pj.Name, cj.Module, cj.Module, pj.SlotWafers.Count); pj.SetState(EnumProcessJobState.Processing); return true; } private bool ActiveControlJob(ControlJobInfo cj) { cj.JetState = EnumJetCtrlJobState.Processing; foreach (var pjName in cj.ProcessJobNameList) { var pj = _lstProcessJobs.Find(x => x.Name == pjName); if (pj == null) { LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Not find pj named {pjName} in {cj.Name}"); continue; } if (pj.State == EnumProcessJobState.Queued) { ActiveProcessJob(pj); } } return true; } private bool IsAllJobWaferProcessedOrProcessing(ControlJobInfo cj) { List allModules = _dictModuleTask.Keys.ToList(); int original = (int)ModuleHelper.Converter(cj.Module); foreach (var mod in allModules) { if (ModuleHelper.IsLoadPort(mod) && (int)mod != original) continue; var wafers = WaferManager.Instance.GetWafers(mod); foreach (var wafer in wafers) { if (wafer.IsEmpty || wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null || wafer.ProcessJob.ControlJobName != cj.Name) continue; if (wafer.ProcessState != EnumWaferProcessStatus.Completed && wafer.ProcessState != EnumWaferProcessStatus.InProcess) return false; ; } } return true; } private bool IsAllProcessJobComplete(ControlJobInfo cj) { foreach (var pj in _lstProcessJobs) { if (pj.ControlJobName == cj.Name && pj.State != EnumProcessJobState.ProcessingComplete) { return false; } } return true; } private bool IsCtrlJobRuning(ControlJobInfo cj) { return cj.JetState == EnumJetCtrlJobState.PreJobClean || cj.JetState == EnumJetCtrlJobState.Processing || cj.JetState == EnumJetCtrlJobState.PostJobClean; } private bool IsCtrlJobEndingState(ControlJobInfo cj) { return cj.JetState == EnumJetCtrlJobState.PostJobClean || (cj.JetState == EnumJetCtrlJobState.Processing && IsAllJobWaferProcessedOrProcessing(cj) && !IsCtrlJobNeedPostClean(cj)); } private bool IsCtrlJobNeedPreClean(ControlJobInfo cj) { return !string.IsNullOrWhiteSpace(cj.PreJobClean); } private bool IsCtrlJobNeedPostClean(ControlJobInfo cj) { return !string.IsNullOrWhiteSpace(cj.PostJobClean.Trim()); } private List GetWaitPreCleanPMsByCtrlJob(ControlJobInfo cj) { var pmlist = new List(); foreach (var pj in _lstProcessJobs) { if (pj.ControlJobName == cj.Name) { foreach (var pm in pj.Sequence.PMs) { if (!pmlist.Contains(pm)) pmlist.Add(pm); } } } return pmlist; } private bool IsPreJobCleanDone(ControlJobInfo cj) { var pms = GetWaitPreCleanPMsByCtrlJob(cj); foreach(var pm in pms) { var pmTask = _dictModuleTask[pm] as PMTask; if (pmTask.Scheduler.IsOnline && !pmTask.IsPreJobCleanDone()) return false; } return true; } private bool IsPostJobCleanDone(ControlJobInfo cj) { var pms = GetWaitPreCleanPMsByCtrlJob(cj); foreach (var pm in pms) { var pmTask = _dictModuleTask[pm] as PMTask; if (pmTask.Scheduler.IsOnline && !pmTask.IsPostJobCleanDone()) return false; } return true; } private void WaferArrived(WaferTask wafer, MoveItem item) { _dictModuleTask[item.DestinationModule].WaferArrived(wafer, item.DestinationSlot); //--2024-03-21 增加了PortJobWaferEnd 上报事件 start-- if (ModuleHelper.IsLoadPort(item.DestinationModule)) { ControlJobInfo currentControlJob = GetLoadPortCurrentControlJob(item.DestinationModule); if (currentControlJob != null) { _faCallback.JobWaferEnd(currentControlJob, item.SourceSlot); } } //--2024-03-21 增加了PortJobWaferEnd 上报事件 end-- } private void WaferLeaved(WaferTask wafer, MoveItem item) { _dictModuleTask[item.SourceModule].WaferLeaved(wafer, item.DestinationSlot); //--2024-03-21 增加了PortJobWaferStart 上报事件 start-- if (ModuleHelper.IsLoadPort(item.SourceModule)) { ControlJobInfo currentControlJob = GetLoadPortCurrentControlJob(item.SourceModule); if (currentControlJob != null) { _faCallback.JobWaferStart(currentControlJob, item.SourceSlot); } } //--2024-03-21 增加了PortJobWaferStart 上报事件 end-- } private ModuleName GetComingAvailablePM(ControlJobInfo cj) { var lstInProcessPMs = new List(); foreach (var wafer in cj.LotWafers) { if(!wafer.IsEmpty && wafer.NextSequenceStep == 0 && wafer.ProcessJob != null) { foreach(var pm in wafer.ProcessJob.Sequence.PMs) { if (!lstInProcessPMs.Contains(pm)) lstInProcessPMs.Add(pm); } } } Dictionary pmAssociatedWaferCount = new Dictionary(); foreach (var mod in _dictModuleTask) { if (ModuleHelper.IsPm(mod.Key) && mod.Value.Scheduler.IsOnline && lstInProcessPMs.Contains(mod.Key)) { pmAssociatedWaferCount[mod.Key] = 0; } } var unprocessedWafer = _lstWaferTasks.Where(task => ModuleHelper.IsPm(task.destMod)); foreach (var wafer in unprocessedWafer) { if (ModuleHelper.IsPm(wafer.destMod) && _dictModuleTask[wafer.destMod].Scheduler.IsOnline && lstInProcessPMs.Contains(wafer.destMod)) { pmAssociatedWaferCount[wafer.destMod]++; } } var oderedPMCount = pmAssociatedWaferCount.OrderBy(p => p.Value).ToDictionary(p => p.Key, o => o.Value); if (oderedPMCount.Count > 0 && oderedPMCount.First().Value < 2) return oderedPMCount.First().Key; return ModuleName.System; } private void CreateNewWaferTask() { var cj = _lstControlJobs.Find(c => c.JetState == EnumJetCtrlJobState.PreJobClean || c.JetState == EnumJetCtrlJobState.Processing); if (cj != null) { var pm = GetComingAvailablePM(cj); if (pm != ModuleName.System) { foreach (var wafer in cj.LotWafers) { if (wafer.IsEmpty || wafer.ProcessJob == null) continue; if (wafer.ProcessJob.Sequence.PMs.Contains(pm) && wafer.NextSequenceStep == 0 && !_lstWaferTasks.Exists(task => task.sourceMod == (ModuleName)wafer.OriginStation && task.sourceSlot == wafer.OriginSlot)) { CreateWaferTasks(wafer, pm, wafer.ProcessJob.Sequence.LLDelayTime); return; } } } } } private void CreateWaferTasks(WaferInfo wafer, ModuleName pm, int LLDeayTime) { var recipeName = wafer.ProcessJob.Sequence.GetRecipe(pm); var recipeContent = RecipeFileManager.Instance.LoadRecipe(pm.ToString(), recipeName, false, RecipeType.Process.ToString()); Recipe recipe = Recipe.Load(recipeContent); int temperature = 0; if(int.TryParse(recipe.Header.Temperature, out int temp)) { temperature = temp; } var waferTask = new WaferTask((ModuleName)wafer.OriginStation, wafer.OriginSlot, pm, temperature, (float)Convert.ToDouble(recipe.Header.Temperature), wafer.InnerId, recipeName, wafer.ProcessJob.Sequence.WTWCleanRecipe, wafer.ProcessJob.Sequence.LLInOutPath, LLDeayTime); waferTask.OnWaferArrived += WaferArrived; waferTask.OnWaferLeaved += WaferLeaved; _lstWaferTasks.Add(waferTask); } private bool ForwardATMWafers(ModuleName ll) { var waferStaus = GetLLReadyInOutSlots(ll); var atmWafers = _lstWaferTasks.Where(wafer => (wafer.movingStatus == RState.End ||wafer.movingStatus == RState.Init) && (ModuleHelper.IsEFEMRobot(wafer.currentMod) || ModuleHelper.IsAligner(wafer.currentMod))).ToList(); var notAlignedWafer = atmWafers.Where(wafer => !wafer.IsAligned).ToList(); var readyInWafers = _lstWaferTasks.Where(wafer => ModuleHelper.IsLoadPort(wafer.currentMod) && wafer.movingStatus == RState.Init && wafer.pressureStatus == RState.Init).OrderBy(wafer => wafer.currentSlot).ToArray(); var freeHands = GetEFEMFreeHand(); if ((atmWafers.Count >= 2 && atmWafers.Count(wafer => !wafer.IsAligned) == 0) || freeHands.Count == 0 || readyInWafers.Length == 0) return false; // force all wafer aligned if (notAlignedWafer.Count > 0 && _lstWaferTasks.Count(wafer => ModuleHelper.IsAligner(wafer.currentMod)) == 0) { notAlignedWafer.First().RouteTo(ModuleName.Aligner1, 0); _efemSchdActions.Enqueue(new List { new MoveItem(notAlignedWafer.First().currentMod, notAlignedWafer.First().currentSlot, ModuleName.Aligner1, 0, (Hand)notAlignedWafer.First().currentSlot) }); } // forward one wafer else if ((readyInWafers.Length > 0) && (atmWafers.Count == 0 || (atmWafers.Count == 1 && _lstWaferTasks.Count(wafer => ModuleHelper.IsAligner(wafer.currentMod)) == 0 && waferStaus.emptySlot.Count >= 2))) { readyInWafers[0].RouteTo(ModuleName.Aligner1, 0); // pick from LP _efemSchdActions.Enqueue(new List { new MoveItem(readyInWafers[0].currentMod, readyInWafers[0].currentSlot, ModuleName.EfemRobot, (int)freeHands[0], freeHands[0]) }); // place to aligner _efemSchdActions.Enqueue(new List { new MoveItem(ModuleName.EfemRobot, (int)freeHands[0], ModuleName.Aligner1, 0, freeHands[0]) }); } // forward aligner wafer else if (atmWafers.Count == 1 && waferStaus.emptySlot.Count >= 2 && ModuleHelper.IsAligner(atmWafers.First().currentMod) && freeHands.Count > 1) { atmWafers.First().RouteTo(ModuleName.EfemRobot, (int)freeHands[1]); _efemSchdActions.Enqueue(new List { new MoveItem(atmWafers.First().currentMod, atmWafers.First().currentSlot, ModuleName.EfemRobot, (int)freeHands[1], freeHands[1]) }); } return _efemSchdActions.Count > 0; } private bool ExchangeWaferWithLL(ModuleName ll) { if (IsLLReservedByTM(ll)) return false; var waferStaus = GetLLReadyInOutSlots(ll); var atmWafers = _lstWaferTasks.Where(wafer => (wafer.movingStatus == RState.End || wafer.movingStatus == RState.Init) && wafer.IsAligned && (ModuleHelper.IsEFEMRobot(wafer.currentMod) || ModuleHelper.IsAligner(wafer.currentMod))).ToList(); var freeHands = GetEFEMFreeHand(); var swapActions = new List(); var validHands = new List(); int placeCount = 0; if ( waferStaus.emptySlot.Count > 0 && freeHands.Count >= 1 && atmWafers.Count(wafer => ModuleHelper.IsAligner(wafer.currentMod)) == 1 && (atmWafers.Count(wafer => ModuleHelper.IsEFEMRobot(wafer.currentMod)) == 0 || waferStaus.emptySlot.Count >= 2)) { var alignerWafer = atmWafers.Where(wafer => ModuleHelper.IsAligner(wafer.currentMod)).First(); if(CanWaferGotoLL(alignerWafer, ll)) { alignerWafer.RouteTo(ll, waferStaus.emptySlot[placeCount]); _efemSchdActions.Enqueue(new List { new MoveItem(alignerWafer.currentMod, alignerWafer.currentSlot, ModuleName.EfemRobot, (int)freeHands[0], freeHands[0]) }); swapActions.Add(new MoveItem(ModuleName.EfemRobot, (int)freeHands[0], ll, waferStaus.emptySlot[placeCount], freeHands[0])); validHands.Add(freeHands[0]); placeCount++; } } var armWafers = atmWafers.Where(wafer => ModuleHelper.IsEFEMRobot(wafer.currentMod)).ToArray(); foreach(var wafer in armWafers) { if(CanWaferGotoLL(wafer, ll) && placeCount < waferStaus.emptySlot.Count) { wafer.RouteTo(ll, waferStaus.emptySlot[placeCount]); swapActions.Add(new MoveItem(wafer.currentMod, wafer.currentSlot, ll, waferStaus.emptySlot[placeCount], (Hand)wafer.currentSlot)); if(!validHands.Contains((Hand)wafer.currentSlot)) validHands.Add((Hand)wafer.currentSlot); placeCount++; } } if (!validHands.Contains(Hand.Blade1) && WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, (int)Hand.Blade1) && _efemRobotSingleArmOption != 2) validHands.Add(Hand.Blade1); if (!validHands.Contains(Hand.Blade2) && WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, (int)Hand.Blade2) && _efemRobotSingleArmOption != 1) validHands.Add(Hand.Blade2); int pickCount = 0; var returnActions = new List(); foreach(var slot in waferStaus.outSlot) { if(pickCount < validHands.Count) { var outWafer = _lstWaferTasks.Find(wafer => (wafer.movingStatus == RState.End || wafer.movingStatus == RState.Init) && wafer.currentMod == ll && wafer.currentSlot == slot); if(outWafer != null) { outWafer.RouteTo(outWafer.destMod, outWafer.destSlot); swapActions.Add(new MoveItem(ll, waferStaus.outSlot[pickCount], ModuleName.EfemRobot, (int)validHands[pickCount], validHands[pickCount])); returnActions.Add(new MoveItem(ModuleName.EfemRobot, (int)validHands[pickCount], outWafer.destMod, outWafer.destSlot, validHands[pickCount])); pickCount++; } } } if(swapActions.Count > 0) { _efemSchdActions.Enqueue(swapActions); } foreach(var action in returnActions) { _efemSchdActions.Enqueue(new List { action }); } return _efemSchdActions.Count > 0; } private void RoutingATMWafers() { if (_efemSchdActions.Count > 0 || _curEfemAction.Count > 0) { RunSchdEFEMActions(); return; } if (_efemRobotStatus != RState.End) return; if(_LLASlotNumber == 2) { Routing2SlotATMSystem(); } else if(_LLASlotNumber == 4) { Routing4SlotATMSystem(); } } private void Routing4SlotATMSystem() { var atmWaferCount = _lstWaferTasks.Where(wafer => ModuleHelper.IsEFEMRobot(wafer.currentMod) || ModuleHelper.IsAligner(wafer.currentMod)).Count(); var efemRobotWafers = _lstWaferTasks.Where(wafer => ModuleHelper.IsEFEMRobot(wafer.currentMod)).ToList(); if (LLInOutPath == SequenceLLInOutPath.AInBOut || LLInOutPath == SequenceLLInOutPath.BInAOut) // don need check system wafer existence as no blocking risk { var inLL = LLInOutPath == SequenceLLInOutPath.AInBOut ? ModuleName.LLA : ModuleName.LLB; var outLL = LLInOutPath == SequenceLLInOutPath.AInBOut ? ModuleName.LLB : ModuleName.LLA; var inLLWaferStatus = GetLLReadyInOutSlots(inLL); var outLLWaferStatus = GetLLReadyInOutSlots(outLL); if (efemRobotWafers.Count() >= 1) { if (inLLWaferStatus.emptySlot.Count >= 2 && !IsLLReservedByTM(inLL)) // wait for in loadlock ready { if (_dictModuleTask[inLL].TimeToReady < 2) { ExchangeWaferWithLL(inLL); } } if ((inLLWaferStatus.emptySlot.Count == 0 || (outLLWaferStatus.outSlot.Count >= 1 && _dictModuleTask[outLL].TimeToReady < 2)) && !IsLLReservedByTM(outLL)) // ready return wafer { ExchangeWaferWithLL(outLL); } } else { if (((outLLWaferStatus.outSlot.Count >= 2 && _dictModuleTask[outLL].TimeToReady < 10) || (outLLWaferStatus.outSlot.Count == 1 && _dictModuleTask[outLL].TimeToReady < 2)) && !IsLLReservedByTM(outLL)) { ExchangeWaferWithLL(outLL); } else if (inLLWaferStatus.emptySlot.Count >= 2) { if (((_dictModuleTask[inLL].TimeToReady > 20 || _dictModuleTask[inLL].Scheduler.IsVac) && atmWaferCount < 2) || atmWaferCount == 0) { ForwardATMWafers(inLL); } else if (atmWaferCount >= 2 && !IsLLReservedByTM(inLL)) { ExchangeWaferWithLL(inLL); } } } } else { RoutingSameLLInOutATMSystem(); } } private void Routing2SlotATMSystem() { var atmWaferCount = _lstWaferTasks.Where(wafer => ModuleHelper.IsEFEMRobot(wafer.currentMod) || ModuleHelper.IsAligner(wafer.currentMod)).Count(); var efemRobotWafers = _lstWaferTasks.Where(wafer => ModuleHelper.IsEFEMRobot(wafer.currentMod)).ToList(); if (LLInOutPath == SequenceLLInOutPath.AInBOut || LLInOutPath == SequenceLLInOutPath.BInAOut) // don need check system wafer existence as no blocking risk { var inLL = LLInOutPath == SequenceLLInOutPath.AInBOut ? ModuleName.LLA : ModuleName.LLB; var outLL = LLInOutPath == SequenceLLInOutPath.AInBOut ? ModuleName.LLB : ModuleName.LLA; var inLLWaferStatus = GetLLReadyInOutSlots(inLL); var outLLWaferStatus = GetLLReadyInOutSlots(outLL); // whether can do double return in 5 second, single return with single arm option or LL under atm pressure if ((outLLWaferStatus.outSlot.Count == 2 && _dictModuleTask[outLL].TimeToReady < 5 && (atmWaferCount < 2 || !_dictModuleTask[outLL].Scheduler.IsAtm)) || (outLLWaferStatus.outSlot.Count == 1 && ((_dictModuleTask[outLL].TimeToReady < 2 && _dictModuleTask[outLL].Scheduler.IsAtm) || _efemRobotSingleArmOption != 0 || _lstWaferTasks.Where(wt => ModuleHelper.IsLoadPort(wt.destMod)).Count() == 1))) { if (ExchangeWaferWithLL(outLL)) return; } if(atmWaferCount == 0 || (atmWaferCount == 1 && inLLWaferStatus.emptySlot.Count == 2 && _efemRobotSingleArmOption == 0 && (outLLWaferStatus.outSlot.Count < 2 || _dictModuleTask[outLL].TimeToReady > 20))) { if (ForwardATMWafers(inLL)) return; } if((inLLWaferStatus.emptySlot.Count == 2 || (inLLWaferStatus.emptySlot.Count == 1 && _efemRobotSingleArmOption != 0) && _dictModuleTask[inLL].TimeToReady < 2)) { ExchangeWaferWithLL(inLL); } } else { RoutingSameLLInOutATMSystem(); } } private void RoutingSameLLInOutATMSystem() { var atmWaferCount = _lstWaferTasks.Where(wafer => ModuleHelper.IsEFEMRobot(wafer.currentMod) || ModuleHelper.IsAligner(wafer.currentMod)).Count(); var vacWaferCount = _lstWaferTasks.Where(task => ModuleHelper.IsPm(task.currentMod) || ModuleHelper.IsTMRobot(task.currentMod) || ModuleHelper.IsLoadLock(task.currentMod)).Count(); var preferWaferVacCount = _dictModuleTask.Where(mod => ModuleHelper.IsPm(mod.Key) && mod.Value.Scheduler.IsOnline).Count() + (LLInOutPath == SequenceLLInOutPath.AInAOut ? _LLASlotNumber / 2 : (LLInOutPath == SequenceLLInOutPath.BInBOut ? _LLBSlotNumber / 2 : _LLASlotNumber)); var inOutIndicator = vacWaferCount - preferWaferVacCount; if (inOutIndicator < 0) { // ready to push in var readyLLs = _dictModuleTask.Where(mod => ModuleHelper.IsLoadLock(mod.Key) && ((mod.Key == ModuleName.LLA && LLInOutPath != SequenceLLInOutPath.BInBOut) || (mod.Key == ModuleName.LLB && LLInOutPath != SequenceLLInOutPath.AInAOut)) && mod.Value.TimeToReady <= 10 && !IsLLReservedByTM(mod.Key) && GetLLReadyInOutSlots(mod.Key).emptySlot.Count >= 1). OrderBy(mod => mod.Value.TimeToReady).ToList(); if (atmWaferCount >= 1) { foreach(var ll in readyLLs) { if (ExchangeWaferWithLL(ll.Key)) return; } } // forward wafer to system if (atmWaferCount < 2) { var targetLL = readyLLs.Count > 0 ? readyLLs.First().Key : (LLInOutPath == SequenceLLInOutPath.BInBOut ? ModuleName.LLB : ModuleName.LLA); ForwardATMWafers(targetLL); } if (_efemSchdActions.Count == 0) { var readyReturnLL = _dictModuleTask.Where(mod => ModuleHelper.IsLoadLock(mod.Key) && ((mod.Key == ModuleName.LLA && LLInOutPath != SequenceLLInOutPath.BInBOut) || (mod.Key == ModuleName.LLB && LLInOutPath != SequenceLLInOutPath.AInAOut)) && mod.Value.TimeToReady <= 5 && !IsLLReservedByTM(mod.Key) && GetLLReadyInOutSlots(mod.Key).outSlot.Count >= 1). OrderByDescending(mod => GetLLReadyInOutSlots(mod.Key).outSlot.Count).ToList(); foreach(var ll in readyReturnLL) { if (ExchangeWaferWithLL(readyReturnLL.First().Key)) return; } } } else { // ready double return LL var readyDoubleReturnLL = _dictModuleTask.Where(mod => ModuleHelper.IsLoadLock(mod.Key) && mod.Value.TimeToReady < 10 && !IsLLReservedByTM(mod.Key) && GetLLReadyInOutSlots(mod.Key).outSlot.Count > 1). OrderBy(mod => mod.Value.TimeToReady).ToList(); foreach(var ll in readyDoubleReturnLL) { if (ExchangeWaferWithLL(ll.Key)) return; } // ready single return LL var readySingleReturnLL = _dictModuleTask.Where(mod => ModuleHelper.IsLoadLock(mod.Key) && mod.Value.TimeToReady < 2 && !IsLLReservedByTM(mod.Key) && GetLLReadyInOutSlots(mod.Key).outSlot.Count == 1). OrderBy(mod => mod.Value.TimeToReady).ToList(); foreach (var ll in readySingleReturnLL) { if (ExchangeWaferWithLL(ll.Key)) return; } if (atmWaferCount == 0) { // ready to push in var readyLLs = _dictModuleTask.Where(mod => ModuleHelper.IsLoadLock(mod.Key) && ((mod.Key != ModuleName.LLA && LLInOutPath == SequenceLLInOutPath.BInBOut) || (mod.Key != ModuleName.LLB && LLInOutPath == SequenceLLInOutPath.AInAOut)) && mod.Value.TimeToReady <= 10 && !IsLLReservedByTM(mod.Key) && GetLLReadyInOutSlots(mod.Key).emptySlot.Count > 1). OrderBy(mod => mod.Value.TimeToReady).ToList(); foreach(var ll in readyLLs) { if (ForwardATMWafers(ll.Key)) return; } } } } private bool isReturnActionsDone(List items) { foreach(var item in items) { if (WaferManager.Instance.CheckHasWafer(item.SourceModule, item.SourceSlot) || WaferManager.Instance.CheckNoWafer(item.DestinationModule, item.DestinationSlot)) return false; } return true; } private bool IsMovingActionsDone(List actions) { foreach(var ac in actions) { var task = _lstWaferTasks.Find(wafer => (wafer.currentMod == ac.SourceModule && wafer.currentSlot == ac.SourceSlot) || (wafer.currentMod == ac.DestinationModule && wafer.currentSlot == ac.DestinationSlot)); if (task != null && task.movingStatus == RState.Running) return false; ; } return true; } private bool IsLLReservedByTM(ModuleName ll) { foreach(var item in _curTmAction) { if (item.DestinationModule == ll || item.SourceModule == ll) return true; } foreach(var action in _tmSchdActions) { foreach(var item in action) { if (item.DestinationModule == ll || item.SourceModule == ll) return true; } } return false; } private bool IsLLReservedByEFEM(ModuleName ll) { foreach (var item in _curEfemAction) { if (item.DestinationModule == ll || item.SourceModule == ll) return true; } foreach (var action in _efemSchdActions) { foreach (var item in action) { if (item.DestinationModule == ll || item.SourceModule == ll) return true; } } return false; } private void RunSchdEFEMActions() { var efemRobot = Singleton.Instance.GetScheduler(ModuleName.EfemRobot) as SchedulerEfemRobot; if (efemRobot == null || !efemRobot.IsAvailable) return; if (_dictModuleTask[ModuleName.EfemRobot].IsIdle) { if(_efemSchdActions.Count > 0 ) { if(_curEfemAction.Count == 0 || IsMovingActionsDone(_curEfemAction)) { var nextActions = _efemSchdActions.First(); if (nextActions.Exists(action => !_lstWaferTasks.Exists(wafer => (wafer.movingStatus == RState.End || wafer.movingStatus == RState.Init) && wafer.currentMod == action.SourceModule && wafer.currentSlot == action.SourceSlot))) return; var nextModule = nextActions.First().Module; if (ModuleHelper.IsLoadLock(nextModule) && !_dictModuleTask[nextModule].IsIdle) return; _curEfemAction = _efemSchdActions.Dequeue(); foreach (var action in _curEfemAction) { var waferTask = _lstWaferTasks.Find(wafer => (wafer.movingStatus == RState.End || wafer.movingStatus == RState.Init) && wafer.currentMod == action.SourceModule && wafer.currentSlot == action.SourceSlot); waferTask.MoveTo(action.DestinationModule, action.DestinationSlot); } (_dictModuleTask[ModuleName.EfemRobot].Scheduler as SchedulerEfemRobot).PostMoveItems(_curEfemAction.ToArray()); } } else if(_curEfemAction.Count >= 0 && IsMovingActionsDone(_curEfemAction)) // all scheduled actions done { _curEfemAction.Clear(); } } } private void RunSchdTMActions() { if (_dictModuleTask[ModuleName.TMRobot].IsIdle) { if (_tmSchdActions.Count > 0) { if (_curTmAction.Count == 0 || IsMovingActionsDone(_curTmAction)) { var nextActions = _tmSchdActions.First(); if (nextActions.Exists(action => !_lstWaferTasks.Exists(wafer => (wafer.movingStatus == RState.End || wafer.movingStatus == RState.Init) && wafer.currentMod == action.SourceModule && wafer.currentSlot == action.SourceSlot))) return; if (ModuleHelper.IsPm(nextActions.First().Module) && !_dictModuleTask[nextActions.First().Module].IsIdle) /// wait PMTask status update to idle return; _curTmAction = _tmSchdActions.Dequeue(); foreach(var action in _curTmAction) { var waferTask = _lstWaferTasks.Find(wafer => (wafer.movingStatus == RState.End || wafer.movingStatus == RState.Init) && wafer.currentMod == action.SourceModule && wafer.currentSlot == action.SourceSlot); waferTask.MoveTo(action.DestinationModule, action.DestinationSlot); } (_dictModuleTask[ModuleName.TMRobot].Scheduler as SchedulerTMRobot).SendMoveItems(_curTmAction.ToArray()); } } else if (_curTmAction.Count >= 0 && IsMovingActionsDone(_curTmAction)) // all scheduled actions done { _curTmAction.Clear(); } } } private int TimeForNextModuleReady(WaferTask task) { if (ModuleHelper.IsPm(task.destMod) && (ModuleHelper.IsLoadLock(task.currentMod) || ModuleHelper.IsTMRobot(task.currentMod))) return _dictModuleTask[task.destMod].TimeToReady; var llbWaferStatus = GetLLReadyInOutSlots(ModuleName.LLB); var llaWaferStatus = GetLLReadyInOutSlots(ModuleName.LLA); if (ModuleHelper.IsLoadPort(task.destMod) && (ModuleHelper.IsPm(task.currentMod) || ModuleHelper.IsTMRobot(task.currentMod))) { if (task.llInOutPath == SequenceLLInOutPath.AInBOut || task.llInOutPath == SequenceLLInOutPath.BInBOut) { if(llbWaferStatus.emptySlot.Count > 0) { return _dictModuleTask[ModuleName.LLB].TimeToReady; } } else if(task.llInOutPath == SequenceLLInOutPath.BInAOut || task.llInOutPath == SequenceLLInOutPath.AInAOut) { if(llaWaferStatus.emptySlot.Count > 0) { return _dictModuleTask[ModuleName.LLA].TimeToReady; } } else if(task.llInOutPath == SequenceLLInOutPath.DInDOut) { if(llaWaferStatus.emptySlot.Count > 0 && llbWaferStatus.emptySlot.Count > 0) { if (_dictModuleTask[ModuleName.LLA].TimeToReady == _dictModuleTask[ModuleName.LLB].TimeToReady) { return _dictModuleTask[ModuleName.LLA].TimeToReady; } else { return Math.Min(_dictModuleTask[ModuleName.LLA].TimeToReady, _dictModuleTask[ModuleName.LLB].TimeToReady); } } else if(llaWaferStatus.emptySlot.Count > 0) { return _dictModuleTask[ModuleName.LLA].TimeToReady; } else if(llbWaferStatus.emptySlot.Count > 0) { return _dictModuleTask[ModuleName.LLB].TimeToReady; } } } else if(ModuleHelper.IsPm(task.destMod) && (ModuleHelper.IsLoadLock(task.currentMod) || ModuleHelper.IsTMRobot(task.currentMod))) { if(_lstWaferTasks.Find(wafer => wafer.currentMod == task.destMod || wafer.routedMod == task.destMod) == null) { return _dictModuleTask[task.destMod].TimeToReady; } } return int.MaxValue; } List GetTMValidFreeHands(List robotWafers, List swapActions) { var hands = new List(); for(int i = 0; i < 2; i++) { if(_tmRobotSingleArmOption == 0 || _tmRobotSingleArmOption == i + 1) { if ((!robotWafers.Exists(wafer => wafer.currentSlot == i) || ( robotWafers.Exists(wafer => wafer.currentSlot == i) && swapActions.Exists(item => item.SourceModule == ModuleName.TMRobot && item.SourceSlot == i))) && !swapActions.Exists(item => item.DestinationModule == ModuleName.TMRobot && item.DestinationSlot == i)) hands.Add((Hand)i); } } return hands; } (ModuleName llPath, List swapActions) FindBestLLSwapPlan(ModuleName ll, List robotWafers) { ModuleName path = ll == ModuleName.System ? ModuleName.System : ll; List lls = ll == ModuleName.System ? new List { ModuleName.LLA, ModuleName.LLB } : new List { ll }; List actions = new List(); Dictionary> llSwapActions = new Dictionary>(); foreach (var loadlock in lls) { llSwapActions[loadlock] = new List(); if (IsLLReservedByEFEM(loadlock)) continue; var llWaferStatus = GetLLReadyInOutSlots(loadlock); foreach(var wafer in robotWafers) { if(_dictModuleTask[loadlock].TimeToReady == 0 && !IsLLReservedByEFEM(loadlock) && CanWaferGotoLL(wafer,loadlock) && llWaferStatus.emptySlot.Count > llSwapActions[loadlock].Count) { llSwapActions[loadlock].Add(new MoveItem(ModuleName.TMRobot, wafer.currentSlot, loadlock, llWaferStatus.emptySlot[llSwapActions[loadlock].Count], (Hand)wafer.currentSlot)); } } int prePickTime = 20; int prePickCount = 0; var hands = GetTMValidFreeHands(robotWafers, llSwapActions[loadlock]); foreach (var slot in llWaferStatus.inSlot) { var wafer = _lstWaferTasks.Find(task => task.currentMod == loadlock && task.currentSlot == slot); if (wafer != null && _dictModuleTask[wafer.destMod].TimeToReady <= prePickTime && _dictModuleTask[wafer.destMod].Scheduler.IsOnline && hands.Count > prePickCount) { if(_lstWaferTasks.Exists(task => task.currentMod == wafer.destMod)) { if( hands.Count == 2 && prePickCount == 0 && (_dictModuleTask.Count(mod => ModuleHelper.IsPm(mod.Key) && mod.Value.TimeToReady < prePickTime && WaferManager.Instance.CheckNoWafer(mod.Key, 0)) == 0 || llWaferStatus.inSlot.Count == 1)) { llSwapActions[loadlock].Add(new MoveItem(loadlock, slot, ModuleName.TMRobot, (int)hands[prePickCount], hands[prePickCount])); prePickCount++; break; } } else { llSwapActions[loadlock].Add(new MoveItem(loadlock, slot, ModuleName.TMRobot, (int)hands[prePickCount], hands[prePickCount])); prePickCount++; } } } } var validateActions = llSwapActions.Where(item => item.Value.Count > 0).ToDictionary(k => k.Key, v => v.Value); if(validateActions.Count == 1) { (path, actions) = (validateActions.First().Key, validateActions.First().Value); } else if(validateActions.Count == 2) { var sortedActions = validateActions.OrderByDescending(item => item.Value.Count + (_dictModuleTask[item.Key].Scheduler.IsVac ? 2 : 0)).ToDictionary(k => k.Key, v => v.Value); (path, actions) = (sortedActions.First().Key, sortedActions.First().Value); } return (path, actions); } (List pmWafers, ModuleName destLL, List swapAction) FindBestReturnWafersPlan(Hand[] freeHands) { Dictionary> returnWafers = new Dictionary>(); Dictionary> llSwapActions = new Dictionary>(); Dictionary llValues = new Dictionary(); foreach(var ll in new List { ModuleName.LLA, ModuleName.LLB}) { var llWaferStatus = GetLLReadyInOutSlots(ll); returnWafers[ll] = new List(); llSwapActions[ll] = new List(); llValues[ll] = 0; if (IsLLReservedByEFEM(ll)) continue; var readyReturnWafers = _lstWaferTasks.Where( wafer => ModuleHelper.IsPm(wafer.currentMod) && ModuleHelper.IsLoadPort(wafer.destMod) && wafer.movingStatus == RState.End && _dictModuleTask[wafer.currentMod].TimeToReady <= 2 && CanWaferGotoLL(wafer, ll)).Take(Math.Min(freeHands.Length, llWaferStatus.emptySlot.Count)).ToList(); int prePickTime = 10 * llSwapActions[ll].Count; int handIndex = 0; if(_dictModuleTask[ll].TimeToReady <= prePickTime) { foreach (var wafer in readyReturnWafers) { if(handIndex < freeHands.Length) { returnWafers[ll].Add(wafer); llSwapActions[ll].Add(new MoveItem(ModuleName.TMRobot, (int)freeHands[handIndex], ll, llWaferStatus.emptySlot[handIndex], freeHands[handIndex])); handIndex++; } } int prePickCount = 0; handIndex = 0; foreach (var slot in llWaferStatus.inSlot) { var wafer = _lstWaferTasks.Find(task => task.currentMod == ll && task.currentSlot == slot); if (wafer != null && _dictModuleTask[wafer.destMod].TimeToReady <= prePickTime && _dictModuleTask[wafer.destMod].Scheduler.IsOnline && freeHands.Length > prePickCount) { if (_lstWaferTasks.Exists(task => task.currentMod == wafer.destMod)) { if (freeHands.Length == 2 && prePickCount == 0 && (_dictModuleTask.Count(mod => ModuleHelper.IsPm(mod.Key) && mod.Value.TimeToReady <= prePickTime && WaferManager.Instance.CheckNoWafer(mod.Key, 0)) == 0 || llWaferStatus.inSlot.Count == 1)) { llSwapActions[ll].Add(new MoveItem(ll, slot, ModuleName.TMRobot, (int)freeHands[prePickCount], freeHands[prePickCount])); prePickCount++; break; } } else { llSwapActions[ll].Add(new MoveItem(ll, slot, ModuleName.TMRobot, (int)freeHands[prePickCount], freeHands[prePickCount])); prePickCount++; } } } llValues[ll] = returnWafers[ll].Count * 2 + llSwapActions[ll].Count + (_dictModuleTask[ll].Scheduler.IsVac && returnWafers[ll].Count > 0 ? 2 : 0); } } var preferLL = llValues.OrderByDescending(v => v.Value).First().Key; return (returnWafers[preferLL], preferLL, llSwapActions[preferLL]); } void RoutingTMSwapActions(List actions) { foreach (var action in actions) { if (ModuleHelper.IsTMRobot(action.SourceModule)) { var waferTask = _lstWaferTasks.Find(wafer => wafer.currentMod == ModuleName.TMRobot && wafer.currentSlot == action.SourceSlot); waferTask.RouteTo(action.DestinationModule, action.DestinationSlot); } else { var waferTask = _lstWaferTasks.Find(wafer => wafer.currentMod == action.SourceModule && wafer.currentSlot == action.SourceSlot); waferTask.RouteTo(action.DestinationModule, action.DestinationSlot); } } } private bool ManaulReturnPMWafer() { var mReturnWafer = _qeReturnWafers.Peek(); if (ModuleHelper.IsPm((ModuleName)mReturnWafer.Station)) { var hands = GetTMValidFreeHands(_lstWaferTasks.Where(wt => ModuleHelper.IsTMRobot(wt.currentMod)).ToList(), new List()); var waferTask = _lstWaferTasks.Find(wt => wt.currentMod == (ModuleName)mReturnWafer.Station && wt.waferId == mReturnWafer.InnerId); if (waferTask != null && hands.Count > 0) { waferTask.Return(); var outLL = _dictModuleTask.Where(mod => ModuleHelper.IsLoadLock(mod.Key) && CanWaferGotoLL(waferTask, mod.Key) && GetLLReadyInOutSlots(mod.Key).emptySlot.Count > 0 && !IsLLReservedByEFEM(mod.Key)); if (outLL.Count() > 0) { var slot = GetLLReadyInOutSlots(outLL.First().Key).emptySlot.First(); waferTask.RouteTo(outLL.First().Key, slot); _tmSchdActions.Enqueue(new List { new MoveItem(waferTask.currentMod, 0, ModuleName.TMRobot, (int)hands.First(), hands.First()) }); _tmSchdActions.Enqueue(new List { new MoveItem(ModuleName.TMRobot, (int)hands.First(), outLL.First().Key, slot, hands.First()) }); _qeReturnWafers.Dequeue(); return true; } } } return false; } private void RoutingVacWafers() { if(_tmSchdActions.Count > 0 || _curTmAction.Count > 0) { RunSchdTMActions(); return; } if(_tmRobotStatus == RState.End) { // handle manual return wafer if exist if(_qeReturnWafers.Count > 0) { if (ManaulReturnPMWafer()) return; } if(_LLASlotNumber == 2) { Routing2SlotVacSystem(); } else if(_LLASlotNumber == 4) { Routing4SlotVacSystem(); } } } private void Routing2SlotVacSystem() { var robotWafers = _lstWaferTasks.Where(wafer => (wafer.movingStatus == RState.End || wafer.movingStatus == RState.Init) && ModuleHelper.IsTMRobot(wafer.currentMod)).OrderBy(wafer => TimeForNextModuleReady(wafer)).ToList(); if (LLInOutPath == SequenceLLInOutPath.AInBOut || LLInOutPath == SequenceLLInOutPath.BInAOut) { var inLL = LLInOutPath == SequenceLLInOutPath.AInBOut ? ModuleName.LLA : ModuleName.LLB; var outLL = LLInOutPath == SequenceLLInOutPath.AInBOut ? ModuleName.LLB : ModuleName.LLA; var inLLWaferStatus = GetLLReadyInOutSlots(inLL); var outLLWaferStatus = GetLLReadyInOutSlots(outLL); if(robotWafers.Count == 2) { int returnCount = 0; foreach (var wafer in robotWafers) { if (ModuleHelper.IsPm(wafer.destMod)) { if (_dictModuleTask[wafer.destMod].TimeToReady <= 5 && !_lstWaferTasks.Exists(waferT => waferT.currentMod == wafer.destMod) && !_lstWaferTasks.Exists(waferT => waferT.routedMod == wafer.destMod)) { wafer.RouteTo(wafer.destMod, 0); _tmSchdActions.Enqueue(new List { new MoveItem(ModuleName.TMRobot, wafer.currentSlot, wafer.destMod, 0, (Hand)wafer.currentSlot) }); } } else { if (_dictModuleTask[outLL].TimeToReady <= 5 && !IsLLReservedByEFEM(outLL) && outLLWaferStatus.emptySlot.Count > returnCount) { wafer.RouteTo(outLL, outLLWaferStatus.emptySlot[returnCount]); _tmSchdActions.Enqueue(new List { new MoveItem(ModuleName.TMRobot, wafer.currentSlot, outLL, outLLWaferStatus.emptySlot[returnCount], (Hand)wafer.currentSlot) }); returnCount++; } } } } else if(robotWafers.Count == 1) { int freeHand = 1 - robotWafers.First().currentSlot; if (ModuleHelper.IsPm(robotWafers.First().destMod)) { if(_dictModuleTask[robotWafers.First().destMod].TimeToReady <= 5) { if(_lstWaferTasks.Exists(waferT => waferT.currentMod == robotWafers.First().destMod)) { var pmActions = new List(); var pmWafer = _lstWaferTasks.Find(wafer => wafer.currentMod == robotWafers.First().destMod); pmWafer.RouteTo(ModuleName.TMRobot, freeHand); pmActions.Add(new MoveItem(pmWafer.currentMod, 0, ModuleName.TMRobot, freeHand, (Hand)freeHand)); pmActions.Add(new MoveItem(ModuleName.TMRobot, robotWafers.First().currentSlot, pmWafer.currentMod, 0, (Hand)robotWafers.First().currentSlot)); _tmSchdActions.Enqueue(pmActions); } else { robotWafers.First().RouteTo(robotWafers.First().destMod, 0); _tmSchdActions.Enqueue(new List { new MoveItem(ModuleName.TMRobot, robotWafers.First().currentSlot, robotWafers.First().destMod, 0, (Hand)robotWafers.First().currentSlot) }); } } } else { if (_dictModuleTask[outLL].TimeToReady <= 5 && !IsLLReservedByEFEM(outLL) && outLLWaferStatus.emptySlot.Count > 0) { robotWafers.First().RouteTo(outLL, outLLWaferStatus.emptySlot[0]); _tmSchdActions.Enqueue(new List { new MoveItem(ModuleName.TMRobot, robotWafers.First().currentSlot, outLL, outLLWaferStatus.emptySlot[0], (Hand)robotWafers.First().currentSlot) }); } } if (_tmSchdActions.Count == 0 && _tmRobotSingleArmOption == 0) { // try push in one wafer if (!IsLLReservedByEFEM(inLL) && _dictModuleTask[inLL].Scheduler.IsVac && inLLWaferStatus.inSlot.Count > 0) { foreach (var slot in inLLWaferStatus.inSlot) { var llWafer = _lstWaferTasks.Find(wafer => wafer.currentMod == inLL && wafer.currentSlot == slot); if (llWafer != null && !_lstWaferTasks.Exists(wt => wt.currentMod == llWafer.destMod) && _dictModuleTask[llWafer.destMod].TimeToReady < 15) { llWafer.RouteTo(llWafer.destMod, 0); _tmSchdActions.Enqueue(new List { new MoveItem(inLL, slot, ModuleName.TMRobot, freeHand, (Hand)freeHand) }); _tmSchdActions.Enqueue(new List { new MoveItem(ModuleName.TMRobot, freeHand, llWafer.destMod, 0, (Hand)freeHand) }); return; } } } // try to return one wafer if (!IsLLReservedByEFEM(outLL) && outLLWaferStatus.emptySlot.Count > 0) { var reayReturnWafer = _lstWaferTasks.Find(wt => ModuleHelper.IsPm(wt.currentMod) && ModuleHelper.IsLoadPort(wt.destMod) && _dictModuleTask[wt.currentMod].TimeToReady <= 2); if (reayReturnWafer != null) { reayReturnWafer.RouteTo(outLL, outLLWaferStatus.emptySlot[0]); _tmSchdActions.Enqueue(new List { new MoveItem(reayReturnWafer.currentMod, 0, ModuleName.TMRobot, freeHand, (Hand)freeHand) }); _tmSchdActions.Enqueue(new List { new MoveItem(ModuleName.TMRobot, freeHand, outLL, outLLWaferStatus.emptySlot[0], (Hand)freeHand) }); return; } } } } else // no wafer on robot arm { var readyInPms = _dictModuleTask.Where(mod => ModuleHelper.IsPm(mod.Key) && !_lstWaferTasks.Exists(wt => wt.currentMod == mod.Key) && mod.Value.Scheduler.IsOnline && mod.Value.TimeToReady <= 15); var readyOutWafers = _lstWaferTasks.Where(wt => ModuleHelper.IsPm(wt.currentMod) && ModuleHelper.IsLoadPort(wt.destMod) && _dictModuleTask[wt.currentMod].TimeToReady <= 2).ToList() ; if(_tmRobotSingleArmOption != 0) { var hands = GetTMValidFreeHands(robotWafers, new List()); if (hands.Count == 0) return; if(!IsLLReservedByEFEM(inLL) && _dictModuleTask[inLL].TimeToReady <= 5 && inLLWaferStatus.inSlot.Count > 0 && readyInPms.Count() > 0) { foreach(var pm in readyInPms) { var llWafer = _lstWaferTasks.Find(wt => wt.currentMod == inLL && inLLWaferStatus.inSlot.Contains(wt.currentSlot) && wt.destMod == pm.Key); if(llWafer != null) { llWafer.RouteTo(llWafer.destMod, 0); _tmSchdActions.Enqueue(new List { new MoveItem(inLL, llWafer.currentSlot, ModuleName.TMRobot, (int)hands.First(), hands.First()) }); _tmSchdActions.Enqueue(new List { new MoveItem(ModuleName.TMRobot, (int)hands.First(), llWafer.destMod, 0, hands.First()) }); return; } } } if(readyOutWafers.Count > 0 && !IsLLReservedByEFEM(outLL) && _dictModuleTask[outLL].TimeToReady < 50 && outLLWaferStatus.emptySlot.Count > 0) { var returnWafer = readyOutWafers.First(); returnWafer.RouteTo(outLL, outLLWaferStatus.emptySlot.First()); _tmSchdActions.Enqueue(new List { new MoveItem(returnWafer.currentMod, 0, ModuleName.TMRobot, (int)hands.First(), hands.First()) }); _tmSchdActions.Enqueue(new List { new MoveItem(ModuleName.TMRobot, (int)hands.First(), outLL, outLLWaferStatus.emptySlot.First(), hands.First()) }); return; } return; } if(!IsLLReservedByEFEM(inLL) && _dictModuleTask[inLL].TimeToReady <= 5 && inLLWaferStatus.inSlot.Count > 0) { if(inLLWaferStatus.inSlot.Count == 2) { if(readyInPms.Count() > 0) // double move from LL to PM { int pickCount = 0; var swapActions = new List(); var singleActions = new List(); foreach(var pm in readyInPms) { var llWafer = _lstWaferTasks.Find(wt => wt.currentMod == inLL && inLLWaferStatus.inSlot.Contains(wt.currentSlot) && wt.destMod == pm.Key); if(llWafer != null) { llWafer.RouteTo(pm.Key, 0); swapActions.Add(new MoveItem(inLL, llWafer.currentSlot, ModuleName.TMRobot, pickCount, (Hand)pickCount)); singleActions.Add(new MoveItem(ModuleName.TMRobot, pickCount, pm.Key, 0, (Hand)pickCount)); pickCount++; } } if(pickCount == 1) { int remainSlot = swapActions.First().SourceSlot == inLLWaferStatus.inSlot[0] ? inLLWaferStatus.inSlot[1] : inLLWaferStatus.inSlot[0]; swapActions.Add(new MoveItem(inLL, remainSlot, ModuleName.TMRobot, 1, Hand.Blade2)); } if(swapActions.Count > 0) { _tmSchdActions.Enqueue(swapActions); foreach(var ac in singleActions) { _tmSchdActions.Enqueue(new List { ac }); } } } else { foreach(var slot in inLLWaferStatus.inSlot) { var llWafer = _lstWaferTasks.Find(wt => wt.currentMod == inLL && wt.currentSlot == slot); if (llWafer != null) { if(!_lstWaferTasks.Exists(wt => wt.currentMod == llWafer.destMod) && _dictModuleTask[llWafer.destMod].Scheduler.IsOnline) { var swapActions = new List(); swapActions.Add(new MoveItem(inLL, slot, ModuleName.TMRobot, 0, Hand.Blade1)); int remainSlot = slot == inLLWaferStatus.inSlot[0] ? inLLWaferStatus.inSlot[1] : inLLWaferStatus.inSlot[0]; swapActions.Add(new MoveItem(inLL, remainSlot, ModuleName.TMRobot, 1, Hand.Blade2)); _tmSchdActions.Enqueue(swapActions); if (_dictModuleTask[llWafer.destMod].TimeToReady <= 30) { llWafer.RouteTo(llWafer.destMod, 0); _tmSchdActions.Enqueue(new List { new MoveItem(ModuleName.TMRobot, 0, llWafer.destMod, 0, Hand.Blade1) }); } return; } } } } } else { var llWafer = _lstWaferTasks.Find(wt => wt.currentMod == inLL && wt.currentSlot == inLLWaferStatus.inSlot.First()); if (llWafer != null) { _tmSchdActions.Enqueue(new List { new MoveItem(inLL, inLLWaferStatus.inSlot.First(), ModuleName.TMRobot, 0, Hand.Blade1) }); if (!_lstWaferTasks.Exists(wt => wt.currentMod == llWafer.destMod) && _dictModuleTask[llWafer.destMod].TimeToReady < 15) { llWafer.RouteTo(llWafer.destMod, 0); _tmSchdActions.Enqueue(new List { new MoveItem(ModuleName.TMRobot, 0, llWafer.destMod, 0, Hand.Blade1) }); } } } } if (_tmSchdActions.Count > 0) return; if(!IsLLReservedByEFEM(outLL) && outLLWaferStatus.emptySlot.Count > 0 && readyOutWafers.Count > 0) { if(readyOutWafers.Count >= 2 && outLLWaferStatus.emptySlot.Count == 2) { readyOutWafers[0].RouteTo(outLL, outLLWaferStatus.emptySlot[0]); readyOutWafers[1].RouteTo(outLL, outLLWaferStatus.emptySlot[1]); _tmSchdActions.Enqueue(new List { new MoveItem(readyOutWafers[0].currentMod, readyOutWafers[0].currentSlot, ModuleName.TMRobot, 0, Hand.Blade1) }); _tmSchdActions.Enqueue(new List { new MoveItem(readyOutWafers[1].currentMod, readyOutWafers[1].currentSlot, ModuleName.TMRobot, 1, Hand.Blade2) }); var swapActions = new List(); swapActions.Add(new MoveItem(ModuleName.TMRobot, 0, outLL, outLLWaferStatus.emptySlot[0], Hand.Blade1)); swapActions.Add(new MoveItem(ModuleName.TMRobot, 1, outLL, outLLWaferStatus.emptySlot[1], Hand.Blade2)); _tmSchdActions.Enqueue(swapActions); } else { var freeHands = GetTMValidFreeHands(robotWafers, new List()); readyOutWafers[0].RouteTo(outLL, outLLWaferStatus.emptySlot[0]); _tmSchdActions.Enqueue(new List { new MoveItem(readyOutWafers[0].currentMod, readyOutWafers[0].currentSlot, ModuleName.TMRobot, (int)freeHands[0], freeHands[0]) }); _tmSchdActions.Enqueue(new List { new MoveItem(ModuleName.TMRobot, (int)freeHands[0], outLL, outLLWaferStatus.emptySlot[0], freeHands[0]) }); } } } } else { if (robotWafers.Count == 2) { foreach (var wafer in robotWafers) { if (wafer.movingStatus == RState.End && ModuleHelper.IsPm(wafer.destMod) && _dictModuleTask[wafer.destMod].TimeToReady == 0 && !_lstWaferTasks.Exists(waferT => waferT.currentMod == wafer.destMod) && !_lstWaferTasks.Exists(waferT => waferT.routedMod == wafer.destMod)) { wafer.RouteTo(wafer.destMod, 0); _tmSchdActions.Enqueue(new List { new MoveItem(ModuleName.TMRobot, wafer.currentSlot, wafer.destMod, 0, (Hand)wafer.currentSlot) }); } } if (_tmSchdActions.Count == 0) { var swapActions = FindBestLLSwapPlan(ModuleName.System, robotWafers); if (swapActions.llPath != ModuleName.System && swapActions.swapActions.Count > 0) { RoutingTMSwapActions(swapActions.swapActions); _tmSchdActions.Enqueue(swapActions.swapActions); } } } else if (robotWafers.Count == 1) { if (ModuleHelper.IsPm(robotWafers[0].destMod) && _dictModuleTask[robotWafers[0].destMod].TimeToReady == 0) { var pmActions = new List(); var pmWafer = _lstWaferTasks.Find(wafer => (wafer.movingStatus == RState.End || wafer.movingStatus == RState.Init) && wafer.currentMod == robotWafers[0].destMod && ModuleHelper.IsLoadPort(wafer.destMod)); if (pmWafer != null && string.IsNullOrWhiteSpace(pmWafer.wtwCleanRecipe)) { int pickSlot = 1 - robotWafers[0].currentSlot; pmWafer.RouteTo(ModuleName.TMRobot, pickSlot); pmActions.Add(new MoveItem(pmWafer.currentMod, 0, ModuleName.TMRobot, pickSlot, (Hand)pickSlot)); pmActions.Add(new MoveItem(ModuleName.TMRobot, robotWafers[0].currentSlot, pmWafer.currentMod, 0, (Hand)robotWafers[0].currentSlot)); _tmSchdActions.Enqueue(pmActions); return; } if (!_lstWaferTasks.Exists(wafer => wafer.currentMod == robotWafers[0].destMod)) { robotWafers[0].RouteTo(robotWafers[0].destMod, 0); pmActions.Add(new MoveItem(ModuleName.TMRobot, robotWafers[0].currentSlot, robotWafers[0].destMod, 0, (Hand)robotWafers[0].currentSlot)); _tmSchdActions.Enqueue(pmActions); return; } } // try to pick a wafer from LL if (_tmSchdActions.Count == 0) { var swapActions = FindBestLLSwapPlan(ModuleName.System, robotWafers); if (swapActions.llPath != ModuleName.System && swapActions.swapActions.Count > 0) { RoutingTMSwapActions(swapActions.swapActions); _tmSchdActions.Enqueue(swapActions.swapActions); return; } } // try to return a wafer from PM var freeHand = GetTMValidFreeHands(robotWafers, new List()); var moveActions = FindBestReturnWafersPlan(freeHand.ToArray()); if (moveActions.pmWafers.Count > 0) { MoveItem placeAction = moveActions.swapAction.Find(ac => ModuleHelper.IsLoadLock(ac.DestinationModule)); moveActions.pmWafers.First().RouteTo(placeAction.DestinationModule, placeAction.DestinationSlot); _tmSchdActions.Enqueue(new List { new MoveItem(moveActions.pmWafers.First().currentMod, 0, ModuleName.TMRobot, (int)freeHand[0], freeHand[0]) }); MoveItem pickAction = moveActions.swapAction.Find(ac => ModuleHelper.IsLoadLock(ac.SourceModule)); if (pickAction != null) { var pickWafer = _lstWaferTasks.Find(wafer => wafer.currentMod == pickAction.SourceModule && wafer.currentSlot == pickAction.SourceSlot); pickWafer.RouteTo(pickAction.DestinationModule, pickAction.DestinationSlot); } _tmSchdActions.Enqueue(moveActions.swapAction); } } else // robot arm is empty { // try return wafers from PM var freeHand = GetTMValidFreeHands(robotWafers, new List()); var moveActions = FindBestReturnWafersPlan(freeHand.ToArray()); if (moveActions.pmWafers.Count > 0) { int handIndex = 0; var placeActions = moveActions.swapAction.Where(ac => ModuleHelper.IsLoadLock(ac.DestinationModule)); foreach (var action in placeActions) { moveActions.pmWafers[handIndex].RouteTo(action.DestinationModule, action.DestinationSlot); _tmSchdActions.Enqueue(new List { new MoveItem(moveActions.pmWafers[handIndex].currentMod, 0, ModuleName.TMRobot, (int)freeHand[handIndex], freeHand[handIndex]) }); handIndex++; } var pickActions = moveActions.swapAction.Where(ac => ModuleHelper.IsLoadLock(ac.SourceModule)).ToList(); foreach (var ac in pickActions) { var llWafer = _lstWaferTasks.Find(wafer => wafer.currentMod == ac.SourceModule && wafer.currentSlot == ac.SourceSlot); llWafer.RouteTo(ac.DestinationModule, ac.DestinationSlot); } _tmSchdActions.Enqueue(moveActions.swapAction); } if (_tmSchdActions.Count == 0) { var swapActions = FindBestLLSwapPlan(ModuleName.System, robotWafers); if (swapActions.llPath != ModuleName.System && swapActions.swapActions.Count > 0) { RoutingTMSwapActions(swapActions.swapActions); _tmSchdActions.Enqueue(swapActions.swapActions); } } } } } private void Routing4SlotVacSystem() { var robotWafers = _lstWaferTasks.Where(wafer => (wafer.movingStatus == RState.End || wafer.movingStatus == RState.Init) && ModuleHelper.IsTMRobot(wafer.currentMod)).OrderBy(wafer => TimeForNextModuleReady(wafer)).ToList(); if (robotWafers.Count == 2) { foreach (var wafer in robotWafers) { if (wafer.movingStatus == RState.End && ModuleHelper.IsPm(wafer.destMod) && _dictModuleTask[wafer.destMod].TimeToReady == 0 && !_lstWaferTasks.Exists(waferT => waferT.currentMod == wafer.destMod) && !_lstWaferTasks.Exists(waferT => waferT.routedMod == wafer.destMod)) { wafer.RouteTo(wafer.destMod, 0); _tmSchdActions.Enqueue(new List { new MoveItem(ModuleName.TMRobot, wafer.currentSlot, wafer.destMod, 0, (Hand)wafer.currentSlot) }); } } if (_tmSchdActions.Count == 0) { var swapActions = FindBestLLSwapPlan(ModuleName.System, robotWafers); if (swapActions.llPath != ModuleName.System && swapActions.swapActions.Count > 0) { RoutingTMSwapActions(swapActions.swapActions); _tmSchdActions.Enqueue(swapActions.swapActions); } } } else if (robotWafers.Count == 1) { if (ModuleHelper.IsPm(robotWafers[0].destMod) && _dictModuleTask[robotWafers[0].destMod].TimeToReady == 0) { var pmActions = new List(); var pmWafer = _lstWaferTasks.Find(wafer => (wafer.movingStatus == RState.End || wafer.movingStatus == RState.Init) && wafer.currentMod == robotWafers[0].destMod && ModuleHelper.IsLoadPort(wafer.destMod)); if (pmWafer != null && string.IsNullOrWhiteSpace(pmWafer.wtwCleanRecipe)) { int pickSlot = 1 - robotWafers[0].currentSlot; pmWafer.RouteTo(ModuleName.TMRobot, pickSlot); pmActions.Add(new MoveItem(pmWafer.currentMod, 0, ModuleName.TMRobot, pickSlot, (Hand)pickSlot)); pmActions.Add(new MoveItem(ModuleName.TMRobot, robotWafers[0].currentSlot, pmWafer.currentMod, 0, (Hand)robotWafers[0].currentSlot)); _tmSchdActions.Enqueue(pmActions); return; } if (!_lstWaferTasks.Exists(wafer => wafer.currentMod == robotWafers[0].destMod)) { robotWafers[0].RouteTo(robotWafers[0].destMod, 0); pmActions.Add(new MoveItem(ModuleName.TMRobot, robotWafers[0].currentSlot, robotWafers[0].destMod, 0, (Hand)robotWafers[0].currentSlot)); _tmSchdActions.Enqueue(pmActions); return; } } // try to pick a wafer from LL if (_tmSchdActions.Count == 0) { var swapActions = FindBestLLSwapPlan(ModuleName.System, robotWafers); if (swapActions.llPath != ModuleName.System && swapActions.swapActions.Count > 0) { RoutingTMSwapActions(swapActions.swapActions); _tmSchdActions.Enqueue(swapActions.swapActions); return; } } // try to return a wafer from PM var freeHand = GetTMValidFreeHands(robotWafers, new List()); var moveActions = FindBestReturnWafersPlan(freeHand.ToArray()); if (moveActions.pmWafers.Count > 0) { MoveItem placeAction = moveActions.swapAction.Find(ac => ModuleHelper.IsLoadLock(ac.DestinationModule)); moveActions.pmWafers.First().RouteTo(placeAction.DestinationModule, placeAction.DestinationSlot); _tmSchdActions.Enqueue(new List { new MoveItem(moveActions.pmWafers.First().currentMod, 0, ModuleName.TMRobot, (int)freeHand[0], freeHand[0]) }); MoveItem pickAction = moveActions.swapAction.Find(ac => ModuleHelper.IsLoadLock(ac.SourceModule)); if (pickAction != null) { var pickWafer = _lstWaferTasks.Find(wafer => wafer.currentMod == pickAction.SourceModule && wafer.currentSlot == pickAction.SourceSlot); pickWafer.RouteTo(pickAction.DestinationModule, pickAction.DestinationSlot); } _tmSchdActions.Enqueue(moveActions.swapAction); } } else // robot arm is empty { // try return wafers from PM var freeHand = GetTMValidFreeHands(robotWafers, new List()); var moveActions = FindBestReturnWafersPlan(freeHand.ToArray()); if (moveActions.pmWafers.Count > 0) { int handIndex = 0; var placeActions = moveActions.swapAction.Where(ac => ModuleHelper.IsLoadLock(ac.DestinationModule)); foreach (var action in placeActions) { moveActions.pmWafers[handIndex].RouteTo(action.DestinationModule, action.DestinationSlot); _tmSchdActions.Enqueue(new List { new MoveItem(moveActions.pmWafers[handIndex].currentMod, 0, ModuleName.TMRobot, (int)freeHand[handIndex], freeHand[handIndex]) }); handIndex++; } var pickActions = moveActions.swapAction.Where(ac => ModuleHelper.IsLoadLock(ac.SourceModule)).ToList(); foreach (var ac in pickActions) { var llWafer = _lstWaferTasks.Find(wafer => wafer.currentMod == ac.SourceModule && wafer.currentSlot == ac.SourceSlot); llWafer.RouteTo(ac.DestinationModule, ac.DestinationSlot); } _tmSchdActions.Enqueue(moveActions.swapAction); } if (_tmSchdActions.Count == 0) { var swapActions = FindBestLLSwapPlan(ModuleName.System, robotWafers); if (swapActions.llPath != ModuleName.System && swapActions.swapActions.Count > 0) { RoutingTMSwapActions(swapActions.swapActions); _tmSchdActions.Enqueue(swapActions.swapActions); } } } } private List GetTMFreeHand() { var lstHands = new List(); if (WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 0) && _tmRobotSingleArmOption != 2) lstHands.Add(Hand.Blade1); if (WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 1) && _tmRobotSingleArmOption != 1) lstHands.Add(Hand.Blade2); return lstHands; } private List GetEFEMFreeHand() { var lstHands = new List(); if (WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 0) && _efemRobotSingleArmOption != 2) lstHands.Add(Hand.Blade1); if (WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, 1) && _efemRobotSingleArmOption != 1) lstHands.Add(Hand.Blade2); return lstHands; } private bool CanWaferGotoLL(WaferTask task, ModuleName ll) { bool bVacWafer = ModuleHelper.IsPm(task.currentMod) || ModuleHelper.IsTMRobot(task.currentMod); if (bVacWafer) { if (ModuleHelper.IsPm(task.destMod)) return false; switch (task.llInOutPath) { case SequenceLLInOutPath.AInAOut: case SequenceLLInOutPath.BInAOut: return ll == ModuleName.LLA; case SequenceLLInOutPath.AInBOut: case SequenceLLInOutPath.BInBOut: return ll == ModuleName.LLB; case SequenceLLInOutPath.DInDOut: return true; } } else { if (ModuleHelper.IsLoadPort(task.destMod)) return false; switch (task.llInOutPath) { case SequenceLLInOutPath.AInAOut: case SequenceLLInOutPath.AInBOut: return ll == ModuleName.LLA; case SequenceLLInOutPath.BInAOut: case SequenceLLInOutPath.BInBOut: return ll == ModuleName.LLB; case SequenceLLInOutPath.DInDOut: return true; } } return false; } private (List inSlot, List outSlot, List emptySlot) GetLLReadyInOutSlots(ModuleName ll) { var readInSlots = new List(); var readyOutSlots = new List(); var emptySlots = new List(); for(int slot = 0; slot < (ll == ModuleName.LLA ? _LLASlotNumber : _LLBSlotNumber); slot++) { if(WaferManager.Instance.CheckNoWafer(ll, slot) && !_lstWaferTasks.Exists(wafer => (wafer.routedMod == ll && wafer.routedSlot == slot) || (wafer.currentMod == ll && wafer.currentSlot == slot) || (wafer.nextMod == ll && wafer.nextSlot == slot))) { emptySlots.Add(slot); } if(WaferManager.Instance.CheckHasWafer(ll, slot)) { Guid waferID = WaferManager.Instance.GetWafer(ll, slot).InnerId; var waferTask = _lstWaferTasks.Find(wafer => wafer.waferId == waferID); if(waferTask != null && waferTask.movingStatus == RState.End) { if (ModuleHelper.IsPm(waferTask.destMod)) readInSlots.Add(slot); else if (_dictModuleTask[ll].Scheduler.WaferArrivedTicks(slot) > waferTask.llDelayTime * 1000) readyOutSlots.Add(slot); } } } return (readInSlots, readyOutSlots, emptySlots); } private (List wafers, List emptySlots) GetLLWaferExistance(ModuleName ll) { var lstWafers = new List(); var lstEmptySlots = new List(); for (int slot = 0; slot < (ll == ModuleName.LLA ? _LLASlotNumber : _LLBSlotNumber); slot++) { var wafer = WaferManager.Instance.GetWafer(ll, slot); if(wafer != null && !wafer.IsEmpty) { lstWafers.Add(wafer); } else { lstEmptySlots.Add(slot); } } return (lstWafers, lstEmptySlots); } private void PrepareLLPressure() { var preaparedLLs = new List(); var lls = _efemSchdActions.Where(acs => ModuleHelper.IsLoadLock(acs.First().Module)).Select(item => item.First().Module).ToList(); if (_curEfemAction.Count == 0 && _efemSchdActions.Count > 0 && ModuleHelper.IsLoadLock(_efemSchdActions.First().First().Module)) lls.Remove(_efemSchdActions.First().First().Module); foreach(var ll in lls) { if(_dictModuleTask[ll].Scheduler.IsAvailable && _dictModuleTask[ll].Scheduler.IsVac && !preaparedLLs.Contains(ll)) { (_dictModuleTask[ll].Scheduler as SchedulerLoadLock).PreVent(); preaparedLLs.Add(ll); } } lls = _tmSchdActions.Where(acs => ModuleHelper.IsLoadLock(acs.First().Module)).Select(item => item.First().Module).ToList(); if(_curTmAction.Count == 0 && _tmSchdActions.Count > 0 && ModuleHelper.IsLoadLock(_tmSchdActions.First().First().Module)) lls.Remove(_tmSchdActions.First().First().Module); foreach (var ll in lls) { if (_dictModuleTask[ll].Scheduler.IsAvailable && _dictModuleTask[ll].Scheduler.IsAtm && !preaparedLLs.Contains(ll)) { (_dictModuleTask[ll].Scheduler as SchedulerLoadLock).PrePump(); preaparedLLs.Add(ll); } } if (_efemSchdActions.Count > 0 || _curEfemAction.Count > 0 || _tmSchdActions.Count > 0 || _curTmAction.Count > 0) return; if (LLInOutPath == SequenceLLInOutPath.AInBOut || LLInOutPath == SequenceLLInOutPath.BInAOut) { var inLL = LLInOutPath == SequenceLLInOutPath.AInBOut ? ModuleName.LLA : ModuleName.LLB; var outLL = LLInOutPath == SequenceLLInOutPath.AInBOut ? ModuleName.LLB : ModuleName.LLA; var inLLWaferCount = _lstWaferTasks.Where(wafer => wafer.currentMod == inLL).Count(); var outLLWaferCount = _lstWaferTasks.Where(wafer => wafer.currentMod == outLL).Count(); if (inLLWaferCount == 0 && !preaparedLLs.Contains(inLL)) { (_dictModuleTask[inLL] as LoadlockTask).PreVent(); preaparedLLs.Add(inLL); } else if(inLLWaferCount == (LLInOutPath == SequenceLLInOutPath.AInBOut ? _LLASlotNumber : _LLBSlotNumber) && !preaparedLLs.Contains(inLL)) { (_dictModuleTask[inLL] as LoadlockTask).PrePump(); preaparedLLs.Add(inLL); } if(outLLWaferCount == 0 && !preaparedLLs.Contains(outLL)) { (_dictModuleTask[outLL] as LoadlockTask).PrePump(); preaparedLLs.Add(outLL); } else if(outLLWaferCount == (LLInOutPath == SequenceLLInOutPath.BInAOut ? _LLASlotNumber : _LLBSlotNumber) && !preaparedLLs.Contains(outLL)) { (_dictModuleTask[outLL] as LoadlockTask).PreVent(); preaparedLLs.Add(outLL); } } } private void ReturnVacWafers() { if (_tmSchdActions.Count > 0 || _curTmAction.Count > 0) { RunSchdTMReturnActions(); return; } if (_tmRobotStatus != RState.End) return; var hands = GetTMFreeHand(); var lls = _dictModuleTask.Where(mod => ModuleHelper.IsLoadLock(mod.Key) && !IsLLReservedByEFEM(mod.Key) && mod.Value.Scheduler.IsIdle && GetLLWaferExistance(mod.Key).emptySlots.Count > 0).OrderByDescending(mod => GetLLReadyInOutSlots(mod.Key).emptySlot.Count); if(lls.Count() > 0) { // return robot wafers int moveCount = 0; var llActions = new List(); var emptySlots = GetLLWaferExistance(lls.First().Key).emptySlots; for(int arm = 0; arm < 2; arm++) { var wafer = WaferManager.Instance.GetWafer(ModuleName.TMRobot, arm); if(wafer != null && !wafer.IsEmpty && moveCount < emptySlots.Count) { llActions.Add(new MoveItem(ModuleName.TMRobot, arm, lls.First().Key, emptySlots[moveCount], (Hand)arm)); moveCount++; } } if(moveCount > 0) { _tmSchdActions.Enqueue(llActions); return; } // return PM wafers var PickActions = new List(); var hasWaferPMs = _dictModuleTask.Where(mod => ModuleHelper.IsPm(mod.Key) && mod.Value.Scheduler.IsIdle && WaferManager.Instance.CheckHasWafer(mod.Key, 0)); foreach(var pm in hasWaferPMs) { if (moveCount < hands.Count && moveCount < emptySlots.Count) { PickActions.Add(new MoveItem(pm.Key, 0, ModuleName.TMRobot, (int)hands[moveCount], hands[moveCount])); llActions.Add(new MoveItem(ModuleName.TMRobot, (int)hands[moveCount], lls.First().Key, emptySlots[moveCount], hands[moveCount])); moveCount++; } } if(moveCount > 0) { foreach(var ac in PickActions) { _tmSchdActions.Enqueue(new List { ac }); } _tmSchdActions.Enqueue(llActions); } } } private void ReturnAtmWafers() { if (_efemSchdActions.Count > 0 || _curEfemAction.Count > 0) { RunSchdEFEMReturnActions(); return; } if (_efemRobotStatus != RState.End) return; // return Robot Wafer for(int i = 0; i < 2; i++) { var wafer = WaferManager.Instance.GetWafer(ModuleName.EfemRobot, i); if(wafer != null && !wafer.IsEmpty) { _efemSchdActions.Enqueue(new List { new MoveItem(ModuleName.EfemRobot, i, (ModuleName)wafer.OriginStation, wafer.OriginSlot, (Hand)i) }); } } if (_efemSchdActions.Count > 0) return; var hands = GetEFEMFreeHand(); // return Aligner wafer var aligner = ModuleHelper.InstalledModules.Where(mod => ModuleHelper.IsAligner(mod)).ToList(); if(aligner.Count > 0 && WaferManager.Instance.CheckHasWafer(aligner.First(), 0) && hands.Count > 0) { var wafer = WaferManager.Instance.GetWafer(aligner.First(), 0); _efemSchdActions.Enqueue(new List { new MoveItem(aligner.First(), 0, ModuleName.EfemRobot, (int)hands.First(), hands.First()) }); _efemSchdActions.Enqueue(new List { new MoveItem(ModuleName.EfemRobot, (int)hands.First(), (ModuleName)wafer.OriginStation, wafer.OriginSlot, hands.First()) }); return; } // return Loadlock wafer var lls = _dictModuleTask.Where(mod => ModuleHelper.IsLoadLock(mod.Key) && !IsLLReservedByTM(mod.Key) && mod.Value.Scheduler.IsIdle && GetLLWaferExistance(mod.Key).wafers.Count > 0).OrderByDescending(mod => GetLLWaferExistance(mod.Key).wafers.Count); if(lls.Count() > 0) { int returnCount = 0; var llActions = new List(); var placActions = new List(); foreach(var wafer in GetLLWaferExistance(lls.First().Key).wafers) { if(returnCount < hands.Count) { llActions.Add(new MoveItem(lls.First().Key, wafer.Slot, ModuleName.EfemRobot, (int)hands[returnCount], hands[returnCount])); placActions.Add(new MoveItem(ModuleName.EfemRobot, (int)hands[returnCount], (ModuleName)wafer.OriginStation, wafer.OriginSlot, hands[returnCount])); returnCount++; } } if (returnCount > 0) { _efemSchdActions.Enqueue(llActions); foreach (var ac in placActions) { _efemSchdActions.Enqueue(new List { ac }); } } } } private void RunSchdEFEMReturnActions() { var efemRobot = Singleton.Instance.GetScheduler(ModuleName.EfemRobot) as SchedulerEfemRobot; if (efemRobot == null || !efemRobot.IsAvailable) return; if (_efemSchdActions.Count > 0) { if (_curEfemAction.Count == 0 || isReturnActionsDone(_curEfemAction)) { var nextActions = _efemSchdActions.First(); var nextModule = nextActions.First().Module; if (ModuleHelper.IsLoadLock(nextModule) && !_dictModuleTask[nextModule].IsIdle) return; _curEfemAction = _efemSchdActions.Dequeue(); efemRobot.PostMoveItems(_curEfemAction.ToArray()); } } else if (_curEfemAction.Count >= 0 && isReturnActionsDone(_curEfemAction)) // all scheduled actions done { _curEfemAction.Clear(); } } private void RunSchdTMReturnActions() { var tmRobot = Singleton.Instance.GetScheduler(ModuleName.TMRobot) as SchedulerTMRobot; if (tmRobot == null || !tmRobot.IsAvailable) return; if (_tmSchdActions.Count > 0) { if (_curTmAction.Count == 0 || isReturnActionsDone(_curTmAction)) { var nextActions = _tmSchdActions.First(); var nextModule = nextActions.First().Module; if (ModuleHelper.IsLoadLock(nextModule) && !_dictModuleTask[nextModule].IsIdle) return; _curTmAction = _tmSchdActions.Dequeue(); tmRobot.SendMoveItems(_curTmAction.ToArray()); } } else if (_curTmAction.Count >= 0 && isReturnActionsDone(_curTmAction)) // all scheduled actions done { _curTmAction.Clear(); } } #endregion #region sequence/recipe operation private bool CheckSequencePmReady(SequenceInfo seq, out string reason) { reason = ""; foreach(var pm in seq.PMs) { if (ModuleHelper.IsInstalled(pm) && (_dictModuleTask[pm].Scheduler.IsOnline || !Singleton.Instance.IsAutoMode)) return true; } reason = $"Sequence {seq.Name} no valid PM, " + string.Join("|", seq.PMs); return false; } private bool CheckSequenceKepler2200TemperatureReady(SequenceInfo seq) { for (int i = 0; i < seq.Steps.Count; i++) { SequenceStepInfo stepInfo = seq.Steps[i]; foreach (var module in stepInfo.StepModules) { if (ModuleHelper.IsPm(module)) { string attr = $"{module}Recipe"; if (stepInfo.StepParameter.ContainsKey(attr) && !string.IsNullOrWhiteSpace((string)stepInfo.StepParameter[attr])) { var recipeName = (string)stepInfo.StepParameter[attr]; var recipeContent = RecipeFileManager.Instance.LoadRecipe($"{module}", recipeName, false, "Process"); var recipe = Recipe.Load(recipeContent); float currentChamberTemperature; switch (module) { case ModuleName.PMA: currentChamberTemperature = Singleton.Instance.PMA.ChamberTemperature; break; case ModuleName.PMB: currentChamberTemperature = Singleton.Instance.PMB.ChamberTemperature; break; case ModuleName.PMC: currentChamberTemperature = Singleton.Instance.PMC.ChamberTemperature; break; case ModuleName.PMD: currentChamberTemperature = Singleton.Instance.PMD.ChamberTemperature; break; default: currentChamberTemperature = 0; break; } if (recipe.Header.Temperature!=null && recipe.Header.Temperature!="" && (currentChamberTemperature > Convert.ToSingle(recipe.Header.Temperature) + 10 || currentChamberTemperature < Convert.ToSingle(recipe.Header.Temperature) - 10)) { LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Start job失败,由于{module}腔体温度{currentChamberTemperature}与{recipeName} Recipe温度{recipe.Header.Temperature}不匹配"); return false; } } } } } return true; } private bool CheckSequenceRecipeFileValid(SequenceInfo seq, out string reason) { for (int i = 0; i < seq.Steps.Count; i++) { SequenceStepInfo stepInfo = seq.Steps[i]; foreach (var module in stepInfo.StepModules) { if (ModuleHelper.IsPm(module)) { string attr = $"{module}Recipe"; if (stepInfo.StepParameter.ContainsKey(attr) && !string.IsNullOrWhiteSpace((string)stepInfo.StepParameter[attr])) { var recipeName = (string)stepInfo.StepParameter[attr]; if (!string.IsNullOrWhiteSpace(recipeName)) { var recipeContent = RecipeFileManager.Instance.LoadRecipe($"{module}", recipeName, false, "Process"); if (string.IsNullOrWhiteSpace(recipeContent)) { reason = $"Can not find recipe file{recipeName}"; return false; } } } } } } reason = ""; return true; } private void UpdateLLInOutPathProperty() { if (_lstControlJobs.Count == 0) return; var inOutPaths = new List(); foreach(var wt in _lstWaferTasks) { if (!inOutPaths.Contains(wt.llInOutPath)) inOutPaths.Add(wt.llInOutPath); } if (inOutPaths.Count == 1) { _LLInOutPath = inOutPaths[0]; } else _LLInOutPath = SequenceLLInOutPath.DInDOut; } #endregion } }