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.CommonData; using System.Windows; using Aitex.Core.RT.IOCore; using Aitex.Core.RT.Log; using Aitex.Core.Util; using MECF.Framework.Common.Routine; using PunkHPX8_RT.Modules; using Aitex.Core.RT.Fsm; using PunkHPX8_RT.Modules.Dummy; using MECF.Framework.Common.SubstrateTrackings; using MECF.Framework.Common.ToolLayout; using MECF.Framework.RT.Core.Equipments; using MECF.Framework.Common.ProcessCell; using SecsGem.Core.ItemModel; using PunkHPX8_RT.Modules.Transporter; using PunkHPX8_Core; using Aitex.Core.RT.SCCore; using PunkHPX8_RT.Modules.SRD; using PunkHPX8_RT.Devices.EFEM; namespace PunkHPX8_RT.Schedulers { public class SchedulerSequenceManager : Singleton { #region 常量 private const string ENGINEERING = "Engineering"; private const string PRODUCTION = "Production"; private const string TRNPA = "TRNPA"; private const string TRNPB = "TRNPB"; #endregion /// /// 解析LoaderTransporter放至Loader第一次确定TRNP的方向 /// /// /// /// private string AnalyseLoadTransporterSide(SequenceRecipe sequenceRecipe,int productWaferCount,int dummyWaferCount) { //单片,同时loader两边尺寸不一致 if ((productWaferCount == 1||dummyWaferCount==1) ) { //recipe使用B面工艺,但loader A面与recipe尺寸一致 if (sequenceRecipe.LastSingleWaferToSideB ) { return "TRNPB"; } //recipe使用A面工艺,但loader B面与recipe尺寸一致 else if (!sequenceRecipe.LastSingleWaferToSideB) { return "TRNPB"; } } return "TRNPA"; } private string GetReverseTransporterLocation(string strTrn) { return strTrn == TRNPA ? TRNPB : TRNPA; } /// /// 检验Loader两边waferSize不一致 /// /// private bool CheckLoaderWaferSizeNotEqual() { return false; } /// /// 创建LoaderTrasporter同步模块消息 /// /// /// private List GenerateLoaderTransporterSyncModuleMessage(string tranporter) { List synModules = new List(); SchedulerSyncModuleMessage syncModuleMessage = new SchedulerSyncModuleMessage(); syncModuleMessage.ModuleEntity = Singleton.Instance.GetModule(ModuleName.Loader1.ToString()); syncModuleMessage.parameters = new object[] { tranporter }; synModules.Add(syncModuleMessage); return synModules; } /// /// 解析Dummy Wafer所有调度工序 /// /// /// public List AnalyDummyWaferAllSchedulerSequence(SequenceRecipe sequenceRecipe,WaferInfo waferInfo, ModuleName pufModule,string side) { waferInfo.LoaderSide = side; 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,sequenceRecipe.SubstrateSize, ref index); schedulerSequences.Add(secondEfemRobotSequence); //Aligner SchedulerSequence alignerSequence = alignerSequence=CreateAlignerSequence(sequenceRecipe, 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,sequenceRecipe.SubstrateSize, ref index); schedulerSequences.Add(alignerToPufEfemRobotSequence); SchedulerSequence pufSequence = CreatePufSequence(pufModule,sequenceRecipe, side,true, ref index); schedulerSequences.Add(pufSequence); return schedulerSequences; } /// /// 分析Sequence recipe对应的调度步骤 /// /// /// private List AnalyseSequenceRecipeScheduler(SequenceRecipe sequenceRecipe) { 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,int waferSize,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; sequence.WaferSize = waferSize; index++; return sequence; } /// /// 创建Aligner步骤 /// /// /// private SchedulerSequence CreateAlignerSequence(SequenceRecipe recipe,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 = recipe; sequence.ModuleType = ModuleType.Aligner; sequence.Parameters = null; sequence.MaterialType = MaterialType.Wafer; sequence.WaferSize = sequence.WaferSize; index++; return sequence; } /// /// 创建PUF步骤 /// /// /// /// private SchedulerSequence CreatePufSequence(ModuleName pufModuleName,SequenceRecipe sequenceRecipe,string side,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 = null; sequence.IsWaitNotify = !forward; sequence.ModuleType = ModuleType.PUF; sequence.MaterialType = MaterialType.Wafer; sequence.WaferSize = sequenceRecipe.SubstrateSize; 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; } /// /// 获取可用Dummy slot /// /// /// public (ModuleName moduleName, int slot) GetAvaibleDummySlots(WaferSize waferSize) { if (ModuleHelper.IsInstalled(ModuleName.Dummy1)) { DummyEntity dummyEntity = Singleton.Instance.GetModule(ModuleName.Dummy1.ToString()); DummyDevice dummyDevice = Singleton.Instance.EFEM.GetDummyDevice(0); if (dummyDevice != null && dummyDevice.HasCassette && dummyDevice.WaferSize == waferSize) { for (int i = 0; i < dummyEntity.MaxSlotNumber; i++) { if (WaferManager.Instance.CheckNoWafer(ModuleName.Dummy1, i)) { return (ModuleName.Dummy1, i); } } } } if (ModuleHelper.IsInstalled(ModuleName.Dummy2)) { DummyEntity dummyEntity = Singleton.Instance.GetModule(ModuleName.Dummy2.ToString()); DummyDevice dummyDevice = Singleton.Instance.EFEM.GetDummyDevice(1); if (dummyDevice != null && dummyDevice.HasCassette && dummyDevice.WaferSize == waferSize) { 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); } } /// /// 获取可用的Dryer cell /// /// /// /// /// public ModuleName GetAvaibleDryerCell(string waferHolderId, DateTime startTime, int dryerTimeLength, bool checkConflict) { List entities = Singleton.Instance.GetModulesByModuleType(ModuleType.Dryer); List avaibleEntities = new List(); foreach (IModuleEntity item in entities) { if ((item.IsIdle || item.IsBusy) && item.IsAuto) { avaibleEntities.Add(item); } } if (checkConflict) { List resets = SchedulerDryerTimeManager.Instance.ResetModuleOrderByUsed(avaibleEntities); List avaibles = new List(); foreach (var item in resets) { var conflict = SchedulerDryerTimeManager.Instance.CheckDryerConflict(item.ToString(), waferHolderId, startTime, dryerTimeLength); if (!conflict.conflict) { return item; } } } else { List resets = SchedulerDryerTimeManager.Instance.ResetModuleOrderBySchedulerEndTime(avaibleEntities); if (resets.Count != 0) { return resets[0]; } } return ModuleName.Unknown; } /// /// 获取可用的Dryer cell /// /// /// /// /// public ModuleName GetAvaibleQdrCell(string waferHolderId, string metalName) { List rinseItems = CellItemManager.Instance.GetRinseItemsByMetal(metalName.ToString()); if (rinseItems.Count == 0) { return ModuleName.Unknown; } List entities = Singleton.Instance.GetModulesByModuleType(ModuleType.Rinse); List avaibles = new List(); foreach (var item in entities) { LayoutCellItem cellItem = rinseItems.Find(O => O.ModuleName == item.Module.ToString()); if (cellItem != null) { } } List resets = SchedulerQdrTimeManager.Instance.ResetModuleOrderBySchedulerEndTime(avaibles); if (resets.Count != 0) { return resets[0]; } return ModuleName.Unknown; } /// /// 根据化学液计算时间获取可用MetalCell(参考其他Metal剩余时间) /// /// /// public ModuleName CalculateAvaibleMetalCellByChemistry(string chemistry,string startRinse,string sequenceType,int waferSize,ref bool isExistEnableMetal) { if(!Enum.TryParse(startRinse,out ModuleName startRinseModule)||!ModuleHelper.IsRinse(startRinseModule)) { startRinse = ""; } isExistEnableMetal = false; return ModuleName.Unknown; } /// /// 根据化学液计算时间获取可用MetalCell(参考其他Metal剩余时间) /// /// /// public (ModuleName metalModule, ModuleName rinseModule) CalculateAvaibleMetalCellByChemistry(string chemistry, string startRinse, string sequenceType, string waferHolderId, int waferSize,DateTime startTime, int depRecipeTimeLength, int qdrRecipeTimeLength, bool checkConflict, SchedulerModulePartTime metalPartTime, SchedulerModulePartTime qdrParTime, ref bool isExistEnableMetal) { bool isShowLog = SC.GetValue("Scheduler.IsShowLog"); if (!Enum.TryParse(startRinse, out ModuleName startRinseModule) || !ModuleHelper.IsRinse(startRinseModule)) { startRinse = ""; } isExistEnableMetal = false; return (ModuleName.Unknown, ModuleName.Unknown); } /// /// 根据化学液获取可用Metal /// /// /// /// public bool CalculateAvaibleMetalCellByChemistry(string chemistry,string sequenceType,int waferSize) { return false; } /// /// 检验Process transporter正在Transfer WH移动至Rinse /// /// private bool CheckProcessTransporterTransfering(List rinseList) { 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; } } 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; } } return true; } /// /// 检验可用 /// /// /// /// /// /// /// /// public bool CheckAvaibleMetalModule(IModuleEntity item, ModuleType moduleType, string sequenceType, string waferHolderId, DateTime startTime, int processLength, bool checkConflict) { bool result = CheckAvaibleModule(item, moduleType, sequenceType); if (!result) { return false; } if (checkConflict) { var conflict = SchedulerMetalTimeManager.Instance.CheckMetalConflict(item.Module.ToString(), waferHolderId, startTime, processLength); return !conflict.conflict; } else { return result; } } /// /// 检验模块是否可用 /// /// /// 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, int depProcessLength, SchedulerModulePartTime metalPartTime) { ModuleName selectedModuleName = ModuleName.Unknown; List minDateModuleLst = new List(); return selectedModuleName; } /// /// 获取电量最小的Metal /// /// /// private ModuleName GetMinUsageMetal(List idleModuleEntities) { ModuleName selectedModuleName = ModuleName.Unknown; 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; } 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; } return ModuleName.Unknown; } /// /// 获取上一个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; } } }