AutoCycle.cs 83 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174
  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 Venus_Unity;
  24. namespace Venus_RT.Modules
  25. {
  26. enum ModulePriority
  27. {
  28. High,
  29. Middle,
  30. Low,
  31. Stop,
  32. }
  33. public enum MovingStatus
  34. {
  35. Idle,
  36. Waiting,
  37. Moving,
  38. // PM Status
  39. WaitProcess,
  40. StartProcess,
  41. Processing,
  42. // Align Status
  43. WaitAlign,
  44. StartAlign,
  45. Aligning,
  46. }
  47. class ModuleFlag
  48. {
  49. public ModulePriority Priority { get; set; }
  50. public MovingStatus MovingStatus { get; set; }
  51. public bool InUsed { get; set; }
  52. public ModuleFlag(ModulePriority _priority)
  53. {
  54. Priority = _priority;
  55. MovingStatus = MovingStatus.Idle;
  56. InUsed = true;
  57. }
  58. }
  59. class AutoCycle : IRoutine
  60. {
  61. private List<ControlJobInfo> _lstControlJobs = new List<ControlJobInfo>();
  62. private List<ProcessJobInfo> _lstProcessJobs = new List<ProcessJobInfo>();
  63. private RState _cycleState = RState.Init;
  64. Dictionary<ModuleName, SchedulerModule> _atmSchedulers = new Dictionary<ModuleName, SchedulerModule>();
  65. Dictionary<ModuleName, ModuleFlag> _atmModules = new Dictionary<ModuleName, ModuleFlag>();
  66. Dictionary<ModuleName, SchedulerModule> _vacSchedulers = new Dictionary<ModuleName, SchedulerModule>();
  67. Dictionary<ModuleName, ModuleFlag> _vacModules = new Dictionary<ModuleName, ModuleFlag>();
  68. SchedulerTMRobot _tmRobot = (SchedulerTMRobot)Singleton<TransferModule>.Instance.GetScheduler(ModuleName.TMRobot);
  69. SchedulerEfemRobot _efemRobot = (SchedulerEfemRobot)Singleton<TransferModule>.Instance.GetScheduler(ModuleName.EfemRobot);
  70. Dictionary<SlotItem, long> _vacReadyOutSlots = new Dictionary<SlotItem, long>();
  71. Dictionary<SlotItem, long> _vacReadyInSlots = new Dictionary<SlotItem, long>();
  72. Dictionary<SlotItem, long> _atmReadyOutSlots = new Dictionary<SlotItem, long>();
  73. Dictionary<SlotItem, long> _atmReadyInSlots = new Dictionary<SlotItem, long>();
  74. List<int> _LLAInSlot = new List<int> { 0, 1, 2, 3 };
  75. List<int> _LLAOutSlot = new List<int> { 0, 1, 2, 3 };
  76. List<int> _LLBInSlot = new List<int> { 0, 1, 2, 3 };
  77. List<int> _LLBOutSlot = new List<int> { 0, 1, 2, 3 };
  78. int _LLASlotNumber = 4;
  79. int _LLBSlotNumber = 4;
  80. int _efemRobotSingleArmOption = 0;
  81. SequenceLLInOutPath _LLInOutPath = SequenceLLInOutPath.DInDOut;
  82. List<MoveItem> _movingItems = new List<MoveItem>();
  83. List<MoveItem> _efemMovingItems = new List<MoveItem>();
  84. Dictionary<SlotItem, Guid> _vacWaferTargets = new Dictionary<SlotItem, Guid>();
  85. Dictionary<SlotItem, Guid> _atmWaferTargets = new Dictionary<SlotItem, Guid>();
  86. R_TRIG _vacMoveFinishTrig = new R_TRIG();
  87. R_TRIG _atmMoveFinishTrig = new R_TRIG();
  88. private SchedulerFACallback _faCallback;
  89. private SchedulerDBCallback _dbCallback;
  90. private bool _isCycleMode;
  91. private int _cycleSetPoint = 0;
  92. private int _cycledCount = 0;
  93. private int _cycledWafer = 0;
  94. public bool HasJobRunning => _lstControlJobs.Count > 0;
  95. #region public interface
  96. public AutoCycle()
  97. {
  98. _faCallback = new SchedulerFACallback();
  99. _dbCallback = new SchedulerDBCallback();
  100. InitModules();
  101. _LLASlotNumber = SC.GetValue<int>("LLA.SlotNumber");
  102. _LLBSlotNumber = SC.GetValue<int>("LLB.SlotNumber");
  103. _LLAInSlot.RemoveAll(item => item >= _LLASlotNumber);
  104. _LLAOutSlot.RemoveAll(item => item >= _LLASlotNumber);
  105. _LLBInSlot.RemoveAll(item => item >= _LLBSlotNumber);
  106. _LLBOutSlot.RemoveAll(item => item >= _LLBSlotNumber);
  107. _efemRobotSingleArmOption = SC.GetValue<int>("EFEM.SingleArmOption");
  108. DATA.Subscribe("Scheduler.CycledCount", () => _cycledCount,SubscriptionAttribute.FLAG.IgnoreSaveDB);
  109. DATA.Subscribe("Scheduler.CycledWafer", () => _cycledWafer, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  110. DATA.Subscribe("Scheduler.CycleSetPoint", () => _cycleSetPoint, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  111. DATA.Subscribe("Scheduler.PjIdList", () => Array.ConvertAll(_lstProcessJobs.ToArray(), x => x.InnerId.ToString()).ToList());
  112. }
  113. public RState Start(params object[] objs)
  114. {
  115. _isCycleMode = SC.GetValue<bool>("System.IsCycleMode");
  116. _cycleSetPoint = _isCycleMode ? SC.GetValue<int>("System.CycleCount") : 0;
  117. _cycledWafer = 0;
  118. _cycledCount = 0;
  119. return RState.Running;
  120. }
  121. public RState Monitor()
  122. {
  123. if(_cycleState == RState.Running)
  124. {
  125. prelude();
  126. driveAtmSystem();
  127. driveVacSystem();
  128. epilogue();
  129. }
  130. return _cycleState;
  131. }
  132. public void Abort()
  133. {
  134. }
  135. public void CreateJob(Dictionary<string, object> param)
  136. {
  137. _isCycleMode = SC.GetValue<bool>("System.IsCycleMode");
  138. _cycleSetPoint = _isCycleMode ? SC.GetValue<int>("System.CycleCount") : 0;
  139. string[] slotSequence = (string[])param["SlotSequence"];
  140. string jobId = (string)param["JobId"];
  141. string module = (string)param["Module"];
  142. //bool autoStart = (bool)param["AutoStart"];
  143. string lotId = jobId;
  144. if (param.ContainsKey("LotId"))
  145. lotId = (string)param["LotId"];
  146. if (slotSequence.Length != SC.GetValue<int>("EFEM.LoadPort.SlotNumber"))
  147. {
  148. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"slot sequence parameter not valid, length is {slotSequence.Length}, should be {SC.GetValue<int>("EFEM.LoadPort.SlotNumber")}");
  149. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  150. return;
  151. }
  152. if (!ModuleHelper.IsLoadPort(ModuleHelper.Converter(module)))
  153. {
  154. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"{module} should be LoadPort");
  155. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  156. return;
  157. }
  158. if (string.IsNullOrEmpty(jobId))
  159. {
  160. jobId = "CJ_Local_" + module;
  161. }
  162. if (_lstControlJobs.Exists(x => x.Name == jobId))
  163. {
  164. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"{jobId} already created");
  165. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  166. return;
  167. }
  168. SchedulerLoadPort lp = _atmSchedulers[ModuleHelper.Converter(module)] as SchedulerLoadPort;
  169. if (!lp.CheckReadyRunJob())
  170. {
  171. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"{module} not ready");
  172. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  173. return;
  174. }
  175. ControlJobInfo cj = new ControlJobInfo();
  176. cj.Name = jobId;
  177. cj.Module = module;
  178. cj.LotName = lotId;
  179. cj.LotInnerId = Guid.NewGuid();
  180. cj.LotWafers = new List<WaferInfo>();
  181. cj.SetState(EnumControlJobState.WaitingForStart);
  182. Dictionary<string, bool[]> seqSlot = new Dictionary<string, bool[]>();
  183. Dictionary<string, List<Tuple<ModuleName, int>>> seqSlotWafers = new Dictionary<string, List<Tuple<ModuleName, int>>>();
  184. Dictionary<string, string> indexSequence = new Dictionary<string, string>();
  185. bool enableGroupBySequence = SC.GetValue<bool>("Scheduler.GroupWaferBySequence");
  186. for (int i = 0; i < SC.GetValue<int>("EFEM.LoadPort.SlotNumber"); i++)
  187. {
  188. if (string.IsNullOrEmpty(slotSequence[i]) || string.IsNullOrEmpty(slotSequence[i].Trim()))
  189. continue;
  190. string groupName = enableGroupBySequence ? slotSequence[i].Trim() : i.ToString();
  191. indexSequence[groupName] = slotSequence[i];
  192. if (!seqSlot.ContainsKey(groupName))
  193. {
  194. seqSlot[groupName] = new bool[SC.GetValue<int>("EFEM.LoadPort.SlotNumber")];
  195. }
  196. if (!seqSlotWafers.ContainsKey(groupName))
  197. {
  198. seqSlotWafers[groupName] = new List<Tuple<ModuleName, int>>();
  199. }
  200. seqSlot[groupName][i] = true;
  201. if (!WaferManager.Instance.CheckHasWafer(module, i))
  202. {
  203. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"job wafer: {module} slot {i + 1} not in the carrier");
  204. return;
  205. }
  206. if (!WaferManager.Instance.CheckWafer(ModuleHelper.Converter(module), i, WaferStatus.Normal))
  207. {
  208. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"job wafer: {module} slot {i + 1} status is {WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).Status}");
  209. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  210. return;
  211. }
  212. if (WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).ProcessState != EnumWaferProcessStatus.Idle)
  213. {
  214. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"job wafer: {module} slot {i + 1} process status is {WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).ProcessState}");
  215. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  216. return;
  217. }
  218. cj.LotWafers.Add(WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i));
  219. WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).SequenceName = slotSequence[i];
  220. seqSlotWafers[groupName].Add(Tuple.Create(ModuleHelper.Converter(module), i));
  221. cj.JobWaferSize = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).Size;
  222. LOG.Write(eEvent.EV_ROUTER, ModuleName.System, $"Assigned wafer job, wafer {module}.{i + 1}, sequence: {slotSequence[i]}");
  223. }
  224. if (seqSlotWafers.Count == 0)
  225. {
  226. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"job has not assign wafer");
  227. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  228. return;
  229. }
  230. List<ProcessJobInfo> pjs = new List<ProcessJobInfo>();
  231. string[] seqs = seqSlot.Keys.ToArray();
  232. for (int i = 0; i < seqs.Length; i++)
  233. {
  234. ProcessJobInfo pj = new ProcessJobInfo();
  235. pj.Name = jobId + "_" + (i + 1);
  236. pj.Sequence = SequenceInfoHelper.GetInfo(indexSequence[seqs[i]]);
  237. pj.ControlJobName = cj.Name;
  238. pj.LotName = lotId;
  239. pj.SlotWafers = seqSlotWafers[seqs[i]];
  240. pj.SetState(EnumProcessJobState.Queued);
  241. if (!CheckSequencePmReady(pj.Sequence, null, out _, out string reason))
  242. {
  243. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"no valid chamber for the {reason}");
  244. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  245. return;
  246. }
  247. if (!RouteManager.IsATMMode && !CheckSequenceRecipeFileValid(pj.Sequence, out reason))
  248. {
  249. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"recipe file not valid in the sequence, {reason}");
  250. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  251. return;
  252. }
  253. pjs.Add(pj);
  254. }
  255. _dbCallback.LotUpdate(cj);
  256. foreach (var pj in pjs)
  257. {
  258. cj.ProcessJobNameList.Add(pj.Name);
  259. _lstProcessJobs.Add(pj);
  260. }
  261. _lstControlJobs.Add(cj);
  262. //AssociatedPMWithLP(cj);
  263. _faCallback.JobCreated(cj, GetFirstProcessJob(cj));
  264. }
  265. public bool CheckAllJobDone()
  266. {
  267. foreach (var cj in _lstControlJobs)
  268. {
  269. if (cj.State == EnumControlJobState.Executing || cj.State == EnumControlJobState.Paused)
  270. return false;
  271. }
  272. return true;
  273. }
  274. public bool CheckJobJustDone(out string sJobName)
  275. {
  276. foreach (var cj in _lstControlJobs)
  277. {
  278. if (cj.State == EnumControlJobState.Completed && !cj.BeenPosted)
  279. {
  280. //LP;WaferSize;Lot;Number;Start;End;
  281. sJobName = $"{cj.Module};{cj.JobWaferSize};{cj.LotName};{cj.LotWafers.Count};{cj.StartTime:T};{cj.EndTime:T}";
  282. cj.BeenPosted = true;
  283. return true;
  284. }
  285. }
  286. sJobName = "NULL";
  287. return false;
  288. }
  289. public ProcessJobInfo GetFirstProcessJob(ControlJobInfo cj)
  290. {
  291. foreach (var pj in _lstProcessJobs)
  292. {
  293. if (pj.ControlJobName == cj.Name)
  294. return pj;
  295. }
  296. return null;
  297. }
  298. public void AbortJob(string jobName)
  299. {
  300. ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
  301. if (cj == null)
  302. {
  303. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"abort job rejected, not found job with id {jobName}");
  304. return;
  305. }
  306. List<ProcessJobInfo> pjAbortList = new List<ProcessJobInfo>();
  307. foreach (var pj in _lstProcessJobs)
  308. {
  309. if (pj.ControlJobName == cj.Name)
  310. {
  311. pj.SetState(EnumProcessJobState.Aborting);
  312. pjAbortList.Add(pj);
  313. int unprocessed = 0;
  314. int aborted = 0;
  315. WaferInfo[] wafers = WaferManager.Instance.GetWaferByProcessJob(pj.Name);
  316. foreach (var waferInfo in wafers)
  317. {
  318. waferInfo.ProcessJob = null;
  319. waferInfo.NextSequenceStep = 0;
  320. if (waferInfo.ProcessState != EnumWaferProcessStatus.Completed)
  321. unprocessed++;
  322. }
  323. JobDataRecorder.EndPJ(pj.InnerId.ToString(), aborted, unprocessed);
  324. }
  325. }
  326. _faCallback.JobAborted(cj, GetFirstProcessJob(cj));
  327. _dbCallback.LotFinished(cj);
  328. foreach (var pj in pjAbortList)
  329. {
  330. _lstProcessJobs.Remove(pj);
  331. }
  332. _lstControlJobs.Remove(cj);
  333. }
  334. public void StopJob(string jobName)
  335. {
  336. ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
  337. if (cj == null)
  338. {
  339. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"stop job rejected, not found job with id {jobName}");
  340. return;
  341. }
  342. foreach (var pj in _lstProcessJobs)
  343. {
  344. if (pj.ControlJobName == cj.Name)
  345. {
  346. pj.SetState(EnumProcessJobState.Stopping);
  347. }
  348. }
  349. _faCallback.JobStopped(cj, GetFirstProcessJob(cj));
  350. _dbCallback.LotFinished(cj);
  351. }
  352. public void ResumeJob(string jobName)
  353. {
  354. ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
  355. if (cj == null)
  356. {
  357. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"resume job rejected, not found job with id {jobName}");
  358. return;
  359. }
  360. if (cj.State == EnumControlJobState.Paused)
  361. {
  362. cj.SetState(EnumControlJobState.Executing);
  363. }
  364. _faCallback.JobResumed(cj, GetFirstProcessJob(cj));
  365. }
  366. public void PauseJob(string jobName)
  367. {
  368. ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
  369. if (cj == null)
  370. {
  371. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"pause job rejected, not found job with id {jobName}");
  372. return;
  373. }
  374. if (cj.State == EnumControlJobState.Executing)
  375. {
  376. cj.SetState(EnumControlJobState.Paused);
  377. }
  378. _faCallback.JobPaused(cj, GetFirstProcessJob(cj));
  379. }
  380. public void StartJob(string jobName)
  381. {
  382. ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
  383. if (cj == null)
  384. {
  385. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"start job rejected, not found job with id {jobName}");
  386. return;
  387. }
  388. if (cj.State == EnumControlJobState.WaitingForStart)
  389. {
  390. cj.SetState(EnumControlJobState.Executing);
  391. //PreJobClean(cj);
  392. (_atmSchedulers[ModuleHelper.Converter(cj.Module)] as SchedulerLoadPort).NoteJobStart();
  393. cj.StartTime = DateTime.Now;
  394. _dbCallback.LotCreated(cj);
  395. _faCallback.JobStarted(cj, GetFirstProcessJob(cj));
  396. //if (!_blockingWatcher.IsRunning)
  397. // _blockingWatcher.Restart();
  398. //ResetTraceFlag();
  399. }
  400. _cycleState = RState.Running;
  401. }
  402. public void Clear()
  403. {
  404. _vacWaferTargets.Clear();
  405. _atmWaferTargets.Clear();
  406. _movingItems.Clear();
  407. _efemMovingItems.Clear();
  408. _vacMoveFinishTrig.RST = true;
  409. _atmMoveFinishTrig.RST = true;
  410. _efemRobot.ResetTask();
  411. _tmRobot.ResetTask();
  412. foreach (var module in _vacSchedulers)
  413. {
  414. module.Value.ResetTask();
  415. _vacModules[module.Key].MovingStatus = MovingStatus.Idle;
  416. }
  417. foreach (var module in _atmSchedulers)
  418. {
  419. module.Value.ResetTask();
  420. _atmModules[module.Key].MovingStatus = MovingStatus.Idle;
  421. }
  422. _lstControlJobs.Clear();
  423. _lstProcessJobs.Clear();
  424. //_mapTarget.Clear();
  425. //queMoveAction.Clear();
  426. //_curAction.state = ActionState.Done;
  427. }
  428. #endregion
  429. private void InitModules()
  430. {
  431. foreach(var module in new ModuleName[]{ ModuleName.LP1, ModuleName.LP2, ModuleName.LP3,
  432. ModuleName.Aligner1, ModuleName.Aligner2, ModuleName.Cooling1, ModuleName.Cooling2})
  433. {
  434. if(ModuleHelper.IsInstalled(module))
  435. {
  436. if(ModuleHelper.IsLoadPort(module))
  437. {
  438. _atmSchedulers[module] = Singleton<TransferModule>.Instance.GetScheduler(module);
  439. _atmModules[module] = new ModuleFlag(ModulePriority.Middle);
  440. }
  441. else if(ModuleHelper.IsAligner(module) || ModuleHelper.IsCooling(module))
  442. {
  443. _atmSchedulers[module] = Singleton<TransferModule>.Instance.GetScheduler(module);
  444. _atmModules[module] = new ModuleFlag(ModulePriority.Middle);
  445. }
  446. }
  447. }
  448. foreach (var module in new ModuleName[] { ModuleName.PMA, ModuleName.PMB, ModuleName.PMC,
  449. ModuleName.PMD, ModuleName.PME, ModuleName.PMF})
  450. {
  451. if (ModuleHelper.IsInstalled(module))
  452. {
  453. _vacSchedulers[module] = Singleton<TransferModule>.Instance.GetScheduler(module);
  454. _vacModules[module] = new ModuleFlag(ModulePriority.Middle);
  455. }
  456. }
  457. foreach (var module in new ModuleName[] { ModuleName.LLA, ModuleName.LLB })
  458. {
  459. if (ModuleHelper.IsInstalled(module))
  460. {
  461. var llScheduler = Singleton<TransferModule>.Instance.GetScheduler(module);
  462. _vacSchedulers[module] = llScheduler;
  463. _vacModules[module] = new ModuleFlag(ModulePriority.Middle);
  464. _atmSchedulers[module] = llScheduler;
  465. _atmModules[module] = new ModuleFlag(ModulePriority.Middle);
  466. }
  467. }
  468. }
  469. private void prelude()
  470. {
  471. }
  472. private void epilogue()
  473. {
  474. CheckWaferArrived();
  475. ProcessPMTask();
  476. ProcessAlignerTask();
  477. UpdateProcessJobStatus();
  478. UpdateControlJobStatus();
  479. StartNewJob();
  480. UpdateLLInOutPathProperty();
  481. }
  482. private void driveVacSystem()
  483. {
  484. PumpingTMRobotTask();
  485. ProcessTMRobotTask();
  486. RuningTMRobotTask();
  487. }
  488. #region Vacuum System
  489. private void PumpingTMRobotTask()
  490. {
  491. if (!_tmRobot.IsAvailable)
  492. return;
  493. foreach(var mod in _vacSchedulers)
  494. {
  495. if (mod.Value.IsAvailable && _vacModules[mod.Key].MovingStatus == MovingStatus.Idle)
  496. {
  497. if(ModuleHelper.IsLoadLock(mod.Key))
  498. {
  499. var inSlots = mod.Key == ModuleName.LLA ? _LLAInSlot : _LLBInSlot;
  500. foreach(var slot in inSlots)
  501. {
  502. if (IsLoadLockReservedByEFEM(mod.Key))
  503. continue;
  504. if(WaferManager.Instance.CheckHasWafer(mod.Key, slot) && IsVacWaferReadyOut(mod.Key, slot))
  505. {
  506. _vacReadyOutSlots.Add(new SlotItem(mod.Key, slot), mod.Value.WaferArrivedTicks(slot));
  507. }
  508. }
  509. var outSlots = mod.Key == ModuleName.LLA ? _LLAOutSlot : _LLBOutSlot;
  510. foreach(var slot in outSlots)
  511. {
  512. if (IsLoadLockReservedByEFEM(mod.Key))
  513. continue;
  514. if (WaferManager.Instance.CheckNoWafer(mod.Key, slot))
  515. {
  516. _vacReadyInSlots.Add(new SlotItem(mod.Key, slot), mod.Value.WaferArrivedTicks(slot));
  517. }
  518. }
  519. }
  520. else
  521. {
  522. if(WaferManager.Instance.CheckHasWafer(mod.Key, 0) && IsVacWaferReadyOut(mod.Key, 0)) // processed?
  523. {
  524. _vacReadyOutSlots.Add(new SlotItem(mod.Key, 0), mod.Value.WaferArrivedTicks(0));
  525. }
  526. else if(WaferManager.Instance.CheckNoWafer(mod.Key, 0))
  527. {
  528. _vacReadyInSlots.Add(new SlotItem(mod.Key, 0), mod.Value.WaferArrivedTicks(0));
  529. }
  530. }
  531. }
  532. }
  533. _vacReadyOutSlots = _vacReadyOutSlots.OrderByDescending(item => item.Value).ToDictionary(k => k.Key, v => v.Value);
  534. }
  535. bool SearchWaferDestination(SlotItem outSlot, out SlotItem destSlot)
  536. {
  537. destSlot = new SlotItem(ModuleName.System, -1);
  538. var wafer = GetCloneWafer(outSlot.Module, outSlot.Slot);
  539. if (wafer.IsEmpty || wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null || wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
  540. return false;
  541. foreach (var next_module in wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules)
  542. {
  543. var validSlots = GetModuleValidSlots(next_module);
  544. foreach (var nSlot in validSlots)
  545. {
  546. if (_movingItems.Exists(mItem => mItem.DestinationModule == next_module && mItem.DestinationSlot == nSlot))
  547. continue;
  548. foreach(var inItem in _vacReadyInSlots)
  549. {
  550. if(inItem.Key.Module == next_module && inItem.Key.Slot == nSlot && _vacModules[next_module].MovingStatus != MovingStatus.Moving)
  551. {
  552. destSlot.Module = next_module;
  553. destSlot.Slot = nSlot;
  554. return true;
  555. }
  556. }
  557. }
  558. }
  559. return false;
  560. }
  561. List<int> GetModuleValidSlots(ModuleName mod)
  562. {
  563. var validSlot = new List<int>();
  564. if(ModuleHelper.IsLoadLock(mod))
  565. {
  566. if(!IsLoadLockReservedByEFEM(mod))
  567. {
  568. var inSlots = mod == ModuleName.LLA ? _LLAInSlot : _LLBInSlot;
  569. foreach (var slot in inSlots)
  570. {
  571. if (WaferManager.Instance.CheckNoWafer(mod, slot) && !_movingItems.Exists(item => item.DestinationModule == mod && item.DestinationSlot == slot))
  572. validSlot.Add(slot);
  573. if (WaferManager.Instance.CheckHasWafer(mod, slot) && _movingItems.Exists(item => item.SourceModule == mod && item.SourceSlot == slot))
  574. validSlot.Add(slot);
  575. }
  576. }
  577. }
  578. else if(ModuleHelper.IsPm(mod))
  579. {
  580. if (WaferManager.Instance.CheckNoWafer(mod, 0) && !_movingItems.Exists(item => item.DestinationModule == mod))
  581. validSlot.Add(0);
  582. if (WaferManager.Instance.CheckHasWafer(mod, 0) && _movingItems.Exists(item => item.SourceModule == mod))
  583. validSlot.Add(0);
  584. }
  585. return validSlot.Distinct().ToList();
  586. }
  587. private int GetModuleSlotCount(ModuleName mod)
  588. {
  589. int nSlotCount = 1;
  590. if(ModuleHelper.IsLoadLock(mod))
  591. {
  592. nSlotCount = mod == ModuleName.LLA ? _LLASlotNumber : _LLBSlotNumber;
  593. }
  594. else if(ModuleHelper.IsLoadPort(mod))
  595. {
  596. nSlotCount = SC.GetValue<int>("EFEM.LoadPort.SlotNumber");
  597. }
  598. else if(ModuleHelper.IsTMRobot(mod) || ModuleHelper.IsEFEMRobot(mod))
  599. {
  600. nSlotCount = 2;
  601. }
  602. return nSlotCount;
  603. }
  604. List<MoveItem> SearchWaitInSlots(ModuleName inModule)
  605. {
  606. List<MoveItem> inSlots = new List<MoveItem>();
  607. var validSlots = GetModuleValidSlots(inModule);
  608. foreach(var slot in _vacReadyOutSlots)
  609. {
  610. if (slot.Key.Module == inModule || _vacModules[slot.Key.Module].MovingStatus != MovingStatus.Idle)
  611. continue;
  612. if (IsLoadLockReservedByEFEM(slot.Key.Module))
  613. continue;
  614. var wafer = GetCloneWafer(slot.Key.Module, slot.Key.Slot);
  615. if (wafer.IsEmpty || wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null || wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
  616. continue;
  617. foreach (var next_module in wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules)
  618. {
  619. if(next_module == inModule && validSlots.Count > 0 && !_movingItems.Exists(item => item.SourceModule == slot.Key.Module && item.SourceSlot == slot.Key.Slot))
  620. {
  621. if(!inSlots.Exists(item => item.SourceModule == slot.Key.Module && item.SourceSlot == slot.Key.Slot))
  622. {
  623. inSlots.Add(new MoveItem(slot.Key.Module, slot.Key.Slot, inModule, validSlots.First(), Hand.None));
  624. }
  625. validSlots.RemoveAt(0);
  626. }
  627. }
  628. }
  629. return inSlots;
  630. }
  631. private void UpdateItemMovingStatus(MoveItem moveItem, MovingStatus status = MovingStatus.Moving)
  632. {
  633. if(!ModuleHelper.IsTMRobot(moveItem.DestinationModule))
  634. {
  635. _vacModules[moveItem.DestinationModule].MovingStatus = status;
  636. }
  637. if(!ModuleHelper.IsTMRobot(moveItem.SourceModule))
  638. {
  639. _vacModules[moveItem.SourceModule].MovingStatus = status;
  640. }
  641. }
  642. private void UpdateModuleMovingStatus(ModuleName module, MovingStatus status = MovingStatus.Moving)
  643. {
  644. if (!ModuleHelper.IsTMRobot(module))
  645. {
  646. _vacModules[module].MovingStatus = status;
  647. }
  648. }
  649. private void ProcessTMRobotTask()
  650. {
  651. if(_tmRobot.IsAvailable)
  652. {
  653. if(WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 0) || WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 1))
  654. {
  655. return;
  656. }
  657. foreach(var slot in _vacReadyOutSlots)
  658. {
  659. if (_vacModules[slot.Key.Module].MovingStatus != MovingStatus.Idle)
  660. continue;
  661. if (ModuleHelper.IsLoadLock(slot.Key.Module))
  662. {
  663. if (IsLoadLockReservedByEFEM(slot.Key.Module))
  664. continue;
  665. if(SearchWaferDestination(slot.Key, out SlotItem destSlot))
  666. {
  667. _movingItems.Add(new MoveItem(slot.Key.Module, slot.Key.Slot, destSlot.Module, destSlot.Slot, Hand.None));
  668. UpdateModuleMovingStatus(slot.Key.Module);
  669. UpdateModuleMovingStatus(destSlot.Module);
  670. // check whether match double pick pattern
  671. foreach(var item in _vacReadyOutSlots)
  672. {
  673. if(item.Key.Module == slot.Key.Module && item.Key.Slot != slot.Key.Slot)
  674. {
  675. if (SearchWaferDestination(item.Key, out SlotItem destSlot_2))
  676. {
  677. _movingItems.Add(new MoveItem(item.Key.Module, item.Key.Slot, destSlot_2.Module, destSlot_2.Slot, Hand.None));
  678. UpdateModuleMovingStatus(item.Key.Module);
  679. UpdateModuleMovingStatus(destSlot_2.Module);
  680. break;
  681. }
  682. }
  683. }
  684. // check whether match swap pattern
  685. int inCount = 0;
  686. var in_slots = SearchWaitInSlots(slot.Key.Module);
  687. foreach(var in_slot in in_slots)
  688. {
  689. if(_vacModules[in_slot.DestinationModule].MovingStatus == MovingStatus.Idle && inCount < 2)
  690. {
  691. _movingItems.Add(in_slot);
  692. UpdateItemMovingStatus(in_slot);
  693. inCount++;
  694. }
  695. }
  696. return;
  697. }
  698. }
  699. else // PM
  700. {
  701. if(SearchWaferDestination(slot.Key, out SlotItem destSlot))
  702. {
  703. _movingItems.Add(new MoveItem(slot.Key.Module, slot.Key.Slot, destSlot.Module, destSlot.Slot, Hand.None));
  704. UpdateModuleMovingStatus(slot.Key.Module);
  705. UpdateModuleMovingStatus(destSlot.Module);
  706. // check whether match swap pattern
  707. int swapCount = 0;
  708. var in_slots = SearchWaitInSlots(slot.Key.Module);
  709. foreach(var swap_slot in in_slots)
  710. {
  711. if(_vacModules[swap_slot.SourceModule].MovingStatus == MovingStatus.Idle && swapCount < 1)
  712. {
  713. _movingItems.Add(swap_slot);
  714. UpdateItemMovingStatus(swap_slot);
  715. swapCount++;
  716. }
  717. }
  718. if(swapCount == 0)
  719. {
  720. // check whether match double move pattern
  721. int inCount = 0;
  722. var same_dest = SearchWaitInSlots(destSlot.Module);
  723. foreach(var in_slot in same_dest)
  724. {
  725. if(_vacModules[in_slot.SourceModule].MovingStatus == MovingStatus.Idle && inCount < 1)
  726. {
  727. _movingItems.Add(in_slot);
  728. UpdateItemMovingStatus(in_slot);
  729. inCount++;
  730. }
  731. }
  732. }
  733. return;
  734. }
  735. }
  736. }
  737. _vacReadyOutSlots.Clear();
  738. _vacReadyInSlots.Clear();
  739. }
  740. }
  741. private void RuningTMRobotTask()
  742. {
  743. if(_tmRobot.IsAvailable)
  744. {
  745. if(_tmRobot.PostMoveItems(_movingItems.ToArray()))
  746. {
  747. foreach(var item in _movingItems)
  748. {
  749. var wafer = WaferManager.Instance.GetWafer(item.SourceModule, item.SourceSlot);
  750. if (wafer.IsEmpty)
  751. {
  752. // post alarm
  753. _cycleState = RState.Failed;
  754. LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Cannot run TM moving task as Get {item.SourceModule}{item.SourceModule} Wafer Info failed");
  755. return;
  756. }
  757. var slot = new SlotItem(item.DestinationModule, item.DestinationSlot);
  758. _vacWaferTargets[slot] = wafer.InnerId;
  759. }
  760. }
  761. }
  762. }
  763. private void ProcessPMTask()
  764. {
  765. foreach(var mod in _vacModules)
  766. {
  767. if(ModuleHelper.IsPm(mod.Key))
  768. {
  769. if(_vacSchedulers[mod.Key].IsAvailable)
  770. {
  771. switch (mod.Value.MovingStatus)
  772. {
  773. case MovingStatus.WaitProcess:
  774. {
  775. _vacSchedulers[mod.Key].EventWaferArrived?.Invoke(this, new WaferMoveArgs(ModuleName.TMRobot, 0, mod.Key, 0));
  776. mod.Value.MovingStatus = MovingStatus.StartProcess;
  777. }
  778. break;
  779. case MovingStatus.Processing:
  780. mod.Value.MovingStatus = MovingStatus.Idle;
  781. break;
  782. }
  783. }
  784. else
  785. {
  786. switch(mod.Value.MovingStatus)
  787. {
  788. case MovingStatus.StartProcess:
  789. mod.Value.MovingStatus = MovingStatus.Processing;
  790. break;
  791. }
  792. }
  793. }
  794. }
  795. }
  796. private Hand GetTMRobotFreeHand()
  797. {
  798. var blade1HasWafer = WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 0);
  799. var blade2HasWafer = WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 1);
  800. if (blade1HasWafer && blade2HasWafer)
  801. return Hand.None;
  802. else if (!blade1HasWafer && !blade2HasWafer)
  803. return Hand.Both;
  804. else if (blade1HasWafer)
  805. return Hand.Blade2;
  806. else
  807. return Hand.Blade1;
  808. }
  809. private bool IsVacWaferReadyOut(ModuleName mod, int slot)
  810. {
  811. var wafer = GetCloneWafer(mod, slot);
  812. if (wafer.IsEmpty)
  813. return false;
  814. if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
  815. return false;
  816. if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
  817. {
  818. // should not go here
  819. //LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Wafer:{wafer.WaferOrigin} NextSequenceStep {wafer.NextSequenceStep} exceeds {wafer.ProcessJob.Sequence.Name} max steps number");
  820. return false;
  821. }
  822. if (wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(mod))
  823. return false;
  824. foreach(var module in wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules)
  825. {
  826. if (ModuleHelper.IsLoadLock(module) || ModuleHelper.IsPm(module))
  827. return true;
  828. }
  829. return false;
  830. }
  831. #endregion Vacuum System
  832. #region Atm System
  833. private void driveAtmSystem()
  834. {
  835. PumpingEFEMRobotTask();
  836. RuningEFEMRobotTask();
  837. }
  838. private void PumpingEFEMRobotTask()
  839. {
  840. if (!_efemRobot.IsAvailable)
  841. return;
  842. foreach(var scheduler in _atmSchedulers)
  843. {
  844. if (!scheduler.Value.IsAvailable)
  845. continue;
  846. if(ModuleHelper.IsAligner(scheduler.Key))
  847. {
  848. if (ProcessAlignerEFEMRobotTask(scheduler.Key))
  849. return;
  850. }
  851. else if (ModuleHelper.IsLoadLock(scheduler.Key))
  852. {
  853. if (ProcessLLEFEMRobotTask(scheduler.Key))
  854. return;
  855. }
  856. else if (ModuleHelper.IsCooling(scheduler.Key))
  857. {
  858. if (ProcessCoolingEFEMRobotTask(scheduler.Key))
  859. return;
  860. }
  861. else if (ModuleHelper.IsLoadPort(scheduler.Key))
  862. {
  863. if (ProcessLPEFEMRobotTask(scheduler.Key))
  864. return;
  865. }
  866. else
  867. {
  868. // should not go here
  869. LOG.Write(eEvent.ERR_ROUTER, $"Wrong Module: {scheduler.Key} in ATM System");
  870. }
  871. }
  872. }
  873. List<int> GetEfemRobotWaferReadyInHands(ModuleName mod)
  874. {
  875. var slots = new List<int>();
  876. for(int i = 0; i < 2; i++)
  877. {
  878. if (_efemRobotSingleArmOption != 0 && _efemRobotSingleArmOption != i + 1)
  879. continue;
  880. var wafer = GetCloneWafer(ModuleName.EfemRobot, i);
  881. if (wafer.IsEmpty)
  882. continue;
  883. if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
  884. continue;
  885. if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
  886. {
  887. // should not go here
  888. LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Wafer:{wafer.WaferOrigin} NextSequenceStep {wafer.NextSequenceStep} exceeds {wafer.ProcessJob.Sequence.Name} max steps number");
  889. continue;
  890. }
  891. if (wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(mod))
  892. {
  893. slots.Add(i);
  894. }
  895. }
  896. return slots;
  897. }
  898. bool IsAtmWaferReadyOut(ModuleName mod, int slot)
  899. {
  900. var wafer = GetCloneWafer(mod, slot);
  901. if (wafer.IsEmpty)
  902. return false;
  903. if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
  904. return false;
  905. if (wafer.NextSequenceStep == wafer.ProcessJob.Sequence.Steps.Count)
  906. {
  907. // need return
  908. return true;
  909. }
  910. else if(wafer.NextSequenceStep > wafer.ProcessJob.Sequence.Steps.Count)
  911. {
  912. // should not go here
  913. LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Wafer:{wafer.WaferOrigin} NextSequenceStep {wafer.NextSequenceStep} exceeds {wafer.ProcessJob.Sequence.Name} max steps number");
  914. return false;
  915. }
  916. if (wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(mod))
  917. return false;
  918. if(ModuleHelper.IsLoadLock(mod))
  919. {
  920. foreach (var module in wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules)
  921. {
  922. if (ModuleHelper.IsPm(module))
  923. return false;
  924. }
  925. }
  926. return true;
  927. }
  928. private bool ProcessLLEFEMRobotTask(ModuleName ll)
  929. {
  930. if (_vacModules[ll].MovingStatus != MovingStatus.Idle || IsLoadLockReservedByTM(ll))
  931. return false;
  932. var robotSlots = GetEfemRobotWaferReadyInHands(ll);
  933. var inSlots = ll == ModuleName.LLA ? _LLAInSlot : _LLBInSlot;
  934. foreach(var slot in inSlots)
  935. {
  936. if(robotSlots.Count >= 1)
  937. {
  938. if(WaferManager.Instance.CheckNoWafer(ll, slot))
  939. {
  940. _efemMovingItems.Add(new MoveItem(ModuleName.EfemRobot, robotSlots.First(), ll, slot, (Hand)robotSlots.First()));
  941. robotSlots.RemoveAt(0);
  942. }
  943. }
  944. }
  945. var outSlots = ll == ModuleName.LLA ? _LLAOutSlot : _LLBOutSlot;
  946. foreach(var slot in outSlots)
  947. {
  948. if(IsAtmWaferReadyOut(ll, slot))
  949. {
  950. var robotHand = GetEFEMRobotFreeHand();
  951. if(robotHand != Hand.None)
  952. {
  953. _efemMovingItems.Add(new MoveItem(ll, slot, ModuleName.EfemRobot, (int)robotHand, robotHand));
  954. }
  955. }
  956. }
  957. return _efemMovingItems.Count > 0;
  958. }
  959. private Tuple<int, int> GetPMWaferExistence()
  960. {
  961. int exist = 0;
  962. int empty = 0;
  963. foreach (var module in _vacModules)
  964. {
  965. if (ModuleHelper.IsPm(module.Key) && _vacSchedulers[module.Key].IsOnline && module.Value.InUsed)
  966. {
  967. if (WaferManager.Instance.CheckHasWafer(module.Key, 0))
  968. exist++;
  969. else
  970. empty++;
  971. }
  972. }
  973. return new Tuple<int, int>(exist, empty);
  974. }
  975. private int GetTMRobotWaferCount()
  976. {
  977. return (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 0) ? 1 : 0) + (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 1) ? 1 : 0);
  978. }
  979. private int GetEfemRoborWaferCount()
  980. {
  981. return (WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 0) ? 1 : 0) + (WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 1) ? 1 : 0);
  982. }
  983. private bool IsLoadLockReservedByEFEM(ModuleName ll)
  984. {
  985. if (_efemMovingItems.Exists(item => item.DestinationModule == ll || item.SourceModule == ll))
  986. return true;
  987. return false;
  988. }
  989. private bool IsLoadLockReservedByTM(ModuleName ll)
  990. {
  991. if (_movingItems.Exists(item => item.DestinationModule == ll || item.SourceModule == ll))
  992. return true;
  993. return false;
  994. }
  995. private Tuple<int, int> GetLLProcessStatusCount(ModuleName ll)
  996. {
  997. int processedCount = 0;
  998. int unprocessCount = 0;
  999. int slotCount = ll == ModuleName.LLA ? _LLASlotNumber : _LLBSlotNumber;
  1000. if(ModuleHelper.IsLoadLock(ll))
  1001. {
  1002. for(int i = 0; i < slotCount;i++)
  1003. {
  1004. if(WaferManager.Instance.CheckHasWafer(ll, i))
  1005. {
  1006. if(CheckWaferNeedProcessAndPMAvailable(ll, i))
  1007. unprocessCount++;
  1008. else
  1009. processedCount++;
  1010. }
  1011. }
  1012. }
  1013. return new Tuple<int, int>(processedCount, unprocessCount);
  1014. }
  1015. private int GetAtmInerWaferCount()
  1016. {
  1017. int nCount = 0;
  1018. foreach(var atmModule in _atmModules)
  1019. {
  1020. if (!ModuleHelper.IsEFEMRobot(atmModule.Key) && !ModuleHelper.IsLoadPort(atmModule.Key) && WaferManager.Instance.CheckHasWafer(atmModule.Key, 0))
  1021. nCount++;
  1022. }
  1023. return nCount;
  1024. }
  1025. private int CanPushInWaferNumber()
  1026. {
  1027. if (_tmRobot.RobotStatus == RState.Running)
  1028. return 0;
  1029. var llaWaferStatus = GetLLProcessStatusCount(ModuleName.LLA);
  1030. var llbWaferStatus = GetLLProcessStatusCount(ModuleName.LLB);
  1031. var pmWaferStatus = GetPMWaferExistence();
  1032. if(_LLInOutPath == SequenceLLInOutPath.AInBOut)
  1033. {
  1034. return _LLASlotNumber + pmWaferStatus.Item2 - llaWaferStatus.Item1 - llaWaferStatus.Item2
  1035. - GetTMRobotWaferCount() - GetAtmInerWaferCount() - GetEfemRoborWaferCount();
  1036. }
  1037. else if(_LLInOutPath == SequenceLLInOutPath.BInAOut)
  1038. {
  1039. return _LLBSlotNumber + pmWaferStatus.Item2 - llbWaferStatus.Item1 - llbWaferStatus.Item2
  1040. - GetTMRobotWaferCount() - GetAtmInerWaferCount() - GetEfemRoborWaferCount();
  1041. }
  1042. else if(_LLInOutPath == SequenceLLInOutPath.AInAOut || (_LLInOutPath == SequenceLLInOutPath.DInDOut && _vacSchedulers[ModuleName.LLA].IsOnline && !_vacSchedulers[ModuleName.LLB].IsOnline))
  1043. {
  1044. return llaWaferStatus.Item1 > 0 ? 0 :
  1045. (_LLASlotNumber) / 2 + pmWaferStatus.Item2 - llaWaferStatus.Item2
  1046. - GetTMRobotWaferCount() - GetEfemRoborWaferCount() - GetAtmInerWaferCount();
  1047. }
  1048. else if (_LLInOutPath == SequenceLLInOutPath.BInBOut || (_LLInOutPath == SequenceLLInOutPath.DInDOut && !_vacSchedulers[ModuleName.LLA].IsOnline && _vacSchedulers[ModuleName.LLB].IsOnline))
  1049. {
  1050. return llbWaferStatus.Item1 > 0 ? 0 :
  1051. (_LLBSlotNumber) / 2 + pmWaferStatus.Item2 - llbWaferStatus.Item2
  1052. -GetTMRobotWaferCount() - GetEfemRoborWaferCount() - GetAtmInerWaferCount();
  1053. }
  1054. else if(_LLInOutPath == SequenceLLInOutPath.DInDOut && _vacSchedulers[ModuleName.LLA].IsOnline && _vacSchedulers[ModuleName.LLB].IsOnline)
  1055. {
  1056. return llaWaferStatus.Item1 + llbWaferStatus.Item1 > 1 ? 0 :
  1057. (_LLASlotNumber + _LLBSlotNumber) / 2 + pmWaferStatus.Item2
  1058. - llaWaferStatus.Item1 - llaWaferStatus.Item2 - llbWaferStatus.Item1 - llbWaferStatus.Item2
  1059. - GetTMRobotWaferCount() - GetEfemRoborWaferCount() - GetAtmInerWaferCount();
  1060. }
  1061. else
  1062. {
  1063. _cycleState = RState.Failed;
  1064. LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, "Both LLA/LLB offline, stop runing.");
  1065. return 0;
  1066. }
  1067. }
  1068. private bool IsForwardPathBlocking(ModuleName mod, int slot)
  1069. {
  1070. var wafer = GetCloneWafer(mod, slot);
  1071. if (wafer.IsEmpty || wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null || wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
  1072. return false;
  1073. foreach (var next_module in wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules)
  1074. {
  1075. var SlotNumber = GetModuleSlotCount(next_module);
  1076. for(int i = 0; i < SlotNumber; i++)
  1077. {
  1078. if (WaferManager.Instance.CheckNoWafer(next_module, i))
  1079. return false;
  1080. }
  1081. }
  1082. return true;
  1083. }
  1084. private bool ProcessLPEFEMRobotTask(ModuleName lp)
  1085. {
  1086. // check return
  1087. for(int i = 0; i < 2; i++)
  1088. {
  1089. if (_efemRobotSingleArmOption != 0 && _efemRobotSingleArmOption != i + 1)
  1090. continue;
  1091. if(WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, i))
  1092. {
  1093. var returnWafer = WaferManager.Instance.GetWafer(ModuleName.EfemRobot, i);
  1094. if (returnWafer.IsEmpty)
  1095. continue;
  1096. if (returnWafer.ProcessJob == null || returnWafer.ProcessJob.Sequence == null)
  1097. continue;
  1098. if (returnWafer.NextSequenceStep >= returnWafer.ProcessJob.Sequence.Steps.Count && lp == (ModuleName)returnWafer.OriginStation) // need return
  1099. {
  1100. _efemMovingItems.Add(new MoveItem(ModuleName.EfemRobot, i, lp, returnWafer.OriginSlot, (Hand)i));
  1101. }
  1102. }
  1103. }
  1104. var canPushInWafers = CanPushInWaferNumber();
  1105. if(_efemMovingItems.Count == 0 && canPushInWafers > 0)
  1106. {
  1107. var outSlots = GetNextWaferInJobQueue(lp);
  1108. var hand = GetEFEMRobotFreeHand();
  1109. if (hand != Hand.None && outSlots.Count > 0 && !IsForwardPathBlocking(lp, outSlots[0]))
  1110. {
  1111. _efemMovingItems.Add(new MoveItem(lp, outSlots[0], ModuleName.EfemRobot, (int)hand, hand));
  1112. }
  1113. if(canPushInWafers > 1)
  1114. {
  1115. hand = GetEFEMRobotFreeHand();
  1116. if (hand != Hand.None && outSlots.Count > 1 && !IsForwardPathBlocking(lp, outSlots[1]))
  1117. {
  1118. _efemMovingItems.Add(new MoveItem(lp, outSlots[1], ModuleName.EfemRobot, (int)hand, hand));
  1119. }
  1120. }
  1121. }
  1122. return _efemMovingItems.Count > 0;
  1123. }
  1124. private List<int> GetNextWaferInJobQueue(ModuleName lp)
  1125. {
  1126. var inSlots = new List<int>();
  1127. foreach (var cj in _lstControlJobs)
  1128. {
  1129. if (lp != ModuleName.System && (cj.Module != lp.ToString()))
  1130. continue;
  1131. if (cj.State == EnumControlJobState.Executing)
  1132. {
  1133. foreach (var pj in _lstProcessJobs)
  1134. {
  1135. if (pj.ControlJobName == cj.Name && pj.State == EnumProcessJobState.Processing)
  1136. {
  1137. foreach (var pjSlotWafer in pj.SlotWafers)
  1138. {
  1139. if (CheckWaferNeedProcessAndPMAvailable(pjSlotWafer.Item1, pjSlotWafer.Item2))
  1140. {
  1141. var wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
  1142. if(!wafer.IsEmpty && wafer.NextSequenceStep == 0)
  1143. {
  1144. inSlots.Add(pjSlotWafer.Item2);
  1145. if (inSlots.Count >= 2)
  1146. return inSlots;
  1147. }
  1148. }
  1149. }
  1150. }
  1151. }
  1152. }
  1153. }
  1154. return inSlots;
  1155. }
  1156. private bool ProcessAlignerEFEMRobotTask(ModuleName aligner)
  1157. {
  1158. if(WaferManager.Instance.CheckHasWafer(aligner, 0) && IsAtmWaferReadyOut(aligner, 0) && _atmModules[aligner].MovingStatus == MovingStatus.Idle)
  1159. {
  1160. var hand = GetEFEMRobotFreeHand();
  1161. if(hand != Hand.None)
  1162. {
  1163. _efemMovingItems.Add(new MoveItem(aligner, 0, ModuleName.EfemRobot, (int)hand, hand));
  1164. }
  1165. //// check with whether another robot arm wafer wait go to aligner
  1166. //var robotSlots = GetEfemRobotWaferReadyInHands(aligner);
  1167. //if (robotSlots.Count > 0)
  1168. //{
  1169. // _efemMovingItems.Add(new MoveItem(ModuleName.EfemRobot, robotSlots.First(), aligner, 0, (Hand)robotSlots.First()));
  1170. //}
  1171. }
  1172. else if(WaferManager.Instance.CheckNoWafer(aligner, 0))
  1173. {
  1174. var robotSlots = GetEfemRobotWaferReadyInHands(aligner);
  1175. if(robotSlots.Count > 0)
  1176. {
  1177. _efemMovingItems.Add(new MoveItem(ModuleName.EfemRobot, robotSlots.First(), aligner, 0, (Hand)robotSlots.First()));
  1178. }
  1179. }
  1180. return _efemMovingItems.Count > 0;
  1181. }
  1182. private bool ProcessCoolingEFEMRobotTask(ModuleName cooling)
  1183. {
  1184. if (WaferManager.Instance.CheckHasWafer(cooling, 0) && IsAtmWaferReadyOut(cooling, 0))
  1185. {
  1186. var hand = GetEFEMRobotFreeHand();
  1187. if (hand != Hand.None)
  1188. {
  1189. _efemMovingItems.Add(new MoveItem(cooling, 0, ModuleName.EfemRobot, (int)hand, hand));
  1190. }
  1191. }
  1192. else
  1193. {
  1194. var robotSlots = GetEfemRobotWaferReadyInHands(cooling);
  1195. if (robotSlots.Count > 0)
  1196. {
  1197. _efemMovingItems.Add(new MoveItem(cooling, 0, ModuleName.EfemRobot, robotSlots.First(), (Hand)robotSlots.First()));
  1198. }
  1199. }
  1200. return _efemMovingItems.Count > 0;
  1201. }
  1202. private void RuningEFEMRobotTask()
  1203. {
  1204. if (_efemRobot.IsAvailable && _efemMovingItems.Count > 0)
  1205. {
  1206. if (_efemRobot.PostMoveItems(_efemMovingItems.ToArray()))
  1207. {
  1208. foreach (var item in _efemMovingItems)
  1209. {
  1210. var wafer = WaferManager.Instance.GetWafer(item.SourceModule, item.SourceSlot);
  1211. if (wafer.IsEmpty)
  1212. {
  1213. // post alarm
  1214. _cycleState = RState.Failed;
  1215. LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Cannot run EFEM moving task as Get {item.SourceModule}{item.SourceModule} Wafer Info failed");
  1216. return;
  1217. }
  1218. var slot = new SlotItem(item.DestinationModule, item.DestinationSlot);
  1219. _atmWaferTargets[slot] = wafer.InnerId;
  1220. if(ModuleHelper.IsLoadLock(item.Module))
  1221. {
  1222. _vacModules[item.Module].MovingStatus = MovingStatus.Moving;
  1223. }
  1224. }
  1225. }
  1226. }
  1227. }
  1228. private Hand GetEFEMRobotFreeHand()
  1229. {
  1230. for(int i = 0; i < 2; i++)
  1231. {
  1232. if (_efemRobotSingleArmOption != 0 && _efemRobotSingleArmOption != i + 1)
  1233. continue;
  1234. if ((WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, i) &&
  1235. !_efemMovingItems.Exists(item => item.DestinationModule == ModuleName.EfemRobot && item.DestinationSlot == i)) ||
  1236. (WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, i) &&
  1237. _efemMovingItems.Exists(item => item.SourceModule == ModuleName.EfemRobot && item.SourceSlot == i) &&
  1238. !_efemMovingItems.Exists(item => item.DestinationModule == ModuleName.EfemRobot && item.DestinationSlot == i)))
  1239. return (Hand)i;
  1240. }
  1241. return Hand.None;
  1242. }
  1243. private void ProcessAlignerTask()
  1244. {
  1245. foreach(var align in _atmModules)
  1246. {
  1247. if(ModuleHelper.IsAligner(align.Key))
  1248. {
  1249. switch(align.Value.MovingStatus)
  1250. {
  1251. case MovingStatus.WaitAlign:
  1252. if(_efemRobot.IsAvailable)
  1253. {
  1254. WaferInfo wafer = WaferManager.Instance.GetWafer(align.Key, 0);
  1255. if(!wafer.IsEmpty)
  1256. {
  1257. string attr = "AlignAngle";
  1258. string angle = string.Empty;
  1259. int step = wafer.NextSequenceStep;
  1260. if (!wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(align.Key))
  1261. {
  1262. step = wafer.NextSequenceStep - 1;
  1263. }
  1264. if (wafer.ProcessJob.Sequence.Steps[step].StepParameter.ContainsKey(attr))
  1265. {
  1266. angle = (string)wafer.ProcessJob.Sequence.Steps[step].StepParameter[attr];
  1267. if (_efemRobot.Align(float.Parse(angle)))
  1268. {
  1269. align.Value.MovingStatus = MovingStatus.StartAlign;
  1270. return;
  1271. }
  1272. }
  1273. }
  1274. align.Value.MovingStatus = MovingStatus.Idle;
  1275. }
  1276. break;
  1277. case MovingStatus.StartAlign:
  1278. if(!_efemRobot.IsAvailable)
  1279. {
  1280. align.Value.MovingStatus = MovingStatus.Aligning;
  1281. }
  1282. break;
  1283. case MovingStatus.Aligning:
  1284. {
  1285. if(_efemRobot.IsAvailable)
  1286. {
  1287. align.Value.MovingStatus = MovingStatus.Idle;
  1288. }
  1289. }
  1290. break;
  1291. }
  1292. }
  1293. }
  1294. }
  1295. #endregion Atm System
  1296. #region Sequence validation
  1297. private bool CheckSequencePmReady(SequenceInfo seq, List<ModuleName> pmOccupied, out List<ModuleName> pmUsed, out string reason)
  1298. {
  1299. pmUsed = new List<ModuleName>();
  1300. reason = "";
  1301. bool pmIsReady = true;
  1302. for (int i = 0; i < seq.Steps.Count; i++)
  1303. {
  1304. SequenceStepInfo stepInfo = seq.Steps[i];
  1305. bool hasPm = false;
  1306. foreach (var module in stepInfo.StepModules)
  1307. {
  1308. if (!ModuleHelper.IsPm(module))
  1309. {
  1310. hasPm = true;
  1311. break;
  1312. }
  1313. if (ModuleHelper.IsInstalled(module) && (pmOccupied == null || !pmOccupied.Contains(module)))
  1314. {
  1315. hasPm = true;
  1316. }
  1317. if (!pmUsed.Contains(module))
  1318. pmUsed.Add(module);
  1319. }
  1320. if (pmIsReady && !hasPm)
  1321. {
  1322. reason = $"Step {i + 1} no valid PM, " + string.Join("|", stepInfo.StepModules);
  1323. pmIsReady = false;
  1324. }
  1325. }
  1326. return pmIsReady;
  1327. }
  1328. private bool CheckSequenceRecipeFileValid(SequenceInfo seq, out string reason)
  1329. {
  1330. for (int i = 0; i < seq.Steps.Count; i++)
  1331. {
  1332. SequenceStepInfo stepInfo = seq.Steps[i];
  1333. foreach (var module in stepInfo.StepModules)
  1334. {
  1335. if (ModuleHelper.IsPm(module))
  1336. {
  1337. string attr = $"{module}Recipe";
  1338. if (stepInfo.StepParameter.ContainsKey(attr)
  1339. && !string.IsNullOrEmpty((string)stepInfo.StepParameter[attr]))
  1340. {
  1341. var recipeName = (string)stepInfo.StepParameter[attr];
  1342. if (!string.IsNullOrEmpty(recipeName))
  1343. {
  1344. var recipeContent =
  1345. RecipeFileManager.Instance.LoadRecipe($"{module}", recipeName, false);
  1346. if (string.IsNullOrEmpty(recipeContent))
  1347. {
  1348. reason = $"Can not find recipe file{recipeName}";
  1349. return false;
  1350. }
  1351. }
  1352. }
  1353. }
  1354. }
  1355. }
  1356. reason = "";
  1357. return true;
  1358. }
  1359. private bool CheckWaferNeedProcessAndPMAvailable(ModuleName waferModule, int waferSlot, ModuleName processIn = ModuleName.System)
  1360. {
  1361. WaferInfo wafer = GetCloneWafer(waferModule, waferSlot);
  1362. if (wafer.IsEmpty)
  1363. return false;
  1364. if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
  1365. return false;
  1366. if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
  1367. return false;
  1368. for (int i = wafer.NextSequenceStep; i < wafer.ProcessJob.Sequence.Steps.Count; i++)
  1369. {
  1370. var hasPmAvailable = false;
  1371. foreach (var stepModule in wafer.ProcessJob.Sequence.Steps[i].StepModules)
  1372. {
  1373. if (!ModuleHelper.IsPm(stepModule))
  1374. break;
  1375. if (!_vacSchedulers.Keys.Contains(stepModule))
  1376. continue;
  1377. var pm = _vacSchedulers[stepModule] as SchedulerPM;
  1378. if (pm != null)
  1379. {
  1380. if (_vacModules[stepModule].InUsed)
  1381. {
  1382. hasPmAvailable = true;
  1383. break;
  1384. }
  1385. }
  1386. }
  1387. if (!hasPmAvailable)
  1388. continue;
  1389. if (processIn == ModuleName.System)
  1390. return true;
  1391. if (wafer.ProcessJob.Sequence.Steps[i].StepModules
  1392. .Contains(processIn))
  1393. return true;
  1394. }
  1395. return false;
  1396. }
  1397. private List<ModuleName> GetPmUsedInRunningPj()
  1398. {
  1399. var pmUsed = new List<ModuleName>();
  1400. foreach (var cj in _lstControlJobs)
  1401. {
  1402. if (cj.State != EnumControlJobState.Executing && cj.State != EnumControlJobState.Paused)
  1403. continue;
  1404. foreach (var pj in _lstProcessJobs)
  1405. {
  1406. if (pj.ControlJobName == cj.Name && (pj.State == EnumProcessJobState.Processing || pj.State == EnumProcessJobState.Paused))
  1407. {
  1408. for (int i = 0; i < pj.Sequence.Steps.Count; i++)
  1409. {
  1410. SequenceStepInfo stepInfo = pj.Sequence.Steps[i];
  1411. foreach (var module in stepInfo.StepModules)
  1412. {
  1413. if (ModuleHelper.IsPm(module) && !pmUsed.Contains(module))
  1414. pmUsed.Add(module);
  1415. }
  1416. }
  1417. }
  1418. }
  1419. }
  1420. return pmUsed;
  1421. }
  1422. private List<SchedulerPM> GetPmNeeded(ControlJobInfo cj)
  1423. {
  1424. List<SchedulerPM> result = new List<SchedulerPM>();
  1425. foreach (var pj in _lstProcessJobs)
  1426. {
  1427. if (pj.ControlJobName != cj.Name)
  1428. continue;
  1429. var seq = pj.Sequence;
  1430. for (int i = 0; i < seq.Steps.Count; i++)
  1431. {
  1432. SequenceStepInfo stepInfo = seq.Steps[i];
  1433. foreach (var module in stepInfo.StepModules)
  1434. {
  1435. if (ModuleHelper.IsPm(module) && _vacSchedulers.ContainsKey(module))
  1436. {
  1437. var pm = _vacSchedulers[module] as SchedulerPM;
  1438. if (pm != null && !result.Contains(pm))
  1439. {
  1440. result.Add(pm);
  1441. }
  1442. }
  1443. }
  1444. }
  1445. }
  1446. return result;
  1447. }
  1448. private void UpateSequenceStep(List<MoveItem> items)
  1449. {
  1450. foreach(var item in items)
  1451. {
  1452. if(!ModuleHelper.IsTMRobot(item.DestinationModule) && !ModuleHelper.IsEFEMRobot(item.DestinationModule))
  1453. {
  1454. var wafer = WaferManager.Instance.GetWafer(item.DestinationModule, item.DestinationSlot);
  1455. if(!wafer.IsEmpty && wafer.ProcessJob != null)
  1456. {
  1457. if (wafer.NextSequenceStep < wafer.ProcessJob.Sequence.Steps.Count && wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(item.DestinationModule))
  1458. wafer.NextSequenceStep++;
  1459. }
  1460. if(wafer.IsEmpty || wafer.ProcessJob == null)
  1461. {
  1462. // should not go here
  1463. LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"UpateSequenceStep() failed, location: {item.DestinationModule}:{item.DestinationSlot + 1}, NextSequenceStep: {wafer.NextSequenceStep}");
  1464. }
  1465. }
  1466. }
  1467. }
  1468. private void CheckWaferArrived()
  1469. {
  1470. if (_cycleState != RState.Running)
  1471. return;
  1472. foreach (var mod in _vacSchedulers.Append(new KeyValuePair<ModuleName, SchedulerModule>( ModuleName.TMRobot, _tmRobot)))
  1473. {
  1474. //if (mod.Value.IsAvailable)
  1475. {
  1476. var tars = _vacWaferTargets.Where(item => item.Key.Module == mod.Key).ToArray();
  1477. foreach (var tar in tars)
  1478. {
  1479. var wafer = WaferManager.Instance.GetWafer(tar.Key.Module, tar.Key.Slot);
  1480. if (wafer.IsEmpty)
  1481. continue;
  1482. if (wafer.InnerId == tar.Value)
  1483. {
  1484. // wafer arrive
  1485. _vacWaferTargets.Remove(tar.Key);
  1486. if(!ModuleHelper.IsTMRobot(tar.Key.Module))
  1487. _vacSchedulers[tar.Key.Module].WaferArrived(tar.Key.Slot);
  1488. LOG.Write(eEvent.EV_ROUTER, ModuleName.System, $"wafer {wafer.WaferOrigin}: {wafer.InnerId} arrived {tar.Key.Module}{tar.Key.Slot + 1}");
  1489. if (ModuleHelper.IsPm(tar.Key.Module))
  1490. {
  1491. _vacModules[tar.Key.Module].MovingStatus = MovingStatus.WaitProcess;
  1492. }
  1493. }
  1494. }
  1495. }
  1496. }
  1497. _vacMoveFinishTrig.CLK = _vacWaferTargets.Count == 0;
  1498. if (_vacMoveFinishTrig.Q)
  1499. {
  1500. foreach(var item in _movingItems)
  1501. {
  1502. if(_vacModules[item.DestinationModule].MovingStatus == MovingStatus.Moving)
  1503. {
  1504. _vacModules[item.DestinationModule].MovingStatus = MovingStatus.Idle;
  1505. }
  1506. if(_vacModules[item.SourceModule].MovingStatus == MovingStatus.Moving)
  1507. {
  1508. _vacModules[item.SourceModule].MovingStatus = MovingStatus.Idle;
  1509. }
  1510. }
  1511. UpateSequenceStep(_movingItems);
  1512. _movingItems.Clear();
  1513. }
  1514. foreach (var mod in _atmSchedulers.Append(new KeyValuePair<ModuleName, SchedulerModule>(ModuleName.EfemRobot, _efemRobot)))
  1515. {
  1516. //if (mod.Value.IsAvailable)
  1517. {
  1518. var tars = _atmWaferTargets.Where(item => item.Key.Module == mod.Key).ToArray();
  1519. foreach (var tar in tars)
  1520. {
  1521. var wafer = WaferManager.Instance.GetWafer(tar.Key.Module, tar.Key.Slot);
  1522. if (wafer.IsEmpty)
  1523. continue;
  1524. if (wafer.InnerId == tar.Value)
  1525. {
  1526. LOG.Write(eEvent.EV_ROUTER, ModuleName.System, $"wafer {wafer.WaferOrigin}: {wafer.InnerId} arrived {tar.Key.Module}{tar.Key.Slot + 1}");
  1527. // wafer arrive
  1528. if(!ModuleHelper.IsLoadPort(tar.Key.Module) && !ModuleHelper.IsEFEMRobot(tar.Key.Module))
  1529. _atmSchedulers[tar.Key.Module].WaferArrived(tar.Key.Slot);
  1530. _atmWaferTargets.Remove(tar.Key);
  1531. if(ModuleHelper.IsAligner(tar.Key.Module))
  1532. {
  1533. _atmModules[tar.Key.Module].MovingStatus = MovingStatus.WaitAlign;
  1534. }
  1535. }
  1536. }
  1537. }
  1538. }
  1539. _atmMoveFinishTrig.CLK = _atmWaferTargets.Count == 0;
  1540. if(_atmMoveFinishTrig.Q)
  1541. {
  1542. foreach(var item in _efemMovingItems)
  1543. {
  1544. if(ModuleHelper.IsLoadLock(item.Module))
  1545. {
  1546. _vacModules[item.Module].MovingStatus = MovingStatus.Idle;
  1547. }
  1548. }
  1549. UpateSequenceStep(_efemMovingItems);
  1550. _efemMovingItems.Clear();
  1551. }
  1552. }
  1553. private void PreJobClean(ControlJobInfo cj)
  1554. {
  1555. if (cj.IsPreJobCleanDone)
  1556. return;
  1557. cj.IsPreJobCleanDone = true;
  1558. List<SchedulerPM> pms = GetPmNeeded(cj);
  1559. foreach (var pm in pms)
  1560. {
  1561. pm.PreJobClean();
  1562. }
  1563. }
  1564. private bool ActiveProcessJob(ProcessJobInfo pj)
  1565. {
  1566. foreach (var pjSlotWafer in pj.SlotWafers)
  1567. {
  1568. WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
  1569. wafer.ProcessJob = pj;
  1570. wafer.NextSequenceStep = 0;
  1571. WaferDataRecorder.SetPjInfo(wafer.InnerId.ToString(), pj.InnerId.ToString());
  1572. }
  1573. ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == pj.ControlJobName);
  1574. CarrierInfo carrier = CarrierManager.Instance.GetCarrier(cj.Module);
  1575. JobDataRecorder.StartPJ(pj.InnerId.ToString(), carrier.InnerId.ToString(), cj.InnerId.ToString(), pj.Name, cj.Module, cj.Module, pj.SlotWafers.Count);
  1576. pj.SetState(EnumProcessJobState.Processing);
  1577. PreJobClean(cj);
  1578. return true;
  1579. }
  1580. private void StartNewJob()
  1581. {
  1582. ControlJobInfo cjActived = null;
  1583. List<ModuleName> pmOccupied = GetPmUsedInRunningPj();
  1584. foreach (var cj in _lstControlJobs)
  1585. {
  1586. if (cj.State != EnumControlJobState.Executing)
  1587. continue;
  1588. cjActived = cj;
  1589. foreach (var pjName in cjActived.ProcessJobNameList)
  1590. {
  1591. var pj = _lstProcessJobs.Find(x => x.Name == pjName);
  1592. if (pj == null)
  1593. {
  1594. LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Not find pj named {pjName} in {cjActived.Name}");
  1595. continue;
  1596. }
  1597. if (pj.State == EnumProcessJobState.Queued)
  1598. {
  1599. if (CheckSequencePmReady(pj.Sequence, pmOccupied, out var pmUsed, out string reason))
  1600. {
  1601. ActiveProcessJob(pj);
  1602. foreach (var moduleName in pmUsed)
  1603. {
  1604. if (!pmOccupied.Contains(moduleName))
  1605. pmOccupied.Add(moduleName);
  1606. }
  1607. }
  1608. break;
  1609. }
  1610. }
  1611. }
  1612. }
  1613. private static bool IsWaferNeedGotoModule(WaferInfo wafer, ModuleName module)
  1614. {
  1615. if (wafer.IsEmpty)
  1616. return false;
  1617. if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
  1618. return false;
  1619. if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
  1620. return false;
  1621. for (int i = wafer.NextSequenceStep; i < wafer.ProcessJob.Sequence.Steps.Count; i++)
  1622. {
  1623. if (wafer.ProcessJob.Sequence.Steps[i].StepModules
  1624. .Contains(module))
  1625. return true;
  1626. }
  1627. return false;
  1628. }
  1629. private bool CheckAllWaferReturned(ProcessJobInfo pj, bool checkAllProcessed)
  1630. {
  1631. bool allWaferReturn = true;
  1632. for (int i = 0; i < pj.SlotWafers.Count; ++i)
  1633. {
  1634. WaferInfo wafer = GetCloneWafer(pj.SlotWafers[i].Item1, pj.SlotWafers[i].Item2);
  1635. if (wafer.IsEmpty)
  1636. continue;
  1637. foreach(var mod in _vacModules)
  1638. {
  1639. if(ModuleHelper.IsPm(mod.Key))
  1640. {
  1641. if (checkAllProcessed && IsWaferNeedGotoModule(wafer, mod.Key))
  1642. {
  1643. mod.Value.InUsed = true;
  1644. allWaferReturn = false;
  1645. }
  1646. }
  1647. }
  1648. }
  1649. return allWaferReturn;
  1650. }
  1651. private void UpdateProcessJobStatus()
  1652. {
  1653. foreach(var mod in _vacModules)
  1654. {
  1655. if (ModuleHelper.IsPm(mod.Key))
  1656. {
  1657. mod.Value.InUsed = false;
  1658. }
  1659. }
  1660. foreach (var pj in _lstProcessJobs)
  1661. {
  1662. if (pj.State == EnumProcessJobState.Processing)
  1663. {
  1664. if (CheckAllWaferReturned(pj, true))
  1665. {
  1666. pj.SetState(EnumProcessJobState.ProcessingComplete);
  1667. JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0);
  1668. }
  1669. }
  1670. else if (pj.State == EnumProcessJobState.Stopping)
  1671. {
  1672. if (CheckAllWaferReturned(pj, false))
  1673. {
  1674. pj.SetState(EnumProcessJobState.ProcessingComplete);
  1675. JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0);
  1676. }
  1677. }
  1678. }
  1679. }
  1680. private void CompleteJobClean(ControlJobInfo cj)
  1681. {
  1682. List<SchedulerPM> pms = GetPmNeeded(cj);
  1683. foreach (var pm in pms)
  1684. {
  1685. pm.CompleteJobClean();
  1686. }
  1687. }
  1688. private void UpdateControlJobStatus()
  1689. {
  1690. if (_lstControlJobs.Count == 0)
  1691. return;
  1692. bool allControlJobComplete = true;
  1693. List<ControlJobInfo> cjRemoveList = new List<ControlJobInfo>();
  1694. foreach (var cj in _lstControlJobs)
  1695. {
  1696. if (!Singleton<TransferModule>.Instance.GetScheduler(ModuleHelper.Converter(cj.Module)).IsAvailable)
  1697. {
  1698. allControlJobComplete = false;
  1699. continue;
  1700. }
  1701. if (cj.State == EnumControlJobState.Executing)
  1702. {
  1703. bool allPjCompleted = true;
  1704. foreach (var pjName in cj.ProcessJobNameList)
  1705. {
  1706. var pj = _lstProcessJobs.Find(x => x.Name == pjName);
  1707. if (pj == null)
  1708. {
  1709. LOG.Write( eEvent.ERR_ROUTER, ModuleName.System, $"Not find pj named {pjName} in {cj.Name}");
  1710. continue;
  1711. }
  1712. if (pj.State != EnumProcessJobState.Complete && pj.State != EnumProcessJobState.ProcessingComplete)
  1713. {
  1714. allPjCompleted = false;
  1715. break;
  1716. }
  1717. if (allPjCompleted)
  1718. {
  1719. pj.SlotWafers.ForEach(p => {
  1720. if (ModuleHelper.IsLoadPort(p.Item1))
  1721. {
  1722. allPjCompleted = allPjCompleted && WaferManager.Instance.CheckHasWafer(ModuleHelper.Converter(p.Item1.ToString()), p.Item2);
  1723. }
  1724. });
  1725. }
  1726. }
  1727. if (allPjCompleted)
  1728. {
  1729. cj.SetState(EnumControlJobState.Completed);
  1730. cj.EndTime = DateTime.Now;
  1731. if (!(_isCycleMode && _cycledCount + 1 < _cycleSetPoint))
  1732. {
  1733. CompleteJobClean(cj);
  1734. }
  1735. _faCallback.JobFinished(cj, GetFirstProcessJob(cj));
  1736. _dbCallback.LotFinished(cj);
  1737. if (!(_isCycleMode && _cycledCount < _cycleSetPoint))
  1738. (Singleton<TransferModule>.Instance.GetScheduler(ModuleHelper.Converter(cj.Module)) as SchedulerLoadPort).NoteJobComplete();
  1739. }
  1740. }
  1741. LoadportCassetteState state = (LoadportCassetteState)DATA.Poll($"{cj.Module}.CassetteState");
  1742. if (cj.State == EnumControlJobState.Completed && state != LoadportCassetteState.Normal)
  1743. {
  1744. cjRemoveList.Add(cj);
  1745. }
  1746. allControlJobComplete = allControlJobComplete && cj.State == EnumControlJobState.Completed;
  1747. }
  1748. if (_isCycleMode && _cycledCount < (_isCycleMode ? _cycleSetPoint : 0))
  1749. {
  1750. int countPerCycle = 0;
  1751. int countProcessed = 0;
  1752. foreach (var pj in _lstProcessJobs)
  1753. {
  1754. foreach (var pjSlotWafer in pj.SlotWafers)
  1755. {
  1756. countPerCycle++;
  1757. WaferInfo wafer = GetCloneWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
  1758. if (!wafer.IsEmpty && !IsWaferNeedGotoModule(wafer, ModuleName.PMA) && !IsWaferNeedGotoModule(wafer, ModuleName.PMB) && !IsWaferNeedGotoModule(wafer, ModuleName.PMC) && !IsWaferNeedGotoModule(wafer, ModuleName.PMD))
  1759. countProcessed++;
  1760. }
  1761. }
  1762. _cycledWafer = _cycledCount * countPerCycle + countProcessed;
  1763. if (allControlJobComplete)
  1764. {
  1765. _cycledCount++;
  1766. if (_cycledCount < _cycleSetPoint)
  1767. {
  1768. foreach (var cj in _lstControlJobs)
  1769. {
  1770. cj.SetState(EnumControlJobState.Executing);
  1771. cj.LotInnerId = Guid.NewGuid();
  1772. _dbCallback.LotCreated(cj);
  1773. }
  1774. foreach (var pj in _lstProcessJobs)
  1775. {
  1776. pj.SetState(EnumProcessJobState.Queued);
  1777. pj.InnerId = Guid.NewGuid();
  1778. foreach (var pjSlotWafer in pj.SlotWafers)
  1779. {
  1780. WaferInfo wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
  1781. wafer.ProcessJob = null;
  1782. wafer.NextSequenceStep = 0;
  1783. wafer.ProcessState = EnumWaferProcessStatus.Idle;
  1784. }
  1785. }
  1786. }
  1787. else
  1788. _cycleState = RState.End;
  1789. }
  1790. }
  1791. foreach (var cj in cjRemoveList)
  1792. {
  1793. List<ProcessJobInfo> pjRemoveList = new List<ProcessJobInfo>();
  1794. foreach (var pj in _lstProcessJobs)
  1795. {
  1796. if (pj.ControlJobName == cj.Name)
  1797. pjRemoveList.Add(pj);
  1798. }
  1799. foreach (var pj in pjRemoveList)
  1800. {
  1801. _lstProcessJobs.Remove(pj);
  1802. }
  1803. _lstControlJobs.Remove(cj);
  1804. }
  1805. }
  1806. private void UpdateLLInOutPathProperty()
  1807. {
  1808. if (_lstControlJobs.Count == 0)
  1809. return;
  1810. List<SequenceLLInOutPath> inOutPaths = new List<SequenceLLInOutPath>();
  1811. foreach (var cj in _lstControlJobs)
  1812. {
  1813. if (cj.State == EnumControlJobState.Executing)
  1814. {
  1815. bool allPjCompleted = true;
  1816. foreach (var pjName in cj.ProcessJobNameList)
  1817. {
  1818. var pj = _lstProcessJobs.Find(x => x.Name == pjName);
  1819. if (pj == null || pj.State != EnumProcessJobState.Processing)
  1820. continue;
  1821. if (!inOutPaths.Exists(item => item == pj.Sequence.LLInOutPath))
  1822. inOutPaths.Add(pj.Sequence.LLInOutPath);
  1823. }
  1824. }
  1825. }
  1826. if (inOutPaths.Count == 1)
  1827. {
  1828. _LLInOutPath = inOutPaths[0];
  1829. }
  1830. }
  1831. private static WaferInfo GetCloneWafer(ModuleName mod, int slot)
  1832. {
  1833. var Wafer = WaferManager.Instance.GetWafer(mod, slot);
  1834. if (Wafer.IsEmpty || Wafer.ProcessJob == null || Wafer.ProcessJob.Sequence == null)
  1835. return Wafer;
  1836. var cloneWafer = SerializeHelper.DeepCopyJson(Wafer);
  1837. if (Wafer.IsEmpty || Wafer.ProcessJob == null || Wafer.ProcessJob.Sequence == null)
  1838. return Wafer;
  1839. return cloneWafer;
  1840. }
  1841. #endregion
  1842. }
  1843. }