VenusDispatcher.cs 83 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Diagnostics;
  5. using Aitex.Core.Common;
  6. using Aitex.Core.RT.Routine;
  7. using Aitex.Core.RT.SCCore;
  8. using Aitex.Sorter.Common;
  9. using Aitex.Core.RT.Log;
  10. using Aitex.Core.Util;
  11. using Aitex.Core.RT.DataCenter;
  12. using Aitex.Core.RT.RecipeCenter;
  13. using Aitex.Core.RT.Fsm;
  14. using MECF.Framework.Common.Jobs;
  15. using MECF.Framework.Common.Routine;
  16. using MECF.Framework.Common.Equipment;
  17. using MECF.Framework.Common.SubstrateTrackings;
  18. using MECF.Framework.Common.Schedulers;
  19. using MECF.Framework.Common.DBCore;
  20. using Venus_Core;
  21. using Venus_RT.Modules.Schedulers;
  22. using Venus_RT.Scheduler;
  23. using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robot;
  24. namespace Venus_RT.Modules
  25. {
  26. class VCETask : ModuleTask
  27. {
  28. public VCETask(ModuleName mod) : base(mod)
  29. {
  30. }
  31. }
  32. class VenusPMTask : ModuleTask
  33. {
  34. enum RecipeJobType
  35. {
  36. PreClean,
  37. Process,
  38. PostClean,
  39. }
  40. public override int TimeToReady
  41. {
  42. get
  43. {
  44. switch (Status)
  45. {
  46. case ModuleStatus.Idle:
  47. case ModuleStatus.IdleClean:
  48. case ModuleStatus.PreJobClean:
  49. case ModuleStatus.PostJobClean:
  50. case ModuleStatus.Processing:
  51. {
  52. return Scheduler.IsAvailable ? 0 : (Scheduler.TimeToReady + 500) / 1000;
  53. }
  54. }
  55. return int.MaxValue;
  56. }
  57. }
  58. private WaferTask _wafer;
  59. private SchedulerPM _pmScheduler => Scheduler as SchedulerPM;
  60. Queue<KeyValuePair<Guid, Queue<KeyValuePair<RecipeJobType, string>>>> _pendingWaferTasks = new Queue<KeyValuePair<Guid, Queue<KeyValuePair<RecipeJobType, string>>>> ();
  61. KeyValuePair<Guid, Queue<KeyValuePair <RecipeJobType, string>>> _runingWaferTask = new KeyValuePair<Guid, Queue<KeyValuePair<RecipeJobType, string>>> (Guid.Empty, new Queue<KeyValuePair<RecipeJobType, string>>());
  62. public VenusPMTask(ModuleName mod) : base(mod)
  63. { }
  64. public override RState Run()
  65. {
  66. if(_runingWaferTask.Value.Count == 0)
  67. {
  68. if(_pendingWaferTasks.Count > 0)
  69. {
  70. _runingWaferTask = _pendingWaferTasks.Dequeue();
  71. }
  72. else
  73. {
  74. if(Scheduler.IsIdle && Status == ModuleStatus.Idle)
  75. {
  76. if (WaferManager.Instance.CheckNoWafer(Module, 0) && Scheduler.IsOnline)
  77. {
  78. if (_pmScheduler.RunIdleCleanTask()) // Check Idle Clean
  79. {
  80. Status = ModuleStatus.StartIdleClean;
  81. }
  82. }
  83. }
  84. }
  85. }
  86. else
  87. {
  88. if(Scheduler.IsIdle && Status == ModuleStatus.Idle)
  89. {
  90. switch(_runingWaferTask.Value.First().Key)
  91. {
  92. case RecipeJobType.PreClean:
  93. {
  94. if(WaferManager.Instance.CheckNoWafer(Module,0))
  95. {
  96. if (_pmScheduler.RunJobCleanTask(_runingWaferTask.Value.First().Value))
  97. {
  98. Status = ModuleStatus.StartPreJobClean;
  99. }
  100. else
  101. {
  102. LOG.Write(eEvent.WARN_ROUTER, Module, $"Run Prejob clean recipe{_runingWaferTask.Value.First().Value} failed");
  103. TryDequeueRuningTask(Status);
  104. Status = ModuleStatus.Idle;
  105. }
  106. }
  107. }
  108. break;
  109. case RecipeJobType.Process:
  110. {
  111. if (WaferManager.Instance.CheckHasWafer(Module, 0))
  112. {
  113. if(_wafer.waferId == _runingWaferTask.Key)
  114. {
  115. Scheduler.EventWaferArrived?.Invoke(this, new WaferMoveArgs(ModuleName.TMRobot, 0, Module, 0));
  116. Status = ModuleStatus.StartProcess;
  117. }
  118. else
  119. {
  120. LOG.Write(eEvent.WARN_ROUTER, Module, $"wafer id dismatch while launch {_wafer.sourceMod}.{_wafer.sourceSlot + 1} process recipe");
  121. }
  122. }
  123. }
  124. break;
  125. case RecipeJobType.PostClean:
  126. {
  127. if (WaferManager.Instance.CheckNoWafer(Module, 0))
  128. {
  129. if (_pmScheduler.RunJobCleanTask(_runingWaferTask.Value.First().Value))
  130. {
  131. Status = ModuleStatus.StartPostJobClean;
  132. }
  133. else
  134. {
  135. LOG.Write(eEvent.WARN_ROUTER, Module, $"Run Postjob clean recipe{_runingWaferTask.Value.First().Value} failed");
  136. TryDequeueRuningTask(Status);
  137. Status = ModuleStatus.Idle;
  138. }
  139. }
  140. }
  141. break;
  142. }
  143. }
  144. }
  145. if(_runingWaferTask.Value.Count > 0 || Status != ModuleStatus.Idle)
  146. {
  147. if (Scheduler.IsIdle)
  148. {
  149. switch (Status)
  150. {
  151. case ModuleStatus.Processing:
  152. {
  153. var wafer = WaferManager.Instance.GetWafer(Module, 0);
  154. if (Scheduler.IsOnline)
  155. {
  156. if (!wafer.IsEmpty && wafer.ProcessState == EnumWaferProcessStatus.Completed)
  157. {
  158. _wafer.Return();
  159. TryDequeueRuningTask(Status);
  160. Status = ModuleStatus.Idle;
  161. }
  162. }
  163. else // handle offline exception situation
  164. {
  165. TryDequeueRuningTask(Status);
  166. Status = ModuleStatus.Idle;
  167. }
  168. }
  169. break;
  170. case ModuleStatus.PreJobClean:
  171. {
  172. TryDequeueRuningTask(Status);
  173. Status = ModuleStatus.Idle;
  174. }
  175. break;
  176. case ModuleStatus.PostJobClean:
  177. {
  178. TryDequeueRuningTask(Status);
  179. Status = ModuleStatus.Idle;
  180. }
  181. break;
  182. case ModuleStatus.IdleClean:
  183. {
  184. Status = ModuleStatus.Idle;
  185. }
  186. break;
  187. case ModuleStatus.StartProcess:
  188. {
  189. if (RouteManager.IsATMMode)
  190. {
  191. Status = ModuleStatus.Processing;
  192. }
  193. }
  194. break;
  195. }
  196. }
  197. else
  198. {
  199. switch (Status)
  200. {
  201. case ModuleStatus.StartProcess:
  202. Status = ModuleStatus.Processing;
  203. break;
  204. case ModuleStatus.StartIdleClean:
  205. Status = ModuleStatus.IdleClean;
  206. break;
  207. case ModuleStatus.StartPreJobClean:
  208. Status = ModuleStatus.PreJobClean;
  209. break;
  210. case ModuleStatus.StartPostJobClean:
  211. Status = ModuleStatus.PostJobClean;
  212. break;
  213. }
  214. }
  215. }
  216. return RState.Running;
  217. }
  218. void TryDequeueRuningTask( ModuleStatus status)
  219. {
  220. bool bMatch = false;
  221. if (_runingWaferTask.Value.Count > 0)
  222. {
  223. switch(status)
  224. {
  225. case ModuleStatus.PreJobClean:
  226. if(_runingWaferTask.Value.First().Key == RecipeJobType.PreClean)
  227. {
  228. _runingWaferTask.Value.Dequeue();
  229. bMatch = true;
  230. }
  231. break;
  232. case ModuleStatus.Processing:
  233. if(_runingWaferTask.Value.First().Key == RecipeJobType.Process)
  234. {
  235. _runingWaferTask.Value.Dequeue();
  236. bMatch = true;
  237. }
  238. break;
  239. case ModuleStatus.PostJobClean:
  240. if(_runingWaferTask.Value.First().Key == RecipeJobType.PostClean)
  241. {
  242. _runingWaferTask.Value.Dequeue();
  243. bMatch = true;
  244. }
  245. break;
  246. case ModuleStatus.WaitPreJobClean:
  247. _runingWaferTask.Value.Dequeue();
  248. break;
  249. case ModuleStatus.WaitProcess:
  250. _runingWaferTask.Value.Dequeue();
  251. break;
  252. case ModuleStatus.WaitPostJobClean:
  253. _runingWaferTask.Value.Dequeue();
  254. break;
  255. }
  256. }
  257. if(!bMatch)
  258. {
  259. string runingTask = _runingWaferTask.Value.Count > 0 ? _runingWaferTask.Value.First().ToString() : "Empty";
  260. LOG.Write(eEvent.WARN_ROUTER, Module, $"PM Status: {status}, runing task : {runingTask}");
  261. }
  262. }
  263. public override void WaferArrived(WaferTask wafer, int slot)
  264. {
  265. _wafer = wafer;
  266. }
  267. public override void WaferLeaved(WaferTask wafer, int slot)
  268. {
  269. _wafer = null;
  270. }
  271. public void SubscribeWaferTask(WaferTask waferTask)
  272. {
  273. var venusWaferTask = waferTask as VenusWaferTask;
  274. var waferRecipes = new Queue<KeyValuePair<RecipeJobType, string>>();
  275. if (!string.IsNullOrWhiteSpace(venusWaferTask.preCleanRecipe))
  276. {
  277. waferRecipes.Enqueue(new KeyValuePair<RecipeJobType, string>(RecipeJobType.PreClean, venusWaferTask.preCleanRecipe));
  278. }
  279. if (!string.IsNullOrWhiteSpace(venusWaferTask.processRecipe))
  280. {
  281. waferRecipes.Enqueue(new KeyValuePair<RecipeJobType, string>(RecipeJobType.Process, venusWaferTask.processRecipe));
  282. }
  283. if (!string.IsNullOrWhiteSpace(venusWaferTask.postCleanRecipe))
  284. {
  285. waferRecipes.Enqueue(new KeyValuePair<RecipeJobType, string>(RecipeJobType.PostClean, venusWaferTask.postCleanRecipe));
  286. }
  287. if(_runingWaferTask.Key == venusWaferTask.waferId || _pendingWaferTasks.ToList().Exists(kv => kv.Key == venusWaferTask.waferId))
  288. {
  289. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"wafer {venusWaferTask.sourceMod}.{venusWaferTask.sourceSlot + 1} already subscribe job task.");
  290. }
  291. else if (_runingWaferTask.Key == Guid.Empty || _runingWaferTask.Value.Count == 0)
  292. {
  293. _runingWaferTask = new KeyValuePair<Guid, Queue<KeyValuePair<RecipeJobType, string>>>(venusWaferTask.waferId, waferRecipes);
  294. }
  295. else
  296. {
  297. _pendingWaferTasks.Enqueue(new KeyValuePair<Guid, Queue<KeyValuePair<RecipeJobType, string>>>(venusWaferTask.waferId, waferRecipes));
  298. }
  299. }
  300. public bool ReadyMoveIn(WaferTask wafer)
  301. {
  302. return _runingWaferTask.Key == wafer.waferId && _runingWaferTask.Value.Count > 0 && _runingWaferTask.Value.First().Key == RecipeJobType.Process;
  303. }
  304. public override void ResetTask()
  305. {
  306. base.ResetTask();
  307. _wafer = null;
  308. _pendingWaferTasks.Clear();
  309. _runingWaferTask = new KeyValuePair<Guid, Queue<KeyValuePair<RecipeJobType, string>>>(Guid.Empty, new Queue<KeyValuePair<RecipeJobType, string>>());
  310. }
  311. }
  312. class PreAlignTask : ModuleTask
  313. {
  314. private WaferTask _wafer;
  315. public PreAlignTask(ModuleName aligner) : base(aligner)
  316. {
  317. }
  318. public override RState Run()
  319. {
  320. var tmRobot = Singleton<TransferModule>.Instance.GetScheduler(ModuleName.TMRobot) as SchedulerSETMRobot;
  321. if (tmRobot == null || !tmRobot.IsAvailable)
  322. return RState.Running;
  323. switch (Status)
  324. {
  325. case ModuleStatus.WaitAlign:
  326. {
  327. tmRobot.Align(0);
  328. Status = ModuleStatus.Aligning;
  329. }
  330. break;
  331. case ModuleStatus.Aligning:
  332. {
  333. _wafer.IsAligned = true;
  334. Status = ModuleStatus.Idle;
  335. }
  336. break;
  337. }
  338. return RState.Running;
  339. }
  340. public override void WaferArrived(WaferTask wafer, int slot)
  341. {
  342. _wafer = wafer;
  343. Status = ModuleStatus.WaitAlign;
  344. }
  345. public override void WaferLeaved(WaferTask wafer, int slot)
  346. {
  347. _wafer = null;
  348. }
  349. }
  350. public class VenusWaferTask : WaferTask
  351. {
  352. public string preCleanRecipe { get; }
  353. public string postCleanRecipe { get; }
  354. public VenusWaferTask(ModuleName source,
  355. int srcSlot,
  356. ModuleName dest,
  357. int dstSlot,
  358. float temp,
  359. Guid waferID,
  360. string recipeName,
  361. string wtwClean,
  362. SequenceLLInOutPath inOutPath,
  363. int LLDelay,
  364. bool needAlign,
  365. string preClean,
  366. string postClean)
  367. : base(source, srcSlot, dest, dstSlot, temp, waferID, recipeName, wtwClean, inOutPath, LLDelay, needAlign)
  368. {
  369. preCleanRecipe = preClean;
  370. postCleanRecipe = postClean;
  371. }
  372. }
  373. class VenusTMRobotTask : ModuleTask
  374. {
  375. public VenusTMRobotTask(ModuleName mod) : base(mod) { }
  376. public override RState Run()
  377. {
  378. return base.Run();
  379. }
  380. }
  381. class VenusDispatcher : ICycle
  382. {
  383. private RState _tmRobotStatus { get { return (_dictModuleTask[ModuleName.TMRobot].Scheduler as SchedulerSETMRobot).RobotStatus; } }
  384. private List<ControlJobInfo> _lstControlJobs = new List<ControlJobInfo>();
  385. private List<ProcessJobInfo> _lstProcessJobs = new List<ProcessJobInfo>();
  386. private List<VenusWaferTask> _lstWaferTasks = new List<VenusWaferTask>();
  387. private Dictionary<ModuleName, ModuleTask> _dictModuleTask = new Dictionary<ModuleName, ModuleTask>();
  388. private Queue<WaferInfo> _qeReturnWafers = new Queue<WaferInfo>();
  389. private Queue<List<MoveItem>> _tmSchdActions = new Queue<List<MoveItem>>();
  390. private List<MoveItem> _curTmAction = new List<MoveItem>();
  391. private bool _isCycleMode;
  392. private int _cycleSetPoint = 0;
  393. private int _cycledCount = 0;
  394. private int _cycledWafer = 0;
  395. private float _throughput = 0.0f;
  396. private int _tmRobotSingleArmOption = 0;
  397. private Dictionary<ModuleName, int> _lpCycleWafer = new Dictionary<ModuleName, int>();
  398. private Dictionary<ModuleName, int> _lpCycleCount = new Dictionary<ModuleName, int>();
  399. private Stopwatch _cycleWatch = new Stopwatch();
  400. private SchedulerFACallback _faCallback;
  401. private SchedulerDBCallback _dbCallback;
  402. public SequenceLLInOutPath LLInOutPath => SequenceLLInOutPath.DInDOut;
  403. public bool HasJobRunning => _lstControlJobs.Count > 0;
  404. private RState _cycleState = RState.Init;
  405. public RState CycleState => _cycleState;
  406. private Dictionary<string, ControlJobInfo> _loadportControlJobDic = new Dictionary<string, ControlJobInfo>();
  407. public List<string> InUseRecipes = new List<string>();
  408. public VenusDispatcher()
  409. {
  410. _faCallback = new SchedulerFACallback();
  411. _dbCallback = new SchedulerDBCallback();
  412. InitModules();
  413. DATA.Subscribe("Scheduler.CycledCount", () => _cycledCount, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  414. DATA.Subscribe("Scheduler.CycledWafer", () => _cycledWafer, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  415. DATA.Subscribe("Scheduler.CycleSetPoint", () => _cycleSetPoint, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  416. DATA.Subscribe("Scheduler.Throughput", () => _throughput, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  417. DATA.Subscribe("Scheduler.PjIdList", () => Array.ConvertAll(_lstProcessJobs.ToArray(), x => x.InnerId.ToString()).ToList());
  418. DATA.Subscribe("Scheduler.PjNameList", () => Array.ConvertAll(_lstProcessJobs.ToArray(), x => x.LotName.ToString()).ToList());
  419. DATA.Subscribe("Scheduler.InUsingRecipe", () => InUseRecipes);
  420. for (int i = 1; i <= 3; i++)
  421. {
  422. _loadportControlJobDic[$"LP{i}"] = null;
  423. string lp = $"LP{i}";
  424. DATA.Subscribe($"{lp}.CurrentControlJob", () => _loadportControlJobDic[lp], SubscriptionAttribute.FLAG.IgnoreSaveDB);
  425. }
  426. }
  427. #region public interface
  428. /// <summary>
  429. /// 获取lp当前的ControlJob
  430. /// </summary>
  431. /// <param name="lp"></param>
  432. /// <returns></returns>
  433. public ControlJobInfo GetLoadPortCurrentControlJob(ModuleName lp)
  434. {
  435. if (ModuleHelper.IsLoadPort(lp))
  436. {
  437. return _loadportControlJobDic.ContainsKey(lp.ToString()) ? _loadportControlJobDic[lp.ToString()] : null;
  438. }
  439. else
  440. {
  441. return null;
  442. }
  443. }
  444. public RState Start(params object[] objs)
  445. {
  446. if (WaferManager.Instance.HasDuplicatedWafer)
  447. {
  448. LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, "System has dummy wafers, please verify all the wafer position, and delete the invalid wafer");
  449. return RState.Failed;
  450. }
  451. _tmRobotSingleArmOption = SC.GetValue<int>("TM.SingleArmOption");
  452. _isCycleMode = SC.GetValue<bool>("System.IsCycleMode");
  453. _cycleSetPoint = _isCycleMode ? SC.GetValue<int>("System.CycleCount") : 0;
  454. _cycledWafer = 0;
  455. _cycledCount = 0;
  456. _throughput = 0;
  457. Clear();
  458. _cycleWatch.Stop();
  459. _lpCycleWafer.Clear();
  460. _lpCycleCount.Clear();
  461. return RState.Running;
  462. }
  463. public bool CreateJob(Dictionary<string, object> param, out string reason)
  464. {
  465. reason = "";
  466. _isCycleMode = SC.GetValue<bool>("System.IsCycleMode");
  467. _cycleSetPoint = _isCycleMode ? SC.GetValue<int>("System.CycleCount") : 0;
  468. string[] slotSequence = (string[])param["SlotSequence"];
  469. string jobId = (string)param["JobId"];
  470. string module = (string)param["Module"];
  471. if (string.IsNullOrEmpty(jobId))
  472. {
  473. jobId = "CJ_Local_" + module;
  474. }
  475. //bool autoStart = (bool)param["AutoStart"];
  476. string lotId = jobId;
  477. if (param.ContainsKey("LotId"))
  478. lotId = (string)param["LotId"];
  479. string preCleanRecipe = param.ContainsKey("PreCleanRecipeName") ? (string)param["PreCleanRecipeName"] : string.Empty;
  480. string postCleanRecipe = param.ContainsKey("PostCleanRecipeName") ? (string)param["PostCleanRecipeName"] : string.Empty;
  481. if (slotSequence.Length != SC.GetValue<int>("EFEM.LoadPort.SlotNumber"))
  482. {
  483. reason = $"slot sequence parameter not valid, length is {slotSequence.Length}, should be {SC.GetValue<int>("EFEM.LoadPort.SlotNumber")}";
  484. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason);
  485. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  486. return false;
  487. }
  488. if (!ModuleHelper.IsLoadPort(ModuleHelper.Converter(module)))
  489. {
  490. reason = $"{module} should be LoadPort";
  491. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason);
  492. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  493. return false;
  494. }
  495. if (_lstControlJobs.Exists(x => x.Name == jobId))
  496. {
  497. reason = $"{jobId} already created";
  498. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason);
  499. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  500. return false;
  501. }
  502. ControlJobInfo cj = new ControlJobInfo();
  503. cj.Name = jobId;
  504. cj.Module = module;
  505. cj.LotName = lotId;
  506. cj.LotInnerId = Guid.NewGuid();
  507. cj.LotWafers = new List<WaferInfo>();
  508. cj.SetState(EnumControlJobState.WaitingForStart);
  509. cj.JetState = EnumJetCtrlJobState.Created;
  510. cj.PreJobClean = preCleanRecipe;
  511. cj.PostJobClean = postCleanRecipe;
  512. cj.SequenceNameList = slotSequence;
  513. Dictionary<string, bool[]> seqSlot = new Dictionary<string, bool[]>();
  514. Dictionary<string, List<Tuple<ModuleName, int>>> seqSlotWafers = new Dictionary<string, List<Tuple<ModuleName, int>>>();
  515. Dictionary<string, string> indexSequence = new Dictionary<string, string>();
  516. bool enableGroupBySequence = SC.GetValue<bool>("Scheduler.GroupWaferBySequence");
  517. for (int i = 0; i < SC.GetValue<int>("EFEM.LoadPort.SlotNumber"); i++)
  518. {
  519. if (string.IsNullOrEmpty(slotSequence[i]) || string.IsNullOrEmpty(slotSequence[i].Trim()))
  520. continue;
  521. string groupName = enableGroupBySequence ? slotSequence[i].Trim() : i.ToString();
  522. indexSequence[groupName] = slotSequence[i];
  523. if (!seqSlot.ContainsKey(groupName))
  524. {
  525. seqSlot[groupName] = new bool[SC.GetValue<int>("EFEM.LoadPort.SlotNumber")];
  526. }
  527. if (!seqSlotWafers.ContainsKey(groupName))
  528. {
  529. seqSlotWafers[groupName] = new List<Tuple<ModuleName, int>>();
  530. }
  531. seqSlot[groupName][i] = true;
  532. if (!WaferManager.Instance.CheckHasWafer(module, i))
  533. {
  534. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"job wafer: {module} slot {i + 1} not in the carrier");
  535. return false;
  536. }
  537. if (!WaferManager.Instance.CheckWafer(ModuleHelper.Converter(module), i, WaferStatus.Normal))
  538. {
  539. reason = $"job wafer: {module} slot {i + 1} status is {WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).Status}";
  540. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason);
  541. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  542. return false;
  543. }
  544. if (WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).ProcessState != EnumWaferProcessStatus.Idle)
  545. {
  546. reason = $"job wafer: {module} slot {i + 1} process status is {WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).ProcessState}";
  547. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason);
  548. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  549. return false;
  550. }
  551. //--- 2024-03-21 增加了waferinfo 相应的lotId信息 start---
  552. WaferInfo waferInfo = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i);
  553. cj.LotWafers.Add(waferInfo);
  554. waferInfo.SequenceName = slotSequence[i];
  555. waferInfo.LotId = lotId;
  556. //--- 2024-03-21 增加了waferinfo 相应的lotId信息 end---
  557. seqSlotWafers[groupName].Add(Tuple.Create(ModuleHelper.Converter(module), i));
  558. cj.JobWaferSize = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).Size;
  559. LOG.Write(eEvent.EV_ROUTER, ModuleName.System, $"Assigned wafer job, wafer {module}.{i + 1}, sequence: {slotSequence[i]}");
  560. }
  561. if (seqSlotWafers.Count == 0)
  562. {
  563. reason = $"job has not assign wafer";
  564. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason);
  565. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  566. return false;
  567. }
  568. List<ProcessJobInfo> pjs = new List<ProcessJobInfo>();
  569. string[] seqs = seqSlot.Keys.ToArray();
  570. for (int i = 0; i < seqs.Length; i++)
  571. {
  572. ProcessJobInfo pj = new ProcessJobInfo();
  573. pj.Name = jobId + "_" + (i + 1);
  574. pj.Sequence = SequenceInfoHelper.GetInfo(indexSequence[seqs[i]]);
  575. if (pj.Sequence == null)
  576. {
  577. reason = $"invalid sequence[{indexSequence[seqs[i]]}]";
  578. return false;
  579. }
  580. pj.ControlJobName = cj.Name;
  581. pj.LotName = lotId;
  582. pj.SlotWafers = seqSlotWafers[seqs[i]];
  583. pj.SetState(EnumProcessJobState.Queued);
  584. if (!CheckSequencePmReady(pj.Sequence, out reason))
  585. {
  586. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"no valid chamber for the {reason}");
  587. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  588. return false;
  589. }
  590. if (!RouteManager.IsATMMode && !CheckSequenceRecipeFileValid(pj.Sequence, out reason))
  591. {
  592. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"recipe file not valid in the sequence, {reason}");
  593. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  594. return false;
  595. }
  596. pjs.Add(pj);
  597. }
  598. _dbCallback.LotUpdate(cj);
  599. foreach (var pj in pjs)
  600. {
  601. cj.ProcessJobNameList.Add(pj.Name);
  602. _lstProcessJobs.Add(pj);
  603. }
  604. _lstControlJobs.Add(cj);
  605. //AssociatedPMWithLP(cj);
  606. _loadportControlJobDic[cj.Module] = cj;
  607. _faCallback.JobCreated(cj, GetFirstProcessJob(cj));
  608. return true;
  609. }
  610. public bool CheckAllJobDone()
  611. {
  612. foreach (var cj in _lstControlJobs)
  613. {
  614. if (cj.State != EnumControlJobState.Completed)
  615. return false;
  616. }
  617. InUseRecipes.Clear();
  618. return true;
  619. }
  620. public bool CheckJobJustDone(out string sJobName)
  621. {
  622. foreach (var cj in _lstControlJobs)
  623. {
  624. if (cj.State == EnumControlJobState.Completed && !cj.BeenPosted)
  625. {
  626. //LP;WaferSize;Lot;Number;Start;End;
  627. sJobName = $"{cj.Module};{cj.JobWaferSize};{cj.LotName};{cj.LotWafers.Count};{cj.StartTime:T};{cj.EndTime:T}";
  628. cj.BeenPosted = true;
  629. return true;
  630. }
  631. }
  632. sJobName = "NULL";
  633. return false;
  634. }
  635. public ProcessJobInfo GetFirstProcessJob(ControlJobInfo cj)
  636. {
  637. foreach (var pj in _lstProcessJobs)
  638. {
  639. if (pj.ControlJobName == cj.Name)
  640. return pj;
  641. }
  642. return null;
  643. }
  644. public bool AbortJob(string jobName, out string reason)
  645. {
  646. reason = "";
  647. ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
  648. if (cj == null)
  649. {
  650. reason = $"abort job rejected, not found job with id {jobName}";
  651. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason);
  652. return false;
  653. }
  654. List<ProcessJobInfo> pjAbortList = new List<ProcessJobInfo>();
  655. foreach (var pj in _lstProcessJobs)
  656. {
  657. if (pj.ControlJobName == cj.Name)
  658. {
  659. pj.SetState(EnumProcessJobState.Aborting);
  660. pjAbortList.Add(pj);
  661. int unprocessed = 0;
  662. int aborted = 0;
  663. WaferInfo[] wafers = WaferManager.Instance.GetWaferByProcessJob(pj.Name);
  664. foreach (var waferInfo in wafers)
  665. {
  666. waferInfo.ProcessJob = null;
  667. waferInfo.NextSequenceStep = 0;
  668. if (waferInfo.ProcessState != EnumWaferProcessStatus.Completed)
  669. unprocessed++;
  670. }
  671. JobDataRecorder.EndPJ(pj.InnerId.ToString(), aborted, unprocessed);
  672. }
  673. }
  674. _faCallback.JobAborted(cj, GetFirstProcessJob(cj));
  675. _dbCallback.LotFinished(cj);
  676. foreach (var pj in pjAbortList)
  677. {
  678. _lstProcessJobs.Remove(pj);
  679. }
  680. _lstControlJobs.Remove(cj);
  681. if (_loadportControlJobDic.ContainsKey(cj.Module))
  682. {
  683. _loadportControlJobDic[cj.Module] = null;
  684. }
  685. return true;
  686. }
  687. public bool StopJob(string jobName, out string reason)
  688. {
  689. reason = "";
  690. ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
  691. if (cj == null)
  692. {
  693. reason = $"stop job rejected, not found job with id {jobName}";
  694. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason);
  695. return false;
  696. }
  697. foreach (var pj in _lstProcessJobs)
  698. {
  699. if (pj.ControlJobName == cj.Name)
  700. {
  701. pj.SetState(EnumProcessJobState.Stopping);
  702. }
  703. }
  704. _faCallback.JobStopped(cj, GetFirstProcessJob(cj));
  705. _dbCallback.LotFinished(cj);
  706. if (_loadportControlJobDic.ContainsKey(cj.Module))
  707. {
  708. _loadportControlJobDic[cj.Module] = null;
  709. }
  710. return true;
  711. }
  712. public bool ResumeJob(string jobName, out string reason)
  713. {
  714. reason = "";
  715. ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
  716. if (cj == null)
  717. {
  718. reason = $"resume job rejected, not found job with id {jobName}";
  719. //LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"resume job rejected, not found job with id {jobName}");
  720. return false;
  721. }
  722. if (cj.State == EnumControlJobState.Paused)
  723. {
  724. cj.SetState(EnumControlJobState.Executing);
  725. }
  726. _faCallback.JobResumed(cj, GetFirstProcessJob(cj));
  727. _cycleState = RState.Running;
  728. return true;
  729. }
  730. public bool PauseJob(string jobName, out string reason)
  731. {
  732. reason = "";
  733. ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
  734. if (cj == null)
  735. {
  736. reason = $"pause job rejected, not found job with id {jobName}";
  737. //LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"pause job rejected, not found job with id {jobName}");
  738. return false;
  739. }
  740. if (cj.State == EnumControlJobState.Executing)
  741. {
  742. cj.SetState(EnumControlJobState.Paused);
  743. }
  744. _faCallback.JobPaused(cj, GetFirstProcessJob(cj));
  745. if (!_lstControlJobs.Exists(job => job.State == EnumControlJobState.Executing))
  746. _cycleState = RState.Paused;
  747. return true;
  748. }
  749. public bool StartJob(string jobName, out string reason)
  750. {
  751. reason = "";
  752. ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
  753. if (cj == null)
  754. {
  755. reason = $"start job rejected, not found job with id {jobName}";
  756. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, reason);
  757. return false;
  758. }
  759. if (cj.State == EnumControlJobState.WaitingForStart)
  760. {
  761. cj.SetState(EnumControlJobState.Queued);
  762. //PreJobClean(cj);
  763. cj.StartTime = DateTime.Now;
  764. _dbCallback.LotCreated(cj);
  765. _faCallback.JobStarted(cj, GetFirstProcessJob(cj));
  766. //if (!_blockingWatcher.IsRunning)
  767. // _blockingWatcher.Restart();
  768. //ResetTraceFlag();
  769. }
  770. if (!_cycleWatch.IsRunning)
  771. {
  772. _cycleWatch.Restart();
  773. }
  774. if (!_lpCycleWafer.Keys.Contains(ModuleHelper.Converter(cj.Module)))
  775. {
  776. _lpCycleCount.Add(ModuleHelper.Converter(cj.Module), 0);
  777. _lpCycleWafer.Add(ModuleHelper.Converter(cj.Module), 0);
  778. }
  779. _cycleState = RState.Running;
  780. return true;
  781. }
  782. public RState Monitor()
  783. {
  784. prelude();
  785. RunWaferTask();
  786. RunModuleTasks();
  787. RoutingWafers();
  788. epilogue();
  789. return _cycleState;
  790. }
  791. public void Abort()
  792. {
  793. }
  794. public void Clear()
  795. {
  796. foreach (var module in _dictModuleTask)
  797. {
  798. module.Value.Status = ModuleStatus.Idle;
  799. module.Value.Scheduler.ResetTask();
  800. module.Value.ResetTask();
  801. }
  802. List<string> keys = _loadportControlJobDic.Keys.ToList();
  803. foreach (var key in keys)
  804. {
  805. _loadportControlJobDic[key] = null;
  806. }
  807. _lstWaferTasks.Clear();
  808. _tmSchdActions.Clear();
  809. _curTmAction.Clear();
  810. _lstControlJobs.Clear();
  811. _lstProcessJobs.Clear();
  812. InUseRecipes.Clear();
  813. _cycleState = RState.End;
  814. }
  815. #endregion
  816. #region manual return wafer
  817. // manual return one wafer while system is auto running
  818. public bool ManualReturnWafer(object[] objs)
  819. {
  820. ModuleName SourceModule = (ModuleName)objs[0];
  821. int SourceSlot = (int)objs[1];
  822. if (!_dictModuleTask.Keys.Contains(SourceModule))
  823. {
  824. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"Invalid source module {SourceModule} for manual return wafer");
  825. return false;
  826. }
  827. if (WaferManager.Instance.CheckNoWafer(SourceModule, SourceSlot))
  828. {
  829. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"Can not return wafer as {SourceModule} {SourceSlot} has no wafer");
  830. return false;
  831. }
  832. if (!_dictModuleTask[SourceModule].Scheduler.IsIdle)
  833. {
  834. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"The module: {SourceModule} is not ready for return wafer");
  835. return false;
  836. }
  837. var wafer = WaferManager.Instance.GetWafer(SourceModule, SourceSlot);
  838. LOG.Write(eEvent.EV_ROUTER, ModuleName.System, $"Manual return wafer: {wafer.WaferOrigin} at {SourceModule} {SourceSlot} while system is auto running");
  839. _qeReturnWafers.Enqueue(wafer);
  840. return true;
  841. }
  842. public RState CheckManualReturnWafer()
  843. {
  844. var pmWaferCount = _dictModuleTask.Where(mod => ModuleHelper.IsPm(mod.Key) && WaferManager.Instance.CheckHasWafer(mod.Key, 0)).Count();
  845. var tmRobotWaferCount = (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 0) ? 1 : 0) + (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 1) ? 1 : 0);
  846. if (!_dictModuleTask[ModuleName.TMRobot].Scheduler.IsIdle && (pmWaferCount > 0 || tmRobotWaferCount > 0))
  847. {
  848. LOG.Write(eEvent.ERR_ROUTER, ModuleName.TMRobot, $"The TM Robot is not ready for return wafer.");
  849. return RState.Failed;
  850. }
  851. foreach (var mod in _dictModuleTask)
  852. {
  853. if (ModuleHelper.IsLoadPort(mod.Key))
  854. continue;
  855. if (!ModuleHelper.IsAligner(mod.Key) && !mod.Value.Scheduler.IsIdle)
  856. {
  857. LOG.Write(eEvent.ERR_ROUTER, mod.Key, $"{mod.Key} is not ready for return wafer.");
  858. return RState.Failed;
  859. }
  860. int nSlotNumber = (ModuleHelper.IsTMRobot(mod.Key) ? 2 : 1);
  861. for (int slot = 0; slot < nSlotNumber; slot++)
  862. {
  863. var wafer = WaferManager.Instance.GetWafer(mod.Key, slot);
  864. if (wafer.IsEmpty)
  865. continue;
  866. var destLP = (ModuleName)wafer.OriginStation;
  867. if (!_dictModuleTask[destLP].Scheduler.IsAvailable)
  868. {
  869. LOG.Write(eEvent.ERR_ROUTER, destLP, $"The destination Loadport {destLP} is not ready for return wafer.");
  870. return RState.Failed;
  871. }
  872. if (!ModuleHelper.IsLoadPort(destLP))
  873. {
  874. LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"The wafer {wafer.WaferOrigin} cannot be return, please manually drag it.");
  875. return RState.Failed;
  876. }
  877. }
  878. }
  879. Clear();
  880. return RState.Running;
  881. }
  882. public RState ReturnAllWafers()
  883. {
  884. int systemWaferCount = 0;
  885. foreach (var mod in _dictModuleTask)
  886. {
  887. if (ModuleHelper.IsLoadPort(mod.Key))
  888. continue;
  889. int nSlotNumber = ModuleHelper.IsTMRobot(mod.Key) ? 2 : 1;
  890. for (int slot = 0; slot < nSlotNumber; slot++)
  891. {
  892. var wafer = WaferManager.Instance.GetWafer(mod.Key, slot);
  893. if (!wafer.IsEmpty)
  894. systemWaferCount++;
  895. }
  896. }
  897. if (systemWaferCount == 0)
  898. return RState.End;
  899. ReturnInternalWafers();
  900. return RState.Running;
  901. }
  902. #endregion
  903. #region internal implementation
  904. private void InitModules()
  905. {
  906. foreach (var module in ModuleHelper.InstalledModules)
  907. {
  908. if (ModuleHelper.IsInstalled(module))
  909. {
  910. if (ModuleHelper.IsPm(module))
  911. {
  912. _dictModuleTask[module] = new VenusPMTask(module);
  913. }
  914. else if (ModuleHelper.IsTMRobot(module))
  915. {
  916. _dictModuleTask[module] = new VenusTMRobotTask(module);
  917. }
  918. else if (ModuleHelper.IsAligner(module))
  919. {
  920. _dictModuleTask[module] = new PreAlignTask(module);
  921. }
  922. else if (ModuleHelper.IsLoadPort(module))
  923. {
  924. _dictModuleTask[module] = new LoadPortTask(module);
  925. }
  926. }
  927. }
  928. }
  929. private void prelude()
  930. {
  931. bool available = true;
  932. foreach (var mod in _dictModuleTask)
  933. {
  934. available = mod.Value.Scheduler.IsAvailable; // force scheduler update
  935. }
  936. }
  937. private void epilogue()
  938. {
  939. UpdateProcessJobStatus();
  940. UpdateControlJobStatus();
  941. CreateNewWaferTask();
  942. _lstWaferTasks.RemoveAll(item => ModuleHelper.IsLoadPort(item.destMod) && ModuleHelper.IsLoadPort(item.currentMod) && item.pressureStatus == RState.End);
  943. }
  944. private void RunWaferTask()
  945. {
  946. foreach (var task in _lstWaferTasks)
  947. {
  948. task.Run();
  949. }
  950. }
  951. private void RunModuleTasks()
  952. {
  953. foreach (var task in _dictModuleTask)
  954. {
  955. task.Value.Run();
  956. }
  957. }
  958. private void RoutingWafers()
  959. {
  960. if (_tmSchdActions.Count > 0 || _curTmAction.Count > 0)
  961. {
  962. RunSchdTMActions();
  963. return;
  964. }
  965. if (_tmRobotStatus != RState.End)
  966. return;
  967. if (_tmRobotSingleArmOption != 0)
  968. {
  969. RoutingWaferWithSingleArm();
  970. return;
  971. }
  972. var waitInWafers = _lstWaferTasks.Where(wt => ModuleHelper.IsLoadPort(wt.currentMod) && ModuleHelper.IsPm(wt.destMod)).OrderBy(wt => wt.currentSlot).ToList();
  973. var readyReturnWafers = _lstWaferTasks.Where(wt => ModuleHelper.IsPm(wt.currentMod) && ModuleHelper.IsLoadPort(wt.destMod)).ToList();
  974. var emptyAndReadyIn20sPMs = _dictModuleTask.Where(pm => ModuleHelper.IsPm(pm.Key) && !_lstWaferTasks.Exists(wt => wt.currentMod == pm.Key) && pm.Value.TimeToReady < 20).OrderBy(pm => pm.Value.TimeToReady).Select(pm => pm.Key).ToList();
  975. var robotWafers = _lstWaferTasks.Where(wt => ModuleHelper.IsTMRobot(wt.currentMod)).ToList();
  976. var aligner = _dictModuleTask.Where(mod => ModuleHelper.IsAligner(mod.Key)).ToList();
  977. if(robotWafers.Count == 0)
  978. {
  979. if(readyReturnWafers.Count > 0)
  980. {
  981. if(readyReturnWafers.Count == 1)
  982. {
  983. // return one wafer
  984. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(readyReturnWafers.First().currentMod, 0, ModuleName.TMRobot, (int)Hand.Blade1, Hand.Blade1) });
  985. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, (int)Hand.Blade1, readyReturnWafers.First().destMod, readyReturnWafers.First().destSlot, Hand.Blade1) });
  986. }
  987. else
  988. {
  989. // return two wafer
  990. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(readyReturnWafers[0].currentMod, 0, ModuleName.TMRobot, (int)Hand.Blade1, Hand.Blade1) });
  991. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(readyReturnWafers[1].currentMod, 0, ModuleName.TMRobot, (int)Hand.Blade2, Hand.Blade2) });
  992. var doublePlaceActions = new List<MoveItem>
  993. {
  994. new MoveItem(ModuleName.TMRobot, (int)Hand.Blade1, readyReturnWafers[0].destMod, readyReturnWafers[0].destSlot, Hand.Blade1),
  995. new MoveItem(ModuleName.TMRobot, (int)Hand.Blade2, readyReturnWafers[1].destMod, readyReturnWafers[1].destSlot, Hand.Blade2)
  996. };
  997. _tmSchdActions.Enqueue(doublePlaceActions);
  998. }
  999. }
  1000. else if (_lstWaferTasks.Exists(wt => ModuleHelper.IsAligner(wt.currentMod)))
  1001. {
  1002. var alignerWafer = _lstWaferTasks.Where(wt => ModuleHelper.IsAligner(wt.currentMod)).First();
  1003. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(alignerWafer.currentMod, alignerWafer.currentSlot, ModuleName.TMRobot, (int)Hand.Blade1, Hand.Blade1) });
  1004. if (emptyAndReadyIn20sPMs.Contains(alignerWafer.destMod))
  1005. {
  1006. var pmTask = _dictModuleTask[alignerWafer.destMod] as VenusPMTask;
  1007. if(pmTask.ReadyMoveIn(alignerWafer))
  1008. {
  1009. // move aligner wafer to PM
  1010. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, (int)Hand.Blade1, alignerWafer.destMod, alignerWafer.destSlot, Hand.Blade1) });
  1011. }
  1012. }
  1013. }
  1014. else
  1015. {
  1016. if(emptyAndReadyIn20sPMs.Count >= 2 && waitInWafers.Count >= 2)
  1017. {
  1018. var doublePickActions = new List<MoveItem>()
  1019. {
  1020. new MoveItem(waitInWafers[0].currentMod, waitInWafers[0].currentSlot, ModuleName.TMRobot, (int)Hand.Blade1, Hand.Blade1),
  1021. new MoveItem(waitInWafers[1].currentMod, waitInWafers[1].currentSlot, ModuleName.TMRobot, (int)Hand.Blade2, Hand.Blade2)
  1022. };
  1023. _tmSchdActions.Enqueue(doublePickActions);
  1024. if(aligner.Count > 0)
  1025. {
  1026. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, (int)Hand.Blade1, aligner.First().Key, 0, Hand.Blade1) });
  1027. }
  1028. }
  1029. else if(emptyAndReadyIn20sPMs.Count >= 1 && waitInWafers.Count >= 1)
  1030. {
  1031. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(waitInWafers[0].currentMod, waitInWafers[0].currentSlot, ModuleName.TMRobot, (int)Hand.Blade1, Hand.Blade1) });
  1032. if (aligner.Count > 0)
  1033. {
  1034. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, (int)Hand.Blade1, aligner.First().Key, 0, Hand.Blade1) });
  1035. }
  1036. }
  1037. }
  1038. }
  1039. else if(robotWafers.Count == 1)
  1040. {
  1041. var freeHand = robotWafers.First().currentSlot == 0 ? Hand.Blade2 : Hand.Blade1;
  1042. if (readyReturnWafers.Count >= 1)
  1043. {
  1044. // return one wafer
  1045. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(readyReturnWafers.First().currentMod, 0, ModuleName.TMRobot, (int)freeHand, freeHand) });
  1046. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, (int)freeHand, readyReturnWafers.First().destMod, readyReturnWafers.First().destSlot, freeHand) });
  1047. }
  1048. else
  1049. {
  1050. if (_lstWaferTasks.Exists(wt => ModuleHelper.IsAligner(wt.currentMod)))
  1051. {
  1052. var alignerWafer = _lstWaferTasks.Where(wt => ModuleHelper.IsAligner(wt.currentMod)).First();
  1053. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(alignerWafer.currentMod, alignerWafer.currentSlot, ModuleName.TMRobot, (int)freeHand, freeHand) });
  1054. if(!robotWafers.First().IsAligned)
  1055. {
  1056. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, robotWafers.First().currentSlot, aligner.First().Key, 0, (Hand)robotWafers.First().currentSlot) });
  1057. }
  1058. if (emptyAndReadyIn20sPMs.Contains(alignerWafer.destMod))
  1059. {
  1060. var pmTask = _dictModuleTask[alignerWafer.destMod] as VenusPMTask;
  1061. if (pmTask.ReadyMoveIn(alignerWafer))
  1062. {
  1063. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, (int)freeHand, alignerWafer.destMod, alignerWafer.destSlot, freeHand) });
  1064. }
  1065. }
  1066. }
  1067. else
  1068. {
  1069. if (ModuleHelper.IsPm(robotWafers.First().destMod))
  1070. {
  1071. if (!robotWafers.First().IsAligned)
  1072. {
  1073. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, robotWafers.First().currentSlot, aligner.First().Key, 0, (Hand)robotWafers.First().currentSlot) });
  1074. }
  1075. else if (emptyAndReadyIn20sPMs.Contains(robotWafers.First().destMod))
  1076. {
  1077. var pmTask = _dictModuleTask[robotWafers.First().destMod] as VenusPMTask;
  1078. if (pmTask.ReadyMoveIn(robotWafers.First()))
  1079. {
  1080. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, robotWafers.First().currentSlot, robotWafers.First().destMod, robotWafers.First().destSlot, (Hand)(robotWafers.First().currentSlot)) });
  1081. }
  1082. }
  1083. }
  1084. else if (ModuleHelper.IsLoadPort(robotWafers.First().destMod) && _dictModuleTask[robotWafers.First().destMod].Scheduler.IsAvailable)
  1085. {
  1086. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, robotWafers.First().currentSlot, robotWafers.First().destMod, robotWafers.First().destSlot, (Hand)(robotWafers.First().currentSlot)) });
  1087. }
  1088. }
  1089. }
  1090. }
  1091. else // had better not go here
  1092. {
  1093. foreach(var wafer in robotWafers)
  1094. {
  1095. if (ModuleHelper.IsPm(wafer.destMod))
  1096. {
  1097. if (!wafer.IsAligned)
  1098. {
  1099. if (!_lstWaferTasks.Exists(wt => ModuleHelper.IsAligner(wt.currentMod)))
  1100. {
  1101. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, wafer.currentSlot, aligner.First().Key, 0, (Hand)wafer.currentSlot) });
  1102. }
  1103. }
  1104. else if (emptyAndReadyIn20sPMs.Contains(wafer.destMod))
  1105. {
  1106. var pmTask = _dictModuleTask[wafer.destMod] as VenusPMTask;
  1107. if (pmTask.ReadyMoveIn(wafer))
  1108. {
  1109. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, wafer.currentSlot, wafer.destMod, wafer.destSlot, (Hand)(wafer.currentSlot)) });
  1110. }
  1111. }
  1112. }
  1113. else if (ModuleHelper.IsLoadPort(wafer.destMod) && _dictModuleTask[wafer.destMod].Scheduler.IsAvailable)
  1114. {
  1115. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, wafer.currentSlot, wafer.destMod, wafer.destSlot, (Hand)(wafer.currentSlot)) });
  1116. }
  1117. }
  1118. }
  1119. }
  1120. private void RoutingWaferWithSingleArm()
  1121. {
  1122. var waitInWafers = _lstWaferTasks.Where(wt => ModuleHelper.IsLoadPort(wt.currentMod) && ModuleHelper.IsPm(wt.destMod)).OrderBy(wt => wt.currentSlot).ToList();
  1123. var readyReturnWafers = _lstWaferTasks.Where(wt => ModuleHelper.IsPm(wt.currentMod) && ModuleHelper.IsLoadPort(wt.destMod)).ToList();
  1124. var emptyAndReadyIn20sPMs = _dictModuleTask.Where(pm => ModuleHelper.IsPm(pm.Key) && !_lstWaferTasks.Exists(wt => wt.currentMod == pm.Key) && pm.Value.TimeToReady < 20).OrderBy(pm => pm.Value.TimeToReady).Select(pm => pm.Key).ToList();
  1125. var aligner = _dictModuleTask.Where(mod => ModuleHelper.IsAligner(mod.Key)).ToList();
  1126. var validHand = _tmRobotSingleArmOption == 1 ? Hand.Blade1 : Hand.Blade2;
  1127. var robotWafers = _lstWaferTasks.Where(wt => wt.currentMod == ModuleName.TMRobot && wt.currentSlot == (int)validHand).ToList();
  1128. if (robotWafers.Count == 0)
  1129. {
  1130. if (readyReturnWafers.Count > 0)
  1131. {
  1132. // return one wafer
  1133. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(readyReturnWafers.First().currentMod, 0, ModuleName.TMRobot, (int)validHand, validHand) });
  1134. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, (int)validHand, readyReturnWafers.First().destMod, readyReturnWafers.First().destSlot, validHand) });
  1135. }
  1136. else
  1137. {
  1138. if(_lstWaferTasks.Exists(wt => ModuleHelper.IsAligner(wt.currentMod)))
  1139. {
  1140. var alignerWafer = _lstWaferTasks.Find(wt => ModuleHelper.IsAligner(wt.currentMod));
  1141. if(emptyAndReadyIn20sPMs.Contains(alignerWafer.destMod))
  1142. {
  1143. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(alignerWafer.currentMod, 0, ModuleName.TMRobot, (int)validHand, validHand) });
  1144. // move aligner wafer to PM
  1145. var pmTask = _dictModuleTask[alignerWafer.destMod] as VenusPMTask;
  1146. if (pmTask.ReadyMoveIn(alignerWafer))
  1147. {
  1148. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, (int)validHand, alignerWafer.destMod, alignerWafer.destSlot, validHand) });
  1149. }
  1150. }
  1151. }
  1152. else
  1153. {
  1154. foreach(var wafer in waitInWafers)
  1155. {
  1156. if(emptyAndReadyIn20sPMs.Contains(wafer.destMod))
  1157. {
  1158. // move one wafer from LP to aligner
  1159. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(wafer.currentMod, wafer.currentSlot, ModuleName.TMRobot, (int)validHand, validHand) });
  1160. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, (int)validHand, aligner.First().Key, 0, validHand) });
  1161. }
  1162. }
  1163. }
  1164. }
  1165. }
  1166. else
  1167. {
  1168. var wafer = robotWafers[0];
  1169. if (ModuleHelper.IsPm(wafer.destMod))
  1170. {
  1171. if (!wafer.IsAligned)
  1172. {
  1173. if (!_lstWaferTasks.Exists(wt => ModuleHelper.IsAligner(wt.currentMod)))
  1174. {
  1175. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, wafer.currentSlot, aligner.First().Key, 0, (Hand)wafer.currentSlot) });
  1176. }
  1177. }
  1178. else if (emptyAndReadyIn20sPMs.Contains(wafer.destMod))
  1179. {
  1180. var pmTask = _dictModuleTask[wafer.destMod] as VenusPMTask;
  1181. if (pmTask.ReadyMoveIn(wafer))
  1182. {
  1183. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, wafer.currentSlot, wafer.destMod, wafer.destSlot, (Hand)(wafer.currentSlot)) });
  1184. }
  1185. }
  1186. }
  1187. else if (ModuleHelper.IsLoadPort(wafer.destMod) && _dictModuleTask[wafer.destMod].Scheduler.IsAvailable)
  1188. {
  1189. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, wafer.currentSlot, wafer.destMod, wafer.destSlot, (Hand)(wafer.currentSlot)) });
  1190. }
  1191. }
  1192. }
  1193. private void RunSchdTMActions()
  1194. {
  1195. if (_dictModuleTask[ModuleName.TMRobot].IsIdle)
  1196. {
  1197. if (_tmSchdActions.Count > 0)
  1198. {
  1199. if (_curTmAction.Count == 0 || IsMovingActionsDone(_curTmAction))
  1200. {
  1201. var nextActions = _tmSchdActions.First();
  1202. if (nextActions.Exists(action => !_lstWaferTasks.Exists(wafer => (wafer.movingStatus == RState.End || wafer.movingStatus == RState.Init) && wafer.currentMod == action.SourceModule && wafer.currentSlot == action.SourceSlot)))
  1203. return;
  1204. if (ModuleHelper.IsPm(nextActions.First().Module) && !_dictModuleTask[nextActions.First().Module].IsIdle) /// wait PMTask status update to idle
  1205. return;
  1206. _curTmAction = _tmSchdActions.Dequeue();
  1207. foreach (var action in _curTmAction)
  1208. {
  1209. var waferTask = _lstWaferTasks.Find(wafer => (wafer.movingStatus == RState.End || wafer.movingStatus == RState.Init) && wafer.currentMod == action.SourceModule && wafer.currentSlot == action.SourceSlot);
  1210. waferTask.MoveTo(action.DestinationModule, action.DestinationSlot);
  1211. }
  1212. (_dictModuleTask[ModuleName.TMRobot].Scheduler as SchedulerSETMRobot).SendMoveItems(_curTmAction.ToArray());
  1213. }
  1214. }
  1215. else if (_curTmAction.Count >= 0 && IsMovingActionsDone(_curTmAction)) // all scheduled actions done
  1216. {
  1217. _curTmAction.Clear();
  1218. }
  1219. }
  1220. }
  1221. private bool isReturnActionsDone(List<MoveItem> items)
  1222. {
  1223. foreach (var item in items)
  1224. {
  1225. if (WaferManager.Instance.CheckHasWafer(item.SourceModule, item.SourceSlot) || WaferManager.Instance.CheckNoWafer(item.DestinationModule, item.DestinationSlot))
  1226. return false;
  1227. }
  1228. return true;
  1229. }
  1230. private bool IsMovingActionsDone(List<MoveItem> actions)
  1231. {
  1232. bool CheckWaferExistence(ModuleName mod, int slot)
  1233. {
  1234. return ModuleHelper.IsLoadPort(mod) ? WaferManager.Instance.CheckHasWafer(mod, slot) : _lstWaferTasks.Exists(wt => wt.currentMod == mod && wt.currentSlot == slot);
  1235. }
  1236. if (actions.Count == 1)
  1237. {
  1238. if (CheckWaferExistence(actions.First().SourceModule, actions.First().SourceSlot) ||
  1239. !CheckWaferExistence(actions.First().DestinationModule, actions.First().DestinationSlot))
  1240. return false;
  1241. }
  1242. else
  1243. {
  1244. // initialize all the wafer existance before move
  1245. var slotWafers = new Dictionary<KeyValuePair<ModuleName, int>, bool>();
  1246. foreach (var ac in actions)
  1247. {
  1248. var scrSlot = new KeyValuePair<ModuleName, int>(ac.SourceModule, ac.SourceSlot);
  1249. var destSlot = new KeyValuePair<ModuleName, int>(ac.DestinationModule, ac.DestinationSlot);
  1250. if (!slotWafers.ContainsKey(scrSlot))
  1251. {
  1252. slotWafers[scrSlot] = true;
  1253. }
  1254. if (!slotWafers.ContainsKey(destSlot))
  1255. {
  1256. slotWafers[destSlot] = false;
  1257. }
  1258. }
  1259. // simulate moved result
  1260. foreach (var ac in actions)
  1261. {
  1262. var scrSlot = new KeyValuePair<ModuleName, int>(ac.SourceModule, ac.SourceSlot);
  1263. var destSlot = new KeyValuePair<ModuleName, int>(ac.DestinationModule, ac.DestinationSlot);
  1264. if (!slotWafers[scrSlot])
  1265. {
  1266. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"{slotWafers[scrSlot]} do not has a wafer");
  1267. }
  1268. else
  1269. {
  1270. slotWafers[scrSlot] = false;
  1271. }
  1272. if (slotWafers[destSlot])
  1273. {
  1274. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"{slotWafers[destSlot]} has a wafer");
  1275. }
  1276. else
  1277. {
  1278. slotWafers[destSlot] = true;
  1279. }
  1280. }
  1281. foreach (var slot in slotWafers)
  1282. {
  1283. if (slot.Value != CheckWaferExistence(slot.Key.Key, slot.Key.Value))
  1284. return false;
  1285. }
  1286. }
  1287. return true;
  1288. }
  1289. private void WaferArrived(WaferTask wafer, MoveItem item)
  1290. {
  1291. _dictModuleTask[item.DestinationModule].WaferArrived(wafer, item.DestinationSlot);
  1292. //--2024-03-21 增加了PortJobWaferEnd 上报事件 start--
  1293. if (ModuleHelper.IsLoadPort(item.DestinationModule))
  1294. {
  1295. ControlJobInfo currentControlJob = GetLoadPortCurrentControlJob(item.DestinationModule);
  1296. if (currentControlJob != null)
  1297. {
  1298. _faCallback.JobWaferEnd(currentControlJob, item.SourceSlot);
  1299. }
  1300. }
  1301. //--2024-03-21 增加了PortJobWaferEnd 上报事件 end--
  1302. }
  1303. private void WaferLeaved(WaferTask wafer, MoveItem item)
  1304. {
  1305. _dictModuleTask[item.SourceModule].WaferLeaved(wafer, item.DestinationSlot);
  1306. //--2024-03-21 增加了PortJobWaferStart 上报事件 start--
  1307. if (ModuleHelper.IsLoadPort(item.SourceModule))
  1308. {
  1309. (_dictModuleTask[wafer.destMod] as VenusPMTask).SubscribeWaferTask(wafer);
  1310. ControlJobInfo currentControlJob = GetLoadPortCurrentControlJob(item.SourceModule);
  1311. if (currentControlJob != null)
  1312. {
  1313. _faCallback.JobWaferStart(currentControlJob, item.SourceSlot);
  1314. }
  1315. }
  1316. //--2024-03-21 增加了PortJobWaferStart 上报事件 end--
  1317. }
  1318. private bool CheckAllWaferReturned(ProcessJobInfo pj, bool checkAllProcessed)
  1319. {
  1320. bool allWaferReturn = true;
  1321. foreach (var slot in pj.SlotWafers)
  1322. {
  1323. var wafer = WaferManager.Instance.GetWafer(slot.Item1, slot.Item2);
  1324. if (wafer.IsEmpty || (wafer.ProcessState != EnumWaferProcessStatus.Completed && checkAllProcessed))
  1325. {
  1326. allWaferReturn = false;
  1327. break;
  1328. }
  1329. }
  1330. return allWaferReturn;
  1331. }
  1332. private void ReturnInternalWafers()
  1333. {
  1334. if (_tmSchdActions.Count > 0 || _curTmAction.Count > 0)
  1335. {
  1336. RunSchdTMReturnActions();
  1337. return;
  1338. }
  1339. if (_tmRobotStatus != RState.End)
  1340. return;
  1341. for (int i = 0; i < 2; i++)
  1342. {
  1343. if(WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, i))
  1344. {
  1345. var wafer = WaferManager.Instance.GetWafer(ModuleName.TMRobot, i);
  1346. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, i, (ModuleName)wafer.OriginStation, wafer.OriginSlot, (Hand)i) });
  1347. return;
  1348. }
  1349. }
  1350. foreach(var mod in _dictModuleTask)
  1351. {
  1352. if (ModuleHelper.IsTMRobot(mod.Key) || ModuleHelper.IsLoadPort(mod.Key))
  1353. continue;
  1354. if(WaferManager.Instance.CheckHasWafer(mod.Key, 0))
  1355. {
  1356. var wafer = WaferManager.Instance.GetWafer(mod.Key, 0);
  1357. var freeHands = GetTMFreeHand();
  1358. if(freeHands.Count > 0)
  1359. {
  1360. var hand = freeHands[0];
  1361. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(mod.Key, 0, ModuleName.TMRobot, (int)hand, hand) });
  1362. _tmSchdActions.Enqueue(new List<MoveItem> { new MoveItem(ModuleName.TMRobot, (int)hand, (ModuleName)wafer.OriginStation, wafer.OriginSlot, hand) });
  1363. return;
  1364. }
  1365. }
  1366. }
  1367. }
  1368. private List<Hand> GetTMFreeHand()
  1369. {
  1370. var lstHands = new List<Hand>();
  1371. if (WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 0) && _tmRobotSingleArmOption != 2)
  1372. lstHands.Add(Hand.Blade1);
  1373. if (WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 1) && _tmRobotSingleArmOption != 1)
  1374. lstHands.Add(Hand.Blade2);
  1375. return lstHands;
  1376. }
  1377. private void UpdateProcessJobStatus()
  1378. {
  1379. if (_tmRobotStatus == RState.Running)
  1380. return;
  1381. foreach (var pj in _lstProcessJobs)
  1382. {
  1383. if (CheckAllWaferReturned(pj, pj.State != EnumProcessJobState.Stopping))
  1384. {
  1385. pj.SetState(EnumProcessJobState.ProcessingComplete);
  1386. JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0);
  1387. }
  1388. }
  1389. }
  1390. private void UpdateControlJobStatus()
  1391. {
  1392. if (_lstControlJobs.Count == 0 || _tmRobotStatus == RState.Running)
  1393. return;
  1394. bool allControlJobComplete = true;
  1395. List<ControlJobInfo> cjRemoveList = new List<ControlJobInfo>();
  1396. var runingJobs = _lstControlJobs.FindAll(cj => cj.State == EnumControlJobState.Executing);
  1397. foreach(var runingjob in runingJobs)
  1398. {
  1399. int countProcessed = 0;
  1400. foreach (var pjName in runingjob.ProcessJobNameList)
  1401. {
  1402. var pj = _lstProcessJobs.Find(x => x.Name == pjName);
  1403. if (pj == null)
  1404. {
  1405. LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Not find pj named {pjName} in {runingjob.Name}");
  1406. continue;
  1407. }
  1408. // caculate process wafer by process
  1409. if (_isCycleMode && _cycledCount < (_isCycleMode ? _cycleSetPoint : 0))
  1410. {
  1411. foreach (var pjSlotWafer in pj.SlotWafers)
  1412. {
  1413. WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
  1414. if (!wafer.IsEmpty && wafer.ProcessState == EnumWaferProcessStatus.Completed)
  1415. countProcessed++;
  1416. }
  1417. }
  1418. }
  1419. int lpCycleWafer = _lpCycleCount[ModuleHelper.Converter(runingjob.Module)] * runingjob.LotWafers.Count + (runingjob.State == EnumControlJobState.Completed&& runingjob.LotWafers.Count == countProcessed ? 0 : countProcessed);
  1420. if (_lpCycleCount[ModuleHelper.Converter(runingjob.Module)] != _cycledCount || lpCycleWafer != _lpCycleWafer[ModuleHelper.Converter(runingjob.Module)])
  1421. {
  1422. _lpCycleWafer[ModuleHelper.Converter(runingjob.Module)] = lpCycleWafer;
  1423. }
  1424. if (IsAllProcessJobComplete(runingjob))
  1425. {
  1426. runingjob.SetState(EnumControlJobState.Completed);
  1427. runingjob.EndTime = DateTime.Now;
  1428. _faCallback.JobFinished(runingjob, GetFirstProcessJob(runingjob));
  1429. _dbCallback.LotFinished(runingjob);
  1430. if (!(_isCycleMode && _cycledCount < _cycleSetPoint))
  1431. (Singleton<TransferModule>.Instance.GetScheduler(ModuleHelper.Converter(runingjob.Module)) as SchedulerLoadPort).NoteJobComplete();
  1432. _lpCycleCount[ModuleHelper.Converter(runingjob.Module)]++;
  1433. }
  1434. }
  1435. var pendingJobs = _lstControlJobs.FindAll(cj => cj.State == EnumControlJobState.Queued).OrderBy(cj => cj.StartTime);
  1436. if(pendingJobs.Count() > 0)
  1437. {
  1438. if (runingJobs.Count == 0 || (runingJobs.Count == 1 && IsAllJobWaferProcessedOrProcessing(runingJobs.First())))
  1439. {
  1440. ActiveControlJob(pendingJobs.First());
  1441. }
  1442. }
  1443. foreach(var cj in _lstControlJobs)
  1444. {
  1445. LoadportCassetteState state = (LoadportCassetteState)DATA.Poll($"{cj.Module}.CassetteState");
  1446. if (cj.State == EnumControlJobState.Completed && state != LoadportCassetteState.Normal)
  1447. {
  1448. cjRemoveList.Add(cj);
  1449. }
  1450. allControlJobComplete = allControlJobComplete && cj.State == EnumControlJobState.Completed;
  1451. }
  1452. if (_isCycleMode && _cycledCount < (_isCycleMode ? _cycleSetPoint : 0))
  1453. {
  1454. int totolCycleWafer = _lpCycleWafer.Sum(item => item.Value);
  1455. if (totolCycleWafer != _cycledWafer || _lpCycleCount.Sum(item => item.Value) > 0 && _throughput < 0.01) // refresh _throughput in time
  1456. {
  1457. _cycledWafer = totolCycleWafer;
  1458. if (_cycledCount > 0 || allControlJobComplete)
  1459. {
  1460. _throughput = (float)(_cycledWafer / _cycleWatch.Elapsed.TotalHours);
  1461. }
  1462. else
  1463. {
  1464. _throughput = 0;
  1465. }
  1466. }
  1467. if (allControlJobComplete)
  1468. {
  1469. _cycledCount++;
  1470. LOG.Write(eEvent.EV_ROUTER, ModuleName.System, $"Cycle Count: {_cycledCount}, Total Processed Wafer: {_cycledWafer}, Throughput: {_throughput}");
  1471. if (_cycledCount < _cycleSetPoint)
  1472. {
  1473. foreach (var cj in _lstControlJobs)
  1474. {
  1475. cj.SetState(EnumControlJobState.Queued);
  1476. cj.LotInnerId = Guid.NewGuid();
  1477. _dbCallback.LotCreated(cj);
  1478. }
  1479. foreach (var pj in _lstProcessJobs)
  1480. {
  1481. pj.SetState(EnumProcessJobState.Queued);
  1482. pj.InnerId = Guid.NewGuid();
  1483. foreach (var pjSlotWafer in pj.SlotWafers)
  1484. {
  1485. WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
  1486. wafer.ProcessJob = null;
  1487. wafer.NextSequenceStep = 0;
  1488. wafer.ProcessState = EnumWaferProcessStatus.Idle;
  1489. }
  1490. }
  1491. _lstWaferTasks.Clear();
  1492. }
  1493. else
  1494. _cycleState = RState.End;
  1495. }
  1496. }
  1497. foreach (var cj in cjRemoveList)
  1498. {
  1499. List<ProcessJobInfo> pjRemoveList = new List<ProcessJobInfo>();
  1500. foreach (var pj in _lstProcessJobs)
  1501. {
  1502. if (pj.ControlJobName == cj.Name)
  1503. pjRemoveList.Add(pj);
  1504. }
  1505. foreach (var pj in pjRemoveList)
  1506. {
  1507. _lstProcessJobs.Remove(pj);
  1508. }
  1509. _lstControlJobs.Remove(cj);
  1510. }
  1511. }
  1512. private bool ActiveProcessJob(ProcessJobInfo pj)
  1513. {
  1514. foreach (var pjSlotWafer in pj.SlotWafers)
  1515. {
  1516. WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
  1517. wafer.ProcessJob = pj;
  1518. wafer.NextSequenceStep = 0;
  1519. WaferDataRecorder.SetPjInfo(wafer.InnerId.ToString(), pj.InnerId.ToString());
  1520. }
  1521. ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == pj.ControlJobName);
  1522. CarrierInfo carrier = CarrierManager.Instance.GetCarrier(cj.Module);
  1523. JobDataRecorder.StartPJ(pj.InnerId.ToString(), carrier.InnerId.ToString(), cj.InnerId.ToString(), pj.Name, cj.Module, cj.Module, pj.SlotWafers.Count);
  1524. pj.SetState(EnumProcessJobState.Processing);
  1525. return true;
  1526. }
  1527. private bool ActiveControlJob(ControlJobInfo cj)
  1528. {
  1529. cj.SetState(EnumControlJobState.Executing);
  1530. foreach (var pjName in cj.ProcessJobNameList)
  1531. {
  1532. var pj = _lstProcessJobs.Find(x => x.Name == pjName);
  1533. if (pj == null)
  1534. {
  1535. LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Not find pj named {pjName} in {cj.Name}");
  1536. continue;
  1537. }
  1538. if (pj.State == EnumProcessJobState.Queued)
  1539. {
  1540. ActiveProcessJob(pj);
  1541. }
  1542. }
  1543. return true;
  1544. }
  1545. private bool IsAllProcessJobComplete(ControlJobInfo cj)
  1546. {
  1547. foreach (var pj in _lstProcessJobs)
  1548. {
  1549. if (pj.ControlJobName == cj.Name && pj.State != EnumProcessJobState.ProcessingComplete)
  1550. {
  1551. return false;
  1552. }
  1553. }
  1554. return true;
  1555. }
  1556. private bool IsAllJobWaferProcessedOrProcessing(ControlJobInfo cj)
  1557. {
  1558. List<ModuleName> allModules = _dictModuleTask.Keys.ToList();
  1559. int original = (int)ModuleHelper.Converter(cj.Module);
  1560. foreach (var mod in allModules)
  1561. {
  1562. if (ModuleHelper.IsLoadPort(mod) && (int)mod != original)
  1563. continue;
  1564. var wafers = WaferManager.Instance.GetWafers(mod);
  1565. foreach (var wafer in wafers)
  1566. {
  1567. if (wafer.IsEmpty || wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null || wafer.ProcessJob.ControlJobName != cj.Name)
  1568. continue;
  1569. if (wafer.ProcessState != EnumWaferProcessStatus.Completed && wafer.ProcessState != EnumWaferProcessStatus.InProcess)
  1570. return false; ;
  1571. }
  1572. }
  1573. return true;
  1574. }
  1575. private ModuleName GetComingAvailablePM(ControlJobInfo cj)
  1576. {
  1577. var lstInProcessPMs = new List<ModuleName>();
  1578. foreach (var wafer in cj.LotWafers)
  1579. {
  1580. if (!wafer.IsEmpty && wafer.NextSequenceStep == 0 && wafer.ProcessJob != null)
  1581. {
  1582. foreach (var pm in wafer.ProcessJob.Sequence.PMs)
  1583. {
  1584. if (!lstInProcessPMs.Contains(pm) && _dictModuleTask[pm].Scheduler.IsOnline)
  1585. lstInProcessPMs.Add(pm);
  1586. }
  1587. }
  1588. }
  1589. Dictionary<ModuleName, int> pmAssociatedWaferCount = new Dictionary<ModuleName, int>();
  1590. foreach (var mod in _dictModuleTask)
  1591. {
  1592. if (ModuleHelper.IsPm(mod.Key) && mod.Value.Scheduler.IsOnline && lstInProcessPMs.Contains(mod.Key))
  1593. {
  1594. pmAssociatedWaferCount[mod.Key] = 0;
  1595. }
  1596. }
  1597. var unprocessedWafer = _lstWaferTasks.Where(task => ModuleHelper.IsPm(task.destMod));
  1598. foreach (var wafer in unprocessedWafer)
  1599. {
  1600. if (ModuleHelper.IsPm(wafer.destMod) && _dictModuleTask[wafer.destMod].Scheduler.IsOnline && lstInProcessPMs.Contains(wafer.destMod))
  1601. {
  1602. pmAssociatedWaferCount[wafer.destMod]++;
  1603. }
  1604. }
  1605. var oderedPMCount = pmAssociatedWaferCount.OrderBy(p => p.Value).ToDictionary(p => p.Key, o => o.Value);
  1606. if (oderedPMCount.Count > 0 && oderedPMCount.First().Value < 2)
  1607. return oderedPMCount.First().Key;
  1608. return ModuleName.System;
  1609. }
  1610. private void CreateNewWaferTask()
  1611. {
  1612. var cj = _lstControlJobs.Find(job => job.State == EnumControlJobState.Executing);
  1613. if (cj != null)
  1614. {
  1615. var pm = GetComingAvailablePM(cj);
  1616. if (pm != ModuleName.System)
  1617. {
  1618. foreach (var wafer in cj.LotWafers)
  1619. {
  1620. if (wafer.IsEmpty || wafer.ProcessJob == null)
  1621. continue;
  1622. if (wafer.ProcessJob.Sequence.PMs.Contains(pm) && wafer.NextSequenceStep == 0 && !_lstWaferTasks.Exists(task => task.sourceMod == (ModuleName)wafer.OriginStation && task.sourceSlot == wafer.OriginSlot))
  1623. {
  1624. CreateWaferTasks(wafer, pm);
  1625. return;
  1626. }
  1627. }
  1628. }
  1629. }
  1630. }
  1631. private void CreateWaferTasks(WaferInfo wafer, ModuleName pm)
  1632. {
  1633. var recipeName = wafer.ProcessJob.Sequence.GetRecipe(pm);
  1634. var recipeContent = RecipeFileManager.Instance.LoadRecipe(pm.ToString(), recipeName, false, RecipeType.Process.ToString());
  1635. Recipe recipe = Recipe.Load(recipeContent);
  1636. int temperature = 0;
  1637. if (int.TryParse(recipe.Header.Temperature, out int temp))
  1638. {
  1639. temperature = temp;
  1640. }
  1641. var waferTask = new VenusWaferTask((ModuleName)wafer.OriginStation,
  1642. wafer.OriginSlot,
  1643. pm,
  1644. 0,
  1645. temperature,
  1646. wafer.InnerId,
  1647. recipeName,
  1648. String.Empty,
  1649. wafer.ProcessJob.Sequence.LLInOutPath,
  1650. wafer.ProcessJob.Sequence.LLDelayTime,
  1651. IsSequenceNeedAlign(wafer.ProcessJob.Sequence),
  1652. wafer.ProcessJob.Sequence.PreWaferCleanRecipe, // pre clean
  1653. wafer.ProcessJob.Sequence.PostWaferCleanRecipe); // post clean
  1654. waferTask.OnWaferArrived += WaferArrived;
  1655. waferTask.OnWaferLeaved += WaferLeaved;
  1656. _lstWaferTasks.Add(waferTask);
  1657. }
  1658. private bool IsSequenceNeedAlign(SequenceInfo sequence)
  1659. {
  1660. // check wether need align
  1661. foreach (var step in sequence.Steps)
  1662. {
  1663. foreach (var mod in step.StepModules)
  1664. {
  1665. if (ModuleHelper.IsAligner(mod))
  1666. return true;
  1667. }
  1668. }
  1669. return false;
  1670. }
  1671. private void RunSchdTMReturnActions()
  1672. {
  1673. var tmRobot = Singleton<TransferModule>.Instance.GetScheduler(ModuleName.TMRobot) as SchedulerSETMRobot;
  1674. if (tmRobot == null || !tmRobot.IsAvailable)
  1675. return;
  1676. if (_tmSchdActions.Count > 0)
  1677. {
  1678. if (_curTmAction.Count == 0 || isReturnActionsDone(_curTmAction))
  1679. {
  1680. var nextActions = _tmSchdActions.First();
  1681. var nextModule = nextActions.First().Module;
  1682. if (!_dictModuleTask[nextModule].IsIdle)
  1683. return;
  1684. _curTmAction = _tmSchdActions.Dequeue();
  1685. tmRobot.SendMoveItems(_curTmAction.ToArray());
  1686. }
  1687. }
  1688. else if (_curTmAction.Count >= 0 && isReturnActionsDone(_curTmAction)) // all scheduled actions done
  1689. {
  1690. _curTmAction.Clear();
  1691. }
  1692. }
  1693. #endregion internal implementation
  1694. #region sequence/recipe validation
  1695. private bool CheckSequencePmReady(SequenceInfo seq, out string reason)
  1696. {
  1697. reason = "";
  1698. foreach (var pm in seq.PMs)
  1699. {
  1700. if (ModuleHelper.IsInstalled(pm) && (_dictModuleTask[pm].Scheduler.IsOnline || !Singleton<RouteManager>.Instance.IsAutoMode))
  1701. return true;
  1702. }
  1703. reason = $"Sequence {seq.Name} no valid PM, " + string.Join("|", seq.PMs);
  1704. return false;
  1705. }
  1706. private bool CheckSequenceRecipeFileValid(SequenceInfo seq, out string reason)
  1707. {
  1708. for (int i = 0; i < seq.Steps.Count; i++)
  1709. {
  1710. SequenceStepInfo stepInfo = seq.Steps[i];
  1711. foreach (var module in stepInfo.StepModules)
  1712. {
  1713. if (ModuleHelper.IsPm(module))
  1714. {
  1715. string attr = $"{module}Recipe";
  1716. if (stepInfo.StepParameter.ContainsKey(attr)
  1717. && !string.IsNullOrWhiteSpace((string)stepInfo.StepParameter[attr]))
  1718. {
  1719. var recipeName = (string)stepInfo.StepParameter[attr];
  1720. if (!string.IsNullOrWhiteSpace(recipeName))
  1721. {
  1722. var recipeContent =
  1723. RecipeFileManager.Instance.LoadRecipe($"{module}", recipeName, false, "Process");
  1724. if (string.IsNullOrWhiteSpace(recipeContent))
  1725. {
  1726. reason = $"Can not find recipe file{recipeName}";
  1727. return false;
  1728. }
  1729. }
  1730. }
  1731. }
  1732. }
  1733. }
  1734. reason = "";
  1735. return true;
  1736. }
  1737. #endregion
  1738. }
  1739. }