SchedulerSequenceManager.cs 79 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713
  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.Modules.Loader;
  37. using CyberX8_RT.Schedulers.Transporter;
  38. using CyberX8_RT.Schedulers.Loader;
  39. using CyberX8_RT.Devices.EFEM;
  40. namespace CyberX8_RT.Schedulers
  41. {
  42. public class SchedulerSequenceManager : Singleton<SchedulerSequenceManager>
  43. {
  44. #region 常量
  45. private const string ENGINEERING = "Engineering";
  46. private const string PRODUCTION = "Production";
  47. private const string TRNPA = "TRNPA";
  48. private const string TRNPB = "TRNPB";
  49. #endregion
  50. /// <summary>
  51. /// 解析Wafer所有调度工序
  52. /// </summary>
  53. /// <param name="sequenceRecipe"></param>
  54. /// <returns></returns>
  55. public List<SchedulerSequence> AnalyWaferAllSchedulerSequence(WaferInfo waferInfo,ModuleName pufModule,string side,WaferHolderInfo waferHolderInfo,SequenceRecipe sequenceRecipe)
  56. {
  57. waferInfo.LoaderSide = side;
  58. List<SchedulerSequence> schedulerSequences = new List<SchedulerSequence>();
  59. int index = 0;
  60. MoveItem moveItem = new MoveItem((ModuleName)waferInfo.OriginStation, waferInfo.OriginSlot, ModuleName.Aligner1, 0, Aitex.Sorter.Common.Hand.Blade1);
  61. SchedulerSequence efemRobotSequence = CreateEfemRobotSequence(moveItem,null,sequenceRecipe.SubstrateSize,ref index);
  62. schedulerSequences.Add(efemRobotSequence);
  63. SchedulerSequence alignerSequence=CreateAlignerSequence(sequenceRecipe,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,sequenceRecipe.SubstrateSize, 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,sequenceRecipe.SubstrateSize, 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,sequenceRecipe.SubstrateSize, 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,sequenceRecipe.SubstrateSize, 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 productWaferCount,int dummyWaferCount)
  139. {
  140. int totalWaferCount = productWaferCount + dummyWaferCount;
  141. int index = 0;
  142. List<SchedulerSequence> schedulerSequences = new List<SchedulerSequence>();
  143. //Buffer To Loader
  144. ModuleName currentLocationModuleName = (ModuleName)Enum.Parse(typeof(ModuleName), waferHolderInfo.CurrentLocation);
  145. TransporterAction transporterAction = GenerateTransporterTransferAction(currentLocationModuleName, ModuleType.Buffer, ModuleName.Loader1, ModuleType.Loader);
  146. string strTRNP = AnalyseLoadTransporterSide(sequenceRecipe, productWaferCount,dummyWaferCount);
  147. List<SchedulerSyncModuleMessage> synModules = GenerateLoaderTransporterSyncModuleMessage(strTRNP);
  148. SchedulerSequence bufferToLoaderSequence = CreateLoaderTransporterSequence(transporterAction,synModules,waferHolderInfo.WaferSize, ref index);
  149. schedulerSequences.Add(bufferToLoaderSequence);
  150. //尺寸不一致
  151. bool needFlip = CheckLoaderWaferSizeNotEqual() && totalWaferCount == 2;
  152. //Loader
  153. LoaderParameter parameter = new LoaderParameter();
  154. parameter.WaferCount= needFlip?1: totalWaferCount;
  155. parameter.LoadCompleteToTransporterSide = strTRNP;
  156. parameter.NeedWaitFlip = needFlip;
  157. SchedulerSequence loaderSequence = CreateLoaderSequence(parameter,sequenceRecipe.SubstrateSize, ref index);
  158. schedulerSequences.Add(loaderSequence);
  159. if (needFlip)
  160. {
  161. string reverse = GetReverseTransporterLocation(strTRNP);
  162. TransporterAction flipAction = GenerateTransporterFlipAction(reverse);
  163. SchedulerSequence flipSequence=CreateLoaderTransporterSequence(flipAction,null,sequenceRecipe.SubstrateSize, ref index);
  164. schedulerSequences.Add(flipSequence);
  165. //Loader
  166. LoaderParameter reverseParameter = new LoaderParameter();
  167. reverseParameter.WaferCount = 1;
  168. reverseParameter.LoadCompleteToTransporterSide = reverse;
  169. reverseParameter.NeedWaitFlip = false;
  170. SchedulerSequence reverseLoadSequence = CreateLoaderSequence(reverseParameter,sequenceRecipe.SubstrateSize, ref index);
  171. schedulerSequences.Add(reverseLoadSequence);
  172. }
  173. //wafer holder装载后的recipe工序
  174. List<SchedulerSequence> waferHolderAfterLoadedAllSequences = WaferHolderAfterLoadedAllSchedulerSequences(waferHolderInfo, sequenceRecipe,ref index);
  175. schedulerSequences.AddRange(waferHolderAfterLoadedAllSequences);
  176. return schedulerSequences;
  177. }
  178. /// <summary>
  179. /// 解析LoaderTransporter放至Loader第一次确定TRNP的方向
  180. /// </summary>
  181. /// <param name="sequenceRecipe"></param>
  182. /// <param name="waferCount"></param>
  183. /// <returns></returns>
  184. private string AnalyseLoadTransporterSide(SequenceRecipe sequenceRecipe,int productWaferCount,int dummyWaferCount)
  185. {
  186. LoaderEntity loaderEntity = Singleton<RouteManager>.Instance.GetModule<LoaderEntity>(ModuleName.Loader1.ToString());
  187. //单片,同时loader两边尺寸不一致
  188. if ((productWaferCount == 1||dummyWaferCount==1) && loaderEntity.SideAWaferSize != loaderEntity.SideBWaferSize)
  189. {
  190. //recipe使用B面工艺,但loader A面与recipe尺寸一致
  191. if (sequenceRecipe.LastSingleWaferToSideB && sequenceRecipe.SubstrateSize == loaderEntity.SideAWaferSize)
  192. {
  193. return "TRNPB";
  194. }
  195. //recipe使用A面工艺,但loader B面与recipe尺寸一致
  196. else if (!sequenceRecipe.LastSingleWaferToSideB && sequenceRecipe.SubstrateSize == loaderEntity.SideBWaferSize)
  197. {
  198. return "TRNPB";
  199. }
  200. }
  201. return "TRNPA";
  202. }
  203. private string GetReverseTransporterLocation(string strTrn)
  204. {
  205. return strTrn == TRNPA ? TRNPB : TRNPA;
  206. }
  207. /// <summary>
  208. /// 创建Transporter transfer指令
  209. /// </summary>
  210. /// <param name="source"></param>
  211. /// <param name="sourceType"></param>
  212. /// <param name="dest"></param>
  213. /// <param name="destType"></param>
  214. /// <returns></returns>
  215. private TransporterAction GenerateTransporterTransferAction(ModuleName source,ModuleType sourceType,ModuleName dest,ModuleType destType)
  216. {
  217. TransporterAction transporterAction = new TransporterAction();
  218. transporterAction.ActionMsg = TransporterMSG.Transfer;
  219. WaferHolderMoveItem waferHolderMoveItem = new WaferHolderMoveItem(source, sourceType, dest, destType);
  220. transporterAction.Parameter = waferHolderMoveItem;
  221. return transporterAction;
  222. }
  223. /// <summary>
  224. /// 创建Transporter pickup指令
  225. /// </summary>
  226. /// <param name="source"></param>
  227. /// <param name="sourceType"></param>
  228. /// <param name="dest"></param>
  229. /// <param name="destType"></param>
  230. /// <returns></returns>
  231. private TransporterAction GenerateTransporterFlipAction(string strTransporter)
  232. {
  233. TransporterAction transporterAction = new TransporterAction();
  234. transporterAction.ActionMsg = TransporterMSG.Flip;
  235. transporterAction.Parameter = strTransporter;
  236. return transporterAction;
  237. }
  238. /// <summary>
  239. /// 检验Loader两边waferSize不一致
  240. /// </summary>
  241. /// <returns></returns>
  242. private bool CheckLoaderWaferSizeNotEqual()
  243. {
  244. LoaderEntity loaderEntity = Singleton<RouteManager>.Instance.GetModule<LoaderEntity>(ModuleName.Loader1.ToString());
  245. return loaderEntity.SideAWaferSize != loaderEntity.SideBWaferSize;
  246. }
  247. /// <summary>
  248. /// 创建LoaderTrasporter同步模块消息
  249. /// </summary>
  250. /// <param name="tranporter"></param>
  251. /// <returns></returns>
  252. private List<SchedulerSyncModuleMessage> GenerateLoaderTransporterSyncModuleMessage(string tranporter)
  253. {
  254. List<SchedulerSyncModuleMessage> synModules = new List<SchedulerSyncModuleMessage>();
  255. SchedulerSyncModuleMessage syncModuleMessage = new SchedulerSyncModuleMessage();
  256. syncModuleMessage.ModuleEntity = Singleton<RouteManager>.Instance.GetModule<IModuleEntity>(ModuleName.Loader1.ToString());
  257. syncModuleMessage.ModuleMsg = LoaderMSG.PrepareForPlace.ToString();
  258. syncModuleMessage.parameters = new object[] { tranporter };
  259. synModules.Add(syncModuleMessage);
  260. return synModules;
  261. }
  262. /// <summary>
  263. /// Dummy Wafer对应WaferHolder任务
  264. /// </summary>
  265. /// <param name="waferHolderInfo"></param>
  266. /// <returns></returns>
  267. public List<SchedulerSequence> AnalyseDummyWaferHolderAllSchedulerSequence(WaferHolderInfo waferHolderInfo,int productWaferCount,int dummyWaferCount)
  268. {
  269. int index = 0;
  270. List<SchedulerSequence> schedulerSequences = new List<SchedulerSequence>();
  271. string strTRNP = AnalyseLoadTransporterSide(waferHolderInfo.SequenceRecipe, productWaferCount,dummyWaferCount);
  272. //Buffer To Loader
  273. ModuleName currentLocationModuleName = (ModuleName)Enum.Parse(typeof(ModuleName), waferHolderInfo.CurrentLocation);
  274. ModuleName bufferModule = (ModuleName)Enum.Parse(typeof(ModuleName), waferHolderInfo.OriginalBuffer);
  275. List<SchedulerSyncModuleMessage> synModules = GenerateLoaderTransporterSyncModuleMessage(strTRNP);
  276. TransporterAction transporterAction = GenerateTransporterTransferAction(currentLocationModuleName, ModuleType.Buffer, ModuleName.Loader1, ModuleType.Loader);
  277. SchedulerSequence bufferToLoaderSequence = CreateLoaderTransporterSequence(transporterAction,synModules,waferHolderInfo.WaferSize, ref index);
  278. schedulerSequences.Add(bufferToLoaderSequence);
  279. //尺寸不一致
  280. bool needFlip = CheckLoaderWaferSizeNotEqual() && dummyWaferCount == 2;
  281. //Loader
  282. LoaderParameter parameter = new LoaderParameter();
  283. parameter.WaferCount = needFlip ? 1 : dummyWaferCount; ;
  284. parameter.LoadCompleteToTransporterSide = strTRNP;
  285. parameter.NeedWaitFlip = needFlip;
  286. SchedulerSequence loaderSequence = CreateLoaderSequence(parameter,waferHolderInfo.WaferSize,ref index);
  287. schedulerSequences.Add(loaderSequence);
  288. if (needFlip)
  289. {
  290. string reverse = GetReverseTransporterLocation(strTRNP);
  291. TransporterAction flipAction = GenerateTransporterFlipAction(reverse);
  292. SchedulerSequence flipSequence = CreateLoaderTransporterSequence(flipAction, null,waferHolderInfo.WaferSize, ref index);
  293. schedulerSequences.Add(flipSequence);
  294. //Loader
  295. LoaderParameter reverseParameter = new LoaderParameter();
  296. reverseParameter.WaferCount = 1;
  297. reverseParameter.LoadCompleteToTransporterSide = reverse;
  298. reverseParameter.NeedWaitFlip = false;
  299. SchedulerSequence reverseLoadSequence = CreateLoaderSequence(reverseParameter,waferHolderInfo.WaferSize, ref index);
  300. schedulerSequences.Add(reverseLoadSequence);
  301. }
  302. //Loader To Buffer
  303. TransporterAction loaderMoveToBufferAction=GenerateTransporterTransferAction (ModuleName.Loader1, ModuleType.Loader,
  304. bufferModule, ModuleType.Buffer);
  305. SchedulerSequence loaderToBufferSequence = CreateLoaderTransporterSequence(loaderMoveToBufferAction,null,waferHolderInfo.WaferSize, ref index);
  306. schedulerSequences.Add(loaderToBufferSequence);
  307. return schedulerSequences;
  308. }
  309. /// <summary>
  310. /// 解析Dummy Wafer所有调度工序
  311. /// </summary>
  312. /// <param name="sequenceRecipe"></param>
  313. /// <returns></returns>
  314. public List<SchedulerSequence> AnalyDummyWaferAllSchedulerSequence(SequenceRecipe sequenceRecipe,WaferInfo waferInfo, ModuleName pufModule,string side)
  315. {
  316. waferInfo.LoaderSide = side;
  317. List<SchedulerSequence> schedulerSequences = new List<SchedulerSequence>();
  318. int index = 0;
  319. //DummyCassete至Aligner
  320. MoveItem moveItem = new MoveItem((ModuleName)waferInfo.Station, waferInfo.Slot, ModuleName.Aligner1, 0, Aitex.Sorter.Common.Hand.Blade1);
  321. SchedulerSequence secondEfemRobotSequence = CreateEfemRobotSequence(moveItem, null,sequenceRecipe.SubstrateSize, ref index);
  322. schedulerSequences.Add(secondEfemRobotSequence);
  323. //Aligner
  324. SchedulerSequence alignerSequence = alignerSequence=CreateAlignerSequence(sequenceRecipe, ref index);
  325. schedulerSequences.Add(alignerSequence);
  326. //Aligner至Puf
  327. MoveItem alignerToPufMoveItem = new MoveItem(ModuleName.Aligner1, 0, pufModule, 1, Aitex.Sorter.Common.Hand.Blade1);
  328. SchedulerSequence alignerToPufEfemRobotSequence = CreateEfemRobotSequence(alignerToPufMoveItem, null,sequenceRecipe.SubstrateSize, ref index);
  329. schedulerSequences.Add(alignerToPufEfemRobotSequence);
  330. SchedulerSequence pufSequence = CreatePufSequence(pufModule,sequenceRecipe, side,true, ref index);
  331. schedulerSequences.Add(pufSequence);
  332. return schedulerSequences;
  333. }
  334. /// <summary>
  335. /// Loader装载后Recipe工序
  336. /// </summary>
  337. /// <param name="waferHolderInfo"></param>
  338. /// <param name="sequenceRecipe"></param>
  339. /// <param name="index"></param>
  340. /// <returns></returns>
  341. private List<SchedulerSequence> WaferHolderAfterLoadedAllSchedulerSequences(WaferHolderInfo waferHolderInfo,SequenceRecipe sequenceRecipe,ref int index)
  342. {
  343. List<SchedulerSequence> schedulerSequences = new List<SchedulerSequence>();
  344. if(!Enum.TryParse(waferHolderInfo.OriginalBuffer,out ModuleName moduleName))
  345. {
  346. return schedulerSequences;
  347. }
  348. //Loader To Buffer
  349. TransporterAction loaderMoveToBufferAction = GenerateTransporterTransferAction(ModuleName.Loader1, ModuleType.Loader,
  350. moduleName, ModuleType.Buffer);
  351. SchedulerSequence loaderToBufferSequence = CreateLoaderTransporterSequence(loaderMoveToBufferAction,null,sequenceRecipe.SubstrateSize, ref index);
  352. schedulerSequences.Add(loaderToBufferSequence);
  353. //解析sequence recipe后续的工序
  354. var sequences = AnalyseSequenceRecipeScheduler(sequenceRecipe);
  355. SchedulerSequence firstSequence = sequences[0];
  356. //buffer to recipe第一个工序
  357. TransporterAction bufferToFirstAction = GenerateTransporterTransferAction(moduleName, ModuleType.Buffer, firstSequence.ModuleName, firstSequence.ModuleType);
  358. SchedulerSequence bufferSequence = CreateLoaderTransporterSequence(bufferToFirstAction,null,sequenceRecipe.SubstrateSize, ref index);
  359. schedulerSequences.Add(bufferSequence);
  360. //调整工序后面的索引
  361. foreach (SchedulerSequence item in sequences)
  362. {
  363. item.SequenceIndex = index;
  364. index++;
  365. }
  366. schedulerSequences.AddRange(sequences);
  367. //从recipe最后工序
  368. SchedulerSequence lastSequence = sequences[sequences.Count - 1];
  369. TransporterAction lastToBufferAction = GenerateTransporterTransferAction(lastSequence.ModuleName, lastSequence.ModuleType, moduleName, ModuleType.Buffer);
  370. SchedulerSequence lastToBufferSequence = CreateLoaderTransporterSequence(lastToBufferAction,null,sequenceRecipe.SubstrateSize, ref index);
  371. schedulerSequences.Add(lastToBufferSequence);
  372. return schedulerSequences;
  373. }
  374. /// <summary>
  375. /// 分析Sequence recipe对应的调度步骤
  376. /// </summary>
  377. /// <param name="sequenceRecipe"></param>
  378. /// <returns></returns>
  379. private List<SchedulerSequence> AnalyseSequenceRecipeScheduler(SequenceRecipe sequenceRecipe)
  380. {
  381. List<SchedulerSequence> schedulerSequences= new List<SchedulerSequence>();
  382. List<SchedulerSequence> tmpLst = new List<SchedulerSequence>();
  383. var processResult = AnalyseLastProcessRecipeIndex(sequenceRecipe.Recipes);
  384. bool isExistSrd = sequenceRecipe.Recipes.FindIndex(O=>O.ToLower().EndsWith("srd.rcp"))!=-1;
  385. int lastIndex = isExistSrd ? sequenceRecipe.Recipes.Count - 2 : sequenceRecipe.Recipes.Count - 1;
  386. for(int i=0;i<sequenceRecipe.Recipes.Count;i++)
  387. {
  388. string item = sequenceRecipe.Recipes[i];
  389. if(item.ToLower().EndsWith("srd.rcp"))//跳过SRD
  390. {
  391. continue;
  392. }
  393. SchedulerSequence schedulerSequence = new SchedulerSequence();
  394. if (i == 0 && item.ToLower().EndsWith("qdr.rcp"))
  395. {
  396. RinseItem rinsePwtItem = RinseItemManager.Instance.GetPrewetRinseItem();
  397. if (rinsePwtItem != null)
  398. {
  399. schedulerSequence.ModuleName = (ModuleName)Enum.Parse(typeof(ModuleName), rinsePwtItem.ModuleName);
  400. schedulerSequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(schedulerSequence.ModuleName);
  401. }
  402. else
  403. {
  404. schedulerSequence.ModuleName = ModuleName.Unknown;
  405. }
  406. }
  407. else
  408. {
  409. schedulerSequence.ModuleName = ModuleName.Unknown;
  410. }
  411. schedulerSequence.ModuleType=SequenceRecipeManager.Instance.GetModuleType(item);
  412. schedulerSequence.SequenceIndex=i;
  413. schedulerSequence.WaferSize = sequenceRecipe.SubstrateSize;
  414. MECF.Framework.Common.RecipeCenter.RecipeType recipeType =SequenceRecipeManager.Instance.GetRecipeType(item);
  415. schedulerSequence.Recipe = SequenceRecipeManager.Instance.LoadSequenceTypeRecipe(sequenceRecipe.SequenceType,item, recipeType);
  416. schedulerSequence.SequenceType = sequenceRecipe.SequenceType;
  417. schedulerSequence.State = RState.Init;
  418. schedulerSequence.MaterialType = MaterialType.WaferHolder;
  419. tmpLst.Add(schedulerSequence);
  420. if (i != lastIndex)
  421. {
  422. string nextModule = sequenceRecipe.Recipes[i + 1];
  423. schedulerSequence.NextModuleType = SequenceRecipeManager.Instance.GetModuleType(nextModule);
  424. MECF.Framework.Common.RecipeCenter.RecipeType nextRecipeType = SequenceRecipeManager.Instance.GetRecipeType(nextModule);
  425. schedulerSequence.NextRecipe = SequenceRecipeManager.Instance.LoadSequenceTypeRecipe(sequenceRecipe.SequenceType, nextModule, nextRecipeType);
  426. }
  427. schedulerSequence.IsProcessSequece = true;
  428. if(i==processResult.lastIndex)
  429. {
  430. schedulerSequence.IsLastProcessSequence = true;
  431. }
  432. }
  433. int index = 0;
  434. for(int i=0;i<tmpLst.Count;i++)
  435. {
  436. tmpLst[i].SequenceIndex = 0;
  437. schedulerSequences.Add(tmpLst[i]);
  438. index++;
  439. if(i<tmpLst.Count-1)
  440. {
  441. TransporterAction transporterAction = new TransporterAction();
  442. transporterAction.ActionMsg = TransporterMSG.Transfer;
  443. WaferHolderMoveItem moveItem = new WaferHolderMoveItem(tmpLst[i].ModuleName, tmpLst[i].ModuleType, tmpLst[i+1].ModuleName, tmpLst[i + 1].ModuleType);
  444. transporterAction.Parameter = moveItem;
  445. SchedulerSequence schedulerSequence=CreateProcessTransporterSequence(transporterAction,sequenceRecipe.SubstrateSize,ref index);
  446. schedulerSequences.Add(schedulerSequence);
  447. }
  448. }
  449. return schedulerSequences;
  450. }
  451. /// <summary>
  452. /// 分析最后加工recipe索引
  453. /// </summary>
  454. /// <param name="recipes"></param>
  455. /// <returns></returns>
  456. private (int lastIndex,List<int> processIndexList) AnalyseLastProcessRecipeIndex(List<string> recipes)
  457. {
  458. int index = 0;
  459. List<int> lst = new List<int>();
  460. for(int i=0;i<recipes.Count; i++)
  461. {
  462. string item=recipes[i];
  463. if(item.ToLower().EndsWith("dep.rcp"))
  464. {
  465. index = i;
  466. if(lst.Contains(i))
  467. {
  468. lst.Add(i);
  469. }
  470. }
  471. }
  472. if(lst.Count==0)
  473. {
  474. lst.Add(0);
  475. }
  476. return (index,lst);
  477. }
  478. /// <summary>
  479. /// 创建EFEM Robot步骤
  480. /// </summary>
  481. /// <param name="index"></param>
  482. /// <returns></returns>
  483. private SchedulerSequence CreateEfemRobotSequence(MoveItem moveItem,List<SchedulerSyncModuleMessage> synModules,int waferSize,ref int index)
  484. {
  485. SchedulerSequence sequence = new SchedulerSequence();
  486. sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.EfemRobot);
  487. sequence.SequenceIndex= index;
  488. sequence.ModuleName=ModuleName.EfemRobot;
  489. sequence.State = RState.Init;
  490. sequence.Recipe = null;
  491. sequence.ModuleType=ModuleType.EfemRobot;
  492. sequence.Parameters =moveItem;
  493. sequence.MaterialType = MaterialType.Wafer;
  494. sequence.SynchronousModuleMessages = synModules;
  495. sequence.WaferSize = waferSize;
  496. index++;
  497. return sequence;
  498. }
  499. /// <summary>
  500. /// 创建Aligner步骤
  501. /// </summary>
  502. /// <param name="index"></param>
  503. /// <returns></returns>
  504. private SchedulerSequence CreateAlignerSequence(SequenceRecipe recipe,ref int index)
  505. {
  506. SchedulerSequence sequence = new SchedulerSequence();
  507. sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.Aligner1);
  508. sequence.SequenceIndex = index;
  509. sequence.ModuleName = ModuleName.Aligner1;
  510. sequence.State = RState.Init;
  511. sequence.Recipe = recipe;
  512. sequence.ModuleType = ModuleType.Aligner;
  513. sequence.Parameters = null;
  514. sequence.MaterialType = MaterialType.Wafer;
  515. sequence.WaferSize = sequence.WaferSize;
  516. index++;
  517. return sequence;
  518. }
  519. /// <summary>
  520. /// 创建PUF步骤
  521. /// </summary>
  522. /// <param name="pufModuleName"></param>
  523. /// <param name="index"></param>
  524. /// <returns></returns>
  525. private SchedulerSequence CreatePufSequence(ModuleName pufModuleName,SequenceRecipe sequenceRecipe,string side,bool forward,ref int index)
  526. {
  527. SchedulerSequence sequence = new SchedulerSequence();
  528. sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(pufModuleName);
  529. sequence.SequenceIndex = index;
  530. sequence.ModuleName = pufModuleName;
  531. sequence.State = RState.Init;
  532. sequence.Recipe = sequenceRecipe;
  533. PufSchedulerParameter parameter = new PufSchedulerParameter()
  534. {
  535. IsForward = forward,
  536. Side = side,
  537. };
  538. sequence.Parameters = parameter;
  539. sequence.IsWaitNotify = !forward;
  540. sequence.ModuleType = ModuleType.PUF;
  541. sequence.MaterialType = MaterialType.Wafer;
  542. sequence.WaferSize = sequenceRecipe.SubstrateSize;
  543. index++;
  544. return sequence;
  545. }
  546. /// <summary>
  547. /// 创建Loader步骤
  548. /// </summary>
  549. /// <param name="index"></param>
  550. /// <returns></returns>
  551. private SchedulerSequence CreateLoaderSequence(LoaderParameter parameter,int waferSize,ref int index)
  552. {
  553. SchedulerSequence sequence = new SchedulerSequence();
  554. sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.Loader1);
  555. sequence.SequenceIndex = index;
  556. sequence.ModuleName = ModuleName.Loader1;
  557. sequence.State = RState.Init;
  558. sequence.Recipe = null;
  559. sequence.Parameters = parameter;
  560. sequence.ModuleType = ModuleType.Loader;
  561. sequence.MaterialType = MaterialType.WaferHolder;
  562. sequence.WaferSize = waferSize;
  563. index++;
  564. return sequence;
  565. }
  566. /// <summary>
  567. /// 创建Loader步骤
  568. /// </summary>
  569. /// <param name="index"></param>
  570. /// <returns></returns>
  571. private SchedulerSequence CreateSRDSequence(SrdRecipe recipe,ref int index)
  572. {
  573. SchedulerSequence sequence = new SchedulerSequence();
  574. sequence.SequenceIndex = index;
  575. sequence.State = RState.Init;
  576. sequence.Recipe = recipe;
  577. sequence.ModuleType = ModuleType.SRD;
  578. sequence.MaterialType = MaterialType.Wafer;
  579. index++;
  580. return sequence;
  581. }
  582. /// <summary>
  583. /// 创建LoaderTransporter步骤
  584. /// </summary>
  585. /// <param name="index"></param>
  586. /// <returns></returns>
  587. private SchedulerSequence CreateLoaderTransporterSequence(TransporterAction transporterAction, List<SchedulerSyncModuleMessage> synModules,int waferSize, ref int index)
  588. {
  589. SchedulerSequence sequence = new SchedulerSequence();
  590. sequence.ModuleType = ModuleType.Transporter;
  591. sequence.ModuleName = ModuleName.Transporter2;
  592. sequence.SequenceIndex = index;
  593. sequence.State = RState.Init;
  594. sequence.Recipe = null;
  595. sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.Transporter2);
  596. sequence.Parameters = transporterAction;
  597. sequence.MaterialType = MaterialType.WaferHolder;
  598. sequence.SynchronousModuleMessages = synModules;
  599. sequence.WaferSize = waferSize;
  600. index++;
  601. return sequence;
  602. }
  603. /// <summary>
  604. /// 创建LoaderTransporter步骤
  605. /// </summary>
  606. /// <param name="index"></param>
  607. /// <returns></returns>
  608. private SchedulerSequence CreateProcessTransporterSequence(TransporterAction transporterAction,int waferSize, ref int index)
  609. {
  610. SchedulerSequence sequence = new SchedulerSequence();
  611. sequence.ModuleType = ModuleType.Transporter;
  612. sequence.ModuleName = ModuleName.Transporter1;
  613. sequence.SequenceIndex = index;
  614. sequence.State = RState.Init;
  615. sequence.Recipe = null;
  616. sequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(ModuleName.Transporter1);
  617. sequence.Parameters= transporterAction;
  618. sequence.MaterialType = MaterialType.WaferHolder;
  619. sequence.WaferSize = waferSize;
  620. index++;
  621. return sequence;
  622. }
  623. /// <summary>
  624. /// 获取可用Dummy slot
  625. /// </summary>
  626. /// <param name="moduleType"></param>
  627. /// <returns></returns>
  628. public (ModuleName moduleName, int slot) GetAvaibleDummySlots(WaferSize waferSize)
  629. {
  630. if (ModuleHelper.IsInstalled(ModuleName.Dummy1))
  631. {
  632. DummyEntity dummyEntity = Singleton<RouteManager>.Instance.GetModule<DummyEntity>(ModuleName.Dummy1.ToString());
  633. DummyDevice dummyDevice = Singleton<RouteManager>.Instance.EFEM.GetDummyDevice(0);
  634. if (dummyDevice != null && dummyDevice.HasCassette && dummyDevice.WaferSize == waferSize)
  635. {
  636. for (int i = 0; i < dummyEntity.MaxSlotNumber; i++)
  637. {
  638. if (WaferManager.Instance.CheckNoWafer(ModuleName.Dummy1, i))
  639. {
  640. return (ModuleName.Dummy1, i);
  641. }
  642. }
  643. }
  644. }
  645. if (ModuleHelper.IsInstalled(ModuleName.Dummy2))
  646. {
  647. DummyEntity dummyEntity = Singleton<RouteManager>.Instance.GetModule<DummyEntity>(ModuleName.Dummy2.ToString());
  648. DummyDevice dummyDevice = Singleton<RouteManager>.Instance.EFEM.GetDummyDevice(1);
  649. if (dummyDevice != null && dummyDevice.HasCassette && dummyDevice.WaferSize == waferSize)
  650. {
  651. for (int i = 0; i < dummyEntity.MaxSlotNumber; i++)
  652. {
  653. if (WaferManager.Instance.CheckNoWafer(ModuleName.Dummy2, i))
  654. {
  655. return (ModuleName.Dummy2, i);
  656. }
  657. }
  658. }
  659. }
  660. return (ModuleName.Unknown, -1);
  661. }
  662. /// <summary>
  663. /// 根据模块类型获取可用模块
  664. /// </summary>
  665. /// <param name="moduleType"></param>
  666. /// <returns></returns>
  667. public ModuleName GetAvaibleModuleCell(string sequenceType,ModuleType moduleType, ModuleName moduleName = ModuleName.Unknown)
  668. {
  669. if (ModuleHelper.IsMetal(moduleName))
  670. {
  671. List<IModuleEntity> entities = Singleton<RouteManager>.Instance.GetModulesByModuleType(moduleType);
  672. return GetMetalAvaibleRinseModule(entities, moduleName);
  673. }
  674. else
  675. {
  676. List<IModuleEntity> entities = Singleton<RouteManager>.Instance.GetModulesByModuleType(moduleType);
  677. List<IModuleEntity> avaibles = new List<IModuleEntity>();
  678. foreach (var item in entities)
  679. {
  680. bool result = CheckAvaibleModule(item,moduleType,sequenceType);
  681. if (result)
  682. {
  683. avaibles.Add(item);
  684. }
  685. }
  686. return GetMinTimeToReadyModule(avaibles,moduleType);
  687. }
  688. }
  689. /// <summary>
  690. /// 获取可用的Dryer cell
  691. /// </summary>
  692. /// <param name="waferHolderId"></param>
  693. /// <param name="startTime"></param>
  694. /// <param name="dryerTimeLength"></param>
  695. /// <returns></returns>
  696. public ModuleName GetAvaibleDryerCell(string waferHolderId, DateTime startTime, int dryerTimeLength, bool checkConflict)
  697. {
  698. List<IModuleEntity> entities = Singleton<RouteManager>.Instance.GetModulesByModuleType(ModuleType.Dryer);
  699. List<IModuleEntity> avaibleEntities = new List<IModuleEntity>();
  700. foreach (IModuleEntity item in entities)
  701. {
  702. if ((item.IsIdle || item.IsBusy) && item.IsAuto)
  703. {
  704. avaibleEntities.Add(item);
  705. }
  706. }
  707. if (checkConflict)
  708. {
  709. List<ModuleName> resets = SchedulerDryerTimeManager.Instance.ResetModuleOrderByUsed(avaibleEntities);
  710. List<IModuleEntity> avaibles = new List<IModuleEntity>();
  711. foreach (var item in resets)
  712. {
  713. var conflict = SchedulerDryerTimeManager.Instance.CheckDryerConflict(item.ToString(), waferHolderId, startTime, dryerTimeLength);
  714. if (!conflict.conflict)
  715. {
  716. return item;
  717. }
  718. }
  719. }
  720. else
  721. {
  722. List<ModuleName> resets = SchedulerDryerTimeManager.Instance.ResetModuleOrderBySchedulerEndTime(avaibleEntities);
  723. if (resets.Count != 0)
  724. {
  725. return resets[0];
  726. }
  727. }
  728. return ModuleName.Unknown;
  729. }
  730. /// <summary>
  731. /// 获取可用的Dryer cell
  732. /// </summary>
  733. /// <param name="waferHolderId"></param>
  734. /// <param name="startTime"></param>
  735. /// <param name="dryerTimeLength"></param>
  736. /// <returns></returns>
  737. public ModuleName GetAvaibleQdrCell(string waferHolderId, string metalName)
  738. {
  739. List<LayoutCellItem> rinseItems = CellItemManager.Instance.GetRinseItemsByMetal(metalName.ToString());
  740. if (rinseItems.Count == 0)
  741. {
  742. return ModuleName.Unknown;
  743. }
  744. List<IModuleEntity> entities = Singleton<RouteManager>.Instance.GetModulesByModuleType(ModuleType.Rinse);
  745. List<IModuleEntity> avaibles = new List<IModuleEntity>();
  746. foreach (var item in entities)
  747. {
  748. LayoutCellItem cellItem = rinseItems.Find(O => O.ModuleName == item.Module.ToString());
  749. if (cellItem != null)
  750. {
  751. RinseEntity rinseEntity = (RinseEntity)item;
  752. if ((rinseEntity.IsBusy || rinseEntity.IsIdle) && rinseEntity.IsAuto)
  753. {
  754. avaibles.Add(rinseEntity);
  755. }
  756. }
  757. }
  758. List<ModuleName> resets = SchedulerQdrTimeManager.Instance.ResetModuleOrderBySchedulerEndTime(avaibles);
  759. if (resets.Count != 0)
  760. {
  761. return resets[0];
  762. }
  763. return ModuleName.Unknown;
  764. }
  765. /// <summary>
  766. /// 根据模块类型获取可用模块(不包含WH)
  767. /// </summary>
  768. /// <param name="moduleType"></param>
  769. /// <returns></returns>
  770. public ModuleName GetAvaibleEmptyModuleCell(ModuleType moduleType,string sequenceType, ModuleName moduleName = ModuleName.Unknown)
  771. {
  772. if (ModuleHelper.IsMetal(moduleName))
  773. {
  774. List<IModuleEntity> entities = Singleton<RouteManager>.Instance.GetModulesByModuleType(moduleType);
  775. return GetMetalAvaibleEmptyRinseModule(entities, moduleName);
  776. }
  777. else
  778. {
  779. List<IModuleEntity> entities = Singleton<RouteManager>.Instance.GetModulesByModuleType(moduleType);
  780. List<IModuleEntity> avaibles = new List<IModuleEntity>();
  781. foreach (var item in entities)
  782. {
  783. bool result = CheckAvaibleModule(item,moduleType,sequenceType);
  784. if (result&&!WaferHolderManager.Instance.HasWaferHolder(item.Module.ToString()))
  785. {
  786. avaibles.Add(item);
  787. }
  788. }
  789. return avaibles.Count != 0 ? avaibles[0].Module : ModuleName.Unknown;
  790. }
  791. }
  792. /// <summary>
  793. /// 根据化学液计算时间获取可用MetalCell(参考其他Metal剩余时间)
  794. /// </summary>
  795. /// <param name="chemistry"></param>
  796. /// <returns></returns>
  797. public ModuleName CalculateAvaibleMetalCellByChemistry(string chemistry,string startRinse,string sequenceType,int waferSize,ref bool isExistEnableMetal)
  798. {
  799. if(!Enum.TryParse(startRinse,out ModuleName startRinseModule)||!ModuleHelper.IsRinse(startRinseModule))
  800. {
  801. startRinse = "";
  802. }
  803. isExistEnableMetal = false;
  804. List<MetalEntity> moduleEntities = GetAvaibleMetalList(chemistry,sequenceType,waferSize,true);
  805. List<IModuleEntity> avaibleMetalEntities = new List<IModuleEntity>();
  806. foreach (var item in moduleEntities)
  807. {
  808. if(CheckAvaibleModule(item,ModuleType.Metal,sequenceType))
  809. {
  810. if (item.WaferHolderInfo == null)
  811. {
  812. if (CheckMetalModuleRinseAvaible(item, startRinse))
  813. {
  814. avaibleMetalEntities.Add(item);
  815. }
  816. }
  817. isExistEnableMetal = true;
  818. }
  819. }
  820. if (avaibleMetalEntities.Count > 0)
  821. {
  822. return GetMinUsageMetal(avaibleMetalEntities);
  823. }
  824. return ModuleName.Unknown;
  825. }
  826. /// <summary>
  827. /// 根据化学液计算时间获取可用MetalCell(参考其他Metal剩余时间)
  828. /// </summary>
  829. /// <param name="chemistry"></param>
  830. /// <returns></returns>
  831. public (ModuleName metalModule, ModuleName rinseModule) CalculateAvaibleMetalCellByChemistry(string chemistry, string startRinse, string sequenceType, string waferHolderId,
  832. int waferSize,DateTime startTime, int depRecipeTimeLength, int qdrRecipeTimeLength, bool checkConflict,
  833. SchedulerModulePartTime metalPartTime, SchedulerModulePartTime qdrParTime, ref bool isExistEnableMetal)
  834. {
  835. bool isShowLog = SC.GetValue<bool>("Scheduler.IsShowLog");
  836. if (!Enum.TryParse(startRinse, out ModuleName startRinseModule) || !ModuleHelper.IsRinse(startRinseModule))
  837. {
  838. startRinse = "";
  839. }
  840. isExistEnableMetal = false;
  841. List<MetalEntity> moduleEntities = GetAvaibleMetalList(chemistry, sequenceType,waferSize, false);
  842. List<IModuleEntity> avaibleMetalEntities = new List<IModuleEntity>();
  843. Dictionary<ModuleName, ModuleName> metalRinseDic = new Dictionary<ModuleName, ModuleName>();
  844. string metals = "";
  845. foreach (var item in moduleEntities)
  846. {
  847. if (CheckAvaibleMetalModule(item, ModuleType.Metal, sequenceType, waferHolderId, startTime, depRecipeTimeLength, checkConflict))
  848. {
  849. isExistEnableMetal = true;
  850. ModuleName tmpRinse = CheckMetalModuleRinseAvaible(item, startRinse, startTime, depRecipeTimeLength, qdrRecipeTimeLength, waferHolderId, checkConflict, qdrParTime);
  851. if (tmpRinse != ModuleName.Unknown)
  852. {
  853. metalRinseDic.Add(item.Module, tmpRinse);
  854. avaibleMetalEntities.Add(item);
  855. }
  856. else
  857. {
  858. metals += "," + item.Module.ToString() + "has no rinse";
  859. continue;
  860. }
  861. }
  862. else
  863. {
  864. metals += "," + item.Module.ToString();
  865. }
  866. }
  867. if (avaibleMetalEntities.Count > 0)
  868. {
  869. int transporterTransferSeconds = SC.GetValue<int>("Transporter.TransporterTransferSeconds");
  870. DateTime transporterMetalTime = startTime.AddSeconds(depRecipeTimeLength);
  871. if (checkConflict)
  872. {
  873. bool isIgnoreTransporterConflict = SC.GetValue<bool>("Scheduler.IsIgnoreTransporterConflict");
  874. if (!isIgnoreTransporterConflict)
  875. {
  876. //校验metal后面的transporter是否时间冲突
  877. var transporterMetalResult = SchedulerTransporterTimeManager.Instance.CheckTransporterConflict(ModuleName.Transporter1.ToString(),
  878. waferHolderId, transporterMetalTime);
  879. if (transporterMetalResult.conflict)
  880. {
  881. if (isShowLog)
  882. {
  883. LOG.WriteLog(eEvent.EV_SCHEDULER, "system", $"{waferHolderId} metal transporter conflict {transporterMetalTime}--{transporterMetalTime.AddSeconds(transporterTransferSeconds)}");
  884. }
  885. return (ModuleName.Unknown, ModuleName.Unknown);
  886. }
  887. //校验qdr后面的transporter是否时间冲突
  888. DateTime transporterQdrTime = startTime.AddSeconds(depRecipeTimeLength).AddSeconds(transporterTransferSeconds).AddSeconds(qdrRecipeTimeLength);
  889. var transporterQdrResult = SchedulerTransporterTimeManager.Instance.CheckTransporterConflict(ModuleName.Transporter1.ToString(),
  890. waferHolderId, transporterQdrTime);
  891. if (transporterQdrResult.conflict)
  892. {
  893. if (isShowLog)
  894. {
  895. LOG.WriteLog(eEvent.EV_SCHEDULER, "system", $"{waferHolderId} qdr transporter conflict {transporterQdrTime}--{transporterQdrTime.AddSeconds(transporterTransferSeconds)}");
  896. }
  897. return (ModuleName.Unknown, ModuleName.Unknown);
  898. }
  899. }
  900. }
  901. ModuleName metalModule = ModuleName.Unknown;
  902. if (checkConflict)
  903. {
  904. metalModule = GetMinUsageMetal(avaibleMetalEntities, depRecipeTimeLength, metalPartTime);
  905. }
  906. else
  907. {
  908. List<ModuleName> resets = SchedulerMetalTimeManager.Instance.ResetModuleOrderBySchedulerEndTime(avaibleMetalEntities);
  909. if (resets.Count != 0)
  910. {
  911. metalModule = resets[0];
  912. }
  913. else
  914. {
  915. return (ModuleName.Unknown, ModuleName.Unknown);
  916. }
  917. }
  918. if (metalRinseDic.ContainsKey(metalModule))
  919. {
  920. return (metalModule, metalRinseDic[metalModule]);
  921. }
  922. else
  923. {
  924. return (ModuleName.Unknown, ModuleName.Unknown);
  925. }
  926. }
  927. else
  928. {
  929. if (isShowLog)
  930. {
  931. LOG.WriteLog(eEvent.EV_SCHEDULER, "system", $"{waferHolderId} metals {metals} no avaible metals {startTime}--{startTime.AddSeconds(depRecipeTimeLength)}");
  932. }
  933. }
  934. return (ModuleName.Unknown, ModuleName.Unknown);
  935. }
  936. /// <summary>
  937. /// 根据化学液获取可用Metal
  938. /// </summary>
  939. /// <param name="chemistry"></param>
  940. /// <param name="sequenceType"></param>
  941. /// <returns></returns>
  942. public bool CalculateAvaibleMetalCellByChemistry(string chemistry,string sequenceType,int waferSize)
  943. {
  944. List<MetalEntity> moduleEntities = GetAvaibleMetalList(chemistry, sequenceType,waferSize,false);
  945. return moduleEntities.Count != 0;
  946. }
  947. /// <summary>
  948. /// 检验Metal模块Rinse可用性
  949. /// </summary>
  950. /// <param name="item"></param>
  951. /// <returns></returns>
  952. private ModuleName CheckMetalModuleRinseAvaible(MetalEntity item, string startRinse, DateTime startTime,
  953. int depRecipeTimeLength, int qdrRecipeTimeLength, string waferHolderId, bool checkConflict, SchedulerModulePartTime qdrPartTime)
  954. {
  955. DateTime qdrStartTime = SchedulerQdrTimeManager.Instance.CalculateQdrSchedulerStartTime(startTime, depRecipeTimeLength);
  956. List<LayoutCellItem> rinseItems = CellItemManager.Instance.GetRinseItemsByMetal(item.Module.ToString());
  957. List<string> sharedRinseItems = new List<string>();
  958. List<string> singleRinseItems = new List<string>();
  959. foreach (var cellItem in rinseItems)
  960. {
  961. RinseEntity rinseEntity = Singleton<RouteManager>.Instance.GetModule<RinseEntity>(cellItem.ModuleName);
  962. if (!CellItemManager.Instance.CheckRinseIsShared(cellItem.ModuleName))
  963. {
  964. if (CheckAvaibleModule(rinseEntity, ModuleType.Rinse, ""))
  965. {
  966. singleRinseItems.Add(cellItem.ModuleName);
  967. }
  968. }
  969. else
  970. {
  971. if (CheckAvaibleModule(rinseEntity, ModuleType.Rinse, ""))
  972. {
  973. sharedRinseItems.Add(cellItem.ModuleName);
  974. }
  975. }
  976. }
  977. //独立的Rinse集合
  978. if (singleRinseItems.Count != 0)
  979. {
  980. if (checkConflict)
  981. {
  982. List<ModuleName> resets = SchedulerQdrTimeManager.Instance.ResetModuleOrder(singleRinseItems, qdrPartTime);
  983. foreach (ModuleName singleItem in resets)
  984. {
  985. var result = SchedulerQdrTimeManager.Instance.CheckQdrConflict(singleItem.ToString(), waferHolderId, qdrStartTime, qdrRecipeTimeLength);
  986. if (!result.conflict)
  987. {
  988. return singleItem;
  989. }
  990. }
  991. }
  992. else
  993. {
  994. List<ModuleName> resets = SchedulerQdrTimeManager.Instance.ResetModuleOrderBySchedulerEndTime(singleRinseItems, qdrPartTime);
  995. if (resets.Count != 0)
  996. {
  997. return resets[0];
  998. }
  999. }
  1000. }
  1001. //仅剩下共享Rinse
  1002. List<string> avaibleSharedList = new List<string>();
  1003. if (sharedRinseItems.Count != 0)
  1004. {
  1005. foreach (string sharedRinse in sharedRinseItems)
  1006. {
  1007. if (!avaibleSharedList.Contains(sharedRinse))
  1008. {
  1009. avaibleSharedList.Add(sharedRinse);
  1010. }
  1011. }
  1012. }
  1013. if (avaibleSharedList.Count != 0)
  1014. {
  1015. if (checkConflict)
  1016. {
  1017. List<ModuleName> resets = SchedulerQdrTimeManager.Instance.ResetModuleOrder(avaibleSharedList, qdrPartTime);
  1018. foreach (ModuleName shardItem in resets)
  1019. {
  1020. var result = SchedulerQdrTimeManager.Instance.CheckQdrConflict(shardItem.ToString(), waferHolderId, qdrStartTime, qdrRecipeTimeLength);
  1021. if (!result.conflict)
  1022. {
  1023. return shardItem;
  1024. }
  1025. }
  1026. }
  1027. else
  1028. {
  1029. List<ModuleName> resets = SchedulerQdrTimeManager.Instance.ResetModuleOrderBySchedulerEndTime(avaibleSharedList, qdrPartTime);
  1030. if (resets.Count != 0)
  1031. {
  1032. return resets[0];
  1033. }
  1034. }
  1035. }
  1036. return ModuleName.Unknown;
  1037. }
  1038. /// <summary>
  1039. /// 检验Metal模块Rinse可用性
  1040. /// </summary>
  1041. /// <param name="item"></param>
  1042. /// <returns></returns>
  1043. private bool CheckMetalModuleRinseAvaible(MetalEntity item,string startRinse)
  1044. {
  1045. List<LayoutCellItem> rinseItems = CellItemManager.Instance.GetRinseItemsByMetal(item.Module.ToString());
  1046. List<string> sharedRinseItems = new List<string>();
  1047. List<string> singleRinseItems = new List<string>();
  1048. foreach (var cellItem in rinseItems)
  1049. {
  1050. RinseEntity rinseEntity = Singleton<RouteManager>.Instance.GetModule<RinseEntity>(cellItem.ModuleName);
  1051. if (!CellItemManager.Instance.CheckRinseIsShared(cellItem.ModuleName))
  1052. {
  1053. if (CheckAvaibleModule(rinseEntity, ModuleType.Rinse, "") && rinseEntity.WaferHolderInfo == null)
  1054. {
  1055. singleRinseItems.Add(cellItem.ModuleName);
  1056. }
  1057. }
  1058. else
  1059. {
  1060. if (CheckAvaibleModule(rinseEntity,ModuleType.Rinse,"") && rinseEntity.WaferHolderInfo == null)
  1061. {
  1062. sharedRinseItems.Add(cellItem.ModuleName);
  1063. }
  1064. //增加自己
  1065. if (cellItem.ModuleName == startRinse && rinseEntity != null && (rinseEntity.IsIdle||rinseEntity.State==(int)RinseState.KeepWeting))
  1066. {
  1067. sharedRinseItems.Add(startRinse);
  1068. }
  1069. }
  1070. }
  1071. //独立的Rinse集合
  1072. if(singleRinseItems.Count!=0)
  1073. {
  1074. bool result = CheckSingleRinseItemsCanUsed(singleRinseItems, item.Module.ToString());
  1075. if(result)
  1076. {
  1077. return true;
  1078. }
  1079. }
  1080. //仅剩下共享Rinse
  1081. List<string> avaibleSharedList = new List<string>();
  1082. if (sharedRinseItems.Count != 0)
  1083. {
  1084. foreach (string sharedRinse in sharedRinseItems)
  1085. {
  1086. RinseEntity rinseEntity = Singleton<RouteManager>.Instance.GetModule<RinseEntity>(sharedRinse);
  1087. if (rinseEntity.IsBusy&&sharedRinse!=startRinse)
  1088. {
  1089. continue;
  1090. }
  1091. //检验共享Rinse是否可用
  1092. if (CheckShardRinseCanUse(sharedRinse, item.Module.ToString(),startRinse))
  1093. {
  1094. avaibleSharedList.Add(sharedRinse);
  1095. }
  1096. }
  1097. }
  1098. if (avaibleSharedList.Count != 0)
  1099. {
  1100. var result = CalculateMetalReservoirAllBusyMetalCount(item.Module.ToString());
  1101. if (result.success)
  1102. {
  1103. bool transporterTransfering = CheckProcessTransporterTransfering(avaibleSharedList);
  1104. if(transporterTransfering)
  1105. {
  1106. return result.busyCount + 1 < avaibleSharedList.Count;
  1107. }
  1108. else
  1109. {
  1110. return result.busyCount < avaibleSharedList.Count+singleRinseItems.Count;
  1111. }
  1112. }
  1113. }
  1114. return false;
  1115. }
  1116. /// <summary>
  1117. /// 检验Process transporter正在Transfer WH移动至Rinse
  1118. /// </summary>
  1119. /// <returns></returns>
  1120. private bool CheckProcessTransporterTransfering(List<string> rinseList)
  1121. {
  1122. TransporterEntity processTransporterEntity = Singleton<RouteManager>.Instance.GetModule<TransporterEntity>(ModuleName.Transporter1.ToString());
  1123. if(processTransporterEntity!=null)
  1124. {
  1125. if (processTransporterEntity.IsBusy)
  1126. {
  1127. string targetCell = processTransporterEntity.TargetCell;
  1128. if (rinseList.Contains(targetCell))
  1129. {
  1130. return true;
  1131. }
  1132. }
  1133. }
  1134. return false;
  1135. }
  1136. /// <summary>
  1137. /// 计算Metal所在Reservoir Busy Metal数量
  1138. /// </summary>
  1139. /// <param name="item"></param>
  1140. /// <returns></returns>
  1141. private (bool success,int busyCount) CalculateMetalReservoirAllBusyMetalCount(string metalName)
  1142. {
  1143. string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(metalName);
  1144. if (string.IsNullOrEmpty(reservoirName))
  1145. {
  1146. return (false,0);
  1147. }
  1148. List<string> metals = ReservoirItemManager.Instance.GetMetalsByReservoir(reservoirName);
  1149. int count = 0;
  1150. foreach (string item in metals)
  1151. {
  1152. if (metalName == item)
  1153. {
  1154. continue;
  1155. }
  1156. MetalEntity metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(item);
  1157. if (metalEntity.IsBusy || metalEntity.WaferHolderInfo != null)
  1158. {
  1159. count++;
  1160. }
  1161. }
  1162. return (true,count);
  1163. }
  1164. /// <summary>
  1165. /// 检验独立Rinse是否可用
  1166. /// </summary>
  1167. /// <param name="singleRinseItems"></param>
  1168. /// <param name="metalName"></param>
  1169. /// <returns></returns>
  1170. private bool CheckSingleRinseItemsCanUsed(List<string> singleRinseItems, string metalName)
  1171. {
  1172. var result = CalculateMetalReservoirAllBusyMetalCount(metalName);
  1173. if(result.success)
  1174. {
  1175. bool transporterTransfering = CheckProcessTransporterTransfering(singleRinseItems);
  1176. if (transporterTransfering)
  1177. {
  1178. return result.busyCount + 1 < singleRinseItems.Count;
  1179. }
  1180. else
  1181. {
  1182. return result.busyCount < singleRinseItems.Count;
  1183. }
  1184. }
  1185. return false;
  1186. }
  1187. /// <summary>
  1188. /// 检验共享Rinse是否可用
  1189. /// </summary>
  1190. /// <param name="sharedRinse"></param>
  1191. /// <param name="metalName"></param>
  1192. /// <returns></returns>
  1193. private bool CheckShardRinseCanUse(string sharedRinse, string metalName,string startRinse)
  1194. {
  1195. string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(metalName);
  1196. List<string> shardReservoirs = CellItemManager.Instance.GetReservoirsBySharedRinse(sharedRinse);
  1197. if (shardReservoirs == null || shardReservoirs.Count == 0)
  1198. {
  1199. return false;
  1200. }
  1201. foreach (string reservoir in shardReservoirs)
  1202. {
  1203. if (reservoir==reservoirName)
  1204. {
  1205. continue;
  1206. }
  1207. List<string> metals=ReservoirItemManager.Instance.GetMetalsByReservoir(reservoir);
  1208. int metalCount = 0;
  1209. int busyMetalCount = 0;
  1210. foreach(string metal in metals)
  1211. {
  1212. MetalEntity metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(metal);
  1213. if(metalEntity.IsAuto&&metalEntity.IsInitialized)
  1214. {
  1215. metalCount++;
  1216. }
  1217. if(metalEntity.IsBusy||metalEntity.WaferHolderInfo!=null)
  1218. {
  1219. busyMetalCount++;
  1220. }
  1221. }
  1222. List<string> reservoirRinseLst = CellItemManager.Instance.GetRinsesByReservoir(reservoir);
  1223. int rinseCount = 0;
  1224. int busyRinseCount = 0;
  1225. foreach(string rinseItem in reservoirRinseLst)
  1226. {
  1227. RinseEntity rinseEntity = Singleton<RouteManager>.Instance.GetModule<RinseEntity>(rinseItem);
  1228. if(rinseEntity.IsAuto&&rinseEntity.IsInitialized)
  1229. {
  1230. rinseCount++;
  1231. }
  1232. if (rinseItem == sharedRinse)
  1233. {
  1234. continue;
  1235. }
  1236. if (rinseItem == startRinse)
  1237. {
  1238. continue;
  1239. }
  1240. if(rinseEntity.IsBusy||rinseEntity.WaferHolderInfo!=null)
  1241. {
  1242. busyRinseCount++;
  1243. }
  1244. }
  1245. int resRinseCount=rinseCount- busyRinseCount;
  1246. //计算剩余Rinse数量小于等于busy metal数量,则不可用
  1247. if (resRinseCount <= busyMetalCount)
  1248. {
  1249. return false;
  1250. }
  1251. }
  1252. return true;
  1253. }
  1254. /// <summary>
  1255. /// 检验模块是否可用(不包含WH)
  1256. /// </summary>
  1257. /// <param name="item"></param>
  1258. /// <returns></returns>
  1259. private bool CheckAvaibleEmptyModule(IModuleEntity item,ModuleType moduleType,string sequenceType)
  1260. {
  1261. if (!CheckAvaibleModule(item, moduleType, sequenceType))
  1262. {
  1263. return false;
  1264. }
  1265. if (!ModuleHelper.IsSRD(item.Module))
  1266. {
  1267. WaferHolderInfo waferHolderInfo = WaferHolderManager.Instance.GetWaferHolder(item.Module.ToString());
  1268. if (waferHolderInfo == null)
  1269. {
  1270. return true;
  1271. }
  1272. }
  1273. else
  1274. {
  1275. if (!WaferManager.Instance.CheckHasWafer(item.Module, 0))
  1276. {
  1277. return true;
  1278. }
  1279. }
  1280. return false;
  1281. }
  1282. /// <summary>
  1283. /// 检验可用
  1284. /// </summary>
  1285. /// <param name="item"></param>
  1286. /// <param name="moduleType"></param>
  1287. /// <param name="sequenceType"></param>
  1288. /// <param name="waferHolderId"></param>
  1289. /// <param name="startTime"></param>
  1290. /// <param name="processLength"></param>
  1291. /// <returns></returns>
  1292. public bool CheckAvaibleMetalModule(IModuleEntity item, ModuleType moduleType, string sequenceType, string waferHolderId, DateTime startTime, int processLength, bool checkConflict)
  1293. {
  1294. bool result = CheckAvaibleModule(item, moduleType, sequenceType);
  1295. if (!result)
  1296. {
  1297. return false;
  1298. }
  1299. if (checkConflict)
  1300. {
  1301. var conflict = SchedulerMetalTimeManager.Instance.CheckMetalConflict(item.Module.ToString(), waferHolderId, startTime, processLength);
  1302. return !conflict.conflict;
  1303. }
  1304. else
  1305. {
  1306. return result;
  1307. }
  1308. }
  1309. /// <summary>
  1310. /// 检验模块是否可用
  1311. /// </summary>
  1312. /// <param name="item"></param>
  1313. /// <returns></returns>
  1314. public bool CheckAvaibleModule(IModuleEntity item,ModuleType moduleType,string sequenceType)
  1315. {
  1316. if (item.IsDisable)
  1317. {
  1318. return false;
  1319. }
  1320. if (!item.IsAuto)
  1321. {
  1322. return false;
  1323. }
  1324. if (item.IsError)
  1325. {
  1326. return false;
  1327. }
  1328. if (item.IsInit)
  1329. {
  1330. return false;
  1331. }
  1332. if (moduleType==ModuleType.Metal)
  1333. {
  1334. if(item.IsProduction && sequenceType == ENGINEERING)
  1335. return false;
  1336. if (item.IsEngineering && sequenceType == PRODUCTION)
  1337. return false;
  1338. }
  1339. return true;
  1340. }
  1341. /// <summary>
  1342. /// 获取剩余时间最小的模块
  1343. /// </summary>
  1344. /// <param name="avaibles"></param>
  1345. /// <returns></returns>
  1346. private ModuleName GetMinTimeToReadyModule(List<IModuleEntity> avaibles,ModuleType moduleType)
  1347. {
  1348. if (avaibles.Count == 1)
  1349. {
  1350. return avaibles[0].Module;
  1351. }
  1352. int timeToReady = int.MaxValue;
  1353. IModuleEntity selectedModule = null;
  1354. List<IModuleEntity> idleModuleEtities = new List<IModuleEntity>();
  1355. foreach (var item in avaibles)
  1356. {
  1357. if (item.IsIdle)
  1358. {
  1359. if(moduleType!=ModuleType.Metal)
  1360. {
  1361. return item.Module;
  1362. }
  1363. idleModuleEtities.Add(item);
  1364. }
  1365. if (item.TimeToReady < timeToReady&&idleModuleEtities.Count==0)
  1366. {
  1367. timeToReady = item.TimeToReady;
  1368. selectedModule = item;
  1369. }
  1370. }
  1371. if (idleModuleEtities.Count != 0)
  1372. {
  1373. return GetMinUsageMetal(idleModuleEtities);
  1374. }
  1375. if (selectedModule != null)
  1376. {
  1377. return selectedModule.Module;
  1378. }
  1379. return ModuleName.Unknown;
  1380. }
  1381. /// <summary>
  1382. /// 获取电量最小的Metal
  1383. /// </summary>
  1384. /// <param name="idleModuleEntities"></param>
  1385. /// <returns></returns>
  1386. private ModuleName GetMinUsageMetal(List<IModuleEntity> idleModuleEntities, int depProcessLength, SchedulerModulePartTime metalPartTime)
  1387. {
  1388. double usage = double.MaxValue;
  1389. ModuleName selectedModuleName = ModuleName.Unknown;
  1390. List<string> minDateModuleLst = new List<string>();
  1391. int count = int.MaxValue;
  1392. foreach (var item in idleModuleEntities)
  1393. {
  1394. MetalEntity metalEntity = item as MetalEntity;
  1395. if (metalEntity != null)
  1396. {
  1397. MetalUsage metalUsage = metalEntity.MetalUsage;
  1398. if (metalUsage == null)
  1399. {
  1400. return metalEntity.Module;
  1401. }
  1402. int usedCount = SchedulerMetalTimeManager.Instance.CalculateMetalUsed(item.Module.ToString(), metalPartTime);
  1403. if (usedCount == 0 && !minDateModuleLst.Contains(item.Module.ToString()))
  1404. {
  1405. minDateModuleLst.Add(item.Module.ToString());
  1406. }
  1407. //未均预占
  1408. if (usedCount == 0)
  1409. {
  1410. if (count == int.MaxValue)
  1411. {
  1412. usage = metalUsage.TotalUsage;
  1413. selectedModuleName = metalEntity.Module;
  1414. //dateTime = DateTime.MinValue;
  1415. }
  1416. else if (count < int.MaxValue && count > 0)
  1417. {
  1418. usage = metalUsage.TotalUsage;
  1419. selectedModuleName = metalEntity.Module;
  1420. }
  1421. else if (count == 0)
  1422. {
  1423. if (metalUsage.TotalUsage < usage)
  1424. {
  1425. usage = metalUsage.TotalUsage;
  1426. selectedModuleName = metalEntity.Module;
  1427. }
  1428. }
  1429. }
  1430. else
  1431. {
  1432. if (minDateModuleLst.Count == 0)
  1433. {
  1434. usage = metalUsage.TotalUsage;
  1435. selectedModuleName = metalEntity.Module;
  1436. count = usedCount;
  1437. }
  1438. }
  1439. }
  1440. }
  1441. return selectedModuleName;
  1442. }
  1443. /// <summary>
  1444. /// 获取电量最小的Metal
  1445. /// </summary>
  1446. /// <param name="idleModuleEntities"></param>
  1447. /// <returns></returns>
  1448. private ModuleName GetMinUsageMetal(List<IModuleEntity> idleModuleEntities)
  1449. {
  1450. double usage = double.MaxValue;
  1451. ModuleName selectedModuleName = ModuleName.Unknown;
  1452. foreach (var item in idleModuleEntities)
  1453. {
  1454. MetalEntity metalEntity= item as MetalEntity;
  1455. if(metalEntity!=null)
  1456. {
  1457. MetalUsage metalUsage = metalEntity.MetalUsage;
  1458. if (metalUsage == null)
  1459. {
  1460. return metalEntity.Module;
  1461. }
  1462. if (metalUsage.TotalUsage < usage)
  1463. {
  1464. usage= metalUsage.TotalUsage;
  1465. selectedModuleName = metalEntity.Module;
  1466. }
  1467. }
  1468. }
  1469. return selectedModuleName;
  1470. }
  1471. /// <summary>
  1472. /// 获取Metal可用的Rinse模块
  1473. /// </summary>
  1474. /// <param name="metalName"></param>
  1475. /// <returns></returns>
  1476. private ModuleName GetMetalAvaibleRinseModule(List<IModuleEntity> items, ModuleName metalName)
  1477. {
  1478. int metalId = CellItemManager.Instance.GetCellIdByModuleName(metalName.ToString());
  1479. if (metalId == 0)
  1480. {
  1481. return ModuleName.Unknown;
  1482. }
  1483. List<LayoutCellItem> rinseItems = CellItemManager.Instance.GetRinseItemsByMetal(metalName.ToString());
  1484. if (rinseItems.Count == 0)
  1485. {
  1486. return ModuleName.Unknown;
  1487. }
  1488. List<IModuleEntity> avaibles = new List<IModuleEntity>();
  1489. foreach (var item in items)
  1490. {
  1491. LayoutCellItem cellItem = rinseItems.Find(O => O.ModuleName == item.Module.ToString());
  1492. if (cellItem != null)
  1493. {
  1494. RinseEntity rinseEntity = (RinseEntity)item;
  1495. if (rinseEntity.IsInitialized && rinseEntity.IsAuto)
  1496. {
  1497. avaibles.Add(rinseEntity);
  1498. }
  1499. }
  1500. }
  1501. int minInterval = int.MaxValue;
  1502. IModuleEntity moduleEntity = null;
  1503. foreach (var item in avaibles)
  1504. {
  1505. LayoutCellItem cellItem = rinseItems.Find(O => O.ModuleName == item.Module.ToString());
  1506. if (cellItem != null)
  1507. {
  1508. int abiasId = Math.Abs(metalId - cellItem.CellID);
  1509. if (abiasId < minInterval)
  1510. {
  1511. minInterval = abiasId;
  1512. moduleEntity = item;
  1513. }
  1514. }
  1515. }
  1516. if (moduleEntity != null)
  1517. {
  1518. return moduleEntity.Module;
  1519. }
  1520. return ModuleName.Unknown;
  1521. }
  1522. /// <summary>
  1523. /// 检验Metal可用的Rinse模块
  1524. /// </summary>
  1525. /// <param name="metalName"></param>
  1526. /// <returns></returns>
  1527. private ModuleName GetMetalAvaibleEmptyRinseModule(List<IModuleEntity> items, ModuleName metalName)
  1528. {
  1529. int metalId = CellItemManager.Instance.GetCellIdByModuleName(metalName.ToString());
  1530. if (metalId == 0)
  1531. {
  1532. return ModuleName.Unknown;
  1533. }
  1534. List<LayoutCellItem> rinseItems = CellItemManager.Instance.GetRinseItemsByMetal(metalName.ToString());
  1535. if (rinseItems.Count == 0)
  1536. {
  1537. return ModuleName.Unknown;
  1538. }
  1539. List<IModuleEntity> avaibles = new List<IModuleEntity>();
  1540. List<ModuleName> sharedRinseList = new List<ModuleName>();
  1541. foreach (var item in items)
  1542. {
  1543. LayoutCellItem cellItem = rinseItems.Find(O => O.ModuleName == item.Module.ToString());
  1544. if (cellItem != null)
  1545. {
  1546. RinseEntity rinseEntity = (RinseEntity)item;
  1547. if (rinseEntity.IsIdle && rinseEntity.IsAuto && rinseEntity.WaferHolderInfo == null)
  1548. {
  1549. avaibles.Add(rinseEntity);
  1550. if(CellItemManager.Instance.CheckRinseIsShared(rinseEntity.Module.ToString()))
  1551. {
  1552. sharedRinseList.Add(rinseEntity.Module);
  1553. }
  1554. }
  1555. }
  1556. }
  1557. int minInterval = int.MaxValue;
  1558. IModuleEntity moduleEntity = null;
  1559. foreach (var item in avaibles)
  1560. {
  1561. if (sharedRinseList.Contains(item.Module))
  1562. {
  1563. continue;
  1564. }
  1565. LayoutCellItem cellItem = rinseItems.Find(O => O.ModuleName == item.Module.ToString());
  1566. if (cellItem != null)
  1567. {
  1568. int abiasId = Math.Abs(metalId - cellItem.CellID);
  1569. if (abiasId < minInterval)
  1570. {
  1571. minInterval = abiasId;
  1572. moduleEntity = item;
  1573. }
  1574. }
  1575. }
  1576. if (moduleEntity != null)
  1577. {
  1578. return moduleEntity.Module;
  1579. }
  1580. else if(sharedRinseList.Count!=0)
  1581. {
  1582. return sharedRinseList[0];
  1583. }
  1584. return ModuleName.Unknown;
  1585. }
  1586. /// <summary>
  1587. /// 检验Metal cell recipe时间是否可用
  1588. /// </summary>
  1589. /// <param name="depRecipe"></param>
  1590. /// <returns></returns>
  1591. public bool CheckMetalCellRecipeTimeAvaible(IModuleEntity metalEntity,DepRecipe depRecipe)
  1592. {
  1593. List<IModuleEntity> metalEntities=Singleton<RouteManager>.Instance.GetModulesByModuleType(ModuleType.Metal);
  1594. int maxTimeToReady = 0;
  1595. foreach (MetalEntity item in metalEntities)
  1596. {
  1597. if (metalEntity.Module == item.Module)
  1598. {
  1599. continue;
  1600. }
  1601. if(item.IsBusy)
  1602. {
  1603. if(maxTimeToReady>item.TimeToReady)
  1604. {
  1605. maxTimeToReady = item.TimeToReady;
  1606. }
  1607. }
  1608. }
  1609. int transferOffSecond = SC.GetValue<int>("Transporter.TransporterTransferOffSeconds");
  1610. int recipeTotalTime = depRecipe.CalculateRecipeTotalTime();
  1611. //增加了Transporter最大传输时间和最小传输时间的差值
  1612. if (recipeTotalTime>=maxTimeToReady+transferOffSecond)
  1613. {
  1614. return true;
  1615. }
  1616. return false;
  1617. }
  1618. /// <summary>
  1619. /// 根据化学液获取可用的metal集合
  1620. /// </summary>
  1621. /// <param name="chemistry"></param>
  1622. /// <returns></returns>
  1623. public List<MetalEntity> GetAvaibleMetalList(string chemistry, string sequenceType,int waferSize, bool isEmpty)
  1624. {
  1625. List<IModuleEntity> reservoirEntities = Singleton<RouteManager>.Instance.GetModulesByModuleType(ModuleType.Reservoir);
  1626. List<string> avaibles = new List<string>();
  1627. foreach (IModuleEntity item in reservoirEntities)
  1628. {
  1629. ReservoirEntity entity = item as ReservoirEntity;
  1630. if (entity.Chemistry == chemistry && entity.IsAuto && entity.IsInitialized)
  1631. {
  1632. avaibles.Add(entity.Module.ToString());
  1633. }
  1634. }
  1635. List<MetalEntity> metals = new List<MetalEntity>();
  1636. foreach (string item in avaibles)
  1637. {
  1638. ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(item);
  1639. if (reservoirItem == null)
  1640. {
  1641. continue;
  1642. }
  1643. foreach (MetalItem subItem in reservoirItem.MetalCells)
  1644. {
  1645. MetalEntity entity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>($"Metal{subItem.MetalID}");
  1646. if (!CheckAvaibleModule(entity, ModuleType.Metal, sequenceType))
  1647. {
  1648. continue;
  1649. }
  1650. if (entity.MetalWaferSize != waferSize)
  1651. {
  1652. continue;
  1653. }
  1654. if (!isEmpty || (isEmpty && entity.WaferHolderInfo == null))
  1655. {
  1656. metals.Add(entity);
  1657. }
  1658. }
  1659. }
  1660. return metals;
  1661. }
  1662. /// <summary>
  1663. /// 获取上一个Metal
  1664. /// </summary>
  1665. /// <param name="sequenceIndex"></param>
  1666. /// <param name="sequences"></param>
  1667. /// <returns></returns>
  1668. public ModuleName GetPreMetalModuleName(int sequenceIndex,List<SchedulerSequence> sequences)
  1669. {
  1670. for(int i = sequenceIndex - 1; i >= 0; i--)
  1671. {
  1672. SchedulerSequence schedulerSequence= sequences[i];
  1673. if (schedulerSequence.ModuleType == ModuleType.Metal && ModuleHelper.IsMetal(schedulerSequence.ModuleName))
  1674. {
  1675. return schedulerSequence.ModuleName;
  1676. }
  1677. }
  1678. return ModuleName.Unknown;
  1679. }
  1680. }
  1681. }