SETMCycle.cs 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  1. using Aitex.Core.Common;
  2. using Aitex.Core.RT.DataCenter;
  3. using Aitex.Core.RT.Fsm;
  4. using Aitex.Core.RT.Log;
  5. using Aitex.Core.RT.RecipeCenter;
  6. using Aitex.Core.RT.Routine;
  7. using Aitex.Core.RT.SCCore;
  8. using Aitex.Core.Util;
  9. using Aitex.Sorter.Common;
  10. using MECF.Framework.Common.Equipment;
  11. using MECF.Framework.Common.Jobs;
  12. using MECF.Framework.Common.Schedulers;
  13. using MECF.Framework.Common.SubstrateTrackings;
  14. using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robot;
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Diagnostics;
  18. using System.Linq;
  19. using System.Text;
  20. using System.Threading.Tasks;
  21. using Venus_Core;
  22. using Venus_RT.Modules.Schedulers;
  23. using Venus_RT.Scheduler;
  24. using static Aitex.Core.Util.SubscriptionAttribute;
  25. namespace Venus_RT.Modules
  26. {
  27. public class SETMCycle : ModuleRoutineBase, IRoutine
  28. {
  29. enum TMCycleStep
  30. {
  31. Start,
  32. ReturnBack,
  33. Cycling,
  34. End,
  35. }
  36. private List<ControlJobInfo> _lstControlJobs = new List<ControlJobInfo>();
  37. private List<ProcessJobInfo> _lstProcessJobs = new List<ProcessJobInfo>();
  38. private Dictionary<ModuleName, SchedulerModule> dictSchedulers = new Dictionary<ModuleName, SchedulerModule>();
  39. private List<ModuleName> tmCycleRoutine = new List<ModuleName>()
  40. {
  41. ModuleName.VCE1,
  42. ModuleName.PMA,
  43. ModuleName.PMB,
  44. ModuleName.PMC,
  45. ModuleName.VCE1
  46. };
  47. private int CycleNum = 0;
  48. private bool _isCycleMode;
  49. private ModuleName _sourceModule = ModuleName.VCE1;
  50. private ModuleName _destinationModule = ModuleName.VCE1;
  51. private int _sourceSlotNumber = 25;
  52. //private int _destinationSlotNumber = 25;
  53. private SchedulerSETMRobot _TMRobot = (SchedulerSETMRobot)Singleton<TransferModule>.Instance.GetScheduler(ModuleName.SETM);
  54. private SchedulerFACallback _faCallback;
  55. private SchedulerDBCallback _dbCallback;
  56. //private readonly int INVALID_SLOT = -1;
  57. private Queue<MoveItem> _runningItems = new Queue<MoveItem>();
  58. private Queue<MoveItem> _CycleWafers = new Queue<MoveItem>();
  59. private RState _cycleState = RState.Init;
  60. private Stopwatch _cycleWatch = new Stopwatch();
  61. private List<MoveItem> _moveQueue = new List<MoveItem>();
  62. private List<MovingStatus> movingStatus = new List<MovingStatus>();
  63. private double _throughput = 0;
  64. private DateTime _starttime;
  65. public int? CycleIndex;
  66. private int CycledWafer => _currentWafer + _pastWafer;
  67. private int _currentWafer;
  68. private int _pastWafer;
  69. private bool IsSequenceCycle = false; //判断是否跑货
  70. #region 构造函数
  71. public SETMCycle(ModuleName module) : base(module)
  72. {
  73. Name = "TM Cycle";
  74. void _initMoudle(ModuleName name, SchedulerModule sche)
  75. {
  76. if (ModuleHelper.IsInstalled(name))
  77. {
  78. dictSchedulers[name] = sche;
  79. }
  80. }
  81. _initMoudle(ModuleName.VCE1, new SchedulerVCE(ModuleName.VCE1));
  82. _initMoudle(ModuleName.PMA, new SchedulerPM(ModuleName.PMA));
  83. _initMoudle(ModuleName.PMB, new SchedulerPM(ModuleName.PMB));
  84. _initMoudle(ModuleName.PMC, new SchedulerPM(ModuleName.PMC));
  85. _initMoudle(ModuleName.PMD, new SchedulerPM(ModuleName.PMD));
  86. _faCallback = new SchedulerFACallback();
  87. _dbCallback = new SchedulerDBCallback();
  88. _currentWafer = 0;
  89. _pastWafer = 0;
  90. DATA.Subscribe("SEScheduler.CycledWafer", ()=> CycledWafer );
  91. DATA.Subscribe("SEScheduler.CycleSetPoint", ()=> CycleNum);
  92. DATA.Subscribe("SEScheduler.CycleCount", ()=> CycleIndex);
  93. DATA.Subscribe("SEScheduler.ThroughPut", ()=> _throughput);
  94. }
  95. #endregion
  96. #region Cycle
  97. //run货模式
  98. public RState StartJob(string jobName)
  99. {
  100. if (_TMRobot.IsVCESlitDoorClosed)
  101. {
  102. LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"VCE SlitDoor is Close cannot run!");
  103. return RState.Failed;
  104. }
  105. //sequenceCycle
  106. CycleIndex = 0;
  107. _pastWafer = 0;
  108. _currentWafer = 0;
  109. CycleNum = SC.GetValue<int>("System.CycleCount");
  110. _CycleWafers.Clear();
  111. IsSequenceCycle = true;
  112. ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
  113. if (cj == null)
  114. {
  115. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"start job rejected, not found job with id {jobName}");
  116. return RState.Failed;
  117. }
  118. if (cj.State == EnumControlJobState.WaitingForStart)
  119. {
  120. cj.SetState(EnumControlJobState.Executing);
  121. //PreJobClean(cj);
  122. cj.JetState = EnumJetCtrlJobState.Quequed;
  123. cj.StartTime = DateTime.Now;
  124. _dbCallback.LotCreated(cj);
  125. _faCallback.JobStarted(cj, GetFirstProcessJob(cj));
  126. int maxslot = 0;
  127. cj.LotWafers.ForEach(x => maxslot = x.OriginSlot > maxslot ? x.OriginSlot : maxslot);
  128. //waiting status means no use
  129. movingStatus = new List<MovingStatus>();
  130. movingStatus.AddRange(new MovingStatus[maxslot + 1]);
  131. for (int i = 0; i < movingStatus.Count; i++)
  132. movingStatus[i] = MovingStatus.Waiting;
  133. foreach (var wafer in cj.LotWafers)
  134. {
  135. WaferInfo currentWafer = WaferManager.Instance.GetWafer((ModuleName)wafer.OriginStation, wafer.OriginSlot);
  136. WaferManager.Instance.UpdateWaferProcessStatus((ModuleName)wafer.OriginStation, wafer.OriginSlot, EnumWaferProcessStatus.Idle);
  137. currentWafer.ProcessJob = _lstProcessJobs.Find(x => x.Sequence.Name == wafer.SequenceName);
  138. if (currentWafer.ProcessJob.Sequence.Steps[0].StepParameter.ContainsValue("VPA"))
  139. movingStatus[wafer.OriginSlot] = MovingStatus.WaitAlign;
  140. else
  141. movingStatus[wafer.OriginSlot] = MovingStatus.WaitProcess;
  142. }
  143. }
  144. if (!_cycleWatch.IsRunning)
  145. {
  146. _cycleWatch.Restart();
  147. }
  148. _starttime = DateTime.Now;
  149. _cycleState = RState.Running;
  150. return _cycleState;
  151. }
  152. //processJob(sequence num) ControlJob(1)
  153. public void CreateJob(Dictionary<string, object> param)
  154. {
  155. _isCycleMode = SC.GetValue<bool>("System.IsCycleMode");
  156. CycleNum = _isCycleMode ? SC.GetValue<int>("System.CycleCount") : 0;
  157. string[] slotSequence = (string[])param["SlotSequence"];
  158. string jobId = (string)param["JobId"];
  159. string module = (string)param["Module"];
  160. string lotId = jobId;
  161. if (param.ContainsKey("LotId"))
  162. lotId = (string)param["LotId"];
  163. if (!ModuleHelper.IsVCE(ModuleHelper.Converter(module)))
  164. {
  165. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"{module} should be VCE");
  166. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  167. return;
  168. }
  169. if (string.IsNullOrEmpty(jobId))
  170. {
  171. jobId = "CJ_Local_" + module;
  172. }
  173. if (_lstControlJobs.Exists(x => x.Name == jobId))
  174. {
  175. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"{jobId} already created");
  176. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  177. return;
  178. }
  179. ControlJobInfo cj = new ControlJobInfo();
  180. cj.Name = jobId;
  181. cj.Module = module;
  182. cj.LotName = lotId;
  183. cj.LotInnerId = Guid.NewGuid();
  184. cj.LotWafers = new List<WaferInfo>();
  185. cj.SetState(EnumControlJobState.WaitingForStart);
  186. cj.JetState = EnumJetCtrlJobState.Created;
  187. Dictionary<string, bool[]> seqSlot = new Dictionary<string, bool[]>();
  188. Dictionary<string, List<Tuple<ModuleName, int>>> seqSlotWafers = new Dictionary<string, List<Tuple<ModuleName, int>>>();
  189. Dictionary<string, string> indexSequence = new Dictionary<string, string>();
  190. bool enableGroupBySequence = SC.GetValue<bool>("Scheduler.GroupWaferBySequence");
  191. for (int i = 0; i < SC.GetValue<int>("VCE1.SlotNumber"); i++)
  192. {
  193. if (string.IsNullOrEmpty(slotSequence[i]) || string.IsNullOrEmpty(slotSequence[i].Trim()))
  194. continue;
  195. string groupName = enableGroupBySequence ? slotSequence[i].Trim() : i.ToString();
  196. indexSequence[groupName] = slotSequence[i];
  197. if (!seqSlot.ContainsKey(groupName))
  198. {
  199. seqSlot[groupName] = new bool[SC.GetValue<int>("VCE1.SlotNumber")];
  200. }
  201. if (!seqSlotWafers.ContainsKey(groupName))
  202. {
  203. seqSlotWafers[groupName] = new List<Tuple<ModuleName, int>>();
  204. }
  205. seqSlot[groupName][i] = true;
  206. if (!WaferManager.Instance.CheckHasWafer(module, i))
  207. {
  208. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"job wafer: {module} slot {i + 1} not in the carrier");
  209. return;
  210. }
  211. if (!WaferManager.Instance.CheckWafer(ModuleHelper.Converter(module), i, WaferStatus.Normal))
  212. {
  213. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"job wafer: {module} slot {i + 1} status is {WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).Status}");
  214. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  215. return;
  216. }
  217. if (WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).ProcessState != EnumWaferProcessStatus.Idle)
  218. {
  219. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"job wafer: {module} slot {i + 1} process status is {WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).ProcessState}");
  220. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  221. return;
  222. }
  223. cj.LotWafers.Add(WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i));
  224. WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).SequenceName = slotSequence[i];
  225. seqSlotWafers[groupName].Add(Tuple.Create(ModuleHelper.Converter(module), i));
  226. cj.JobWaferSize = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i).Size;
  227. LOG.Write(eEvent.EV_ROUTER, ModuleName.System, $"Assigned wafer job, wafer {module}.{i + 1}, sequence: {slotSequence[i]}");
  228. }
  229. if (seqSlotWafers.Count == 0)
  230. {
  231. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"job has not assign wafer");
  232. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  233. return;
  234. }
  235. List<ProcessJobInfo> pjs = new List<ProcessJobInfo>();
  236. string[] seqs = seqSlot.Keys.ToArray();
  237. for (int i = 0; i < seqs.Length; i++)
  238. {
  239. ProcessJobInfo pj = new ProcessJobInfo();
  240. pj.Name = jobId + "_" + (i + 1);
  241. pj.Sequence = SequenceInfoHelper.GetInfo(indexSequence[seqs[i]]);
  242. pj.ControlJobName = cj.Name;
  243. pj.LotName = lotId;
  244. pj.SlotWafers = seqSlotWafers[seqs[i]];
  245. pj.SetState(EnumProcessJobState.Queued);
  246. if (!CheckSequencePmReady(pj.Sequence, null, out _, out string reason))
  247. {
  248. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"no valid chamber for the {reason}");
  249. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  250. return;
  251. }
  252. if (!RouteManager.IsATMMode && !CheckSequenceRecipeFileValid(pj.Sequence, out reason))
  253. {
  254. LOG.Write(eEvent.WARN_ROUTER, ModuleName.System, $"recipe file not valid in the sequence, {reason}");
  255. _faCallback.JobCreateFailed(module, lotId, jobId, "");
  256. return;
  257. }
  258. pjs.Add(pj);
  259. }
  260. _dbCallback.LotUpdate(cj);
  261. foreach (var pj in pjs)
  262. {
  263. cj.ProcessJobNameList.Add(pj.Name);
  264. _lstProcessJobs.Add(pj);
  265. }
  266. _lstControlJobs.Add(cj);
  267. }
  268. public void AbortJob(string jobName)
  269. {
  270. }
  271. public RState Start(params object[] objs)
  272. {
  273. if (_TMRobot.IsVCESlitDoorClosed)
  274. {
  275. LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"VCE SlitDoor is Close cannot run!");
  276. return RState.Failed;
  277. }
  278. //普通Cycle
  279. if (objs.Length == 2)
  280. {
  281. var modules = ((string[])objs[0]).ToList();
  282. if (modules.Count >= 2)
  283. tmCycleRoutine.Clear();
  284. foreach (var mod in modules)
  285. {
  286. try
  287. {
  288. ModuleName module = ModuleHelper.Converter(mod);
  289. tmCycleRoutine.Add(module);
  290. }
  291. catch (Exception _)
  292. {
  293. LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Invalid module string: {mod}");
  294. return RState.Failed;
  295. }
  296. }
  297. CycleNum = (int)objs[1];
  298. CycleNum = SC.GetValue<int>("System.CycleCount");
  299. _CycleWafers.Clear();
  300. CycleIndex = 0;
  301. for (int i = 0; i < _sourceSlotNumber; i++)
  302. {
  303. if (WaferManager.Instance.CheckHasWafer(_sourceModule, i))
  304. _CycleWafers.Enqueue(new MoveItem(_sourceModule, i, _destinationModule, i, Hand.None));
  305. }
  306. IsSequenceCycle = false;
  307. _cycleState = RState.Running;
  308. }
  309. else
  310. {
  311. LOG.Write(eEvent.ERR_TM,Module,"Invalid parameter for cycle!");
  312. _cycleState = RState.Failed;
  313. }
  314. return _cycleState;
  315. }
  316. public RState Monitor()
  317. {
  318. if (_cycleState == RState.Running)
  319. {
  320. //run sequence
  321. if (IsSequenceCycle)
  322. {
  323. CheckCycleDone();
  324. SETMRobotTask();
  325. SERunTMRobotTask();
  326. SEPMTask();
  327. }
  328. //only TMCycle
  329. else
  330. {
  331. Cycling();
  332. //PMProcess();
  333. }
  334. }
  335. return _cycleState;
  336. }
  337. #endregion
  338. #region 推进|检查|计数
  339. private void CheckCycleDone()
  340. {
  341. //how to calculate current wafer? => _currentWafer
  342. //1. wafer in vce
  343. //2. wafer is Idle
  344. _currentWafer = 0;
  345. for (int index = 0; index < movingStatus.Count;++index)
  346. {
  347. if(WaferManager.Instance.CheckHasWafer(ModuleName.VCE1,index) && movingStatus[index] == MovingStatus.Idle)
  348. _currentWafer ++;
  349. }
  350. //throughput = CycledWafer/time, time(h)
  351. _throughput = Math.Round(CycledWafer / (DateTime.Now - _starttime).TotalSeconds * 3600,2);
  352. //how to confirm a sequence is over?
  353. //3、wafer is all in vce
  354. //2、all status is over => idle
  355. //1、TMRobot and PM is available
  356. if (_TMRobot.IsAvailable && AllPMIsAvailable() && ALLStatusIsOver() && WaferAllInVCE())
  357. {
  358. ++CycleIndex;
  359. if (CycleIndex >= CycleNum)
  360. {
  361. _lstControlJobs.Find(lcj => lcj.State == EnumControlJobState.Executing).SetState(EnumControlJobState.WaitingForStart);
  362. _cycleState = RState.End;
  363. }
  364. else
  365. {
  366. _pastWafer += _currentWafer;
  367. ControlJobInfo cj = _lstControlJobs.Find(lcj => lcj.State == EnumControlJobState.Executing);
  368. _currentWafer = 0;
  369. int maxslot = 0;
  370. cj.LotWafers.ForEach(x => maxslot = x.OriginSlot > maxslot ? x.OriginSlot : maxslot);
  371. //waiting status means no use
  372. movingStatus = new List<MovingStatus>();
  373. movingStatus.AddRange(new MovingStatus[maxslot + 1]);
  374. for (int i = 0; i < movingStatus.Count; i++)
  375. movingStatus[i] = MovingStatus.Waiting;
  376. foreach (var wafer in cj.LotWafers)
  377. {
  378. WaferInfo currentWafer = WaferManager.Instance.GetWafer((ModuleName)wafer.OriginStation, wafer.OriginSlot);
  379. WaferManager.Instance.UpdateWaferProcessStatus((ModuleName)wafer.OriginStation, wafer.OriginSlot, EnumWaferProcessStatus.Idle);
  380. currentWafer.ProcessJob = _lstProcessJobs.Find(x => x.Sequence.Name == wafer.SequenceName);
  381. if (currentWafer.ProcessJob.Sequence.Steps[0].StepParameter.ContainsValue("VPA"))
  382. movingStatus[wafer.OriginSlot] = MovingStatus.WaitAlign;
  383. else
  384. movingStatus[wafer.OriginSlot] = MovingStatus.WaitProcess;
  385. }
  386. }
  387. }
  388. }
  389. //movingStatus is all Idle or no use
  390. private bool ALLStatusIsOver()
  391. {
  392. bool flag = true;
  393. movingStatus.ForEach(x => flag = (x == MovingStatus.Idle || x == MovingStatus.Waiting) && flag) ;
  394. return flag;
  395. }
  396. private bool WaferAllInVCE()
  397. {
  398. ControlJobInfo cj = _lstControlJobs.Find(lcj => lcj.State == EnumControlJobState.Executing);
  399. bool flag = true;
  400. cj.LotWafers.ForEach(wafer => flag = WaferManager.Instance.CheckHasWafer((ModuleName)wafer.OriginStation, wafer.OriginSlot) && flag);
  401. return flag;
  402. }
  403. private bool AllPMIsAvailable()
  404. {
  405. foreach (KeyValuePair<ModuleName,SchedulerModule> pair in dictSchedulers)
  406. if (ModuleHelper.IsPm(pair.Key) && !pair.Value.IsAvailable)
  407. return false;
  408. return true;
  409. }
  410. private void SERunTMRobotTask()
  411. {
  412. if (_TMRobot.IsAvailable)
  413. {
  414. if (_moveQueue.Count > 0 &&_TMRobot.PostMoveItems(_moveQueue.ToArray()))
  415. {
  416. foreach (var item in _moveQueue)
  417. {
  418. var wafer = WaferManager.Instance.GetWafer(item.SourceModule, item.SourceSlot);
  419. if (wafer.IsEmpty)
  420. {
  421. // post alarm
  422. _cycleState = RState.Failed;
  423. LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Cannot run TM moving task as Get {item.SourceModule}{item.SourceModule} Wafer Info failed");
  424. return;
  425. }
  426. }
  427. _moveQueue.Clear();
  428. }
  429. }
  430. }
  431. private void SERunPMTask()
  432. {
  433. }
  434. private void SETMRobotTask()
  435. {
  436. //tm is free
  437. if (_TMRobot.IsAvailable)
  438. {
  439. CheckWaferFromVceNeedAlign();
  440. PrepareWaferOnRBToPM();
  441. GetBackWafer();
  442. GetNextWaferPickFromVCE();
  443. }
  444. }
  445. private void SEPMTask()
  446. {
  447. //foreach all pms and the wafer's receipe
  448. foreach (KeyValuePair<ModuleName,SchedulerModule> dict in dictSchedulers)
  449. {
  450. //pm has wafer && pm is available => find the wafer's receipe
  451. if (ModuleHelper.IsPm(dict.Key))
  452. {
  453. if (dict.Value.IsAvailable)
  454. {
  455. foreach (var ctrljob in _lstControlJobs)
  456. {
  457. //Port is run
  458. if (ctrljob.State == EnumControlJobState.Executing)
  459. {
  460. if (WaferManager.Instance.CheckHasWafer(dict.Key, 0))
  461. {
  462. WaferInfo currentWafer = WaferManager.Instance.GetWafer(dict.Key, 0);
  463. switch (movingStatus[currentWafer.OriginSlot])
  464. {
  465. case MovingStatus.WaitProcess:
  466. dict.Value.EventWaferArrived?.Invoke(this, new WaferMoveArgs(ModuleName.TMRobot, 0, dict.Key, 0));
  467. movingStatus[currentWafer.OriginSlot] = MovingStatus.StartProcess;
  468. break;
  469. case MovingStatus.Processing:
  470. movingStatus[currentWafer.OriginSlot] = MovingStatus.Idle;
  471. break;
  472. case MovingStatus.StartProcess:
  473. movingStatus[currentWafer.OriginSlot] = MovingStatus.Processing;
  474. break;
  475. default:
  476. break;
  477. }
  478. }
  479. }
  480. }
  481. }
  482. }
  483. }
  484. }
  485. //get the wafer need back
  486. private void GetBackWafer()
  487. {
  488. //find
  489. foreach (KeyValuePair<ModuleName, SchedulerModule> dict in dictSchedulers)
  490. {
  491. //pm has wafer && pm is available => find the wafer's receipe
  492. if (ModuleHelper.IsPm(dict.Key) && WaferManager.Instance.CheckHasWafer(dict.Key, 0) && WaferManager.Instance.CheckNoWafer(ModuleName.VPA, 0))
  493. {
  494. WaferInfo currentWafer = WaferManager.Instance.GetWafer(dict.Key, 0);
  495. //if the wafer has been processed, we need to pickfrom it.
  496. if (dict.Value.IsAvailable && movingStatus[currentWafer.OriginSlot] == MovingStatus.Idle && _TMRobot.IsAvailable)
  497. {
  498. _moveQueue.Add(new MoveItem(dict.Key,0, (ModuleName)currentWafer.OriginStation, currentWafer.OriginSlot,0));
  499. //one hand has wafer
  500. if (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 0)
  501. && movingStatus[WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0).OriginSlot] == MovingStatus.WaitProcess
  502. && WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 1))
  503. {
  504. WaferInfo wafer = WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0);
  505. if (wafer.ProcessJob.Sequence.PMs.Contains(dict.Key))
  506. {
  507. _moveQueue.Add(new MoveItem(ModuleName.TMRobot,0,dict.Key,0,0));
  508. }
  509. }
  510. else if (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 1)
  511. && movingStatus[WaferManager.Instance.GetWafer(ModuleName.TMRobot, 1).OriginSlot] == MovingStatus.WaitProcess
  512. && WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 0))
  513. {
  514. WaferInfo wafer = WaferManager.Instance.GetWafer(ModuleName.TMRobot, 1);
  515. if (wafer.ProcessJob.Sequence.PMs.Contains(dict.Key))
  516. {
  517. _moveQueue.Add(new MoveItem(ModuleName.TMRobot, 1, dict.Key, 0, (Hand)1));
  518. }
  519. }
  520. return;
  521. }
  522. }
  523. }
  524. }
  525. //get the wafer need Pick From vce
  526. private void GetNextWaferPickFromVCE()
  527. {
  528. if (_TMRobot.IsAvailable)
  529. {
  530. Dictionary<int, ModuleName> nextslot = new Dictionary<int, ModuleName>();
  531. foreach (var ctrljob in _lstControlJobs)
  532. {
  533. //Port is run
  534. if (ctrljob.State == EnumControlJobState.Executing)
  535. {
  536. bool nohastowaitpm = false;
  537. foreach (WaferInfo wafer in ctrljob.LotWafers)
  538. {
  539. //if need pm available =>pick 2
  540. if (!wafer.IsEmpty
  541. && SequenceNeedPMsAvailable(_lstProcessJobs.Find(x => x.Sequence.Name == wafer.SequenceName).Sequence.PMs)
  542. && ModuleHelper.IsVCE((ModuleName)wafer.OriginStation)
  543. && (movingStatus[wafer.OriginSlot] == MovingStatus.WaitProcess))
  544. {
  545. nohastowaitpm = true;
  546. ModuleName _destination = SearchPM(_lstProcessJobs.Find(x => x.Sequence.Name == wafer.SequenceName).Sequence.PMs, nextslot);
  547. nextslot.Add(wafer.OriginSlot, _destination);
  548. _moveQueue.Add(new MoveItem(ModuleName.VCE1, wafer.OriginSlot, _destination, 0, 0));
  549. if (nextslot.Count >= 2 || _moveQueue.Count >= 4)
  550. {
  551. return;
  552. }
  553. }
  554. //if need align available => pick 2
  555. if (!wafer.IsEmpty
  556. && WaferManager.Instance.CheckNoWafer(ModuleName.VPA, 0)
  557. && ModuleHelper.IsVCE((ModuleName)wafer.OriginStation)
  558. && SequenceNeedPMsAvailable(_lstProcessJobs.Find(x => x.Sequence.Name == wafer.SequenceName).Sequence.PMs)
  559. && (movingStatus[wafer.OriginSlot] == MovingStatus.WaitAlign))
  560. {
  561. nohastowaitpm = true;
  562. ModuleName _destination = ModuleName.TMRobot;
  563. //double pick
  564. if (WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 0) && WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 1))
  565. {
  566. nextslot.Add(wafer.OriginSlot, _destination);
  567. _moveQueue.Add(new MoveItem(ModuleName.VCE1, wafer.OriginSlot, _destination, 0, 0));
  568. }
  569. if (nextslot.Count >= 2 || _moveQueue.Count >= 4)
  570. {
  571. return;
  572. }
  573. }
  574. }
  575. //if all need PM unavailable =>pick 1 wait for swap
  576. //or 1 can input pm => pick 2, A in pm ,B wait for swap
  577. if (nextslot.Count == 0 || nohastowaitpm && nextslot.Count == 1
  578. && WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot,0)
  579. && WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot,1)
  580. && WaferManager.Instance.CheckNoWafer(ModuleName.VPA, 0))
  581. {
  582. foreach (WaferInfo wafer in ctrljob.LotWafers)
  583. {
  584. if (wafer.NextSequenceStep == 0 && !wafer.IsEmpty
  585. && ModuleHelper.IsVCE((ModuleName)wafer.SourceStation))
  586. {
  587. ModuleName _destination = _lstProcessJobs.Find(x => x.Sequence.Name == wafer.SequenceName).Sequence.PMs[0];
  588. nextslot.Add(wafer.SourceSlot, _destination);
  589. foreach (KeyValuePair<int, ModuleName> slot in nextslot)
  590. {
  591. _moveQueue.Add(new MoveItem(ModuleName.VCE1, slot.Key, slot.Value, 0, 0));
  592. }
  593. return;
  594. }
  595. if (movingStatus[wafer.OriginSlot] == MovingStatus.WaitAlign && !wafer.IsEmpty
  596. && WaferManager.Instance.CheckHasWafer((ModuleName)wafer.OriginStation, wafer.OriginSlot)
  597. && WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 0)
  598. && WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 1)
  599. && _moveQueue.Count == 0
  600. )
  601. {
  602. ModuleName _destination = ModuleName.TMRobot;
  603. _moveQueue.Add(new MoveItem((ModuleName)wafer.OriginStation, wafer.OriginSlot, ModuleName.TMRobot, 0, 0));
  604. return;
  605. }
  606. }
  607. }
  608. }
  609. }
  610. return;
  611. }
  612. }
  613. private void PrepareWaferOnRBToPM()
  614. {
  615. //tm robot has wafer and wait for process which means have to go to PM
  616. if (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 0)
  617. && movingStatus[WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0).OriginSlot] == MovingStatus.WaitProcess
  618. )
  619. {
  620. //find PM has no wafer
  621. WaferInfo wafer = WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0);
  622. if (SequenceNeedPMsAvailable(wafer.ProcessJob.Sequence.PMs))
  623. {
  624. ModuleName _destination = SearchPM(wafer.ProcessJob.Sequence.PMs, new Dictionary<int, ModuleName>());
  625. if (ModuleHelper.IsPm(_destination) && _TMRobot.IsAvailable)
  626. {
  627. _moveQueue.Add(new MoveItem(ModuleName.TMRobot, 0, _destination, 0, 0));
  628. SERunTMRobotTask();
  629. return;
  630. }
  631. }
  632. }
  633. if (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 1)
  634. && movingStatus[WaferManager.Instance.GetWafer(ModuleName.TMRobot, 1).OriginSlot] == MovingStatus.WaitProcess)
  635. {
  636. WaferInfo wafer = WaferManager.Instance.GetWafer(ModuleName.TMRobot, 1);
  637. if (SequenceNeedPMsAvailable(wafer.ProcessJob.Sequence.PMs))
  638. {
  639. ModuleName _destination = SearchPM(wafer.ProcessJob.Sequence.PMs, new Dictionary<int, ModuleName>());
  640. if (ModuleHelper.IsPm(_destination) && _TMRobot.IsAvailable)
  641. {
  642. _moveQueue.Add(new MoveItem(ModuleName.TMRobot, 1, _destination, 0, (Hand)1));
  643. SERunTMRobotTask();
  644. return;
  645. }
  646. }
  647. }
  648. }
  649. private void CheckWaferFromVceNeedAlign()
  650. {
  651. //if has wafer and need align and align is empty => goto PA
  652. if (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot,0)
  653. && movingStatus[WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0).OriginSlot] == MovingStatus.WaitAlign
  654. && WaferManager.Instance.CheckNoWafer(ModuleName.VPA, 0)
  655. &&_TMRobot.IsAvailable)
  656. {
  657. _moveQueue.Add(new MoveItem(ModuleName.TMRobot, 0,ModuleName.VPA, 0, 0));
  658. movingStatus[WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0).OriginSlot] = MovingStatus.StartAlign;
  659. SERunTMRobotTask();
  660. return;
  661. }
  662. if (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 1)
  663. && movingStatus[WaferManager.Instance.GetWafer(ModuleName.TMRobot, 1).OriginSlot] == MovingStatus.WaitAlign
  664. && WaferManager.Instance.CheckNoWafer(ModuleName.VPA, 0)
  665. && _TMRobot.IsAvailable)
  666. {
  667. _moveQueue.Add(new MoveItem(ModuleName.TMRobot, 1, ModuleName.VPA, 0, (Hand)1));
  668. movingStatus[WaferManager.Instance.GetWafer(ModuleName.TMRobot, 1).OriginSlot] = MovingStatus.StartAlign;
  669. SERunTMRobotTask();
  670. return;
  671. }
  672. //PA has wafer need align =>
  673. if (WaferManager.Instance.CheckHasWafer(ModuleName.VPA, 0) && _TMRobot.IsAvailable)
  674. {
  675. WaferInfo currentwafer = WaferManager.Instance.GetWafer(ModuleName.VPA, 0);
  676. switch (movingStatus[currentwafer.OriginSlot])
  677. {
  678. case MovingStatus.StartAlign:
  679. if(_TMRobot.IsAvailable)
  680. {
  681. float angle = float.Parse(currentwafer.ProcessJob.Sequence.Steps[0].StepParameter["AlignAngle"].ToString());
  682. _TMRobot.Align(angle);
  683. movingStatus[currentwafer.OriginSlot] = MovingStatus.Aligning;
  684. SERunTMRobotTask();
  685. return;
  686. }
  687. break;
  688. case MovingStatus.Aligning:
  689. movingStatus[currentwafer.OriginSlot] = MovingStatus.WaitProcess;
  690. if (WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 0) && _TMRobot.IsAvailable)
  691. {
  692. _moveQueue.Add(new MoveItem(ModuleName.VPA, 0, ModuleName.TMRobot, 0, 0));
  693. SERunTMRobotTask();
  694. return;
  695. }
  696. if (WaferManager.Instance.CheckNoWafer(ModuleName.TMRobot, 1) && _TMRobot.IsAvailable)
  697. {
  698. _moveQueue.Add(new MoveItem(ModuleName.VPA, 0, ModuleName.TMRobot, 1, (Hand)1));
  699. SERunTMRobotTask();
  700. return;
  701. }
  702. break;
  703. }
  704. }
  705. }
  706. private void PrepareTMMoveitems()
  707. {
  708. }
  709. private void Cycling()
  710. {
  711. //所有的PM都Idle TM都空闲的情况
  712. if (IsAllNeedPMsAvailabe() && IsModuleAvailable(_destinationModule) && IsModuleAvailable(_sourceModule) && _TMRobot.IsAvailable)
  713. {
  714. //如果PM没有wafer tm也闲置 但Cycle数量未达到目标
  715. if (!PMsHasWafers() && _TMRobot.IsAvailable && _CycleWafers.Count == 0)
  716. {
  717. ++CycleIndex;
  718. if (CycleIndex < CycleNum)
  719. {
  720. for (int i = 0; i < _sourceSlotNumber; i++)
  721. {
  722. if (WaferManager.Instance.CheckHasWafer(_sourceModule, i))
  723. _CycleWafers.Enqueue(new MoveItem(_sourceModule, i, _destinationModule, i, Hand.None));
  724. }
  725. }
  726. else
  727. {
  728. _cycleState = RState.End;
  729. return;
  730. }
  731. }
  732. //wafer返回
  733. if (PMsHasWafers())
  734. {
  735. var pmSlots = GetReadyOutPMs();
  736. //var inSlots = GetReadyInSlot(_destinationModule, _destinationSlotNumber);
  737. for (int i = 0; i < pmSlots.Count ; i++)
  738. {
  739. WaferInfo _endwafer = WaferManager.Instance.GetWafer(pmSlots[i], 0);
  740. int _endslot = _endwafer.OriginSlot;
  741. _runningItems.Enqueue(new MoveItem(pmSlots[i], 0, _destinationModule, _endslot, Hand.Both));
  742. }
  743. }
  744. else
  745. {
  746. //进腔环节 可在此处根据PM的角度 增加进入角度
  747. //三个腔体的进入方式
  748. var InPMs = GetReadyInPMs();
  749. if (_CycleWafers.Count > 0 && InPMs.Count >= 1)
  750. {
  751. var item = _CycleWafers.Dequeue();
  752. _runningItems.Enqueue(new MoveItem(item.SourceModule, item.SourceSlot, InPMs[0], 0, Hand.Both));
  753. }
  754. if (_CycleWafers.Count > 0 && InPMs.Count >= 2)
  755. {
  756. var item = _CycleWafers.Dequeue();
  757. _runningItems.Enqueue(new MoveItem(item.SourceModule, item.SourceSlot, InPMs[1], 0, Hand.Both));
  758. }
  759. if (_CycleWafers.Count > 0 && InPMs.Count >= 3)
  760. {
  761. var item = _CycleWafers.Dequeue();
  762. _runningItems.Enqueue(new MoveItem(item.SourceModule, item.SourceSlot, InPMs[2], 0, Hand.Both));
  763. }
  764. }
  765. if (_runningItems.Count > 0)
  766. {
  767. if (_TMRobot.PostMoveItems(_runningItems.ToArray()))
  768. _runningItems.Clear();
  769. }
  770. }
  771. //存在PM可用
  772. //else if (IsExistPMsAvailabe() && IsModuleAvailable(_destinationModule) && IsModuleAvailable(_sourceModule) && _TMRobot.IsAvailable)
  773. //{
  774. // //获得可以用的chamber 向里面传片
  775. //}
  776. }
  777. private void PMProcess()
  778. {
  779. //foreach (ModuleName chamber in tmCycleRoutine)
  780. //{
  781. // if (ModuleHelper.IsPm(chamber) && WaferManager.Instance.CheckHasWafer(chamber, 0) && ModuleHelper.IsInstalled(chamber))
  782. // {
  783. // WaferInfo info = WaferManager.Instance.GetWafer(chamber, 0);
  784. //
  785. // dictSchedulers[chamber].EventWaferArrived?.Invoke(this, new WaferMoveArgs(ModuleName.TMRobot, 0, chamber, 0));
  786. // }
  787. //}
  788. }
  789. public void Abort()
  790. {
  791. CycleIndex = null;
  792. _runningItems.Clear();
  793. _CycleWafers.Clear();
  794. _moveQueue.Clear();
  795. movingStatus.Clear();
  796. foreach(var cj in _lstControlJobs.FindAll(x => x.State == EnumControlJobState.Executing))
  797. cj.SetState(EnumControlJobState.WaitingForStart);
  798. _TMRobot._entityTaskToken = (int)FSM_MSG.NONE;
  799. _cycleState = RState.End;
  800. }
  801. #endregion
  802. #region 搜索函数
  803. //回到的槽位确认 采用补进方式即自底向上填
  804. private List<int> GetReadyInSlot(ModuleName module, int slotCount)
  805. {
  806. List<int> slots = new List<int>();
  807. for (int i = 0; i < slotCount; i++)
  808. {
  809. if (WaferManager.Instance.CheckNoWafer(module, i))
  810. slots.Add(i);
  811. if (slots.Count >= 2)
  812. return slots;
  813. }
  814. return slots;
  815. }
  816. //确认
  817. private List<int> GetReadyOutSlot(ModuleName module, int slotCount)
  818. {
  819. List<int> slots = new List<int>();
  820. for (int i = 0; i < slotCount; i++)
  821. {
  822. if (WaferManager.Instance.CheckHasWafer(module, i))
  823. slots.Add(i);
  824. if (slots.Count >= 2)
  825. return slots;
  826. }
  827. return slots;
  828. }
  829. //确认PM是否可用 且没有wafer
  830. private List<ModuleName> GetReadyInPMs()
  831. {
  832. List<ModuleName> inpm = new List<ModuleName>();
  833. foreach (var module in tmCycleRoutine)
  834. {
  835. if (ModuleHelper.IsPm(module))
  836. {
  837. if (IsModuleAvailable(module) && WaferManager.Instance.CheckNoWafer(module, 0))
  838. {
  839. inpm.Add(module);
  840. if (inpm.Count >= 3)
  841. break;
  842. }
  843. }
  844. }
  845. return inpm;
  846. }
  847. private List<ModuleName> GetReadyOutPMs()
  848. {
  849. List<ModuleName> outpm = new List<ModuleName>();
  850. foreach (var module in tmCycleRoutine)
  851. {
  852. if (ModuleHelper.IsPm(module))
  853. {
  854. if (IsModuleAvailable(module) && WaferManager.Instance.CheckHasWafer(module, 0))
  855. {
  856. outpm.Add(module);
  857. if (outpm.Count >= 3)
  858. break;
  859. }
  860. }
  861. }
  862. return outpm;
  863. }
  864. //PM有wafer
  865. private bool PMsHasWafers()
  866. {
  867. foreach (var module in tmCycleRoutine)
  868. {
  869. if (ModuleHelper.IsPm(module) && ModuleHelper.IsInstalled(module))
  870. {
  871. if (WaferManager.Instance.CheckHasWafer(module, 0))
  872. return true;
  873. }
  874. }
  875. return false;
  876. }
  877. //PM全可用
  878. private bool IsAllNeedPMsAvailabe()
  879. {
  880. foreach (var module in tmCycleRoutine)
  881. {
  882. if (ModuleHelper.IsPm(module) && ModuleHelper.IsInstalled(module))
  883. {
  884. if (!IsModuleAvailable(module))
  885. return false;
  886. }
  887. }
  888. return true;
  889. }
  890. //PM存在可用
  891. private bool SequenceNeedPMsAvailable(List<ModuleName> needPMs)
  892. {
  893. foreach (var module in needPMs)
  894. {
  895. if (ModuleHelper.IsPm(module) && ModuleHelper.IsInstalled(module))
  896. {
  897. if (IsModuleAvailable(module) && WaferManager.Instance.CheckNoWafer(module,0))
  898. return true;
  899. }
  900. }
  901. return false;
  902. }
  903. private ModuleName SearchPM(List<ModuleName> needPMs,Dictionary<int,ModuleName> PMsChoice)
  904. {
  905. foreach (var module in needPMs)
  906. {
  907. if (ModuleHelper.IsPm(module) && ModuleHelper.IsInstalled(module))
  908. {
  909. if (IsModuleAvailable(module) && !PMsChoice.ContainsValue(module) && WaferManager.Instance.CheckNoWafer(module,0))
  910. return module;
  911. }
  912. }
  913. return ModuleName.TMRobot;
  914. }
  915. private bool IsModuleAvailable(ModuleName module)
  916. {
  917. return dictSchedulers.Keys.Contains(module) && dictSchedulers[module].IsAvailable;
  918. }
  919. //检查需要使用的pm
  920. private bool CheckSequencePmReady(SequenceInfo seq, List<ModuleName> pmOccupied, out List<ModuleName> pmUsed, out string reason)
  921. {
  922. pmUsed = new List<ModuleName>();
  923. reason = "";
  924. bool pmIsReady = true;
  925. for (int i = 0; i < seq.Steps.Count; i++)
  926. {
  927. SequenceStepInfo stepInfo = seq.Steps[i];
  928. bool hasPm = false;
  929. foreach (var module in stepInfo.StepModules)
  930. {
  931. if (!ModuleHelper.IsPm(module))
  932. {
  933. hasPm = true;
  934. break;
  935. }
  936. if (ModuleHelper.IsInstalled(module) && (pmOccupied == null || !pmOccupied.Contains(module)))
  937. {
  938. hasPm = true;
  939. }
  940. if (!pmUsed.Contains(module))
  941. pmUsed.Add(module);
  942. }
  943. if (pmIsReady && !hasPm)
  944. {
  945. reason = $"Step {i + 1} no valid PM, " + string.Join("|", stepInfo.StepModules);
  946. pmIsReady = false;
  947. }
  948. }
  949. return pmIsReady;
  950. }
  951. //检查是否又对应PM的recipe
  952. private bool CheckSequenceRecipeFileValid(SequenceInfo seq, out string reason)
  953. {
  954. for (int i = 0; i < seq.Steps.Count; i++)
  955. {
  956. SequenceStepInfo stepInfo = seq.Steps[i];
  957. foreach (var module in stepInfo.StepModules)
  958. {
  959. if (ModuleHelper.IsPm(module))
  960. {
  961. string attr = $"{module}Recipe";
  962. if (stepInfo.StepParameter.ContainsKey(attr)
  963. && !string.IsNullOrEmpty((string)stepInfo.StepParameter[attr]))
  964. {
  965. var recipeName = (string)stepInfo.StepParameter[attr];
  966. if (!string.IsNullOrEmpty(recipeName))
  967. {
  968. var recipeContent =
  969. RecipeFileManager.Instance.LoadRecipe($"{module}", recipeName, false, "Process");
  970. if (string.IsNullOrEmpty(recipeContent))
  971. {
  972. reason = $"Can not find recipe file{recipeName}";
  973. return false;
  974. }
  975. }
  976. }
  977. }
  978. }
  979. }
  980. reason = "";
  981. return true;
  982. }
  983. //找到对应sequence
  984. public ProcessJobInfo GetFirstProcessJob(ControlJobInfo cj)
  985. {
  986. foreach (var pj in _lstProcessJobs)
  987. {
  988. if (pj.ControlJobName == cj.Name)
  989. return pj;
  990. }
  991. return null;
  992. }
  993. #endregion
  994. }
  995. }