SchedulerSequenceManager.cs 53 KB

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