SchedulerSequenceManager.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. using MECF.Framework.Common.RecipeCenter;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using MECF.Framework.Common.Equipment;
  8. using MECF.Framework.Common.Schedulers;
  9. using Aitex.Core.Common;
  10. using MECF.Framework.Common.CommonData;
  11. using System.Windows;
  12. using Aitex.Core.RT.IOCore;
  13. using Aitex.Core.RT.Log;
  14. using Aitex.Core.Util;
  15. using MECF.Framework.Common.Routine;
  16. using PunkHPX8_RT.Modules;
  17. using Aitex.Core.RT.Fsm;
  18. using MECF.Framework.Common.SubstrateTrackings;
  19. using MECF.Framework.Common.ToolLayout;
  20. using MECF.Framework.RT.Core.Equipments;
  21. using MECF.Framework.Common.ProcessCell;
  22. using SecsGem.Core.ItemModel;
  23. using PunkHPX8_RT.Modules.Transporter;
  24. using PunkHPX8_Core;
  25. using Aitex.Core.RT.SCCore;
  26. using PunkHPX8_RT.Modules.SRD;
  27. using PunkHPX8_RT.Devices.EFEM;
  28. using Aitex.Sorter.Common;
  29. using PunkHPX8_RT.Modules.Reservoir;
  30. using PunkHPX8_RT.Modules.PlatingCell;
  31. namespace PunkHPX8_RT.Schedulers
  32. {
  33. public class SchedulerSequenceManager : Singleton<SchedulerSequenceManager>
  34. {
  35. #region 常量
  36. private const string ENGINEERING = "Engineering";
  37. private const string PRODUCTION = "Production";
  38. private const string TRNPA = "TRNPA";
  39. private const string TRNPB = "TRNPB";
  40. #endregion
  41. /// <summary>
  42. /// 解析Wafer所有调度工序
  43. /// </summary>
  44. /// <param name="sequenceRecipe"></param>
  45. /// <returns></returns>
  46. public List<SchedulerSequence> AnalyWaferAllSchedulerSequence(WaferInfo waferInfo, SequenceRecipe sequenceRecipe)
  47. {
  48. List<SchedulerSequence> schedulerSequences = new List<SchedulerSequence>();
  49. int index = 0;
  50. MoveItem moveItem = new MoveItem((ModuleName)waferInfo.OriginStation, waferInfo.OriginSlot, ModuleName.Aligner1, 0,
  51. Hand.Blade1,Flip.Upper,Flip.Upper);
  52. SchedulerSequence efemRobotSequence = CreateEfemRobotSequence(moveItem, null, sequenceRecipe.SubstrateSize, ref index);
  53. schedulerSequences.Add(efemRobotSequence);
  54. SchedulerSequence alignerSequence = CreateAlignerSequence(sequenceRecipe, ref index);
  55. schedulerSequences.Add(alignerSequence);
  56. //解析sequence recipe后续的工序
  57. var sequences = AnalyseSequenceRecipeScheduler(sequenceRecipe,false);
  58. if (sequences.Count == 0)
  59. {
  60. return schedulerSequences;
  61. }
  62. SchedulerSequence firstSequence = sequences[0];
  63. if (firstSequence.ModuleType != ModuleType.VPW)
  64. {
  65. return schedulerSequences;
  66. }
  67. MoveItem alignerToFirstMoveItem = new MoveItem();
  68. alignerToFirstMoveItem.SourceModule = ModuleName.Aligner1;
  69. alignerToFirstMoveItem.SourceSlot = 0;
  70. alignerToFirstMoveItem.DestinationType = firstSequence.ModuleType;
  71. alignerToFirstMoveItem.DestinationSlot = 0;
  72. alignerToFirstMoveItem.RobotHand = Hand.Blade1;
  73. alignerToFirstMoveItem.PickRobotFlip = Flip.Upper;
  74. alignerToFirstMoveItem.PlaceRobotFlip = Flip.Upper;
  75. SchedulerSequence alignerToFirstSequence = CreateEfemRobotSequence(moveItem, null, sequenceRecipe.SubstrateSize, ref index);
  76. schedulerSequences.Add(efemRobotSequence);
  77. //调整工序后面的索引
  78. foreach (SchedulerSequence item in sequences)
  79. {
  80. item.SequenceIndex = index;
  81. index++;
  82. }
  83. schedulerSequences.AddRange(sequences);
  84. //若经过srd
  85. if (SequenceRecipeManager.Instance.IsContainedSrd(sequenceRecipe))
  86. {
  87. SrdRecipe srdRecipe = SequenceRecipeManager.Instance.GetSrdRecipeBySequenceRecipe(sequenceRecipe);
  88. if (srdRecipe != null)
  89. {
  90. //从VPW取至SRD
  91. MoveItem lastToSrdItem = new MoveItem();
  92. lastToSrdItem.SourceModule = ModuleName.Unknown;
  93. //A面
  94. lastToSrdItem.SourceSlot = 0;
  95. lastToSrdItem.SourceType = ModuleType.VPW;
  96. lastToSrdItem.DestinationType = ModuleType.SRD;
  97. lastToSrdItem.SourceSlot = 0;
  98. lastToSrdItem.DestinationModule = ModuleName.Unknown;
  99. lastToSrdItem.RobotHand = Hand.Blade1;
  100. lastToSrdItem.PickRobotFlip = Flip.Upper;
  101. lastToSrdItem.PlaceRobotFlip = Flip.Upper;
  102. SchedulerSequence lastToSrdSequence = CreateEfemRobotSequence(lastToSrdItem, null,sequenceRecipe.SubstrateSize, ref index);
  103. schedulerSequences.Add(lastToSrdSequence);
  104. SchedulerSequence srdSequence = CreateSRDSequence(srdRecipe, ref index);
  105. schedulerSequences.Add(srdSequence);
  106. //SRD完成后回至LoadPort
  107. MoveItem srdToLoadPortItem = new MoveItem();
  108. srdToLoadPortItem.SourceModule = ModuleName.Unknown;
  109. srdToLoadPortItem.SourceType = ModuleType.SRD;
  110. srdToLoadPortItem.SourceSlot = 0;
  111. srdToLoadPortItem.DestinationType = ModuleType.LoadPort;
  112. srdToLoadPortItem.DestinationModule = (ModuleName)waferInfo.OriginStation;
  113. srdToLoadPortItem.DestinationSlot = waferInfo.OriginSlot;
  114. srdToLoadPortItem.RobotHand = Hand.Blade1;
  115. lastToSrdItem.PickRobotFlip = Flip.Upper;
  116. lastToSrdItem.PlaceRobotFlip = Flip.Upper;
  117. SchedulerSequence srdToLoadPortSequence = CreateEfemRobotSequence(srdToLoadPortItem, null,sequenceRecipe.SubstrateSize, ref index);
  118. schedulerSequences.Add(srdToLoadPortSequence);
  119. }
  120. else
  121. {
  122. LOG.WriteBackgroundLog(eEvent.ERR_SEQUENCE, "System", $"{sequenceRecipe.Ppid} srd recipe is invalid");
  123. return new List<SchedulerSequence>();
  124. }
  125. }
  126. else
  127. {
  128. //若无SRD,直接从VPW转LoadPort
  129. MoveItem srdToLoadPortItem = new MoveItem();
  130. srdToLoadPortItem.SourceModule = ModuleName.Unknown;
  131. srdToLoadPortItem.SourceType = ModuleType.VPW;
  132. srdToLoadPortItem.SourceSlot = 0;
  133. srdToLoadPortItem.DestinationType = ModuleType.LoadPort;
  134. srdToLoadPortItem.DestinationModule = (ModuleName)waferInfo.OriginStation;
  135. srdToLoadPortItem.DestinationSlot = waferInfo.OriginSlot;
  136. srdToLoadPortItem.RobotHand = Hand.Blade1;
  137. srdToLoadPortItem.PickRobotFlip = Flip.Upper;
  138. srdToLoadPortItem.PlaceRobotFlip = Flip.Upper;
  139. SchedulerSequence pufToLoaderSequence = CreateEfemRobotSequence(srdToLoadPortItem, null,sequenceRecipe.SubstrateSize, ref index);
  140. schedulerSequences.Add(pufToLoaderSequence);
  141. }
  142. return schedulerSequences;
  143. }
  144. /// <summary>
  145. /// 解析Dummy Wafer所有调度工序
  146. /// </summary>
  147. /// <param name="sequenceRecipe"></param>
  148. /// <returns></returns>
  149. public List<SchedulerSequence> AnalyDummyWaferAllSchedulerSequence(SequenceRecipe sequenceRecipe,WaferInfo waferInfo)
  150. {
  151. List<SchedulerSequence> schedulerSequences = new List<SchedulerSequence>();
  152. int index = 0;
  153. MoveItem moveItem = new MoveItem((ModuleName)waferInfo.OriginStation, waferInfo.OriginSlot, ModuleName.Aligner1, 0,
  154. Hand.Blade1, Flip.Upper, Flip.Upper);
  155. SchedulerSequence efemRobotSequence = CreateEfemRobotSequence(moveItem, null, sequenceRecipe.SubstrateSize, ref index);
  156. schedulerSequences.Add(efemRobotSequence);
  157. SchedulerSequence alignerSequence = CreateAlignerSequence(sequenceRecipe, ref index);
  158. schedulerSequences.Add(alignerSequence);
  159. //解析sequence recipe后续的工序
  160. var sequences = AnalyseSequenceRecipeScheduler(sequenceRecipe, false);
  161. if (sequences.Count == 0)
  162. {
  163. return schedulerSequences;
  164. }
  165. SchedulerSequence firstSequence = sequences[0];
  166. if (firstSequence.ModuleType != ModuleType.VPW)
  167. {
  168. return schedulerSequences;
  169. }
  170. SchedulerSequence lastSequence=sequences[sequences.Count - 1];
  171. MoveItem alignerToFirstMoveItem = new MoveItem();
  172. alignerToFirstMoveItem.SourceModule = ModuleName.Aligner1;
  173. alignerToFirstMoveItem.SourceSlot = 0;
  174. alignerToFirstMoveItem.DestinationType = firstSequence.ModuleType;
  175. alignerToFirstMoveItem.DestinationSlot = 0;
  176. alignerToFirstMoveItem.RobotHand = Hand.Blade1;
  177. alignerToFirstMoveItem.PickRobotFlip = Flip.Upper;
  178. alignerToFirstMoveItem.PlaceRobotFlip = Flip.Upper;
  179. SchedulerSequence alignerToFirstSequence = CreateEfemRobotSequence(moveItem, null, sequenceRecipe.SubstrateSize, ref index);
  180. schedulerSequences.Add(efemRobotSequence);
  181. //调整工序后面的索引
  182. foreach (SchedulerSequence item in sequences)
  183. {
  184. item.SequenceIndex = index;
  185. index++;
  186. }
  187. schedulerSequences.AddRange(sequences);
  188. //若无SRD,直接从VPW转LoadPort
  189. MoveItem srdToLoadPortItem = new MoveItem();
  190. srdToLoadPortItem.SourceModule = ModuleName.Unknown;
  191. srdToLoadPortItem.SourceType = lastSequence.ModuleType;
  192. srdToLoadPortItem.SourceSlot = 0;
  193. srdToLoadPortItem.DestinationType = ModuleType.Dummy;
  194. srdToLoadPortItem.DestinationModule = (ModuleName)waferInfo.OriginStation;
  195. srdToLoadPortItem.DestinationSlot = waferInfo.OriginSlot;
  196. srdToLoadPortItem.RobotHand = Hand.Blade1;
  197. srdToLoadPortItem.PickRobotFlip = Flip.Upper;
  198. srdToLoadPortItem.PlaceRobotFlip = Flip.Upper;
  199. SchedulerSequence toDummySequence = CreateEfemRobotSequence(srdToLoadPortItem, null, sequenceRecipe.SubstrateSize, ref index);
  200. schedulerSequences.Add(toDummySequence);
  201. return schedulerSequences;
  202. }
  203. /// <summary>
  204. /// 分析Sequence recipe对应的调度步骤
  205. /// </summary>
  206. /// <param name="sequenceRecipe"></param>
  207. /// <returns></returns>
  208. private List<SchedulerSequence> AnalyseSequenceRecipeScheduler(SequenceRecipe sequenceRecipe,bool isDummy)
  209. {
  210. List<SchedulerSequence> schedulerSequences= new List<SchedulerSequence>();
  211. List<SchedulerSequence> tmpLst = new List<SchedulerSequence>();
  212. var processResult = AnalyseLastProcessRecipeIndex(sequenceRecipe.Recipes);
  213. bool isExistSrd = sequenceRecipe.Recipes.FindIndex(O=>O.ToLower().EndsWith("srd.rcp"))!=-1;
  214. int lastIndex = isExistSrd ? sequenceRecipe.Recipes.Count - 2 : sequenceRecipe.Recipes.Count - 1;
  215. for(int i=0;i<sequenceRecipe.Recipes.Count;i++)
  216. {
  217. string item = sequenceRecipe.Recipes[i];
  218. if(item.ToLower().EndsWith("srd.rcp"))//跳过SRD
  219. {
  220. continue;
  221. }
  222. SchedulerSequence schedulerSequence = new SchedulerSequence();
  223. schedulerSequence.ModuleName = ModuleName.Unknown;
  224. schedulerSequence.ModuleType=SequenceRecipeManager.Instance.GetModuleType(item);
  225. schedulerSequence.SequenceIndex=i;
  226. schedulerSequence.WaferSize = sequenceRecipe.SubstrateSize;
  227. MECF.Framework.Common.RecipeCenter.RecipeType recipeType =SequenceRecipeManager.Instance.GetRecipeType(item);
  228. schedulerSequence.Recipe = SequenceRecipeManager.Instance.LoadSequenceTypeRecipe(sequenceRecipe.SequenceType,item, recipeType);
  229. schedulerSequence.SequenceType = sequenceRecipe.SequenceType;
  230. schedulerSequence.State = RState.Init;
  231. schedulerSequence.MaterialType = MaterialType.WaferHolder;
  232. tmpLst.Add(schedulerSequence);
  233. if (i != lastIndex)
  234. {
  235. string nextModule = sequenceRecipe.Recipes[i + 1];
  236. schedulerSequence.NextModuleType = SequenceRecipeManager.Instance.GetModuleType(nextModule);
  237. MECF.Framework.Common.RecipeCenter.RecipeType nextRecipeType = SequenceRecipeManager.Instance.GetRecipeType(nextModule);
  238. schedulerSequence.NextRecipe = SequenceRecipeManager.Instance.LoadSequenceTypeRecipe(sequenceRecipe.SequenceType, nextModule, nextRecipeType);
  239. }
  240. schedulerSequence.IsProcessSequece = true;
  241. if(i==processResult.lastIndex)
  242. {
  243. schedulerSequence.IsLastProcessSequence = true;
  244. }
  245. }
  246. int index = 0;
  247. for(int i=0;i<tmpLst.Count;i++)
  248. {
  249. tmpLst[i].SequenceIndex = 0;
  250. schedulerSequences.Add(tmpLst[i]);
  251. index++;
  252. if (i < tmpLst.Count - 1)
  253. {
  254. MoveItem moveItem = new MoveItem();
  255. moveItem.SourceModule = tmpLst[i].ModuleName;
  256. moveItem.SourceType = tmpLst[i].ModuleType;
  257. moveItem.SourceSlot = 0;
  258. moveItem.DestinationModule = tmpLst[i + 1].ModuleName;
  259. moveItem.DestinationSlot = 0;
  260. moveItem.DestinationType = tmpLst[i+1].ModuleType;
  261. moveItem.RobotHand = Hand.Blade2;
  262. //源来自于Plating cell,向下取
  263. if (tmpLst[i].ModuleType == ModuleType.PlatingCell)
  264. {
  265. moveItem.PickRobotFlip = Flip.Down;
  266. }
  267. else
  268. {
  269. moveItem.PickRobotFlip = Flip.Upper;
  270. }
  271. //目标来自于Plating cell,向下放
  272. if (tmpLst[i + 1].ModuleType == ModuleType.PlatingCell)
  273. {
  274. moveItem.PlaceRobotFlip = Flip.Down;
  275. }
  276. else
  277. {
  278. moveItem.PlaceRobotFlip = Flip.Upper;
  279. }
  280. SchedulerSequence robotSequence = CreateEfemRobotSequence(moveItem,null,sequenceRecipe.SubstrateSize, ref index);
  281. schedulerSequences.Add(robotSequence);
  282. }
  283. else
  284. {
  285. //生产片最后退至VPW中转
  286. if (!isDummy)
  287. {
  288. MoveItem moveItem = new MoveItem();
  289. moveItem.SourceModule = tmpLst[i].ModuleName;
  290. moveItem.SourceType = tmpLst[i].ModuleType;
  291. moveItem.SourceSlot = 0;
  292. moveItem.DestinationModule = ModuleName.Unknown;
  293. moveItem.DestinationSlot = 0;
  294. moveItem.DestinationType = ModuleType.VPW;
  295. moveItem.RobotHand = Hand.Blade2;
  296. //源来自于Plating cell,向下取
  297. if (tmpLst[i].ModuleType == ModuleType.PlatingCell)
  298. {
  299. moveItem.PickRobotFlip = Flip.Down;
  300. }
  301. else
  302. {
  303. moveItem.PickRobotFlip = Flip.Upper;
  304. }
  305. moveItem.PlaceRobotFlip = Flip.Upper;
  306. SchedulerSequence robotSequence = CreateEfemRobotSequence(moveItem, null, sequenceRecipe.SubstrateSize, ref index);
  307. schedulerSequences.Add(robotSequence);
  308. }
  309. }
  310. }
  311. return schedulerSequences;
  312. }
  313. /// <summary>
  314. /// 分析最后加工recipe索引
  315. /// </summary>
  316. /// <param name="recipes"></param>
  317. /// <returns></returns>
  318. private (int lastIndex,List<int> processIndexList) AnalyseLastProcessRecipeIndex(List<string> recipes)
  319. {
  320. int index = 0;
  321. List<int> lst = new List<int>();
  322. for(int i=0;i<recipes.Count; i++)
  323. {
  324. string item=recipes[i];
  325. if(item.ToLower().EndsWith("dep.rcp"))
  326. {
  327. index = i;
  328. if(lst.Contains(i))
  329. {
  330. lst.Add(i);
  331. }
  332. }
  333. }
  334. if(lst.Count==0)
  335. {
  336. lst.Add(0);
  337. }
  338. return (index,lst);
  339. }
  340. /// <summary>
  341. /// 创建EFEM Robot步骤
  342. /// </summary>
  343. /// <param name="index"></param>
  344. /// <returns></returns>
  345. private SchedulerSequence CreateEfemRobotSequence(MoveItem moveItem,List<SchedulerSyncModuleMessage> synModules,int waferSize,ref int index)
  346. {
  347. SchedulerSequence sequence = new SchedulerSequence();
  348. sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.EfemRobot);
  349. sequence.SequenceIndex= index;
  350. sequence.ModuleName=ModuleName.EfemRobot;
  351. sequence.State = RState.Init;
  352. sequence.Recipe = null;
  353. sequence.ModuleType=ModuleType.EfemRobot;
  354. sequence.Parameters =moveItem;
  355. sequence.MaterialType = MaterialType.Wafer;
  356. sequence.SynchronousModuleMessages = synModules;
  357. sequence.WaferSize = waferSize;
  358. index++;
  359. return sequence;
  360. }
  361. /// <summary>
  362. /// 创建Aligner步骤
  363. /// </summary>
  364. /// <param name="index"></param>
  365. /// <returns></returns>
  366. private SchedulerSequence CreateAlignerSequence(SequenceRecipe recipe,ref int index)
  367. {
  368. SchedulerSequence sequence = new SchedulerSequence();
  369. sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.Aligner1);
  370. sequence.SequenceIndex = index;
  371. sequence.ModuleName = ModuleName.Aligner1;
  372. sequence.State = RState.Init;
  373. sequence.Recipe = recipe;
  374. sequence.ModuleType = ModuleType.Aligner;
  375. sequence.Parameters = null;
  376. sequence.MaterialType = MaterialType.Wafer;
  377. sequence.WaferSize = sequence.WaferSize;
  378. index++;
  379. return sequence;
  380. }
  381. /// <summary>
  382. /// 创建Loader步骤
  383. /// </summary>
  384. /// <param name="index"></param>
  385. /// <returns></returns>
  386. private SchedulerSequence CreateSRDSequence(SrdRecipe recipe,ref int index)
  387. {
  388. SchedulerSequence sequence = new SchedulerSequence();
  389. sequence.SequenceIndex = index;
  390. sequence.State = RState.Init;
  391. sequence.Recipe = recipe;
  392. sequence.ModuleType = ModuleType.SRD;
  393. sequence.MaterialType = MaterialType.Wafer;
  394. index++;
  395. return sequence;
  396. }
  397. /// <summary>
  398. /// 根据模块类型获取可用模块
  399. /// </summary>
  400. /// <param name="moduleType"></param>
  401. /// <returns></returns>
  402. public ModuleName GetAvaibleModuleCell(string sequenceType,ModuleType moduleType)
  403. {
  404. List<IModuleEntity> entities = Singleton<RouteManager>.Instance.GetModulesByModuleType(moduleType);
  405. List<IModuleEntity> avaibles = new List<IModuleEntity>();
  406. foreach (var item in entities)
  407. {
  408. bool result = CheckAvaibleModule(item,moduleType,sequenceType);
  409. if (result)
  410. {
  411. avaibles.Add(item);
  412. }
  413. }
  414. return GetMinTimeToReadyModule(avaibles,moduleType);
  415. }
  416. /// <summary>
  417. /// 根据化学液计算时间获取可用PlatingCellCell(参考其他PlatingCell剩余时间)
  418. /// </summary>
  419. /// <param name="chemistry"></param>
  420. /// <returns></returns>
  421. public (ModuleName platingCellModule, ModuleName rinseModule) CalculateAvaiblePlatingCellCellByChemistry(string chemistry, string startRinse, string sequenceType, string waferHolderId,
  422. int waferSize,DateTime startTime, int depRecipeTimeLength, int qdrRecipeTimeLength, bool checkConflict,
  423. SchedulerModulePartTime platingCellPartTime, SchedulerModulePartTime qdrParTime, ref bool isExistEnablePlatingCell)
  424. {
  425. bool isShowLog = SC.GetValue<bool>("Scheduler.IsShowLog");
  426. if (!Enum.TryParse(startRinse, out ModuleName startRinseModule) )
  427. {
  428. startRinse = "";
  429. }
  430. isExistEnablePlatingCell = false;
  431. return (ModuleName.Unknown, ModuleName.Unknown);
  432. }
  433. /// <summary>
  434. /// 根据化学液获取可用PlatingCell
  435. /// </summary>
  436. /// <param name="chemistry"></param>
  437. /// <param name="sequenceType"></param>
  438. /// <returns></returns>
  439. public bool CalculateAvaiblePlatingCellCellByChemistry(string chemistry,string sequenceType,int waferSize)
  440. {
  441. return false;
  442. }
  443. /// <summary>
  444. /// 检验Process transporter正在Transfer WH移动至Rinse
  445. /// </summary>
  446. /// <returns></returns>
  447. private bool CheckProcessTransporterTransfering(List<string> rinseList)
  448. {
  449. return false;
  450. }
  451. /// <summary>
  452. /// 计算PlatingCell所在Reservoir Busy PlatingCell数量
  453. /// </summary>
  454. /// <param name="item"></param>
  455. /// <returns></returns>
  456. private (bool success,int busyCount) CalculatePlatingCellReservoirAllBusyPlatingCellCount(string platingCellName)
  457. {
  458. string reservoirName = ReservoirItemManager.Instance.GetReservoirByPlatingCell(platingCellName);
  459. if (string.IsNullOrEmpty(reservoirName))
  460. {
  461. return (false,0);
  462. }
  463. List<string> platingCells = ReservoirItemManager.Instance.GetPlatingCellsByReservoir(reservoirName);
  464. int count = 0;
  465. foreach (string item in platingCells)
  466. {
  467. if (platingCellName == item)
  468. {
  469. continue;
  470. }
  471. }
  472. return (true,count);
  473. }
  474. /// <summary>
  475. /// 检验独立Rinse是否可用
  476. /// </summary>
  477. /// <param name="singleRinseItems"></param>
  478. /// <param name="platingCellName"></param>
  479. /// <returns></returns>
  480. private bool CheckSingleRinseItemsCanUsed(List<string> singleRinseItems, string platingCellName)
  481. {
  482. var result = CalculatePlatingCellReservoirAllBusyPlatingCellCount(platingCellName);
  483. if(result.success)
  484. {
  485. bool transporterTransfering = CheckProcessTransporterTransfering(singleRinseItems);
  486. if (transporterTransfering)
  487. {
  488. return result.busyCount + 1 < singleRinseItems.Count;
  489. }
  490. else
  491. {
  492. return result.busyCount < singleRinseItems.Count;
  493. }
  494. }
  495. return false;
  496. }
  497. /// <summary>
  498. /// 检验可用
  499. /// </summary>
  500. /// <param name="item"></param>
  501. /// <param name="moduleType"></param>
  502. /// <param name="sequenceType"></param>
  503. /// <param name="waferHolderId"></param>
  504. /// <param name="startTime"></param>
  505. /// <param name="processLength"></param>
  506. /// <returns></returns>
  507. public bool CheckAvaiblePlatingCellModule(IModuleEntity item, ModuleType moduleType, string sequenceType, string waferHolderId, DateTime startTime, int processLength, bool checkConflict)
  508. {
  509. bool result = CheckAvaibleModule(item, moduleType, sequenceType);
  510. if (!result)
  511. {
  512. return false;
  513. }
  514. if (checkConflict)
  515. {
  516. var conflict = SchedulerPlatingCellTimeManager.Instance.CheckPlatingCellConflict(item.Module.ToString(), waferHolderId, startTime, processLength);
  517. return !conflict.conflict;
  518. }
  519. else
  520. {
  521. return result;
  522. }
  523. }
  524. /// <summary>
  525. /// 检验模块是否可用
  526. /// </summary>
  527. /// <param name="item"></param>
  528. /// <returns></returns>
  529. public bool CheckAvaibleModule(IModuleEntity item,ModuleType moduleType,string sequenceType)
  530. {
  531. if (item.IsDisable)
  532. {
  533. return false;
  534. }
  535. if (!item.IsAuto)
  536. {
  537. return false;
  538. }
  539. if (item.IsError)
  540. {
  541. return false;
  542. }
  543. if (item.IsInit)
  544. {
  545. return false;
  546. }
  547. if (moduleType==ModuleType.PlatingCell)
  548. {
  549. if(item.IsProduction && sequenceType == ENGINEERING)
  550. return false;
  551. if (item.IsEngineering && sequenceType == PRODUCTION)
  552. return false;
  553. }
  554. return true;
  555. }
  556. /// <summary>
  557. /// 获取剩余时间最小的模块
  558. /// </summary>
  559. /// <param name="avaibles"></param>
  560. /// <returns></returns>
  561. private ModuleName GetMinTimeToReadyModule(List<IModuleEntity> avaibles,ModuleType moduleType)
  562. {
  563. if (avaibles.Count == 1)
  564. {
  565. return avaibles[0].Module;
  566. }
  567. int timeToReady = int.MaxValue;
  568. IModuleEntity selectedModule = null;
  569. List<IModuleEntity> idleModuleEtities = new List<IModuleEntity>();
  570. foreach (var item in avaibles)
  571. {
  572. if (item.IsIdle)
  573. {
  574. if(moduleType!=ModuleType.PlatingCell)
  575. {
  576. return item.Module;
  577. }
  578. idleModuleEtities.Add(item);
  579. }
  580. if (item.TimeToReady < timeToReady&&idleModuleEtities.Count==0)
  581. {
  582. timeToReady = item.TimeToReady;
  583. selectedModule = item;
  584. }
  585. }
  586. if (idleModuleEtities.Count != 0)
  587. {
  588. return GetMinUsagePlatingCell(idleModuleEtities);
  589. }
  590. if (selectedModule != null)
  591. {
  592. return selectedModule.Module;
  593. }
  594. return ModuleName.Unknown;
  595. }
  596. /// <summary>
  597. /// 获取电量最小的PlatingCell
  598. /// </summary>
  599. /// <param name="idleModuleEntities"></param>
  600. /// <returns></returns>
  601. private ModuleName GetMinUsagePlatingCell(List<IModuleEntity> idleModuleEntities, int depProcessLength, SchedulerModulePartTime platingCellPartTime)
  602. {
  603. ModuleName selectedModuleName = ModuleName.Unknown;
  604. List<string> minDateModuleLst = new List<string>();
  605. return selectedModuleName;
  606. }
  607. /// <summary>
  608. /// 获取电量最小的PlatingCell
  609. /// </summary>
  610. /// <param name="idleModuleEntities"></param>
  611. /// <returns></returns>
  612. private ModuleName GetMinUsagePlatingCell(List<IModuleEntity> idleModuleEntities)
  613. {
  614. ModuleName selectedModuleName = ModuleName.Unknown;
  615. return selectedModuleName;
  616. }
  617. /// <summary>
  618. /// 获取PlatingCell可用的Rinse模块
  619. /// </summary>
  620. /// <param name="platingCellName"></param>
  621. /// <returns></returns>
  622. private ModuleName GetPlatingCellAvaibleRinseModule(List<IModuleEntity> items, ModuleName platingCellName)
  623. {
  624. int platingCellId = CellItemManager.Instance.GetCellIdByModuleName(platingCellName.ToString());
  625. if (platingCellId == 0)
  626. {
  627. return ModuleName.Unknown;
  628. }
  629. List<LayoutCellItem> rinseItems = CellItemManager.Instance.GetRinseItemsByPlatingCell(platingCellName.ToString());
  630. if (rinseItems.Count == 0)
  631. {
  632. return ModuleName.Unknown;
  633. }
  634. return ModuleName.Unknown;
  635. }
  636. /// <summary>
  637. /// 根据化学液获取可用的PlatingCell集合
  638. /// </summary>
  639. /// <param name="chemistry"></param>
  640. /// <returns></returns>
  641. public List<PlatingCellEntity> GetAvaiblePlatingCellList(string chemistry, string sequenceType, bool isEmpty)
  642. {
  643. List<IModuleEntity> reservoirEntities = Singleton<RouteManager>.Instance.GetModulesByModuleType(ModuleType.Reservoir);
  644. List<string> avaibles = new List<string>();
  645. foreach (IModuleEntity item in reservoirEntities)
  646. {
  647. ReservoirEntity entity = item as ReservoirEntity;
  648. if (entity.Chemistry == chemistry && entity.IsAuto && entity.IsInitialized)
  649. {
  650. avaibles.Add(entity.Module.ToString());
  651. }
  652. }
  653. List<PlatingCellEntity> metals = new List<PlatingCellEntity>();
  654. foreach (string item in avaibles)
  655. {
  656. ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(item);
  657. if (reservoirItem == null)
  658. {
  659. continue;
  660. }
  661. foreach (PlatingCellItem subItem in reservoirItem.PlatingCells)
  662. {
  663. PlatingCellEntity entity = Singleton<RouteManager>.Instance.GetModule<PlatingCellEntity>($"PlatingCell{subItem.PlatingCellID}");
  664. if (!CheckAvaibleModule(entity, ModuleType.PlatingCell, sequenceType))
  665. {
  666. continue;
  667. }
  668. if (!isEmpty || (isEmpty && entity.WaferInfo == null))
  669. {
  670. metals.Add(entity);
  671. }
  672. }
  673. }
  674. return metals;
  675. }
  676. }
  677. }