SETMCycle.cs 56 KB

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