SchedulerSequenceManager.cs 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185
  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.WaferHolder;
  11. using MECF.Framework.Common.CommonData;
  12. using System.Windows;
  13. using Aitex.Core.RT.IOCore;
  14. using Aitex.Core.RT.Log;
  15. using Aitex.Core.Util;
  16. using MECF.Framework.Common.Routine;
  17. using CyberX8_RT.Modules;
  18. using Aitex.Core.RT.Fsm;
  19. using CyberX8_RT.Modules.PUF;
  20. using CyberX8_RT.Modules.Dummy;
  21. using MECF.Framework.Common.SubstrateTrackings;
  22. using MECF.Framework.Common.ToolLayout;
  23. using CyberX8_RT.Modules.Metal;
  24. using CyberX8_RT.Modules.Rinse;
  25. using MECF.Framework.RT.Core.Equipments;
  26. using MECF.Framework.Common.ProcessCell;
  27. using SecsGem.Core.ItemModel;
  28. using CyberX8_RT.Modules.Transporter;
  29. using CyberX8_Core;
  30. using Aitex.Core.RT.SCCore;
  31. using CyberX8_RT.Modules.Dryer;
  32. using CyberX8_RT.Modules.Prewet;
  33. using CyberX8_RT.Modules.SRD;
  34. using CyberX8_RT.Modules.Reservoir;
  35. using CyberX8_RT.Schedulers.Puf;
  36. namespace CyberX8_RT.Schedulers
  37. {
  38. public class SchedulerSequenceManager : Singleton<SchedulerSequenceManager>
  39. {
  40. #region 常量
  41. private const string ENGINEERING = "Engineering";
  42. private const string PRODUCTION = "Production";
  43. #endregion
  44. /// <summary>
  45. /// 解析Wafer所有调度工序
  46. /// </summary>
  47. /// <param name="sequenceRecipe"></param>
  48. /// <returns></returns>
  49. public List<SchedulerSequence> AnalyWaferAllSchedulerSequence(WaferInfo waferInfo,ModuleName pufModule,string side,WaferHolderInfo waferHolderInfo,SequenceRecipe sequenceRecipe)
  50. {
  51. List<SchedulerSequence> schedulerSequences = new List<SchedulerSequence>();
  52. int index = 0;
  53. MoveItem moveItem = new MoveItem((ModuleName)waferInfo.OriginStation, waferInfo.OriginSlot, ModuleName.Aligner1, 0, Aitex.Sorter.Common.Hand.Blade1);
  54. List<SchedulerSyncModuleMessage> synModules = new List<SchedulerSyncModuleMessage>();
  55. SchedulerSyncModuleMessage pufModuleMessage = new SchedulerSyncModuleMessage();
  56. pufModuleMessage.ModuleEntity = Singleton<RouteManager>.Instance.GetModule<IModuleEntity>(pufModule.ToString());
  57. pufModuleMessage.ModuleMsg = PUFMSG.ReadyForRobotPlace.ToString();
  58. synModules.Add(pufModuleMessage);
  59. SchedulerSequence efemRobotSequence = CreateEfemRobotSequence(moveItem,synModules,ref index);
  60. schedulerSequences.Add(efemRobotSequence);
  61. SchedulerSequence alignerSequence=CreateAlignerSequence(sequenceRecipe.AlignmentAngle,ref index);
  62. schedulerSequences.Add(alignerSequence);
  63. //从Aligner至Puf B面
  64. MoveItem moveItem2 = new MoveItem(ModuleName.Aligner1, 0, pufModule, 1, Aitex.Sorter.Common.Hand.Blade1);
  65. SchedulerSequence secondEfemRobotSequence = CreateEfemRobotSequence(moveItem2,null,ref index);
  66. schedulerSequences.Add(secondEfemRobotSequence);
  67. SchedulerSequence pufSequence=CreatePufSequence(pufModule,sequenceRecipe,side,true,ref index);
  68. schedulerSequences.Add(pufSequence);
  69. ////Loader
  70. //SchedulerSequence loaderSequence = CreateLoaderSequence(ref index);
  71. //schedulerSequences.Add(loaderSequence);
  72. ////wafer holder装载后的recipe工序
  73. //List<SchedulerSequence> waferHolderAfterLoadedAllSequences = WaferHolderAfterLoadedAllSchedulerSequences(waferHolderInfo, sequenceRecipe, ref index);
  74. //schedulerSequences.AddRange(waferHolderAfterLoadedAllSequences);
  75. ////buffer模块至Loader
  76. //ModuleName bufferModule = ConvertToBufferModule(waferHolderInfo.BufferId);
  77. //WaferHolderMoveItem bufferToLoaderItem = new WaferHolderMoveItem(bufferModule,ModuleType.Buffer , ModuleName.Loader1, ModuleType.Loader);
  78. //SchedulerSequence bufferToLoaderSequence = CreateLoaderTransporterSequence(bufferToLoaderItem, ref index);
  79. //schedulerSequences.Add(bufferToLoaderSequence);
  80. ////Loader
  81. //SchedulerSequence backLoaderSequence = CreateLoaderSequence(ref index);
  82. //schedulerSequences.Add(backLoaderSequence);
  83. //puf模块
  84. SchedulerSequence backPufSequence = CreatePufSequence(pufModule,sequenceRecipe,"",false, ref index);
  85. schedulerSequences.Add(backPufSequence);
  86. //若经过srd
  87. if(SequenceRecipeManager.Instance.IsContainedSrd(sequenceRecipe))
  88. {
  89. SrdRecipe srdRecipe=SequenceRecipeManager.Instance.GetSrdRecipeBySequenceRecipe(sequenceRecipe);
  90. if(srdRecipe!=null)
  91. {
  92. MoveItem pufToSrdItem = new MoveItem();
  93. pufToSrdItem.SourceModule = pufModule;
  94. //A面
  95. pufToSrdItem.SourceSlot = 0;
  96. pufToSrdItem.DestinationType = ModuleType.SRD;
  97. pufToSrdItem.SourceSlot = 0;
  98. pufToSrdItem.DestinationModule = ModuleName.Unknown;
  99. pufToSrdItem.RobotHand = Aitex.Sorter.Common.Hand.Blade1;
  100. SchedulerSequence backEfemRobotSequence = CreateEfemRobotSequence(pufToSrdItem,null, ref index);
  101. schedulerSequences.Add(backEfemRobotSequence);
  102. SchedulerSequence srdSequence = CreateSRDSequence(srdRecipe, ref index);
  103. schedulerSequences.Add(srdSequence);
  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 = Aitex.Sorter.Common.Hand.Blade1;
  112. SchedulerSequence srdToLoadPortSequence = CreateEfemRobotSequence(srdToLoadPortItem,null, ref index);
  113. schedulerSequences.Add(srdToLoadPortSequence);
  114. }
  115. else
  116. {
  117. LOG.WriteLog(eEvent.ERR_SEQUENCE, "System", $"{sequenceRecipe.Ppid} srd recipe is invalid");
  118. return new List<SchedulerSequence>();
  119. }
  120. }
  121. else
  122. {
  123. MoveItem pufToLoadPortItem=new MoveItem(pufModule,0,(ModuleName)waferInfo.OriginStation,
  124. waferInfo.OriginSlot,Aitex.Sorter.Common.Hand.Blade1);
  125. SchedulerSequence pufToLoaderSequence=CreateEfemRobotSequence(pufToLoadPortItem,null, ref index);
  126. schedulerSequences.Add(pufToLoaderSequence);
  127. }
  128. return schedulerSequences;
  129. }
  130. /// <summary>
  131. /// 解析WaferHolder的所有工序
  132. /// </summary>
  133. /// <param name="waferHolderInfo"></param>
  134. /// <param name="sequenceRecipe"></param>
  135. /// <returns></returns>
  136. public List<SchedulerSequence> AnalyWaferHolderAllSchedulerSequence(WaferHolderInfo waferHolderInfo, SequenceRecipe sequenceRecipe)
  137. {
  138. int index = 0;
  139. List<SchedulerSequence> schedulerSequences = new List<SchedulerSequence>();
  140. //Buffer To Loader
  141. ModuleName currentLocationModuleName = (ModuleName)Enum.Parse(typeof(ModuleName), waferHolderInfo.CurrentLocation);
  142. WaferHolderMoveItem bufferMoveToLoaderItem = new WaferHolderMoveItem(currentLocationModuleName, ModuleType.Buffer, ModuleName.Loader1, ModuleType.Loader);
  143. SchedulerSequence bufferToLoaderSequence = CreateLoaderTransporterSequence(bufferMoveToLoaderItem, ref index);
  144. schedulerSequences.Add(bufferToLoaderSequence);
  145. //Loader
  146. SchedulerSequence loaderSequence = CreateLoaderSequence(ref index);
  147. schedulerSequences.Add(loaderSequence);
  148. //wafer holder装载后的recipe工序
  149. List<SchedulerSequence> waferHolderAfterLoadedAllSequences = WaferHolderAfterLoadedAllSchedulerSequences(waferHolderInfo, sequenceRecipe,ref index);
  150. schedulerSequences.AddRange(waferHolderAfterLoadedAllSequences);
  151. return schedulerSequences;
  152. }
  153. /// <summary>
  154. /// Dummy Wafer对应WaferHolder任务
  155. /// </summary>
  156. /// <param name="waferHolderInfo"></param>
  157. /// <returns></returns>
  158. public List<SchedulerSequence> AnalyseDummyWaferHolderAllSchedulerSequence(WaferHolderInfo waferHolderInfo)
  159. {
  160. int index = 0;
  161. List<SchedulerSequence> schedulerSequences = new List<SchedulerSequence>();
  162. //Buffer To Loader
  163. ModuleName currentLocationModuleName = (ModuleName)Enum.Parse(typeof(ModuleName), waferHolderInfo.CurrentLocation);
  164. ModuleName bufferModule = (ModuleName)Enum.Parse(typeof(ModuleName), waferHolderInfo.OriginalBuffer);
  165. WaferHolderMoveItem bufferMoveToLoaderItem = new WaferHolderMoveItem(currentLocationModuleName, ModuleType.Buffer, ModuleName.Loader1, ModuleType.Loader);
  166. SchedulerSequence bufferToLoaderSequence = CreateLoaderTransporterSequence(bufferMoveToLoaderItem, ref index);
  167. schedulerSequences.Add(bufferToLoaderSequence);
  168. //Loader
  169. SchedulerSequence loaderSequence = CreateLoaderSequence(ref index);
  170. schedulerSequences.Add(loaderSequence);
  171. //Loader To Buffer
  172. WaferHolderMoveItem loaderMoveToBufferItem = new WaferHolderMoveItem(ModuleName.Loader1, ModuleType.Loader,
  173. bufferModule, ModuleType.Buffer);
  174. SchedulerSequence loaderToBufferSequence = CreateLoaderTransporterSequence(loaderMoveToBufferItem, ref index);
  175. schedulerSequences.Add(loaderToBufferSequence);
  176. return schedulerSequences;
  177. }
  178. /// <summary>
  179. /// 解析Dummy Wafer所有调度工序
  180. /// </summary>
  181. /// <param name="sequenceRecipe"></param>
  182. /// <returns></returns>
  183. public List<SchedulerSequence> AnalyDummyWaferAllSchedulerSequence(SequenceRecipe sequenceRecipe,WaferInfo waferInfo, ModuleName pufModule,string side)
  184. {
  185. List<SchedulerSequence> schedulerSequences = new List<SchedulerSequence>();
  186. int index = 0;
  187. //DummyCassete至Aligner
  188. MoveItem moveItem = new MoveItem((ModuleName)waferInfo.Station, waferInfo.Slot, ModuleName.Aligner1, 0, Aitex.Sorter.Common.Hand.Blade1);
  189. SchedulerSequence secondEfemRobotSequence = CreateEfemRobotSequence(moveItem, null, ref index);
  190. schedulerSequences.Add(secondEfemRobotSequence);
  191. //Aligner
  192. SchedulerSequence alignerSequence = null;
  193. if (sequenceRecipe == null)
  194. {
  195. alignerSequence= CreateAlignerSequence(0, ref index);
  196. }
  197. else
  198. {
  199. alignerSequence=CreateAlignerSequence(sequenceRecipe.AlignmentAngle, ref index);
  200. }
  201. schedulerSequences.Add(alignerSequence);
  202. //Aligner至Puf
  203. MoveItem alignerToPufMoveItem = new MoveItem(ModuleName.Aligner1, 0, pufModule, 1, Aitex.Sorter.Common.Hand.Blade1);
  204. SchedulerSequence alignerToPufEfemRobotSequence = CreateEfemRobotSequence(alignerToPufMoveItem, null, ref index);
  205. schedulerSequences.Add(alignerToPufEfemRobotSequence);
  206. SchedulerSequence pufSequence = CreatePufSequence(pufModule,sequenceRecipe, side,true, ref index);
  207. schedulerSequences.Add(pufSequence);
  208. return schedulerSequences;
  209. }
  210. /// <summary>
  211. /// Loader装载后Recipe工序
  212. /// </summary>
  213. /// <param name="waferHolderInfo"></param>
  214. /// <param name="sequenceRecipe"></param>
  215. /// <param name="index"></param>
  216. /// <returns></returns>
  217. private List<SchedulerSequence> WaferHolderAfterLoadedAllSchedulerSequences(WaferHolderInfo waferHolderInfo,SequenceRecipe sequenceRecipe,ref int index)
  218. {
  219. List<SchedulerSequence> schedulerSequences = new List<SchedulerSequence>();
  220. if(!Enum.TryParse(waferHolderInfo.OriginalBuffer,out ModuleName moduleName))
  221. {
  222. return schedulerSequences;
  223. }
  224. //Loader To Buffer
  225. WaferHolderMoveItem loaderMoveToBufferItem = new WaferHolderMoveItem(ModuleName.Loader1, ModuleType.Loader,
  226. moduleName, ModuleType.Buffer);
  227. SchedulerSequence loaderToBufferSequence = CreateLoaderTransporterSequence(loaderMoveToBufferItem, ref index);
  228. schedulerSequences.Add(loaderToBufferSequence);
  229. //解析sequence recipe后续的工序
  230. var result = AnalyseSequenceRecipeScheduler(sequenceRecipe);
  231. //buffer to recipe第一个工序
  232. WaferHolderMoveItem bufferToFirstItem = new WaferHolderMoveItem(moduleName, ModuleType.Buffer, ModuleName.Unknown, result.firstModuleType);
  233. SchedulerSequence bufferSequence = CreateLoaderTransporterSequence(bufferToFirstItem, ref index);
  234. schedulerSequences.Add(bufferSequence);
  235. //调整工序后面的索引
  236. foreach (SchedulerSequence item in result.sequences)
  237. {
  238. item.SequenceIndex = index;
  239. index++;
  240. }
  241. schedulerSequences.AddRange(result.sequences);
  242. //从recipe最后工序
  243. WaferHolderMoveItem lastToBufferItem = new WaferHolderMoveItem(ModuleName.Unknown, result.lastModuleType, moduleName, ModuleType.Buffer);
  244. SchedulerSequence lastToBufferSequence = CreateLoaderTransporterSequence(lastToBufferItem, ref index);
  245. schedulerSequences.Add(lastToBufferSequence);
  246. return schedulerSequences;
  247. }
  248. /// <summary>
  249. /// 分析Sequence recipe对应的调度步骤
  250. /// </summary>
  251. /// <param name="sequenceRecipe"></param>
  252. /// <returns></returns>
  253. private (ModuleType firstModuleType,List<SchedulerSequence> sequences,ModuleType lastModuleType) AnalyseSequenceRecipeScheduler(SequenceRecipe sequenceRecipe)
  254. {
  255. ModuleType firstModuleType = default;
  256. ModuleType lastModuleType = default;
  257. List<SchedulerSequence> schedulerSequences= new List<SchedulerSequence>();
  258. List<SchedulerSequence> tmpLst = new List<SchedulerSequence>();
  259. var processResult = AnalyseLastProcessRecipeIndex(sequenceRecipe.Recipes);
  260. bool isExistSrd = sequenceRecipe.Recipes.FindIndex(O=>O.ToLower().EndsWith("srd.rcp"))!=-1;
  261. int lastIndex = isExistSrd ? sequenceRecipe.Recipes.Count - 2 : sequenceRecipe.Recipes.Count - 1;
  262. for(int i=0;i<sequenceRecipe.Recipes.Count;i++)
  263. {
  264. string item = sequenceRecipe.Recipes[i];
  265. if(item.ToLower().EndsWith("srd.rcp"))//跳过SRD
  266. {
  267. continue;
  268. }
  269. SchedulerSequence schedulerSequence = new SchedulerSequence();
  270. schedulerSequence.ModuleName = ModuleName.Unknown;
  271. schedulerSequence.ModuleType=SequenceRecipeManager.Instance.GetModuleType(item);
  272. schedulerSequence.SequenceIndex=i;
  273. MECF.Framework.Common.RecipeCenter.RecipeType recipeType =SequenceRecipeManager.Instance.GetRecipeType(item);
  274. schedulerSequence.Recipe = SequenceRecipeManager.Instance.LoadSequenceTypeRecipe(sequenceRecipe.SequenceType,item, recipeType);
  275. schedulerSequence.SequenceType = sequenceRecipe.SequenceType;
  276. schedulerSequence.State = RState.Init;
  277. schedulerSequence.MaterialType = MaterialType.WaferHolder;
  278. tmpLst.Add(schedulerSequence);
  279. if (i == 0)
  280. {
  281. firstModuleType = schedulerSequence.ModuleType;
  282. }
  283. if(i==lastIndex)
  284. {
  285. lastModuleType = schedulerSequence.ModuleType;
  286. }
  287. else
  288. {
  289. string nextModule = sequenceRecipe.Recipes[i + 1];
  290. schedulerSequence.NextModuleType= SequenceRecipeManager.Instance.GetModuleType(nextModule);
  291. MECF.Framework.Common.RecipeCenter.RecipeType nextRecipeType = SequenceRecipeManager.Instance.GetRecipeType(nextModule);
  292. schedulerSequence.NextRecipe= SequenceRecipeManager.Instance.LoadSequenceTypeRecipe(sequenceRecipe.SequenceType,nextModule,nextRecipeType);
  293. }
  294. schedulerSequence.IsProcessSequece = true;
  295. if(i==processResult.lastIndex)
  296. {
  297. schedulerSequence.IsLastProcessSequence = true;
  298. }
  299. }
  300. int index = 0;
  301. for(int i=0;i<tmpLst.Count;i++)
  302. {
  303. tmpLst[i].SequenceIndex = 0;
  304. schedulerSequences.Add(tmpLst[i]);
  305. index++;
  306. if(i<tmpLst.Count-1)
  307. {
  308. WaferHolderMoveItem moveItem = new WaferHolderMoveItem(ModuleName.Unknown, tmpLst[i].ModuleType, ModuleName.Unknown, tmpLst[i + 1].ModuleType);
  309. SchedulerSequence schedulerSequence=CreateProcessTransporterSequence(moveItem,ref index);
  310. schedulerSequences.Add(schedulerSequence);
  311. }
  312. }
  313. return (firstModuleType,schedulerSequences,lastModuleType);
  314. }
  315. /// <summary>
  316. /// 分析最后加工recipe索引
  317. /// </summary>
  318. /// <param name="recipes"></param>
  319. /// <returns></returns>
  320. private (int lastIndex,List<int> processIndexList) AnalyseLastProcessRecipeIndex(List<string> recipes)
  321. {
  322. int index = 0;
  323. List<int> lst = new List<int>();
  324. for(int i=0;i<recipes.Count; i++)
  325. {
  326. string item=recipes[i];
  327. if(item.ToLower().EndsWith("dep.rcp"))
  328. {
  329. index = i;
  330. if(lst.Contains(i))
  331. {
  332. lst.Add(i);
  333. }
  334. }
  335. }
  336. if(lst.Count==0)
  337. {
  338. lst.Add(0);
  339. }
  340. return (index,lst);
  341. }
  342. /// <summary>
  343. /// 创建EFEM Robot步骤
  344. /// </summary>
  345. /// <param name="index"></param>
  346. /// <returns></returns>
  347. private SchedulerSequence CreateEfemRobotSequence(MoveItem moveItem,List<SchedulerSyncModuleMessage> synModules,ref int index)
  348. {
  349. SchedulerSequence sequence = new SchedulerSequence();
  350. sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.EfemRobot);
  351. sequence.SequenceIndex= index;
  352. sequence.ModuleName=ModuleName.EfemRobot;
  353. sequence.State = RState.Init;
  354. sequence.Recipe = null;
  355. sequence.ModuleType=ModuleType.EfemRobot;
  356. sequence.Parameters =moveItem;
  357. sequence.MaterialType = MaterialType.Wafer;
  358. sequence.SynchronousModuleMessages = synModules;
  359. index++;
  360. return sequence;
  361. }
  362. /// <summary>
  363. /// 创建Aligner步骤
  364. /// </summary>
  365. /// <param name="index"></param>
  366. /// <returns></returns>
  367. private SchedulerSequence CreateAlignerSequence(double angle,ref int index)
  368. {
  369. SchedulerSequence sequence = new SchedulerSequence();
  370. sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.Aligner1);
  371. sequence.SequenceIndex = index;
  372. sequence.ModuleName = ModuleName.Aligner1;
  373. sequence.State = RState.Init;
  374. sequence.Recipe = null;
  375. sequence.ModuleType = ModuleType.Aligner;
  376. sequence.Parameters = angle;
  377. sequence.MaterialType = MaterialType.Wafer;
  378. index++;
  379. return sequence;
  380. }
  381. /// <summary>
  382. /// 创建PUF步骤
  383. /// </summary>
  384. /// <param name="pufModuleName"></param>
  385. /// <param name="index"></param>
  386. /// <returns></returns>
  387. private SchedulerSequence CreatePufSequence(ModuleName pufModuleName,SequenceRecipe sequenceRecipe,string side,bool forward,ref int index)
  388. {
  389. SchedulerSequence sequence = new SchedulerSequence();
  390. sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(pufModuleName);
  391. sequence.SequenceIndex = index;
  392. sequence.ModuleName = pufModuleName;
  393. sequence.State = RState.Init;
  394. sequence.Recipe = sequenceRecipe;
  395. PufSchedulerParameter parameter = new PufSchedulerParameter()
  396. {
  397. IsForward = forward,
  398. Side = side,
  399. };
  400. sequence.Parameters = parameter;
  401. sequence.IsWaitNotify = !forward;
  402. sequence.ModuleType = ModuleType.PUF;
  403. sequence.MaterialType = MaterialType.Wafer;
  404. index++;
  405. return sequence;
  406. }
  407. /// <summary>
  408. /// 创建Loader步骤
  409. /// </summary>
  410. /// <param name="index"></param>
  411. /// <returns></returns>
  412. private SchedulerSequence CreateLoaderSequence(ref int index)
  413. {
  414. SchedulerSequence sequence = new SchedulerSequence();
  415. sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.Loader1);
  416. sequence.SequenceIndex = index;
  417. sequence.ModuleName = ModuleName.Loader1;
  418. sequence.State = RState.Init;
  419. sequence.Recipe = null;
  420. sequence.ModuleType = ModuleType.Loader;
  421. sequence.MaterialType = MaterialType.WaferHolder;
  422. index++;
  423. return sequence;
  424. }
  425. /// <summary>
  426. /// 创建Loader步骤
  427. /// </summary>
  428. /// <param name="index"></param>
  429. /// <returns></returns>
  430. private SchedulerSequence CreateSRDSequence(SrdRecipe recipe,ref int index)
  431. {
  432. SchedulerSequence sequence = new SchedulerSequence();
  433. sequence.SequenceIndex = index;
  434. sequence.State = RState.Init;
  435. sequence.Recipe = recipe;
  436. sequence.ModuleType = ModuleType.SRD;
  437. sequence.MaterialType = MaterialType.Wafer;
  438. index++;
  439. return sequence;
  440. }
  441. /// <summary>
  442. /// 创建LoaderTransporter步骤
  443. /// </summary>
  444. /// <param name="index"></param>
  445. /// <returns></returns>
  446. private SchedulerSequence CreateLoaderTransporterSequence(WaferHolderMoveItem waferHolderMoveItem, ref int index)
  447. {
  448. SchedulerSequence sequence = new SchedulerSequence();
  449. sequence.ModuleType = ModuleType.Transporter;
  450. sequence.ModuleName = ModuleName.Transporter2;
  451. sequence.SequenceIndex = index;
  452. sequence.State = RState.Init;
  453. sequence.Recipe = null;
  454. sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.Transporter2);
  455. sequence.Parameters = waferHolderMoveItem;
  456. sequence.MaterialType = MaterialType.WaferHolder;
  457. index++;
  458. return sequence;
  459. }
  460. /// <summary>
  461. /// 创建LoaderTransporter步骤
  462. /// </summary>
  463. /// <param name="index"></param>
  464. /// <returns></returns>
  465. private SchedulerSequence CreateProcessTransporterSequence(WaferHolderMoveItem waferHolderMoveItem,ref int index)
  466. {
  467. SchedulerSequence sequence = new SchedulerSequence();
  468. sequence.ModuleType = ModuleType.Transporter;
  469. sequence.ModuleName = ModuleName.Transporter1;
  470. sequence.SequenceIndex = index;
  471. sequence.State = RState.Init;
  472. sequence.Recipe = null;
  473. sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.Transporter1);
  474. sequence.Parameters= waferHolderMoveItem;
  475. sequence.MaterialType = MaterialType.WaferHolder;
  476. index++;
  477. return sequence;
  478. }
  479. /// <summary>
  480. /// 获取可用Dummy slot
  481. /// </summary>
  482. /// <param name="moduleType"></param>
  483. /// <returns></returns>
  484. public (ModuleName moduleName,int slot) GetAvaibleDummySlots()
  485. {
  486. if(ModuleHelper.IsInstalled(ModuleName.Dummy1))
  487. {
  488. DummyEntity dummyEntity = Singleton<RouteManager>.Instance.GetModule<DummyEntity>(ModuleName.Dummy1.ToString());
  489. for(int i=0;i<dummyEntity.MaxSlotNumber;i++)
  490. {
  491. if(WaferManager.Instance.CheckNoWafer(ModuleName.Dummy1,i))
  492. {
  493. return (ModuleName.Dummy1, i);
  494. }
  495. }
  496. }
  497. if(ModuleHelper.IsInstalled(ModuleName.Dummy2))
  498. {
  499. DummyEntity dummyEntity = Singleton<RouteManager>.Instance.GetModule<DummyEntity>(ModuleName.Dummy2.ToString());
  500. for (int i = 0; i < dummyEntity.MaxSlotNumber; i++)
  501. {
  502. if (WaferManager.Instance.CheckNoWafer(ModuleName.Dummy2, i))
  503. {
  504. return (ModuleName.Dummy2, i);
  505. }
  506. }
  507. }
  508. return (ModuleName.Unknown, -1);
  509. }
  510. /// <summary>
  511. /// 根据模块类型获取可用模块
  512. /// </summary>
  513. /// <param name="moduleType"></param>
  514. /// <returns></returns>
  515. public ModuleName GetAvaibleModuleCell(string sequenceType,ModuleType moduleType, ModuleName moduleName = ModuleName.Unknown)
  516. {
  517. if (ModuleHelper.IsMetal(moduleName))
  518. {
  519. List<IModuleEntity> entities = Singleton<RouteManager>.Instance.GetModulesByModuleType(moduleType);
  520. return GetMetalAvaibleRinseModule(entities, moduleName);
  521. }
  522. else
  523. {
  524. List<IModuleEntity> entities = Singleton<RouteManager>.Instance.GetModulesByModuleType(moduleType);
  525. List<IModuleEntity> avaibles = new List<IModuleEntity>();
  526. foreach (var item in entities)
  527. {
  528. bool result = CheckAvaibleModule(item,moduleType,sequenceType);
  529. if (result)
  530. {
  531. avaibles.Add(item);
  532. }
  533. }
  534. return GetMinTimeToReadyModule(avaibles,moduleType);
  535. }
  536. }
  537. /// <summary>
  538. /// 根据模块类型获取可用模块(不包含WH)
  539. /// </summary>
  540. /// <param name="moduleType"></param>
  541. /// <returns></returns>
  542. public ModuleName GetAvaibleEmptyModuleCell(ModuleType moduleType,string sequenceType, ModuleName moduleName = ModuleName.Unknown)
  543. {
  544. if (ModuleHelper.IsMetal(moduleName))
  545. {
  546. List<IModuleEntity> entities = Singleton<RouteManager>.Instance.GetModulesByModuleType(moduleType);
  547. return GetMetalAvaibleEmptyRinseModule(entities, moduleName);
  548. }
  549. else
  550. {
  551. List<IModuleEntity> entities = Singleton<RouteManager>.Instance.GetModulesByModuleType(moduleType);
  552. List<IModuleEntity> avaibles = new List<IModuleEntity>();
  553. foreach (var item in entities)
  554. {
  555. bool result = CheckAvaibleModule(item,moduleType,sequenceType);
  556. if (result&&!WaferHolderManager.Instance.HasWaferHolder(item.Module.ToString()))
  557. {
  558. avaibles.Add(item);
  559. }
  560. }
  561. return avaibles.Count != 0 ? avaibles[0].Module : ModuleName.Unknown;
  562. }
  563. }
  564. /// <summary>
  565. /// 根据化学液计算时间获取可用MetalCell(参考其他Metal剩余时间)
  566. /// </summary>
  567. /// <param name="chemistry"></param>
  568. /// <returns></returns>
  569. public ModuleName CalculateAvaibleMetalCellByChemistry(string chemistry,string startRinse,string sequenceType,ref bool isExistEnableMetal)
  570. {
  571. if(!Enum.TryParse(startRinse,out ModuleName startRinseModule)||!ModuleHelper.IsRinse(startRinseModule))
  572. {
  573. startRinse = "";
  574. }
  575. isExistEnableMetal = false;
  576. List<MetalEntity> moduleEntities = GetAvaibleMetalList(chemistry,sequenceType,true);
  577. List<IModuleEntity> avaibleMetalEntities = new List<IModuleEntity>();
  578. foreach (var item in moduleEntities)
  579. {
  580. if(CheckAvaibleModule(item,ModuleType.Metal,sequenceType))
  581. {
  582. if (item.WaferHolderInfo == null)
  583. {
  584. if (CheckMetalModuleRinseAvaible(item, startRinse))
  585. {
  586. avaibleMetalEntities.Add(item);
  587. }
  588. }
  589. isExistEnableMetal = true;
  590. }
  591. }
  592. if (avaibleMetalEntities.Count > 0)
  593. {
  594. return GetMinUsageMetal(avaibleMetalEntities);
  595. }
  596. return ModuleName.Unknown;
  597. }
  598. /// <summary>
  599. /// 根据化学液获取可用Metal
  600. /// </summary>
  601. /// <param name="chemistry"></param>
  602. /// <param name="sequenceType"></param>
  603. /// <returns></returns>
  604. public bool CalculateAvaibleMetalCellByChemistry(string chemistry,string sequenceType)
  605. {
  606. List<MetalEntity> moduleEntities = GetAvaibleMetalList(chemistry, sequenceType, false);
  607. return moduleEntities.Count != 0;
  608. }
  609. /// <summary>
  610. /// 检验Metal模块Rinse可用性
  611. /// </summary>
  612. /// <param name="item"></param>
  613. /// <returns></returns>
  614. private bool CheckMetalModuleRinseAvaible(MetalEntity item,string startRinse)
  615. {
  616. List<LayoutCellItem> rinseItems = CellItemManager.Instance.GetRinseItemsByMetal(item.Module.ToString());
  617. List<string> sharedRinseItems = new List<string>();
  618. List<string> singleRinseItems = new List<string>();
  619. foreach (var cellItem in rinseItems)
  620. {
  621. RinseEntity rinseEntity = Singleton<RouteManager>.Instance.GetModule<RinseEntity>(cellItem.ModuleName);
  622. if (!CellItemManager.Instance.CheckRinseIsShared(cellItem.ModuleName))
  623. {
  624. if (CheckAvaibleModule(rinseEntity, ModuleType.Rinse, "") && rinseEntity.WaferHolderInfo == null)
  625. {
  626. singleRinseItems.Add(cellItem.ModuleName);
  627. }
  628. }
  629. else
  630. {
  631. if (CheckAvaibleModule(rinseEntity,ModuleType.Rinse,"") && rinseEntity.WaferHolderInfo == null)
  632. {
  633. sharedRinseItems.Add(cellItem.ModuleName);
  634. }
  635. //增加自己
  636. if (cellItem.ModuleName == startRinse && rinseEntity != null && (rinseEntity.IsIdle||rinseEntity.State==(int)RinseState.KeepWeting))
  637. {
  638. sharedRinseItems.Add(startRinse);
  639. }
  640. }
  641. }
  642. //独立的Rinse集合
  643. if(singleRinseItems.Count!=0)
  644. {
  645. bool result = CheckSingleRinseItemsCanUsed(singleRinseItems, item.Module.ToString());
  646. if(result)
  647. {
  648. return true;
  649. }
  650. }
  651. //仅剩下共享Rinse
  652. List<string> avaibleSharedList = new List<string>();
  653. if (sharedRinseItems.Count != 0)
  654. {
  655. foreach (string sharedRinse in sharedRinseItems)
  656. {
  657. RinseEntity rinseEntity = Singleton<RouteManager>.Instance.GetModule<RinseEntity>(sharedRinse);
  658. if (rinseEntity.IsBusy&&sharedRinse!=startRinse)
  659. {
  660. continue;
  661. }
  662. //检验共享Rinse是否可用
  663. if (CheckShardRinseCanUse(sharedRinse, item.Module.ToString(),startRinse))
  664. {
  665. avaibleSharedList.Add(sharedRinse);
  666. }
  667. }
  668. }
  669. if (avaibleSharedList.Count != 0)
  670. {
  671. var result = CalculateMetalReservoirAllBusyMetalCount(item.Module.ToString());
  672. if (result.success)
  673. {
  674. bool transporterTransfering = CheckProcessTransporterTransfering(avaibleSharedList);
  675. if(transporterTransfering)
  676. {
  677. return result.busyCount + 1 < avaibleSharedList.Count;
  678. }
  679. else
  680. {
  681. return result.busyCount < avaibleSharedList.Count+singleRinseItems.Count;
  682. }
  683. }
  684. }
  685. return false;
  686. }
  687. /// <summary>
  688. /// 检验Process transporter正在Transfer WH移动至Rinse
  689. /// </summary>
  690. /// <returns></returns>
  691. private bool CheckProcessTransporterTransfering(List<string> rinseList)
  692. {
  693. TransporterEntity processTransporterEntity = Singleton<RouteManager>.Instance.GetModule<TransporterEntity>(ModuleName.Transporter1.ToString());
  694. if(processTransporterEntity!=null)
  695. {
  696. if (processTransporterEntity.IsBusy)
  697. {
  698. string targetCell = processTransporterEntity.TargetCell;
  699. if (rinseList.Contains(targetCell))
  700. {
  701. return true;
  702. }
  703. }
  704. }
  705. return false;
  706. }
  707. /// <summary>
  708. /// 计算Metal所在Reservoir Busy Metal数量
  709. /// </summary>
  710. /// <param name="item"></param>
  711. /// <returns></returns>
  712. private (bool success,int busyCount) CalculateMetalReservoirAllBusyMetalCount(string metalName)
  713. {
  714. string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(metalName);
  715. if (string.IsNullOrEmpty(reservoirName))
  716. {
  717. return (false,0);
  718. }
  719. List<string> metals = ReservoirItemManager.Instance.GetMetalsByReservoir(reservoirName);
  720. int count = 0;
  721. foreach (string item in metals)
  722. {
  723. if (metalName == item)
  724. {
  725. continue;
  726. }
  727. MetalEntity metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(item);
  728. if (metalEntity.IsBusy || metalEntity.WaferHolderInfo != null)
  729. {
  730. count++;
  731. }
  732. }
  733. return (true,count);
  734. }
  735. /// <summary>
  736. /// 检验独立Rinse是否可用
  737. /// </summary>
  738. /// <param name="singleRinseItems"></param>
  739. /// <param name="metalName"></param>
  740. /// <returns></returns>
  741. private bool CheckSingleRinseItemsCanUsed(List<string> singleRinseItems, string metalName)
  742. {
  743. var result = CalculateMetalReservoirAllBusyMetalCount(metalName);
  744. if(result.success)
  745. {
  746. bool transporterTransfering = CheckProcessTransporterTransfering(singleRinseItems);
  747. if (transporterTransfering)
  748. {
  749. return result.busyCount + 1 < singleRinseItems.Count;
  750. }
  751. else
  752. {
  753. return result.busyCount < singleRinseItems.Count;
  754. }
  755. }
  756. return false;
  757. }
  758. /// <summary>
  759. /// 检验共享Rinse是否可用
  760. /// </summary>
  761. /// <param name="sharedRinse"></param>
  762. /// <param name="metalName"></param>
  763. /// <returns></returns>
  764. private bool CheckShardRinseCanUse(string sharedRinse, string metalName,string startRinse)
  765. {
  766. string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(metalName);
  767. List<string> shardReservoirs = CellItemManager.Instance.GetReservoirsBySharedRinse(sharedRinse);
  768. if (shardReservoirs == null || shardReservoirs.Count == 0)
  769. {
  770. return false;
  771. }
  772. foreach (string reservoir in shardReservoirs)
  773. {
  774. if (reservoir==reservoirName)
  775. {
  776. continue;
  777. }
  778. List<string> metals=ReservoirItemManager.Instance.GetMetalsByReservoir(reservoir);
  779. int metalCount = 0;
  780. int busyMetalCount = 0;
  781. foreach(string metal in metals)
  782. {
  783. MetalEntity metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(metal);
  784. if(metalEntity.IsAuto&&metalEntity.IsInitialized)
  785. {
  786. metalCount++;
  787. }
  788. if(metalEntity.IsBusy||metalEntity.WaferHolderInfo!=null)
  789. {
  790. busyMetalCount++;
  791. }
  792. }
  793. List<string> reservoirRinseLst = CellItemManager.Instance.GetRinsesByReservoir(reservoir);
  794. int rinseCount = 0;
  795. int busyRinseCount = 0;
  796. foreach(string rinseItem in reservoirRinseLst)
  797. {
  798. RinseEntity rinseEntity = Singleton<RouteManager>.Instance.GetModule<RinseEntity>(rinseItem);
  799. if(rinseEntity.IsAuto&&rinseEntity.IsInitialized)
  800. {
  801. rinseCount++;
  802. }
  803. if (rinseItem == sharedRinse)
  804. {
  805. continue;
  806. }
  807. if (rinseItem == startRinse)
  808. {
  809. continue;
  810. }
  811. if(rinseEntity.IsBusy||rinseEntity.WaferHolderInfo!=null)
  812. {
  813. busyRinseCount++;
  814. }
  815. }
  816. int resRinseCount=rinseCount- busyRinseCount;
  817. //计算剩余Rinse数量小于等于busy metal数量,则不可用
  818. if (resRinseCount <= busyMetalCount)
  819. {
  820. return false;
  821. }
  822. }
  823. return true;
  824. }
  825. /// <summary>
  826. /// 检验模块是否可用(不包含WH)
  827. /// </summary>
  828. /// <param name="item"></param>
  829. /// <returns></returns>
  830. private bool CheckAvaibleEmptyModule(IModuleEntity item,ModuleType moduleType,string sequenceType)
  831. {
  832. if (!CheckAvaibleModule(item, moduleType, sequenceType))
  833. {
  834. return false;
  835. }
  836. if (!ModuleHelper.IsSRD(item.Module))
  837. {
  838. WaferHolderInfo waferHolderInfo = WaferHolderManager.Instance.GetWaferHolder(item.Module.ToString());
  839. if (waferHolderInfo == null)
  840. {
  841. return true;
  842. }
  843. }
  844. else
  845. {
  846. if (!WaferManager.Instance.CheckHasWafer(item.Module, 0))
  847. {
  848. return true;
  849. }
  850. }
  851. return false;
  852. }
  853. /// <summary>
  854. /// 检验模块是否可用
  855. /// </summary>
  856. /// <param name="item"></param>
  857. /// <returns></returns>
  858. public bool CheckAvaibleModule(IModuleEntity item,ModuleType moduleType,string sequenceType)
  859. {
  860. if (item.IsDisable)
  861. {
  862. return false;
  863. }
  864. if (!item.IsAuto)
  865. {
  866. return false;
  867. }
  868. if (item.IsError)
  869. {
  870. return false;
  871. }
  872. if (item.IsInit)
  873. {
  874. return false;
  875. }
  876. if (moduleType==ModuleType.Metal)
  877. {
  878. if(item.IsProduction && sequenceType == ENGINEERING)
  879. return false;
  880. if (item.IsEngineering && sequenceType == PRODUCTION)
  881. return false;
  882. }
  883. return true;
  884. }
  885. /// <summary>
  886. /// 获取剩余时间最小的模块
  887. /// </summary>
  888. /// <param name="avaibles"></param>
  889. /// <returns></returns>
  890. private ModuleName GetMinTimeToReadyModule(List<IModuleEntity> avaibles,ModuleType moduleType)
  891. {
  892. if (avaibles.Count == 1)
  893. {
  894. return avaibles[0].Module;
  895. }
  896. int timeToReady = int.MaxValue;
  897. IModuleEntity selectedModule = null;
  898. List<IModuleEntity> idleModuleEtities = new List<IModuleEntity>();
  899. foreach (var item in avaibles)
  900. {
  901. if (item.IsIdle)
  902. {
  903. if(moduleType!=ModuleType.Metal)
  904. {
  905. return item.Module;
  906. }
  907. idleModuleEtities.Add(item);
  908. }
  909. if (item.TimeToReady < timeToReady&&idleModuleEtities.Count==0)
  910. {
  911. timeToReady = item.TimeToReady;
  912. selectedModule = item;
  913. }
  914. }
  915. if (idleModuleEtities.Count != 0)
  916. {
  917. return GetMinUsageMetal(idleModuleEtities);
  918. }
  919. if (selectedModule != null)
  920. {
  921. return selectedModule.Module;
  922. }
  923. return ModuleName.Unknown;
  924. }
  925. /// <summary>
  926. /// 获取电量最小的Metal
  927. /// </summary>
  928. /// <param name="idleModuleEntities"></param>
  929. /// <returns></returns>
  930. private ModuleName GetMinUsageMetal(List<IModuleEntity> idleModuleEntities)
  931. {
  932. double usage = double.MaxValue;
  933. ModuleName selectedModuleName = ModuleName.Unknown;
  934. foreach (var item in idleModuleEntities)
  935. {
  936. MetalEntity metalEntity= item as MetalEntity;
  937. if(metalEntity!=null)
  938. {
  939. MetalUsage metalUsage = metalEntity.MetalUsage;
  940. if (metalUsage == null)
  941. {
  942. return metalEntity.Module;
  943. }
  944. if (metalUsage.TotalUsage < usage)
  945. {
  946. usage= metalUsage.TotalUsage;
  947. selectedModuleName = metalEntity.Module;
  948. }
  949. }
  950. }
  951. return selectedModuleName;
  952. }
  953. /// <summary>
  954. /// 获取Metal可用的Rinse模块
  955. /// </summary>
  956. /// <param name="metalName"></param>
  957. /// <returns></returns>
  958. private ModuleName GetMetalAvaibleRinseModule(List<IModuleEntity> items, ModuleName metalName)
  959. {
  960. int metalId = CellItemManager.Instance.GetCellIdByModuleName(metalName.ToString());
  961. if (metalId == 0)
  962. {
  963. return ModuleName.Unknown;
  964. }
  965. List<LayoutCellItem> rinseItems = CellItemManager.Instance.GetRinseItemsByMetal(metalName.ToString());
  966. if (rinseItems.Count == 0)
  967. {
  968. return ModuleName.Unknown;
  969. }
  970. List<IModuleEntity> avaibles = new List<IModuleEntity>();
  971. foreach (var item in items)
  972. {
  973. LayoutCellItem cellItem = rinseItems.Find(O => O.ModuleName == item.Module.ToString());
  974. if (cellItem != null)
  975. {
  976. RinseEntity rinseEntity = (RinseEntity)item;
  977. if (rinseEntity.IsInitialized && rinseEntity.IsAuto)
  978. {
  979. avaibles.Add(rinseEntity);
  980. }
  981. }
  982. }
  983. int minInterval = int.MaxValue;
  984. IModuleEntity moduleEntity = null;
  985. foreach (var item in avaibles)
  986. {
  987. LayoutCellItem cellItem = rinseItems.Find(O => O.ModuleName == item.Module.ToString());
  988. if (cellItem != null)
  989. {
  990. int abiasId = Math.Abs(metalId - cellItem.CellID);
  991. if (abiasId < minInterval)
  992. {
  993. minInterval = abiasId;
  994. moduleEntity = item;
  995. }
  996. }
  997. }
  998. if (moduleEntity != null)
  999. {
  1000. return moduleEntity.Module;
  1001. }
  1002. return ModuleName.Unknown;
  1003. }
  1004. /// <summary>
  1005. /// 检验Metal可用的Rinse模块
  1006. /// </summary>
  1007. /// <param name="metalName"></param>
  1008. /// <returns></returns>
  1009. private ModuleName GetMetalAvaibleEmptyRinseModule(List<IModuleEntity> items, ModuleName metalName)
  1010. {
  1011. int metalId = CellItemManager.Instance.GetCellIdByModuleName(metalName.ToString());
  1012. if (metalId == 0)
  1013. {
  1014. return ModuleName.Unknown;
  1015. }
  1016. List<LayoutCellItem> rinseItems = CellItemManager.Instance.GetRinseItemsByMetal(metalName.ToString());
  1017. if (rinseItems.Count == 0)
  1018. {
  1019. return ModuleName.Unknown;
  1020. }
  1021. List<IModuleEntity> avaibles = new List<IModuleEntity>();
  1022. List<ModuleName> sharedRinseList = new List<ModuleName>();
  1023. foreach (var item in items)
  1024. {
  1025. LayoutCellItem cellItem = rinseItems.Find(O => O.ModuleName == item.Module.ToString());
  1026. if (cellItem != null)
  1027. {
  1028. RinseEntity rinseEntity = (RinseEntity)item;
  1029. if (rinseEntity.IsIdle && rinseEntity.IsAuto && rinseEntity.WaferHolderInfo == null)
  1030. {
  1031. avaibles.Add(rinseEntity);
  1032. if(CellItemManager.Instance.CheckRinseIsShared(rinseEntity.Module.ToString()))
  1033. {
  1034. sharedRinseList.Add(rinseEntity.Module);
  1035. }
  1036. }
  1037. }
  1038. }
  1039. int minInterval = int.MaxValue;
  1040. IModuleEntity moduleEntity = null;
  1041. foreach (var item in avaibles)
  1042. {
  1043. if (sharedRinseList.Contains(item.Module))
  1044. {
  1045. continue;
  1046. }
  1047. LayoutCellItem cellItem = rinseItems.Find(O => O.ModuleName == item.Module.ToString());
  1048. if (cellItem != null)
  1049. {
  1050. int abiasId = Math.Abs(metalId - cellItem.CellID);
  1051. if (abiasId < minInterval)
  1052. {
  1053. minInterval = abiasId;
  1054. moduleEntity = item;
  1055. }
  1056. }
  1057. }
  1058. if (moduleEntity != null)
  1059. {
  1060. return moduleEntity.Module;
  1061. }
  1062. else if(sharedRinseList.Count!=0)
  1063. {
  1064. return sharedRinseList[0];
  1065. }
  1066. return ModuleName.Unknown;
  1067. }
  1068. /// <summary>
  1069. /// 检验Metal cell recipe时间是否可用
  1070. /// </summary>
  1071. /// <param name="depRecipe"></param>
  1072. /// <returns></returns>
  1073. public bool CheckMetalCellRecipeTimeAvaible(IModuleEntity metalEntity,DepRecipe depRecipe)
  1074. {
  1075. List<IModuleEntity> metalEntities=Singleton<RouteManager>.Instance.GetModulesByModuleType(ModuleType.Metal);
  1076. int maxTimeToReady = 0;
  1077. foreach (MetalEntity item in metalEntities)
  1078. {
  1079. if (metalEntity.Module == item.Module)
  1080. {
  1081. continue;
  1082. }
  1083. if(item.IsBusy)
  1084. {
  1085. if(maxTimeToReady>item.TimeToReady)
  1086. {
  1087. maxTimeToReady = item.TimeToReady;
  1088. }
  1089. }
  1090. }
  1091. int transferOffSecond = SC.GetValue<int>("Transporter.TransporterTransferOffSeconds");
  1092. int recipeTotalTime = depRecipe.CalculateRecipeTotalTime();
  1093. //增加了Transporter最大传输时间和最小传输时间的差值
  1094. if (recipeTotalTime>=maxTimeToReady+transferOffSecond)
  1095. {
  1096. return true;
  1097. }
  1098. return false;
  1099. }
  1100. /// <summary>
  1101. /// 根据化学液获取可用的metal集合
  1102. /// </summary>
  1103. /// <param name="chemistry"></param>
  1104. /// <returns></returns>
  1105. public List<MetalEntity> GetAvaibleMetalList(string chemistry, string sequenceType, bool isEmpty)
  1106. {
  1107. List<IModuleEntity> reservoirEntities = Singleton<RouteManager>.Instance.GetModulesByModuleType(ModuleType.Reservoir);
  1108. List<string> avaibles = new List<string>();
  1109. foreach (IModuleEntity item in reservoirEntities)
  1110. {
  1111. ReservoirEntity entity = item as ReservoirEntity;
  1112. if (entity.Chemistry == chemistry && entity.IsAuto && entity.IsInitialized)
  1113. {
  1114. avaibles.Add(entity.Module.ToString());
  1115. }
  1116. }
  1117. List<MetalEntity> metals = new List<MetalEntity>();
  1118. foreach (string item in avaibles)
  1119. {
  1120. ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(item);
  1121. if (reservoirItem == null)
  1122. {
  1123. continue;
  1124. }
  1125. foreach (MetalItem subItem in reservoirItem.MetalCells)
  1126. {
  1127. MetalEntity entity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>($"Metal{subItem.MetalID}");
  1128. if (!CheckAvaibleModule(entity, ModuleType.Metal, sequenceType))
  1129. {
  1130. continue;
  1131. }
  1132. if (!isEmpty || (isEmpty && entity.WaferHolderInfo == null))
  1133. {
  1134. metals.Add(entity);
  1135. }
  1136. }
  1137. }
  1138. return metals;
  1139. }
  1140. /// <summary>
  1141. /// 获取上一个Metal
  1142. /// </summary>
  1143. /// <param name="sequenceIndex"></param>
  1144. /// <param name="sequences"></param>
  1145. /// <returns></returns>
  1146. public ModuleName GetPreMetalModuleName(int sequenceIndex,List<SchedulerSequence> sequences)
  1147. {
  1148. for(int i = sequenceIndex - 1; i >= 0; i--)
  1149. {
  1150. SchedulerSequence schedulerSequence= sequences[i];
  1151. if (schedulerSequence.ModuleType == ModuleType.Metal && ModuleHelper.IsMetal(schedulerSequence.ModuleName))
  1152. {
  1153. return schedulerSequence.ModuleName;
  1154. }
  1155. }
  1156. return ModuleName.Unknown;
  1157. }
  1158. }
  1159. }