using MECF.Framework.Common.RecipeCenter; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.Schedulers; using Aitex.Core.Common; using MECF.Framework.Common.WaferHolder; using MECF.Framework.Common.CommonData; using System.Windows; using Aitex.Core.RT.IOCore; using Aitex.Core.RT.Log; using Aitex.Core.Util; using MECF.Framework.Common.Routine; using CyberX8_RT.Modules; using Aitex.Core.RT.Fsm; using CyberX8_RT.Modules.PUF; using CyberX8_RT.Modules.Dummy; using MECF.Framework.Common.SubstrateTrackings; using MECF.Framework.Common.ToolLayout; using CyberX8_RT.Modules.Metal; using CyberX8_RT.Modules.Rinse; using MECF.Framework.RT.Core.Equipments; using MECF.Framework.Common.ProcessCell; using SecsGem.Core.ItemModel; using CyberX8_RT.Modules.Transporter; using CyberX8_Core; using Aitex.Core.RT.SCCore; using CyberX8_RT.Modules.Dryer; using CyberX8_RT.Modules.Prewet; using CyberX8_RT.Modules.SRD; using CyberX8_RT.Modules.Reservoir; namespace CyberX8_RT.Schedulers { public class SchedulerSequenceManager : Singleton { #region 常量 private const string ENGINEERING = "Engineering"; private const string PRODUCTION = "Production"; #endregion /// /// 解析Wafer所有调度工序 /// /// /// public List AnalyWaferAllSchedulerSequence(WaferInfo waferInfo,ModuleName pufModule,WaferHolderInfo waferHolderInfo,SequenceRecipe sequenceRecipe) { List schedulerSequences = new List(); int index = 0; MoveItem moveItem = new MoveItem((ModuleName)waferInfo.OriginStation, waferInfo.OriginSlot, ModuleName.Aligner1, 0, Aitex.Sorter.Common.Hand.Blade1); List synModules = new List(); SchedulerSyncModuleMessage pufModuleMessage = new SchedulerSyncModuleMessage(); pufModuleMessage.ModuleEntity = Singleton.Instance.GetModule(pufModule.ToString()); pufModuleMessage.ModuleMsg = PUFMSG.ReadyForRobotPlace.ToString(); synModules.Add(pufModuleMessage); SchedulerSequence efemRobotSequence = CreateEfemRobotSequence(moveItem,synModules,ref index); schedulerSequences.Add(efemRobotSequence); SchedulerSequence alignerSequence=CreateAlignerSequence(sequenceRecipe.AlignmentAngle,ref index); schedulerSequences.Add(alignerSequence); //从Aligner至Puf B面 MoveItem moveItem2 = new MoveItem(ModuleName.Aligner1, 0, pufModule, 1, Aitex.Sorter.Common.Hand.Blade1); SchedulerSequence secondEfemRobotSequence = CreateEfemRobotSequence(moveItem2,null,ref index); schedulerSequences.Add(secondEfemRobotSequence); SchedulerSequence pufSequence=CreatePufSequence(pufModule,sequenceRecipe,true,ref index); schedulerSequences.Add(pufSequence); ////Loader //SchedulerSequence loaderSequence = CreateLoaderSequence(ref index); //schedulerSequences.Add(loaderSequence); ////wafer holder装载后的recipe工序 //List waferHolderAfterLoadedAllSequences = WaferHolderAfterLoadedAllSchedulerSequences(waferHolderInfo, sequenceRecipe, ref index); //schedulerSequences.AddRange(waferHolderAfterLoadedAllSequences); ////buffer模块至Loader //ModuleName bufferModule = ConvertToBufferModule(waferHolderInfo.BufferId); //WaferHolderMoveItem bufferToLoaderItem = new WaferHolderMoveItem(bufferModule,ModuleType.Buffer , ModuleName.Loader1, ModuleType.Loader); //SchedulerSequence bufferToLoaderSequence = CreateLoaderTransporterSequence(bufferToLoaderItem, ref index); //schedulerSequences.Add(bufferToLoaderSequence); ////Loader //SchedulerSequence backLoaderSequence = CreateLoaderSequence(ref index); //schedulerSequences.Add(backLoaderSequence); //puf模块 SchedulerSequence backPufSequence = CreatePufSequence(pufModule,sequenceRecipe,false, ref index); schedulerSequences.Add(backPufSequence); //若经过srd if(SequenceRecipeManager.Instance.IsContainedSrd(sequenceRecipe)) { SrdRecipe srdRecipe=SequenceRecipeManager.Instance.GetSrdRecipeBySequenceRecipe(sequenceRecipe); if(srdRecipe!=null) { MoveItem pufToSrdItem = new MoveItem(); pufToSrdItem.SourceModule = pufModule; //A面 pufToSrdItem.SourceSlot = 0; pufToSrdItem.DestinationType = ModuleType.SRD; pufToSrdItem.SourceSlot = 0; pufToSrdItem.DestinationModule = ModuleName.Unknown; pufToSrdItem.RobotHand = Aitex.Sorter.Common.Hand.Blade1; SchedulerSequence backEfemRobotSequence = CreateEfemRobotSequence(pufToSrdItem,null, ref index); schedulerSequences.Add(backEfemRobotSequence); SchedulerSequence srdSequence = CreateSRDSequence(srdRecipe, ref index); schedulerSequences.Add(srdSequence); MoveItem srdToLoadPortItem = new MoveItem(); srdToLoadPortItem.SourceModule = ModuleName.Unknown; srdToLoadPortItem.SourceType = ModuleType.SRD; srdToLoadPortItem.SourceSlot = 0; srdToLoadPortItem.DestinationType = ModuleType.LoadPort; srdToLoadPortItem.DestinationModule = (ModuleName)waferInfo.OriginStation; srdToLoadPortItem.DestinationSlot = waferInfo.OriginSlot; srdToLoadPortItem.RobotHand = Aitex.Sorter.Common.Hand.Blade1; SchedulerSequence srdToLoadPortSequence = CreateEfemRobotSequence(srdToLoadPortItem,null, ref index); schedulerSequences.Add(srdToLoadPortSequence); } else { LOG.WriteLog(eEvent.ERR_SEQUENCE, "System", $"{sequenceRecipe.Ppid} srd recipe is invalid"); return new List(); } } else { MoveItem pufToLoadPortItem=new MoveItem(pufModule,0,(ModuleName)waferInfo.OriginStation, waferInfo.OriginSlot,Aitex.Sorter.Common.Hand.Blade1); SchedulerSequence pufToLoaderSequence=CreateEfemRobotSequence(pufToLoadPortItem,null, ref index); schedulerSequences.Add(pufToLoaderSequence); } return schedulerSequences; } /// /// 解析WaferHolder的所有工序 /// /// /// /// public List AnalyWaferHolderAllSchedulerSequence(WaferHolderInfo waferHolderInfo, SequenceRecipe sequenceRecipe) { int index = 0; List schedulerSequences = new List(); //Buffer To Loader ModuleName currentLocationModuleName = (ModuleName)Enum.Parse(typeof(ModuleName), waferHolderInfo.CurrentLocation); WaferHolderMoveItem bufferMoveToLoaderItem = new WaferHolderMoveItem(currentLocationModuleName, ModuleType.Buffer, ModuleName.Loader1, ModuleType.Loader); SchedulerSequence bufferToLoaderSequence = CreateLoaderTransporterSequence(bufferMoveToLoaderItem, ref index); schedulerSequences.Add(bufferToLoaderSequence); //Loader SchedulerSequence loaderSequence = CreateLoaderSequence(ref index); schedulerSequences.Add(loaderSequence); //wafer holder装载后的recipe工序 List waferHolderAfterLoadedAllSequences = WaferHolderAfterLoadedAllSchedulerSequences(waferHolderInfo, sequenceRecipe,ref index); schedulerSequences.AddRange(waferHolderAfterLoadedAllSequences); return schedulerSequences; } /// /// Dummy Wafer对应WaferHolder任务 /// /// /// public List AnalyseDummyWaferHolderAllSchedulerSequence(WaferHolderInfo waferHolderInfo) { int index = 0; List schedulerSequences = new List(); //Buffer To Loader ModuleName currentLocationModuleName = (ModuleName)Enum.Parse(typeof(ModuleName), waferHolderInfo.CurrentLocation); ModuleName bufferModule = (ModuleName)Enum.Parse(typeof(ModuleName), waferHolderInfo.OriginalBuffer); WaferHolderMoveItem bufferMoveToLoaderItem = new WaferHolderMoveItem(currentLocationModuleName, ModuleType.Buffer, ModuleName.Loader1, ModuleType.Loader); SchedulerSequence bufferToLoaderSequence = CreateLoaderTransporterSequence(bufferMoveToLoaderItem, ref index); schedulerSequences.Add(bufferToLoaderSequence); //Loader SchedulerSequence loaderSequence = CreateLoaderSequence(ref index); schedulerSequences.Add(loaderSequence); //Loader To Buffer WaferHolderMoveItem loaderMoveToBufferItem = new WaferHolderMoveItem(ModuleName.Loader1, ModuleType.Loader, bufferModule, ModuleType.Buffer); SchedulerSequence loaderToBufferSequence = CreateLoaderTransporterSequence(loaderMoveToBufferItem, ref index); schedulerSequences.Add(loaderToBufferSequence); return schedulerSequences; } /// /// 解析Dummy Wafer所有调度工序 /// /// /// public List AnalyDummyWaferAllSchedulerSequence(SequenceRecipe sequenceRecipe,WaferInfo waferInfo, ModuleName pufModule) { List schedulerSequences = new List(); int index = 0; //DummyCassete至Aligner MoveItem moveItem = new MoveItem((ModuleName)waferInfo.Station, waferInfo.Slot, ModuleName.Aligner1, 0, Aitex.Sorter.Common.Hand.Blade1); SchedulerSequence secondEfemRobotSequence = CreateEfemRobotSequence(moveItem, null, ref index); schedulerSequences.Add(secondEfemRobotSequence); //Aligner SchedulerSequence alignerSequence = null; if (sequenceRecipe == null) { alignerSequence= CreateAlignerSequence(0, ref index); } else { alignerSequence=CreateAlignerSequence(sequenceRecipe.AlignmentAngle, ref index); } schedulerSequences.Add(alignerSequence); //Aligner至Puf MoveItem alignerToPufMoveItem = new MoveItem(ModuleName.Aligner1, 0, pufModule, 1, Aitex.Sorter.Common.Hand.Blade1); SchedulerSequence alignerToPufEfemRobotSequence = CreateEfemRobotSequence(alignerToPufMoveItem, null, ref index); schedulerSequences.Add(alignerToPufEfemRobotSequence); SchedulerSequence pufSequence = CreatePufSequence(pufModule,sequenceRecipe, true, ref index); schedulerSequences.Add(pufSequence); return schedulerSequences; } /// /// Loader装载后Recipe工序 /// /// /// /// /// private List WaferHolderAfterLoadedAllSchedulerSequences(WaferHolderInfo waferHolderInfo,SequenceRecipe sequenceRecipe,ref int index) { List schedulerSequences = new List(); if(!Enum.TryParse(waferHolderInfo.OriginalBuffer,out ModuleName moduleName)) { return schedulerSequences; } //Loader To Buffer WaferHolderMoveItem loaderMoveToBufferItem = new WaferHolderMoveItem(ModuleName.Loader1, ModuleType.Loader, moduleName, ModuleType.Buffer); SchedulerSequence loaderToBufferSequence = CreateLoaderTransporterSequence(loaderMoveToBufferItem, ref index); schedulerSequences.Add(loaderToBufferSequence); //解析sequence recipe后续的工序 var result = AnalyseSequenceRecipeScheduler(sequenceRecipe); //buffer to recipe第一个工序 WaferHolderMoveItem bufferToFirstItem = new WaferHolderMoveItem(moduleName, ModuleType.Buffer, ModuleName.Unknown, result.firstModuleType); SchedulerSequence bufferSequence = CreateLoaderTransporterSequence(bufferToFirstItem, ref index); schedulerSequences.Add(bufferSequence); //调整工序后面的索引 foreach (SchedulerSequence item in result.sequences) { item.SequenceIndex = index; index++; } schedulerSequences.AddRange(result.sequences); //从recipe最后工序 WaferHolderMoveItem lastToBufferItem = new WaferHolderMoveItem(ModuleName.Unknown, result.lastModuleType, moduleName, ModuleType.Buffer); SchedulerSequence lastToBufferSequence = CreateLoaderTransporterSequence(lastToBufferItem, ref index); schedulerSequences.Add(lastToBufferSequence); return schedulerSequences; } /// /// 分析Sequence recipe对应的调度步骤 /// /// /// private (ModuleType firstModuleType,List sequences,ModuleType lastModuleType) AnalyseSequenceRecipeScheduler(SequenceRecipe sequenceRecipe) { ModuleType firstModuleType = default; ModuleType lastModuleType = default; List schedulerSequences= new List(); List tmpLst = new List(); var processResult = AnalyseLastProcessRecipeIndex(sequenceRecipe.Recipes); bool isExistSrd = sequenceRecipe.Recipes.FindIndex(O=>O.ToLower().EndsWith("srd.rcp"))!=-1; int lastIndex = isExistSrd ? sequenceRecipe.Recipes.Count - 2 : sequenceRecipe.Recipes.Count - 1; for(int i=0;i /// 分析最后加工recipe索引 /// /// /// private (int lastIndex,List processIndexList) AnalyseLastProcessRecipeIndex(List recipes) { int index = 0; List lst = new List(); for(int i=0;i /// 创建EFEM Robot步骤 /// /// /// private SchedulerSequence CreateEfemRobotSequence(MoveItem moveItem,List synModules,ref int index) { SchedulerSequence sequence = new SchedulerSequence(); sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.EfemRobot); sequence.SequenceIndex= index; sequence.ModuleName=ModuleName.EfemRobot; sequence.State = RState.Init; sequence.Recipe = null; sequence.ModuleType=ModuleType.EfemRobot; sequence.Parameters =moveItem; sequence.MaterialType = MaterialType.Wafer; sequence.SynchronousModuleMessages = synModules; index++; return sequence; } /// /// 创建Aligner步骤 /// /// /// private SchedulerSequence CreateAlignerSequence(double angle,ref int index) { SchedulerSequence sequence = new SchedulerSequence(); sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.Aligner1); sequence.SequenceIndex = index; sequence.ModuleName = ModuleName.Aligner1; sequence.State = RState.Init; sequence.Recipe = null; sequence.ModuleType = ModuleType.Aligner; sequence.Parameters = angle; sequence.MaterialType = MaterialType.Wafer; index++; return sequence; } /// /// 创建PUF步骤 /// /// /// /// private SchedulerSequence CreatePufSequence(ModuleName pufModuleName,SequenceRecipe sequenceRecipe,bool forward,ref int index) { SchedulerSequence sequence = new SchedulerSequence(); sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(pufModuleName); sequence.SequenceIndex = index; sequence.ModuleName = pufModuleName; sequence.State = RState.Init; sequence.Recipe = sequenceRecipe; sequence.Parameters = forward; sequence.IsWaitNotify = !forward; sequence.ModuleType = ModuleType.PUF; sequence.MaterialType = MaterialType.Wafer; index++; return sequence; } /// /// 创建Loader步骤 /// /// /// private SchedulerSequence CreateLoaderSequence(ref int index) { SchedulerSequence sequence = new SchedulerSequence(); sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.Loader1); sequence.SequenceIndex = index; sequence.ModuleName = ModuleName.Loader1; sequence.State = RState.Init; sequence.Recipe = null; sequence.ModuleType = ModuleType.Loader; sequence.MaterialType = MaterialType.WaferHolder; index++; return sequence; } /// /// 创建Loader步骤 /// /// /// private SchedulerSequence CreateSRDSequence(SrdRecipe recipe,ref int index) { SchedulerSequence sequence = new SchedulerSequence(); sequence.SequenceIndex = index; sequence.State = RState.Init; sequence.Recipe = recipe; sequence.ModuleType = ModuleType.SRD; sequence.MaterialType = MaterialType.Wafer; index++; return sequence; } /// /// 创建LoaderTransporter步骤 /// /// /// private SchedulerSequence CreateLoaderTransporterSequence(WaferHolderMoveItem waferHolderMoveItem, ref int index) { SchedulerSequence sequence = new SchedulerSequence(); sequence.ModuleType = ModuleType.Transporter; sequence.ModuleName = ModuleName.Transporter2; sequence.SequenceIndex = index; sequence.State = RState.Init; sequence.Recipe = null; sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.Transporter2); sequence.Parameters = waferHolderMoveItem; sequence.MaterialType = MaterialType.WaferHolder; index++; return sequence; } /// /// 创建LoaderTransporter步骤 /// /// /// private SchedulerSequence CreateProcessTransporterSequence(WaferHolderMoveItem waferHolderMoveItem,ref int index) { SchedulerSequence sequence = new SchedulerSequence(); sequence.ModuleType = ModuleType.Transporter; sequence.ModuleName = ModuleName.Transporter1; sequence.SequenceIndex = index; sequence.State = RState.Init; sequence.Recipe = null; sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.Transporter1); sequence.Parameters= waferHolderMoveItem; sequence.MaterialType = MaterialType.WaferHolder; index++; return sequence; } /// /// 获取可用Dummy slot /// /// /// public (ModuleName moduleName,int slot) GetAvaibleDummySlots() { if(ModuleHelper.IsInstalled(ModuleName.Dummy1)) { DummyEntity dummyEntity = Singleton.Instance.GetModule(ModuleName.Dummy1.ToString()); for(int i=0;i.Instance.GetModule(ModuleName.Dummy2.ToString()); for (int i = 0; i < dummyEntity.MaxSlotNumber; i++) { if (WaferManager.Instance.CheckNoWafer(ModuleName.Dummy2, i)) { return (ModuleName.Dummy2, i); } } } return (ModuleName.Unknown, -1); } /// /// 根据模块类型获取可用模块 /// /// /// public ModuleName GetAvaibleModuleCell(string sequenceType,ModuleType moduleType, ModuleName moduleName = ModuleName.Unknown) { if (ModuleHelper.IsMetal(moduleName)) { List entities = Singleton.Instance.GetModulesByModuleType(moduleType); return GetMetalAvaibleRinseModule(entities, moduleName); } else { List entities = Singleton.Instance.GetModulesByModuleType(moduleType); List avaibles = new List(); foreach (var item in entities) { bool result = CheckAvaibleModule(item,moduleType,sequenceType); if (result) { avaibles.Add(item); } } return GetMinTimeToReadyModule(avaibles,moduleType); } } /// /// 根据模块类型获取可用模块(不包含WH) /// /// /// public ModuleName GetAvaibleEmptyModuleCell(ModuleType moduleType,string sequenceType, ModuleName moduleName = ModuleName.Unknown) { if (ModuleHelper.IsMetal(moduleName)) { List entities = Singleton.Instance.GetModulesByModuleType(moduleType); return GetMetalAvaibleEmptyRinseModule(entities, moduleName); } else { List entities = Singleton.Instance.GetModulesByModuleType(moduleType); List avaibles = new List(); foreach (var item in entities) { bool result = CheckAvaibleModule(item,moduleType,sequenceType); if (result&&!WaferHolderManager.Instance.HasWaferHolder(item.Module.ToString())) { avaibles.Add(item); } } return avaibles.Count != 0 ? avaibles[0].Module : ModuleName.Unknown; } } /// /// 根据化学液计算时间获取可用MetalCell(参考其他Metal剩余时间) /// /// /// public ModuleName CalculateAvaibleMetalCellByChemistry(string chemistry,string startRinse,string sequenceType,ref bool isExistEnableMetal) { if(!Enum.TryParse(startRinse,out ModuleName startRinseModule)||!ModuleHelper.IsRinse(startRinseModule)) { startRinse = ""; } isExistEnableMetal = false; List moduleEntities = GetAvaibleMetalList(chemistry,sequenceType,true); List avaibleMetalEntities = new List(); foreach (var item in moduleEntities) { if(CheckAvaibleModule(item,ModuleType.Metal,sequenceType)) { if (item.WaferHolderInfo == null) { if (CheckMetalModuleRinseAvaible(item, startRinse)) { avaibleMetalEntities.Add(item); } } isExistEnableMetal = true; } } if (avaibleMetalEntities.Count > 0) { return GetMinUsageMetal(avaibleMetalEntities); } return ModuleName.Unknown; } /// /// 根据化学液获取可用Metal /// /// /// /// public bool CalculateAvaibleMetalCellByChemistry(string chemistry,string sequenceType) { List moduleEntities = GetAvaibleMetalList(chemistry, sequenceType, false); return moduleEntities.Count != 0; } /// /// 检验Metal模块Rinse可用性 /// /// /// private bool CheckMetalModuleRinseAvaible(MetalEntity item,string startRinse) { List rinseItems = CellItemManager.Instance.GetRinseItemsByMetal(item.Module.ToString()); List sharedRinseItems = new List(); List singleRinseItems = new List(); foreach (var cellItem in rinseItems) { RinseEntity rinseEntity = Singleton.Instance.GetModule(cellItem.ModuleName); if (!CellItemManager.Instance.CheckRinseIsShared(cellItem.ModuleName)) { if (CheckAvaibleModule(rinseEntity, ModuleType.Rinse, "") && rinseEntity.WaferHolderInfo == null) { singleRinseItems.Add(cellItem.ModuleName); } } else { if (CheckAvaibleModule(rinseEntity,ModuleType.Rinse,"") && rinseEntity.WaferHolderInfo == null) { sharedRinseItems.Add(cellItem.ModuleName); } //增加自己 if (cellItem.ModuleName == startRinse && rinseEntity != null && (rinseEntity.IsIdle||rinseEntity.State==(int)RinseState.KeepWeting)) { sharedRinseItems.Add(startRinse); } } } //独立的Rinse集合 if(singleRinseItems.Count!=0) { bool result = CheckSingleRinseItemsCanUsed(singleRinseItems, item.Module.ToString()); if(result) { return true; } } //仅剩下共享Rinse List avaibleSharedList = new List(); if (sharedRinseItems.Count != 0) { foreach (string sharedRinse in sharedRinseItems) { RinseEntity rinseEntity = Singleton.Instance.GetModule(sharedRinse); if (rinseEntity.IsBusy&&sharedRinse!=startRinse) { continue; } //检验共享Rinse是否可用 if (CheckShardRinseCanUse(sharedRinse, item.Module.ToString(),startRinse)) { avaibleSharedList.Add(sharedRinse); } } } if (avaibleSharedList.Count != 0) { var result = CalculateMetalReservoirAllBusyMetalCount(item.Module.ToString()); if (result.success) { bool transporterTransfering = CheckProcessTransporterTransfering(avaibleSharedList); if(transporterTransfering) { return result.busyCount + 1 < avaibleSharedList.Count; } else { return result.busyCount < avaibleSharedList.Count+singleRinseItems.Count; } } } return false; } /// /// 检验Process transporter正在Transfer WH移动至Rinse /// /// private bool CheckProcessTransporterTransfering(List rinseList) { TransporterEntity processTransporterEntity = Singleton.Instance.GetModule(ModuleName.Transporter1.ToString()); if(processTransporterEntity!=null) { if (processTransporterEntity.IsBusy) { string targetCell = processTransporterEntity.TargetCell; if (rinseList.Contains(targetCell)) { return true; } } } return false; } /// /// 计算Metal所在Reservoir Busy Metal数量 /// /// /// private (bool success,int busyCount) CalculateMetalReservoirAllBusyMetalCount(string metalName) { string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(metalName); if (string.IsNullOrEmpty(reservoirName)) { return (false,0); } List metals = ReservoirItemManager.Instance.GetMetalsByReservoir(reservoirName); int count = 0; foreach (string item in metals) { if (metalName == item) { continue; } MetalEntity metalEntity = Singleton.Instance.GetModule(item); if (metalEntity.IsBusy || metalEntity.WaferHolderInfo != null) { count++; } } return (true,count); } /// /// 检验独立Rinse是否可用 /// /// /// /// private bool CheckSingleRinseItemsCanUsed(List singleRinseItems, string metalName) { var result = CalculateMetalReservoirAllBusyMetalCount(metalName); if(result.success) { bool transporterTransfering = CheckProcessTransporterTransfering(singleRinseItems); if (transporterTransfering) { return result.busyCount + 1 < singleRinseItems.Count; } else { return result.busyCount < singleRinseItems.Count; } } return false; } /// /// 检验共享Rinse是否可用 /// /// /// /// private bool CheckShardRinseCanUse(string sharedRinse, string metalName,string startRinse) { string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(metalName); List shardReservoirs = CellItemManager.Instance.GetReservoirsBySharedRinse(sharedRinse); if (shardReservoirs == null || shardReservoirs.Count == 0) { return false; } foreach (string reservoir in shardReservoirs) { if (reservoir==reservoirName) { continue; } List metals=ReservoirItemManager.Instance.GetMetalsByReservoir(reservoir); int metalCount = 0; int busyMetalCount = 0; foreach(string metal in metals) { MetalEntity metalEntity = Singleton.Instance.GetModule(metal); if(metalEntity.IsAuto&&metalEntity.IsInitialized) { metalCount++; } if(metalEntity.IsBusy||metalEntity.WaferHolderInfo!=null) { busyMetalCount++; } } List reservoirRinseLst = CellItemManager.Instance.GetRinsesByReservoir(reservoir); int rinseCount = 0; int busyRinseCount = 0; foreach(string rinseItem in reservoirRinseLst) { RinseEntity rinseEntity = Singleton.Instance.GetModule(rinseItem); if(rinseEntity.IsAuto&&rinseEntity.IsInitialized) { rinseCount++; } if (rinseItem == sharedRinse) { continue; } if (rinseItem == startRinse) { continue; } if(rinseEntity.IsBusy||rinseEntity.WaferHolderInfo!=null) { busyRinseCount++; } } int resRinseCount=rinseCount- busyRinseCount; //计算剩余Rinse数量小于等于busy metal数量,则不可用 if (resRinseCount <= busyMetalCount) { return false; } } return true; } /// /// 检验模块是否可用(不包含WH) /// /// /// private bool CheckAvaibleEmptyModule(IModuleEntity item,ModuleType moduleType,string sequenceType) { if (!CheckAvaibleModule(item, moduleType, sequenceType)) { return false; } if (!ModuleHelper.IsSRD(item.Module)) { WaferHolderInfo waferHolderInfo = WaferHolderManager.Instance.GetWaferHolder(item.Module.ToString()); if (waferHolderInfo == null) { return true; } } else { if (!WaferManager.Instance.CheckHasWafer(item.Module, 0)) { return true; } } return false; } /// /// 检验模块是否可用 /// /// /// public bool CheckAvaibleModule(IModuleEntity item,ModuleType moduleType,string sequenceType) { if (item.IsDisable) { return false; } if (!item.IsAuto) { return false; } if (item.IsError) { return false; } if (item.IsInit) { return false; } if (moduleType==ModuleType.Metal) { if(item.IsProduction && sequenceType == ENGINEERING) return false; if (item.IsEngineering && sequenceType == PRODUCTION) return false; } return true; } /// /// 获取剩余时间最小的模块 /// /// /// private ModuleName GetMinTimeToReadyModule(List avaibles,ModuleType moduleType) { if (avaibles.Count == 1) { return avaibles[0].Module; } int timeToReady = int.MaxValue; IModuleEntity selectedModule = null; List idleModuleEtities = new List(); foreach (var item in avaibles) { if (item.IsIdle) { if(moduleType!=ModuleType.Metal) { return item.Module; } idleModuleEtities.Add(item); } if (item.TimeToReady < timeToReady&&idleModuleEtities.Count==0) { timeToReady = item.TimeToReady; selectedModule = item; } } if (idleModuleEtities.Count != 0) { return GetMinUsageMetal(idleModuleEtities); } if (selectedModule != null) { return selectedModule.Module; } return ModuleName.Unknown; } /// /// 获取电量最小的Metal /// /// /// private ModuleName GetMinUsageMetal(List idleModuleEntities) { double usage = double.MaxValue; ModuleName selectedModuleName = ModuleName.Unknown; foreach (var item in idleModuleEntities) { MetalEntity metalEntity= item as MetalEntity; if(metalEntity!=null) { MetalUsage metalUsage = metalEntity.MetalUsage; if (metalUsage == null) { return metalEntity.Module; } if (metalUsage.TotalUsage < usage) { usage= metalUsage.TotalUsage; selectedModuleName = metalEntity.Module; } } } return selectedModuleName; } /// /// 获取Metal可用的Rinse模块 /// /// /// private ModuleName GetMetalAvaibleRinseModule(List items, ModuleName metalName) { int metalId = CellItemManager.Instance.GetCellIdByModuleName(metalName.ToString()); if (metalId == 0) { return ModuleName.Unknown; } List rinseItems = CellItemManager.Instance.GetRinseItemsByMetal(metalName.ToString()); if (rinseItems.Count == 0) { return ModuleName.Unknown; } List avaibles = new List(); foreach (var item in items) { LayoutCellItem cellItem = rinseItems.Find(O => O.ModuleName == item.Module.ToString()); if (cellItem != null) { RinseEntity rinseEntity = (RinseEntity)item; if (rinseEntity.IsInitialized && rinseEntity.IsAuto) { avaibles.Add(rinseEntity); } } } int minInterval = int.MaxValue; IModuleEntity moduleEntity = null; foreach (var item in avaibles) { LayoutCellItem cellItem = rinseItems.Find(O => O.ModuleName == item.Module.ToString()); if (cellItem != null) { int abiasId = Math.Abs(metalId - cellItem.CellID); if (abiasId < minInterval) { minInterval = abiasId; moduleEntity = item; } } } if (moduleEntity != null) { return moduleEntity.Module; } return ModuleName.Unknown; } /// /// 检验Metal可用的Rinse模块 /// /// /// private ModuleName GetMetalAvaibleEmptyRinseModule(List items, ModuleName metalName) { int metalId = CellItemManager.Instance.GetCellIdByModuleName(metalName.ToString()); if (metalId == 0) { return ModuleName.Unknown; } List rinseItems = CellItemManager.Instance.GetRinseItemsByMetal(metalName.ToString()); if (rinseItems.Count == 0) { return ModuleName.Unknown; } List avaibles = new List(); List sharedRinseList = new List(); foreach (var item in items) { LayoutCellItem cellItem = rinseItems.Find(O => O.ModuleName == item.Module.ToString()); if (cellItem != null) { RinseEntity rinseEntity = (RinseEntity)item; if (rinseEntity.IsIdle && rinseEntity.IsAuto && rinseEntity.WaferHolderInfo == null) { avaibles.Add(rinseEntity); if(CellItemManager.Instance.CheckRinseIsShared(rinseEntity.Module.ToString())) { sharedRinseList.Add(rinseEntity.Module); } } } } int minInterval = int.MaxValue; IModuleEntity moduleEntity = null; foreach (var item in avaibles) { if (sharedRinseList.Contains(item.Module)) { continue; } LayoutCellItem cellItem = rinseItems.Find(O => O.ModuleName == item.Module.ToString()); if (cellItem != null) { int abiasId = Math.Abs(metalId - cellItem.CellID); if (abiasId < minInterval) { minInterval = abiasId; moduleEntity = item; } } } if (moduleEntity != null) { return moduleEntity.Module; } else if(sharedRinseList.Count!=0) { return sharedRinseList[0]; } return ModuleName.Unknown; } /// /// 检验Metal cell recipe时间是否可用 /// /// /// public bool CheckMetalCellRecipeTimeAvaible(IModuleEntity metalEntity,DepRecipe depRecipe) { List metalEntities=Singleton.Instance.GetModulesByModuleType(ModuleType.Metal); int maxTimeToReady = 0; foreach (MetalEntity item in metalEntities) { if (metalEntity.Module == item.Module) { continue; } if(item.IsBusy) { if(maxTimeToReady>item.TimeToReady) { maxTimeToReady = item.TimeToReady; } } } int transferOffSecond = SC.GetValue("Transporter.TransporterTransferOffSeconds"); int recipeTotalTime = depRecipe.CalculateRecipeTotalTime(); //增加了Transporter最大传输时间和最小传输时间的差值 if (recipeTotalTime>=maxTimeToReady+transferOffSecond) { return true; } return false; } /// /// 根据化学液获取可用的metal集合 /// /// /// public List GetAvaibleMetalList(string chemistry, string sequenceType, bool isEmpty) { List reservoirEntities = Singleton.Instance.GetModulesByModuleType(ModuleType.Reservoir); List avaibles = new List(); foreach (IModuleEntity item in reservoirEntities) { ReservoirEntity entity = item as ReservoirEntity; if (entity.Chemistry == chemistry && entity.IsAuto && entity.IsInitialized) { avaibles.Add(entity.Module.ToString()); } } List metals = new List(); foreach (string item in avaibles) { ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(item); if (reservoirItem == null) { continue; } foreach (MetalItem subItem in reservoirItem.MetalCells) { MetalEntity entity = Singleton.Instance.GetModule($"Metal{subItem.MetalID}"); if (!CheckAvaibleModule(entity, ModuleType.Metal, sequenceType)) { continue; } if (!isEmpty || (isEmpty && entity.WaferHolderInfo == null)) { metals.Add(entity); } } } return metals; } /// /// 获取上一个Metal /// /// /// /// public ModuleName GetPreMetalModuleName(int sequenceIndex,List sequences) { for(int i = sequenceIndex - 1; i >= 0; i--) { SchedulerSequence schedulerSequence= sequences[i]; if (schedulerSequence.ModuleType == ModuleType.Metal && ModuleHelper.IsMetal(schedulerSequence.ModuleName)) { return schedulerSequence.ModuleName; } } return ModuleName.Unknown; } } }