SETMCycle.cs 45 KB

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