SETMCycle.cs 57 KB

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