SchedulerSequenceManager.cs 26 KB

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