VenusDispatcher.cs 77 KB

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