SchedulerSequenceManager.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  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,ModuleName vpw, 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. MoveItem alignerToMoveItem = new MoveItem(ModuleName.Aligner1, 0, vpw, 0,Hand.Blade1, Flip.Upper, Flip.Upper);
  57. SchedulerSequence alignerRobotSequence = CreateEfemRobotSequence(alignerToMoveItem, null, sequenceRecipe.SubstrateSize, ref index);
  58. schedulerSequences.Add(alignerRobotSequence);
  59. //解析sequence recipe后续的工序
  60. var sequences = AnalyseSequenceRecipeScheduler(sequenceRecipe,false);
  61. if (sequences.Count == 0)
  62. {
  63. return schedulerSequences;
  64. }
  65. SchedulerSequence firstSequence = sequences[0];
  66. if (firstSequence.ModuleType != ModuleType.VPW)
  67. {
  68. return schedulerSequences;
  69. }
  70. firstSequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(vpw);
  71. firstSequence.ModuleName = vpw;
  72. //调整工序后面的索引
  73. foreach (SchedulerSequence item in sequences)
  74. {
  75. item.SequenceIndex = index;
  76. index++;
  77. }
  78. schedulerSequences.AddRange(sequences);
  79. //若经过srd
  80. if (SequenceRecipeManager.Instance.IsContainedSrd(sequenceRecipe))
  81. {
  82. SrdRecipe srdRecipe = SequenceRecipeManager.Instance.GetSrdRecipeBySequenceRecipe(sequenceRecipe);
  83. if (srdRecipe != null)
  84. {
  85. //从VPW取至SRD
  86. MoveItem lastToSrdItem = new MoveItem();
  87. lastToSrdItem.SourceModule = ModuleName.Unknown;
  88. //A面
  89. lastToSrdItem.SourceSlot = 0;
  90. lastToSrdItem.SourceType = ModuleType.VPW;
  91. lastToSrdItem.DestinationType = ModuleType.SRD;
  92. lastToSrdItem.SourceSlot = 0;
  93. lastToSrdItem.DestinationModule = ModuleName.Unknown;
  94. lastToSrdItem.RobotHand = Hand.Blade1;
  95. lastToSrdItem.PickRobotFlip = Flip.Upper;
  96. lastToSrdItem.PlaceRobotFlip = Flip.Upper;
  97. SchedulerSequence lastToSrdSequence = CreateEfemRobotSequence(lastToSrdItem, null,sequenceRecipe.SubstrateSize, ref index);
  98. schedulerSequences.Add(lastToSrdSequence);
  99. SchedulerSequence srdSequence = CreateSRDSequence(srdRecipe, ref index);
  100. schedulerSequences.Add(srdSequence);
  101. //SRD完成后回至LoadPort
  102. MoveItem srdToLoadPortItem = new MoveItem();
  103. srdToLoadPortItem.SourceModule = ModuleName.Unknown;
  104. srdToLoadPortItem.SourceType = ModuleType.SRD;
  105. srdToLoadPortItem.SourceSlot = 0;
  106. srdToLoadPortItem.DestinationType = ModuleType.LoadPort;
  107. srdToLoadPortItem.DestinationModule = (ModuleName)waferInfo.OriginStation;
  108. srdToLoadPortItem.DestinationSlot = waferInfo.OriginSlot;
  109. srdToLoadPortItem.RobotHand = Hand.Blade1;
  110. lastToSrdItem.PickRobotFlip = Flip.Upper;
  111. lastToSrdItem.PlaceRobotFlip = Flip.Upper;
  112. SchedulerSequence srdToLoadPortSequence = CreateEfemRobotSequence(srdToLoadPortItem, null,sequenceRecipe.SubstrateSize, ref index);
  113. schedulerSequences.Add(srdToLoadPortSequence);
  114. }
  115. else
  116. {
  117. LOG.WriteBackgroundLog(eEvent.ERR_SEQUENCE, "System", $"{sequenceRecipe.Ppid} srd recipe is invalid");
  118. return new List<SchedulerSequence>();
  119. }
  120. }
  121. else
  122. {
  123. //若无SRD,直接从VPW转LoadPort
  124. MoveItem srdToLoadPortItem = new MoveItem();
  125. srdToLoadPortItem.SourceModule = ModuleName.Unknown;
  126. srdToLoadPortItem.SourceType = ModuleType.VPW;
  127. srdToLoadPortItem.SourceSlot = 0;
  128. srdToLoadPortItem.DestinationType = ModuleType.LoadPort;
  129. srdToLoadPortItem.DestinationModule = (ModuleName)waferInfo.OriginStation;
  130. srdToLoadPortItem.DestinationSlot = waferInfo.OriginSlot;
  131. srdToLoadPortItem.RobotHand = Hand.Blade1;
  132. srdToLoadPortItem.PickRobotFlip = Flip.Upper;
  133. srdToLoadPortItem.PlaceRobotFlip = Flip.Upper;
  134. SchedulerSequence pufToLoaderSequence = CreateEfemRobotSequence(srdToLoadPortItem, null,sequenceRecipe.SubstrateSize, ref index);
  135. schedulerSequences.Add(pufToLoaderSequence);
  136. }
  137. return schedulerSequences;
  138. }
  139. /// <summary>
  140. /// 解析Dummy Wafer所有调度工序
  141. /// </summary>
  142. /// <param name="sequenceRecipe"></param>
  143. /// <returns></returns>
  144. public List<SchedulerSequence> AnalyDummyWaferAllSchedulerSequence(SequenceRecipe sequenceRecipe,WaferInfo waferInfo)
  145. {
  146. List<SchedulerSequence> schedulerSequences = new List<SchedulerSequence>();
  147. int index = 0;
  148. MoveItem moveItem = new MoveItem((ModuleName)waferInfo.OriginStation, waferInfo.OriginSlot, ModuleName.Aligner1, 0,
  149. Hand.Blade1, Flip.Upper, Flip.Upper);
  150. SchedulerSequence efemRobotSequence = CreateEfemRobotSequence(moveItem, null, sequenceRecipe.SubstrateSize, ref index);
  151. schedulerSequences.Add(efemRobotSequence);
  152. SchedulerSequence alignerSequence = CreateAlignerSequence(sequenceRecipe, ref index);
  153. schedulerSequences.Add(alignerSequence);
  154. //解析sequence recipe后续的工序
  155. var sequences = AnalyseSequenceRecipeScheduler(sequenceRecipe, false);
  156. if (sequences.Count == 0)
  157. {
  158. return schedulerSequences;
  159. }
  160. SchedulerSequence firstSequence = sequences[0];
  161. if (firstSequence.ModuleType != ModuleType.VPW)
  162. {
  163. return schedulerSequences;
  164. }
  165. SchedulerSequence lastSequence=sequences[sequences.Count - 1];
  166. MoveItem alignerToFirstMoveItem = new MoveItem();
  167. alignerToFirstMoveItem.SourceModule = ModuleName.Aligner1;
  168. alignerToFirstMoveItem.SourceSlot = 0;
  169. alignerToFirstMoveItem.DestinationType = firstSequence.ModuleType;
  170. alignerToFirstMoveItem.DestinationSlot = 0;
  171. alignerToFirstMoveItem.RobotHand = Hand.Blade1;
  172. alignerToFirstMoveItem.PickRobotFlip = Flip.Upper;
  173. alignerToFirstMoveItem.PlaceRobotFlip = Flip.Upper;
  174. SchedulerSequence alignerToFirstSequence = CreateEfemRobotSequence(moveItem, null, sequenceRecipe.SubstrateSize, ref index);
  175. schedulerSequences.Add(efemRobotSequence);
  176. //调整工序后面的索引
  177. foreach (SchedulerSequence item in sequences)
  178. {
  179. item.SequenceIndex = index;
  180. index++;
  181. }
  182. schedulerSequences.AddRange(sequences);
  183. //若无SRD,直接从VPW转LoadPort
  184. MoveItem srdToLoadPortItem = new MoveItem();
  185. srdToLoadPortItem.SourceModule = ModuleName.Unknown;
  186. srdToLoadPortItem.SourceType = lastSequence.ModuleType;
  187. srdToLoadPortItem.SourceSlot = 0;
  188. srdToLoadPortItem.DestinationType = ModuleType.Dummy;
  189. srdToLoadPortItem.DestinationModule = (ModuleName)waferInfo.OriginStation;
  190. srdToLoadPortItem.DestinationSlot = waferInfo.OriginSlot;
  191. srdToLoadPortItem.RobotHand = Hand.Blade1;
  192. srdToLoadPortItem.PickRobotFlip = Flip.Upper;
  193. srdToLoadPortItem.PlaceRobotFlip = Flip.Upper;
  194. SchedulerSequence toDummySequence = CreateEfemRobotSequence(srdToLoadPortItem, null, sequenceRecipe.SubstrateSize, ref index);
  195. schedulerSequences.Add(toDummySequence);
  196. return schedulerSequences;
  197. }
  198. /// <summary>
  199. /// 分析Sequence recipe对应的调度步骤
  200. /// </summary>
  201. /// <param name="sequenceRecipe"></param>
  202. /// <returns></returns>
  203. private List<SchedulerSequence> AnalyseSequenceRecipeScheduler(SequenceRecipe sequenceRecipe,bool isDummy)
  204. {
  205. List<SchedulerSequence> schedulerSequences= new List<SchedulerSequence>();
  206. List<SchedulerSequence> tmpLst = new List<SchedulerSequence>();
  207. var processResult = AnalyseLastProcessRecipeIndex(sequenceRecipe.Recipes);
  208. bool isExistSrd = sequenceRecipe.Recipes.FindIndex(O=>O.ToLower().EndsWith("srd.rcp"))!=-1;
  209. int lastIndex = isExistSrd ? sequenceRecipe.Recipes.Count - 2 : sequenceRecipe.Recipes.Count - 1;
  210. for(int i=0;i<sequenceRecipe.Recipes.Count;i++)
  211. {
  212. string item = sequenceRecipe.Recipes[i];
  213. if(item.ToLower().EndsWith("srd.rcp"))//跳过SRD
  214. {
  215. continue;
  216. }
  217. SchedulerSequence schedulerSequence = new SchedulerSequence();
  218. schedulerSequence.ModuleName = ModuleName.Unknown;
  219. schedulerSequence.ModuleType=SequenceRecipeManager.Instance.GetModuleType(item);
  220. schedulerSequence.SequenceIndex=i;
  221. schedulerSequence.WaferSize = sequenceRecipe.SubstrateSize;
  222. MECF.Framework.Common.RecipeCenter.RecipeType recipeType =SequenceRecipeManager.Instance.GetRecipeType(item);
  223. schedulerSequence.Recipe = SequenceRecipeManager.Instance.LoadSequenceTypeRecipe(sequenceRecipe.SequenceType,item, recipeType);
  224. schedulerSequence.SequenceType = sequenceRecipe.SequenceType;
  225. schedulerSequence.State = RState.Init;
  226. schedulerSequence.MaterialType = MaterialType.Wafer;
  227. tmpLst.Add(schedulerSequence);
  228. if (i != lastIndex)
  229. {
  230. string nextModule = sequenceRecipe.Recipes[i + 1];
  231. schedulerSequence.NextModuleType = SequenceRecipeManager.Instance.GetModuleType(nextModule);
  232. MECF.Framework.Common.RecipeCenter.RecipeType nextRecipeType = SequenceRecipeManager.Instance.GetRecipeType(nextModule);
  233. schedulerSequence.NextRecipe = SequenceRecipeManager.Instance.LoadSequenceTypeRecipe(sequenceRecipe.SequenceType, nextModule, nextRecipeType);
  234. }
  235. schedulerSequence.IsProcessSequece = true;
  236. if(i==processResult.lastIndex)
  237. {
  238. schedulerSequence.IsLastProcessSequence = true;
  239. }
  240. }
  241. int index = 0;
  242. for(int i=0;i<tmpLst.Count;i++)
  243. {
  244. tmpLst[i].SequenceIndex = 0;
  245. schedulerSequences.Add(tmpLst[i]);
  246. index++;
  247. if (i < tmpLst.Count - 1)
  248. {
  249. MoveItem moveItem = new MoveItem();
  250. moveItem.SourceModule = tmpLst[i].ModuleName;
  251. moveItem.SourceType = tmpLst[i].ModuleType;
  252. moveItem.SourceSlot = 0;
  253. moveItem.DestinationModule = tmpLst[i + 1].ModuleName;
  254. moveItem.DestinationSlot = 0;
  255. moveItem.DestinationType = tmpLst[i+1].ModuleType;
  256. moveItem.RobotHand = Hand.Blade2;
  257. //源来自于Plating cell,向下取
  258. if (tmpLst[i].ModuleType == ModuleType.PlatingCell)
  259. {
  260. moveItem.PickRobotFlip = Flip.Down;
  261. }
  262. else
  263. {
  264. moveItem.PickRobotFlip = Flip.Upper;
  265. }
  266. //目标来自于Plating cell,向下放
  267. if (tmpLst[i + 1].ModuleType == ModuleType.PlatingCell)
  268. {
  269. moveItem.PlaceRobotFlip = Flip.Down;
  270. }
  271. else
  272. {
  273. moveItem.PlaceRobotFlip = Flip.Upper;
  274. }
  275. SchedulerSequence robotSequence = CreateEfemRobotSequence(moveItem,null,sequenceRecipe.SubstrateSize, ref index);
  276. schedulerSequences.Add(robotSequence);
  277. }
  278. else
  279. {
  280. //生产片最后退至VPW中转
  281. if (!isDummy)
  282. {
  283. MoveItem moveItem = new MoveItem();
  284. moveItem.SourceModule = tmpLst[i].ModuleName;
  285. moveItem.SourceType = tmpLst[i].ModuleType;
  286. moveItem.SourceSlot = 0;
  287. moveItem.DestinationModule = ModuleName.Unknown;
  288. moveItem.DestinationSlot = 0;
  289. moveItem.DestinationType = ModuleType.VPW;
  290. moveItem.RobotHand = Hand.Blade2;
  291. //源来自于Plating cell,向下取
  292. if (tmpLst[i].ModuleType == ModuleType.PlatingCell)
  293. {
  294. moveItem.PickRobotFlip = Flip.Down;
  295. }
  296. else
  297. {
  298. moveItem.PickRobotFlip = Flip.Upper;
  299. }
  300. moveItem.PlaceRobotFlip = Flip.Upper;
  301. SchedulerSequence robotSequence = CreateEfemRobotSequence(moveItem, null, sequenceRecipe.SubstrateSize, ref index);
  302. schedulerSequences.Add(robotSequence);
  303. }
  304. }
  305. }
  306. return schedulerSequences;
  307. }
  308. /// <summary>
  309. /// 分析最后加工recipe索引
  310. /// </summary>
  311. /// <param name="recipes"></param>
  312. /// <returns></returns>
  313. private (int lastIndex,List<int> processIndexList) AnalyseLastProcessRecipeIndex(List<string> recipes)
  314. {
  315. int index = 0;
  316. List<int> lst = new List<int>();
  317. for(int i=0;i<recipes.Count; i++)
  318. {
  319. string item=recipes[i];
  320. if(item.ToLower().EndsWith("dep.rcp"))
  321. {
  322. index = i;
  323. if(lst.Contains(i))
  324. {
  325. lst.Add(i);
  326. }
  327. }
  328. }
  329. if(lst.Count==0)
  330. {
  331. lst.Add(0);
  332. }
  333. return (index,lst);
  334. }
  335. /// <summary>
  336. /// 创建EFEM Robot步骤
  337. /// </summary>
  338. /// <param name="index"></param>
  339. /// <returns></returns>
  340. private SchedulerSequence CreateEfemRobotSequence(MoveItem moveItem,List<SchedulerSyncModuleMessage> synModules,int waferSize,ref int index)
  341. {
  342. SchedulerSequence sequence = new SchedulerSequence();
  343. sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.EfemRobot);
  344. sequence.SequenceIndex= index;
  345. sequence.ModuleName=ModuleName.EfemRobot;
  346. sequence.State = RState.Init;
  347. sequence.Recipe = null;
  348. sequence.ModuleType=ModuleType.EfemRobot;
  349. sequence.Parameters =moveItem;
  350. sequence.MaterialType = MaterialType.Wafer;
  351. sequence.SynchronousModuleMessages = synModules;
  352. sequence.WaferSize = waferSize;
  353. index++;
  354. return sequence;
  355. }
  356. /// <summary>
  357. /// 创建Aligner步骤
  358. /// </summary>
  359. /// <param name="index"></param>
  360. /// <returns></returns>
  361. private SchedulerSequence CreateAlignerSequence(SequenceRecipe recipe,ref int index)
  362. {
  363. SchedulerSequence sequence = new SchedulerSequence();
  364. sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.Aligner1);
  365. sequence.SequenceIndex = index;
  366. sequence.ModuleName = ModuleName.Aligner1;
  367. sequence.State = RState.Init;
  368. sequence.Recipe = recipe;
  369. sequence.ModuleType = ModuleType.Aligner;
  370. sequence.Parameters = null;
  371. sequence.MaterialType = MaterialType.Wafer;
  372. sequence.WaferSize = sequence.WaferSize;
  373. index++;
  374. return sequence;
  375. }
  376. /// <summary>
  377. /// 创建Loader步骤
  378. /// </summary>
  379. /// <param name="index"></param>
  380. /// <returns></returns>
  381. private SchedulerSequence CreateSRDSequence(SrdRecipe recipe,ref int index)
  382. {
  383. SchedulerSequence sequence = new SchedulerSequence();
  384. sequence.SequenceIndex = index;
  385. sequence.State = RState.Init;
  386. sequence.Recipe = recipe;
  387. sequence.ModuleType = ModuleType.SRD;
  388. sequence.MaterialType = MaterialType.Wafer;
  389. index++;
  390. return sequence;
  391. }
  392. /// <summary>
  393. /// 根据模块类型获取可用模块
  394. /// </summary>
  395. /// <param name="moduleType"></param>
  396. /// <returns></returns>
  397. public ModuleName GetAvaibleModuleCell(string sequenceType,ModuleType moduleType)
  398. {
  399. List<IModuleEntity> entities = Singleton<RouteManager>.Instance.GetModulesByModuleType(moduleType);
  400. List<IModuleEntity> avaibles = new List<IModuleEntity>();
  401. foreach (var item in entities)
  402. {
  403. bool result = CheckAvaibleModule(item,moduleType,sequenceType);
  404. if (result)
  405. {
  406. avaibles.Add(item);
  407. }
  408. }
  409. return GetMinTimeToReadyModule(avaibles,moduleType);
  410. }
  411. /// <summary>
  412. /// 根据化学液计算时间获取可用PlatingCellCell(参考其他PlatingCell剩余时间)
  413. /// </summary>
  414. /// <param name="chemistry"></param>
  415. /// <returns></returns>
  416. public (ModuleName platingCellModule, ModuleName rinseModule) CalculateAvaiblePlatingCellCellByChemistry(string chemistry, string startRinse, string sequenceType, string waferHolderId,
  417. int waferSize,DateTime startTime, int depRecipeTimeLength, int qdrRecipeTimeLength, bool checkConflict,
  418. SchedulerModulePartTime platingCellPartTime, SchedulerModulePartTime qdrParTime, ref bool isExistEnablePlatingCell)
  419. {
  420. bool isShowLog = SC.GetValue<bool>("Scheduler.IsShowLog");
  421. if (!Enum.TryParse(startRinse, out ModuleName startRinseModule) )
  422. {
  423. startRinse = "";
  424. }
  425. isExistEnablePlatingCell = false;
  426. return (ModuleName.Unknown, ModuleName.Unknown);
  427. }
  428. /// <summary>
  429. /// 检验模块是否可用
  430. /// </summary>
  431. /// <param name="item"></param>
  432. /// <returns></returns>
  433. public bool CheckAvaibleModule(IModuleEntity item,ModuleType moduleType,string sequenceType)
  434. {
  435. if (item.IsDisable)
  436. {
  437. return false;
  438. }
  439. if (!item.IsAuto)
  440. {
  441. return false;
  442. }
  443. if (item.IsError)
  444. {
  445. return false;
  446. }
  447. if (item.IsInit)
  448. {
  449. return false;
  450. }
  451. if (moduleType==ModuleType.PlatingCell)
  452. {
  453. if(item.IsProduction && sequenceType == ENGINEERING)
  454. return false;
  455. if (item.IsEngineering && sequenceType == PRODUCTION)
  456. return false;
  457. }
  458. return true;
  459. }
  460. /// <summary>
  461. /// 获取剩余时间最小的模块
  462. /// </summary>
  463. /// <param name="avaibles"></param>
  464. /// <returns></returns>
  465. private ModuleName GetMinTimeToReadyModule(List<IModuleEntity> avaibles,ModuleType moduleType)
  466. {
  467. if (avaibles.Count == 1)
  468. {
  469. return avaibles[0].Module;
  470. }
  471. int timeToReady = int.MaxValue;
  472. IModuleEntity selectedModule = null;
  473. List<IModuleEntity> idleModuleEtities = new List<IModuleEntity>();
  474. foreach (var item in avaibles)
  475. {
  476. if (item.IsIdle)
  477. {
  478. if(moduleType!=ModuleType.PlatingCell)
  479. {
  480. return item.Module;
  481. }
  482. idleModuleEtities.Add(item);
  483. }
  484. if (item.TimeToReady < timeToReady&&idleModuleEtities.Count==0)
  485. {
  486. timeToReady = item.TimeToReady;
  487. selectedModule = item;
  488. }
  489. }
  490. if (selectedModule != null)
  491. {
  492. return selectedModule.Module;
  493. }
  494. return ModuleName.Unknown;
  495. }
  496. /// <summary>
  497. /// 根据化学液获取可用的PlatingCell集合
  498. /// </summary>
  499. /// <param name="chemistry"></param>
  500. /// <returns></returns>
  501. public List<PlatingCellEntity> GetAvaiblePlatingCellList(string chemistry, string sequenceType, int waferSize, bool isEmpty)
  502. {
  503. List<IModuleEntity> reservoirEntities = Singleton<RouteManager>.Instance.GetModulesByModuleType(ModuleType.Reservoir);
  504. List<string> avaibles = new List<string>();
  505. foreach (IModuleEntity item in reservoirEntities)
  506. {
  507. ReservoirEntity entity = item as ReservoirEntity;
  508. if (entity.Chemistry == chemistry && entity.IsAuto && entity.IsInitialized)
  509. {
  510. avaibles.Add(entity.Module.ToString());
  511. }
  512. }
  513. List<PlatingCellEntity> metals = new List<PlatingCellEntity>();
  514. foreach (string item in avaibles)
  515. {
  516. ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(item);
  517. if (reservoirItem == null)
  518. {
  519. continue;
  520. }
  521. foreach (PlatingCellItem subItem in reservoirItem.PlatingCells)
  522. {
  523. PlatingCellEntity entity = Singleton<RouteManager>.Instance.GetModule<PlatingCellEntity>($"PlatingCell{subItem.PlatingCellID}");
  524. if (!CheckAvaibleModule(entity, ModuleType.PlatingCell, sequenceType))
  525. {
  526. continue;
  527. }
  528. if (entity.MetalWaferSize != waferSize)
  529. {
  530. continue;
  531. }
  532. if (!isEmpty || (isEmpty && entity.WaferInfo == null))
  533. {
  534. metals.Add(entity);
  535. }
  536. }
  537. }
  538. return metals;
  539. }
  540. }
  541. }