Process.cs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Xml;
  4. using Aitex.Core.RT.Device;
  5. using Aitex.Core.RT.Event;
  6. using Aitex.Core.RT.Job;
  7. using Aitex.Core.RT.Log;
  8. using Aitex.Core.RT.RecipeCenter;
  9. using Aitex.Core.RT.Routine;
  10. using Aitex.Core.Util;
  11. using Aitex.Core.RT.SCCore;
  12. using Aitex.Platform;
  13. using Aitex.RT.Properties;
  14. using Aitex.Triton160.Common;
  15. using Aitex.Triton160.RT.Device;
  16. using Aitex.Triton160.RT.Module;
  17. namespace Aitex.Triton160.RT.Routine.Process
  18. {
  19. public class Process : CommonRoutine
  20. {
  21. /// <summary>
  22. /// 工艺程序运行引擎状态定义
  23. /// </summary>
  24. enum RecipeEngineState
  25. {
  26. Error,
  27. RecipeCompleted,
  28. ExecStep,
  29. TimeWait,
  30. ConditionWait,
  31. StepCompleted,
  32. Paused,
  33. }
  34. enum CycleCountResetFlag
  35. {
  36. ResetByDay,
  37. ResetByRecipe,
  38. }
  39. /// <summary>
  40. /// 工艺程序数据
  41. /// </summary>
  42. private object _lockerTotalCycle = new object();
  43. private Dictionary<string, int> _recipeTotalCycle = new Dictionary<string, int>();
  44. //public bool IsAtmRecipeRun { private set; get; }
  45. private DeviceTimer _beginPauseTimer = new DeviceTimer();
  46. /// <summary>
  47. /// 防止工艺程序运行线程和外部更新工艺程序数据的线程并发进行
  48. /// </summary>
  49. private object _recipeLocker = new object();
  50. /// <summary>
  51. /// 当前工艺执行引擎的状态
  52. /// </summary>
  53. private RecipeEngineState _state = RecipeEngineState.ExecStep;
  54. private RecipeEngineState _pausedState = RecipeEngineState.ExecStep;
  55. private DeviceTimer _estimatedTimeCalcTimer = new DeviceTimer();//用于定时计算工艺程序估计的结束时间
  56. private int _currentRecipeCycleCount = 0;
  57. private string _previousRecipeName;
  58. private string _processCompleteInfo;
  59. private bool _isProcessCompleted;
  60. public DateTime RecipeStartTime
  61. {
  62. get;
  63. private set;
  64. }
  65. public int RecipeChangeNo
  66. {
  67. get;
  68. private set;
  69. }
  70. public string CurrentRecipeBaseName { get; private set; }
  71. public string CurrentRecipeRunningName { get; private set; }
  72. public string CurrentRecipeContent { get; private set; }
  73. public string CurrentLotName
  74. {
  75. get; set;
  76. }
  77. public string CurrentJobName
  78. {
  79. get;
  80. set;
  81. }
  82. private List<RecipeStep> _recipeStepList = new List<RecipeStep>();
  83. public List<RecipeStep> CurrentRecipeStepList
  84. {
  85. get
  86. {
  87. return _recipeStepList;
  88. }
  89. set
  90. {
  91. _recipeStepList = value;
  92. }
  93. }
  94. public RecipeHead CurrentRecipeHead
  95. {
  96. get; set;
  97. }
  98. public int CurStepNum
  99. {
  100. get;
  101. private set;
  102. }
  103. public int CurStepTotalLoopCount
  104. {
  105. get;
  106. private set;
  107. }
  108. public double CurStepTotalTime
  109. {
  110. get
  111. {
  112. if (_recipeStepList == null || _recipeStepList.Count == 0 || _state == RecipeEngineState.RecipeCompleted || _state == RecipeEngineState.Error)
  113. return 0;
  114. return _recipeStepList[CurStepNum].StepTime * 1000;
  115. }
  116. }
  117. public int CurrentLoopCount
  118. {
  119. get;
  120. private set;
  121. }
  122. private DeviceTimer StepTimer = new DeviceTimer();
  123. public bool IsPaused
  124. {
  125. private set;
  126. get;
  127. }
  128. public string CurStepComment
  129. {
  130. get
  131. {
  132. if (_recipeStepList == null || _recipeStepList.Count == 0)
  133. return String.Empty;
  134. return _recipeStepList[CurStepNum].StepName;
  135. }
  136. }
  137. public double CurStepLeftTime
  138. {
  139. get
  140. {
  141. if (IsPaused)
  142. return StepTimer.GetTotalTime() - StepTimer.GetElapseTime() + _beginPauseTimer.GetElapseTime();
  143. //return Math.Max(0,StepTimer.GetTotalTime() - StepTimer.GetElapseTime());
  144. return StepTimer.GetTotalTime() - StepTimer.GetElapseTime();
  145. }
  146. }
  147. public double CurStepElpasedTime
  148. {
  149. get
  150. {
  151. if (_recipeStepList == null || _recipeStepList.Count == 0 || _state == RecipeEngineState.RecipeCompleted || _state == RecipeEngineState.Error)
  152. return 0;
  153. return StepTimer.GetElapseTime();
  154. }
  155. }
  156. public double CurStepTotalRfTime
  157. {
  158. get
  159. {
  160. if (_recipeStepList == null || _recipeStepList.Count == 0 || _state == RecipeEngineState.RecipeCompleted || _state == RecipeEngineState.Error)
  161. return 0;
  162. if (_recipeStepList[CurStepNum].RecipeCommands.ContainsKey("Rf.SetPower") &&
  163. !string.IsNullOrEmpty(_recipeStepList[CurStepNum].RecipeCommands["Rf.SetPower"]) &&
  164. (Convert.ToDouble(_recipeStepList[CurStepNum].RecipeCommands["Rf.SetPower"]) > 0.1))
  165. return CurStepTotalTime;
  166. return 0;
  167. }
  168. }
  169. public int TotalCycle
  170. {
  171. get
  172. {
  173. if (string.IsNullOrEmpty(DateTimeRecipeBaseName))
  174. return 0;
  175. var ResetFlag = (int)SC.GetValue<double>(SCName.ProcessConfig_RecipeCycleCouterFlag);
  176. lock (_lockerTotalCycle)
  177. {
  178. if (ResetFlag == (int)CycleCountResetFlag.ResetByDay)
  179. {
  180. if (_recipeTotalCycle.ContainsKey(DateTimeRecipeBaseName))
  181. return _recipeTotalCycle[DateTimeRecipeBaseName];
  182. }
  183. else
  184. {
  185. return _currentRecipeCycleCount;
  186. }
  187. }
  188. return 0;
  189. }
  190. }
  191. public string DateTimeRecipeBaseName
  192. {
  193. get
  194. {
  195. if (string.IsNullOrEmpty(CurrentRecipeBaseName))
  196. return "";
  197. return DateTime.Now.ToString("yyyyMMdd") + CurrentRecipeBaseName;
  198. }
  199. }
  200. public double PausedTime
  201. {
  202. get
  203. {
  204. return IsPaused ? _beginPauseTimer.GetElapseTime() : 0;
  205. }
  206. }
  207. public double EstimatedTotalLeftTime
  208. {
  209. get;
  210. private set;
  211. }
  212. public int RecipeTotalStepNum
  213. {
  214. get
  215. {
  216. return _recipeStepList.Count;
  217. }
  218. }
  219. public Process(string module, string name)
  220. {
  221. Module = module;
  222. Name = name;
  223. Display = Resources.Process_Process_Process;
  224. RecipeStartTime = new DateTime(0);
  225. EstimatedTotalLeftTime = 0;
  226. }
  227. public bool Initialize()
  228. {
  229. InitCommon();
  230. CalcEstimatedRecipeEndTime();
  231. return true;
  232. }
  233. public Result Start(params object[] param)
  234. {
  235. RecipeStartTime = DateTime.Now;
  236. CurrentRecipeBaseName = (string)param[0];
  237. if (String.Equals(_previousRecipeName,CurrentRecipeBaseName))
  238. _currentRecipeCycleCount++;
  239. else
  240. {
  241. _currentRecipeCycleCount = 1;
  242. _previousRecipeName = CurrentRecipeBaseName;
  243. }
  244. CurrentRecipeRunningName = (string)param[1];
  245. RecipeChangeNo = (int)param[2];
  246. CurrentLotName = (string)param[3];
  247. CurrentRecipeContent = (string)param[4];
  248. CurrentRecipeHead = (RecipeHead)param[5];
  249. CurrentRecipeStepList = (List<RecipeStep>)param[6];
  250. CurrentJobName = (string)param[7];
  251. lock (_lockerTotalCycle)
  252. {
  253. if (_recipeTotalCycle.ContainsKey(DateTimeRecipeBaseName))
  254. _recipeTotalCycle[DateTimeRecipeBaseName] += 1;
  255. else
  256. {
  257. _recipeTotalCycle[DateTimeRecipeBaseName] = 1;
  258. }
  259. List<string> keys = new List<string>();
  260. foreach (KeyValuePair<string, int> item in _recipeTotalCycle)
  261. {
  262. if (!item.Key.StartsWith(DateTime.Now.ToString("yyyyMMdd")))
  263. keys.Add(item.Key);
  264. }
  265. foreach (string key in keys)
  266. {
  267. _recipeTotalCycle.Remove(key);
  268. }
  269. }
  270. CurStepNum = CurStepTotalLoopCount = 0;
  271. _estimatedTimeCalcTimer.Start(1000);
  272. //TmService.NotifySusceptorStatusChanged(RecipeName, SusceptorStatus.InProcessing); //@AAA
  273. EV.PostSoundMessage(String.Format("Run Recipe {0}", CurrentRecipeRunningName));
  274. EV.PostMessage(Module, EventEnum.RecipeStart, Module, CurrentRecipeRunningName);
  275. //更新当前的工艺状态到数据库中
  276. Singleton<PMEntity>.Instance.CurrentRunningJob.JobResult = JobStatus.InProcessing;
  277. Singleton<ProcessRecorder>.Instance.UpdateProcessStatus(Singleton<PMEntity>.Instance.CurrentRunningJob.RecipeRunId, JobStatus.InProcessing);
  278. _state = RecipeEngineState.ExecStep;
  279. return Result.RUN;
  280. }
  281. public void PopProcessEndDialog()
  282. {
  283. if(_isProcessCompleted)
  284. {
  285. if (_trigExitMessage.Q)
  286. {
  287. EV.PostPopDialogMessage(EventLevel.InformationNoDelay, string.Format(Resources.Process_Exit_0RecipeCompletelyRun, Module), _processCompleteInfo);
  288. }
  289. }
  290. else
  291. {
  292. EV.PostPopDialogMessage(EventLevel.Warning, string.Format(Resources.Process_Exit_0RecipeWasAborted, Module), _processCompleteInfo);
  293. }
  294. }
  295. /// <summary>
  296. /// quiting current state
  297. /// </summary>
  298. /// <param name="nextState"></param>
  299. public void Exit()
  300. {
  301. if (DeviceModel.PressureControl != null)
  302. {
  303. DeviceModel.PressureControl.EnableTolerance = false;
  304. }
  305. var ts = DateTime.Now - RecipeStartTime;
  306. var totalTime = string.Format("{0}:{1}:{2}", Convert.ToInt32(ts.TotalHours), ts.Minutes, ts.Seconds);
  307. JobInfo job = Singleton<PMEntity>.Instance.CurrentRunningJob;
  308. _isProcessCompleted = _state == RecipeEngineState.RecipeCompleted;
  309. if (_isProcessCompleted)
  310. {
  311. //正常工艺运行结束
  312. Singleton<ProcessRecorder>.Instance.AddRecord(job.RecipeRunId, CarrierDataType.ProcessNormalEnd, totalTime, "recipe finished");
  313. _processCompleteInfo = string.Format(Resources.Process_Exit_Recipe0RNStartTime1RNEndTime2RNTotalTime3,
  314. CurrentRecipeRunningName, RecipeStartTime.ToString("yyyy/MM/dd HH:mm:ss"),
  315. DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), totalTime);
  316. EV.PostMessage(Module, EventEnum.ProcessSuccEnd, Module, _processCompleteInfo);
  317. _trigExitMessage.CLK = true;
  318. job.JobResult = JobStatus.Processed;
  319. }
  320. else
  321. {
  322. //人为终止工艺运行结束
  323. Singleton<ProcessRecorder>.Instance.AddRecord(job.RecipeRunId, CarrierDataType.PostProcessErrorEnd, totalTime, "recipe aborted");
  324. string _processCompleteInfo = string.Format(Resources.Process_Exit_Recipe0RNStartTime1RNEndTime2RNTotalTime3,
  325. CurrentRecipeRunningName, RecipeStartTime.ToString("yyyy/MM/dd HH:mm:ss"),
  326. DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), totalTime);
  327. EV.PostMessage(Module, EventEnum.RecipeAborted, Module, _processCompleteInfo);
  328. //TmProxy.NotifyProcessEnded(false);
  329. //Update susceptor information
  330. job.JobResult = JobStatus.Troubled;
  331. }
  332. if((int)SC.GetValue<double>(SCName.ProcessConfig_ProcessFinishedReminderFlag) == 0)
  333. {
  334. PopProcessEndDialog();
  335. }
  336. job.ProcessEndTime = DateTime.Now;
  337. //重置工艺程序名
  338. CurrentRecipeRunningName = string.Empty;
  339. CurrentLotName = string.Empty;
  340. //stop all ramping when quiting processing state
  341. StopRamp();
  342. }
  343. private void CheckPressureStability()
  344. {
  345. //如果有ThrottleValve 就检查Throttle Valve的tolerance
  346. if (DeviceModel.PressureControl != null)
  347. {
  348. DeviceModel.PressureControl.EnableTolerance =
  349. (DeviceModel.MfcGas1 != null && DeviceModel.MfcGas1.SetPoint > 0.001) ||
  350. (DeviceModel.MfcGas2 != null && DeviceModel.MfcGas2.SetPoint > 0.001) ||
  351. (DeviceModel.MfcGas3 != null && DeviceModel.MfcGas3.SetPoint > 0.001) ||
  352. (DeviceModel.MfcGas4 != null && DeviceModel.MfcGas4.SetPoint > 0.001) ||
  353. (DeviceModel.MfcGas5 != null && DeviceModel.MfcGas5.SetPoint > 0.001);
  354. }
  355. }
  356. /// <summary>
  357. /// 工艺程序运行引擎放于此处
  358. /// </summary>
  359. public Result Monitor()
  360. {
  361. string reason = string.Empty;
  362. CalcEstimatedRecipeEndTime();
  363. //检查软件互锁是否强制停止运行工艺程序
  364. //if (!doRoutineRunning.Value)
  365. //{
  366. // if (!doRoutineRunning.Check(true, out reason))
  367. // {
  368. // EV.PostMessage(Module, EventEnum.RecipeAbortedByInterlock, Module, reason);
  369. // return Result.FAIL; // Reactor.PostEvent(new AlarmHandleCommand("软件互锁"));
  370. // }
  371. //}
  372. //工艺程序运行监控,自动打开阀门如果对应的MFC设定设置大于0
  373. if (DeviceModel.ValveMfc1 != null && DeviceModel.MfcGas1 != null)
  374. DeviceModel.ValveMfc1.TurnValve(DeviceModel.MfcGas1.SetPoint > 0, out reason);
  375. if (DeviceModel.ValveMfc2 != null && DeviceModel.MfcGas2 != null)
  376. DeviceModel.ValveMfc2.TurnValve(DeviceModel.MfcGas2.SetPoint > 0, out reason);
  377. if (DeviceModel.ValveMfc3 != null && DeviceModel.MfcGas3 != null)
  378. DeviceModel.ValveMfc3.TurnValve(DeviceModel.MfcGas3.SetPoint > 0, out reason);
  379. if (DeviceModel.ValveMfc4 != null && DeviceModel.MfcGas4 != null)
  380. DeviceModel.ValveMfc4.TurnValve(DeviceModel.MfcGas4.SetPoint > 0, out reason);
  381. if (DeviceModel.ValveMfc5 != null && DeviceModel.MfcGas5 != null)
  382. DeviceModel.ValveMfc5.TurnValve(DeviceModel.MfcGas5.SetPoint > 0, out reason);
  383. if (DeviceModel.ValveProcessGasFinal != null)
  384. {
  385. DeviceModel.ValveProcessGasFinal.TurnValve(
  386. (DeviceModel.MfcGas1 != null && DeviceModel.MfcGas1.SetPoint > 0)
  387. || (DeviceModel.MfcGas2 != null && DeviceModel.MfcGas2.SetPoint > 0)
  388. || (DeviceModel.MfcGas3 != null && DeviceModel.MfcGas3.SetPoint > 0)
  389. || (DeviceModel.MfcGas4 != null && DeviceModel.MfcGas4.SetPoint > 0)
  390. || (DeviceModel.MfcGas5 != null && DeviceModel.MfcGas5.SetPoint > 0), out reason);
  391. }
  392. //工艺程序运行引擎
  393. lock (_recipeLocker)
  394. {
  395. try
  396. {
  397. switch (_state)
  398. {
  399. case RecipeEngineState.ExecStep:
  400. {
  401. //工艺程序循环设置
  402. if (_recipeStepList[CurStepNum].IsLoopStartStep)
  403. {
  404. CurStepTotalLoopCount = _recipeStepList[CurStepNum].LoopCount;
  405. if (CurStepTotalLoopCount == 0)
  406. {
  407. CurrentLoopCount = 0;
  408. }
  409. else
  410. {
  411. CurrentLoopCount++;
  412. }
  413. }
  414. //当前工艺程序步的定时器设定
  415. StepTimer.Start(_recipeStepList[CurStepNum].StepTime * 1000);
  416. Singleton<ProcessRecorder>.Instance.AddRecord(Singleton<PMEntity>.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeStepStart, (CurStepNum + 1).ToString(), string.Format(Resources.Process_Monitor_RecipeRunningStartStep01, CurStepNum + 1, _recipeStepList[CurStepNum].StepName));
  417. //发送信息到用户界面
  418. EV.PostMessage(Module, EventEnum.RecipeStepStart, Module, CurrentRecipeRunningName, CurStepNum + 1, _recipeStepList[CurStepNum].StepName);
  419. //执行工艺程序命令
  420. foreach (var recipeCmd in _recipeStepList[CurStepNum].RecipeCommands.Keys)
  421. {
  422. if (!DEVICE.CanDo(recipeCmd))
  423. {
  424. EV.PostMessage(Module, EventEnum.RecipeItemUnknow, Module, recipeCmd);
  425. }
  426. else
  427. {
  428. var rampTime_ms = (int)(_recipeStepList[CurStepNum].StepTime * 1000);
  429. if (_recipeStepList[CurStepNum].IsJumpStep)
  430. rampTime_ms = 0;
  431. DEVICE.Do(recipeCmd, rampTime_ms, false, _recipeStepList[CurStepNum].RecipeCommands[recipeCmd]);
  432. }
  433. }
  434. //if (string.IsNullOrEmpty(_recipeStepList[CurStepNum].EndBy) || String.Compare(_recipeStepList[CurStepNum].EndBy, "None", true) == 0)
  435. {
  436. _state = RecipeEngineState.TimeWait;
  437. }
  438. //else
  439. //{
  440. // _state = RecipeEngineState.ConditionWait;
  441. //}
  442. }
  443. break;
  444. case RecipeEngineState.TimeWait:
  445. CheckPressureStability();
  446. if (StepTimer.IsTimeout())
  447. {
  448. _state = RecipeEngineState.StepCompleted;
  449. }
  450. break;
  451. case RecipeEngineState.ConditionWait:
  452. {
  453. //var endbyCondition = (EndByCondition)Enum.Parse(typeof(EndByCondition), _recipeStepList[CurStepNum].EndBy, true);
  454. //var endbyValue = Convert.ToDouble(_recipeStepList[CurStepNum].EndByValue);
  455. //if (isStepEndby(endbyCondition, endbyValue))
  456. {
  457. _state = RecipeEngineState.StepCompleted;
  458. }
  459. }
  460. break;
  461. case RecipeEngineState.Paused:
  462. break;
  463. case RecipeEngineState.StepCompleted:
  464. {
  465. //发送新的一步开始的信息到用户界面
  466. EV.PostMessage(Module, EventEnum.RecipeStepComplete, Module, CurrentRecipeRunningName, CurStepNum + 1);
  467. //添加石墨盘信息
  468. Singleton<ProcessRecorder>.Instance.AddRecord(Singleton<PMEntity>.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeStepNormalEnd, (CurStepNum + 1).ToString(), string.Format("recipe running:end step {0}", CurStepNum + 1));
  469. //判断是否当前步循环终止
  470. if (_recipeStepList[CurStepNum].IsLoopEndStep)
  471. {
  472. //重新读取循环的设定次数
  473. for (int nn = CurStepNum; nn >= 0; nn--)
  474. {
  475. if (_recipeStepList[nn].IsLoopStartStep)
  476. {
  477. CurStepTotalLoopCount = _recipeStepList[nn].LoopCount;
  478. break;
  479. }
  480. }
  481. if (CurrentLoopCount >= CurStepTotalLoopCount)
  482. {
  483. CurrentLoopCount = CurStepTotalLoopCount = 0;
  484. CurStepNum++;
  485. }
  486. else
  487. {
  488. int n = CurStepNum - 1;
  489. int next = -1;
  490. while (n >= 0)
  491. {
  492. if (_recipeStepList[n].IsLoopStartStep)
  493. {
  494. next = n;
  495. break;
  496. }
  497. n--;
  498. }
  499. if (next == -1)
  500. throw new Exception("Loop End control error");
  501. CurStepNum = next;
  502. }
  503. }
  504. else
  505. {
  506. CurStepNum++;
  507. }
  508. if (CurStepNum >= _recipeStepList.Count)
  509. {
  510. //EV.PostMessage(Module, EventEnum.RecipeComplete, Module, RecipeName);
  511. CurStepNum = _recipeStepList.Count - 1;
  512. _state = RecipeEngineState.RecipeCompleted;
  513. return Result.DONE;
  514. }
  515. else
  516. {
  517. _state = RecipeEngineState.ExecStep;
  518. }
  519. }
  520. break;
  521. case RecipeEngineState.RecipeCompleted:
  522. {
  523. return Result.DONE;
  524. }
  525. case RecipeEngineState.Error:
  526. return Result.FAIL;
  527. default:
  528. break;
  529. }
  530. }
  531. catch (Exception ex)
  532. {
  533. EV.PostMessage(Module, EventEnum.RecipeProcessException, Module, CurStepNum + 1, "语法错误");
  534. LOG.Write(ex);
  535. return Result.FAIL;
  536. }
  537. }
  538. return Result.RUN;
  539. }
  540. /// <summary>
  541. /// 暂停工艺程序运行
  542. /// </summary>
  543. public void PauseRecipe()
  544. {
  545. if (_state != RecipeEngineState.TimeWait && _state != RecipeEngineState.ConditionWait)
  546. return;
  547. if (!IsPaused)
  548. {
  549. string reason = String.Empty;
  550. IsPaused = true;
  551. _pausedState = _state;
  552. _state = RecipeEngineState.Paused;
  553. _beginPauseTimer.Start(0);
  554. Singleton<ProcessRecorder>.Instance.AddRecord(Singleton<PMEntity>.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeStepPaused, CurStepNum.ToString(), string.Format(Resources.Process_PauseRecipe_工艺运行中当前第0步暂停, CurStepNum + 1));
  555. EV.PostMessage(Module, EventEnum.RecipePaused, Module, CurrentRecipeRunningName, CurStepNum + 1);
  556. //pause mfc
  557. //pause pc
  558. StopRamp();
  559. }
  560. }
  561. /// <summary>
  562. /// 恢复工艺程序运行
  563. /// </summary>
  564. public void ResumeRecipe()
  565. {
  566. if (IsPaused)
  567. {
  568. //update current recipe step time
  569. string recipeXml = CurrentRecipeContent;
  570. int currentStepNo = CurStepNum;
  571. XmlDocument xmlDoc = new XmlDocument();
  572. xmlDoc.LoadXml(recipeXml);
  573. var stepNodes = xmlDoc.SelectNodes("/TableRecipeData/Step");
  574. if (currentStepNo >= 0 && currentStepNo < stepNodes.Count)
  575. {
  576. var curStepNode = stepNodes[currentStepNo] as XmlElement;
  577. var curStepNewTime = CurStepTotalTime + PausedTime;
  578. if (curStepNewTime < 0)
  579. curStepNewTime = 0;
  580. TimeSpan tspan = new TimeSpan(0, 0, 0, 0, (int)curStepNewTime);
  581. var timeString = string.Format("{0}:{1}:{2}", ((int)tspan.TotalHours).ToString("00"), tspan.Minutes.ToString("00"), tspan.Seconds.ToString("00"));
  582. curStepNode.SetAttribute("Time", timeString);
  583. LOG.Write(string.Format("执行Resume命令,将当前第{0}步时间修改为{1}", currentStepNo, timeString));
  584. UpdateRecipe(xmlDoc.OuterXml);
  585. }
  586. //Resume recipe
  587. IsPaused = false;
  588. _state = _pausedState;
  589. Singleton<ProcessRecorder>.Instance.AddRecord(Singleton<PMEntity>.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeStepResume, CurStepNum.ToString(), string.Format("工艺运行中:当前第{0}步,取消暂停", CurStepNum + 1));
  590. EV.PostMessage(Module, EventEnum.RecipeResumed, Module, CurrentRecipeRunningName, CurStepNum + 1);
  591. //resume recipe
  592. double stepElapsedTime = StepTimer.GetElapseTime() - _beginPauseTimer.GetElapseTime();
  593. double stepLeftTime = StepTimer.GetTotalTime() - stepElapsedTime;
  594. if (stepLeftTime < 0)
  595. stepLeftTime = 0;
  596. //更新当前步的定时器时间
  597. StepTimer.Restart(StepTimer.GetTotalTime() + _beginPauseTimer.GetElapseTime());
  598. //重新执行当前工艺程序步
  599. foreach (var recipeCmd in _recipeStepList[CurStepNum].RecipeCommands.Keys)
  600. {
  601. if (!DEVICE.CanDo(recipeCmd))
  602. {
  603. EV.PostMessage(Module, EventEnum.RecipeItemUnknow, Module, recipeCmd);
  604. }
  605. else
  606. {
  607. var rampTime_ms = (int)(_recipeStepList[CurStepNum].StepTime * 1000);
  608. if (_recipeStepList[CurStepNum].IsJumpStep)
  609. rampTime_ms = 0;
  610. DEVICE.Do(recipeCmd, rampTime_ms, false, _recipeStepList[CurStepNum].RecipeCommands[recipeCmd]);
  611. }
  612. }
  613. }
  614. }
  615. /// <summary>
  616. /// 终止工艺程序运行
  617. /// </summary>
  618. public void AbortRecipe()
  619. {
  620. ResumeRecipe();
  621. _state = RecipeEngineState.RecipeCompleted;
  622. CalcEstimatedRecipeEndTime();
  623. StopRamp();
  624. //send informational event
  625. Singleton<ProcessRecorder>.Instance.AddRecord(Singleton<PMEntity>.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeStepResume, CurStepNum.ToString(), string.Format("recipe running:aborted in step {0}", CurStepNum + 1));
  626. EV.PostMessage(Module, EventEnum.RecipeAborted, Module, Resources.Process_AbortRecipe_UserAbortedRecipe);
  627. }
  628. /// <summary>
  629. /// 跳至工艺程序下一步
  630. /// </summary>
  631. public void SkipCurrentRecipeStep()
  632. {
  633. if (_state == RecipeEngineState.Paused)
  634. {
  635. EV.PostMessage(Module, EventEnum.ReactorCmdReject, Module, "Pause Recipe", "Skip to next step");
  636. return;
  637. }
  638. try
  639. {
  640. //update current recipe step time
  641. string recipeXml = CurrentRecipeContent;
  642. int currentStepNo = CurStepNum;
  643. XmlDocument xmlDoc = new XmlDocument();
  644. xmlDoc.LoadXml(recipeXml);
  645. var stepNodes = xmlDoc.SelectNodes("/TableRecipeData/Step");
  646. if (currentStepNo >= 0 && currentStepNo < stepNodes.Count)
  647. {
  648. var curStepNode = stepNodes[currentStepNo] as XmlElement;
  649. var curStepElapsedTime = CurStepTotalTime - CurStepLeftTime;//ms
  650. if (curStepElapsedTime < 0)
  651. curStepElapsedTime = 0;
  652. TimeSpan tspan = new TimeSpan(0, 0, 0, 0, (int)curStepElapsedTime);
  653. var timeString = string.Format("{0}:{1}:{2}", ((int)tspan.TotalHours).ToString("00"), tspan.Minutes.ToString("00"), tspan.Seconds.ToString("00"));
  654. curStepNode.SetAttribute("Time", timeString);
  655. LOG.Write(string.Format("step skipped,step {0} time changed to {1}", currentStepNo, timeString));
  656. //recipe update command
  657. UpdateRecipe(xmlDoc.OuterXml);
  658. }
  659. }
  660. catch (Exception ex)
  661. {
  662. LOG.Write(ex);
  663. }
  664. if (_state == RecipeEngineState.ConditionWait || _state == RecipeEngineState.TimeWait)
  665. {
  666. _state = RecipeEngineState.StepCompleted;
  667. //send informational event
  668. EV.PostMessage(Module, EventEnum.RecipeStepSkipped, Module, CurrentRecipeRunningName, CurStepNum + 1);
  669. Singleton<ProcessRecorder>.Instance.AddRecord(Singleton<PMEntity>.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeStepJump, CurStepNum.ToString(), string.Format("Recipe Running:current step {0},skip to next step", CurStepNum + 1));
  670. }
  671. }
  672. public bool UpdateRecipe(string newRecipeContent)
  673. {
  674. lock (_recipeLocker)
  675. {
  676. RecipeHead head = null;
  677. List<RecipeStep> newRecipeData = null;
  678. if (!Recipe.Parse(newRecipeContent, out head, out newRecipeData))
  679. {
  680. EV.PostMessage(Module, EventEnum.ReadRecipeFail, Module, CurrentRecipeRunningName);
  681. return false;
  682. }
  683. else
  684. {
  685. string oldRecipeName = CurrentRecipeRunningName;
  686. CurrentRecipeRunningName = string.Format("{0}-{1}-({2})", DateTime.Now.ToString("yyyyMMddHHmmss"), CurrentRecipeBaseName, RecipeChangeNo++);
  687. //update local recipe data
  688. _recipeStepList = newRecipeData;
  689. CurrentRecipeContent = newRecipeContent;
  690. Singleton<ProcessRecorder>.Instance.UpdateProcessRecipeName(Singleton<PMEntity>.Instance.CurrentRunningJob.RecipeRunId, CurrentRecipeRunningName);
  691. //update susceptor recipe name
  692. //Susceptor sus = SusceptorManager.Instance.GetSystemSusceptors()[ModuleName.System];
  693. //if (sus != null)
  694. //{
  695. // sus.RecipeName = RecipeName;
  696. // SusceptorManager.Instance.Persist();
  697. //}
  698. //send informational event
  699. EV.PostMessage(Module, EventEnum.RecipeUpdated, Module, oldRecipeName, CurStepNum + 1, CurrentRecipeRunningName);
  700. Singleton<ProcessRecorder>.Instance.AddRecord(Singleton<PMEntity>.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeUpdated, CurStepNum.ToString(), string.Format("工艺运行中:当前第{0}步,更新程序:{1}", CurStepNum + 1, CurrentRecipeRunningName));
  701. //notify recipe change event to TM
  702. RecipeFileManager.Instance.SaveRecipeHistory(ModuleName.System.ToString(), CurrentRecipeRunningName, CurrentRecipeContent);
  703. }
  704. }
  705. return true;
  706. }
  707. /// <summary>
  708. /// Status name
  709. /// </summary>
  710. /// <returns></returns>
  711. public override string ToString()
  712. {
  713. return "recipe running";
  714. }
  715. protected void sendRecipeStopToSmart()
  716. {
  717. ///工艺停止发送StreamOffCommand
  718. // NotifierSmart.SendCommand("StreamOffCommand", Reactor.ChamId);
  719. }
  720. /// <summary>
  721. /// 工艺程序估计结束时间计算
  722. /// </summary>
  723. protected void CalcEstimatedRecipeEndTime()
  724. {
  725. try
  726. {
  727. //(*计算当前工艺程序预计所需的总时间,从当前步开始计算剩余步的估算时间+已经既成事实的时间 => 总的估计时间,采用该种方式进行总工艺时间理论上最为精确*)
  728. if (!_estimatedTimeCalcTimer.IsTimeout())
  729. return;
  730. _estimatedTimeCalcTimer.Start(1000);
  731. EstimatedTotalLeftTime = 0;
  732. if (_state == RecipeEngineState.RecipeCompleted)
  733. return;
  734. if (!(CurStepNum >= 0 && CurStepNum <= _recipeStepList.Count - 1))
  735. return;
  736. if (CurStepLeftTime > 0)
  737. {
  738. EstimatedTotalLeftTime = CurStepLeftTime;
  739. }
  740. int nextBegin = CurStepNum;
  741. //(*判断当前是否处于循环之中*)
  742. bool IsInLoop = false;
  743. int iNum1 = 0;
  744. int iNum2 = 0;
  745. //int j=i;
  746. for (int j = CurStepNum; j < _recipeStepList.Count; j++)
  747. {
  748. if (_recipeStepList[j].IsLoopEndStep)
  749. {
  750. iNum2 = j;
  751. IsInLoop = true;
  752. break;
  753. }
  754. else if (j > CurStepNum && _recipeStepList[j].IsLoopStartStep)
  755. {
  756. IsInLoop = false;
  757. break;
  758. }
  759. }
  760. if (IsInLoop)
  761. {
  762. //(*当前步处于循环中*)
  763. iNum1 = CurStepNum;
  764. for (int j = CurStepNum; j >= 0; j--)
  765. {
  766. if (_recipeStepList[j].IsLoopStartStep)
  767. {
  768. iNum1 = j;
  769. break;
  770. }
  771. }
  772. for (int j = CurStepNum + 1; j <= iNum2; j++)
  773. {
  774. EstimatedTotalLeftTime += _recipeStepList[j].StepTime * 1000 * (_recipeStepList[iNum1].LoopCount - CurrentLoopCount + 1);
  775. }
  776. for (int j = iNum1; j <= CurStepNum; j++)
  777. {
  778. EstimatedTotalLeftTime += _recipeStepList[j].StepTime * 1000 * (_recipeStepList[iNum1].LoopCount - CurrentLoopCount);
  779. }
  780. nextBegin = iNum2 + 1;
  781. }
  782. else
  783. {
  784. nextBegin++;
  785. }
  786. //(*当前步处于循环外*)
  787. for (int j = nextBegin; j < _recipeStepList.Count; j++)
  788. {
  789. if (_recipeStepList[j].IsLoopStartStep)
  790. {
  791. //j=i;
  792. iNum1 = j;
  793. iNum2 = j + 1;
  794. double lr1 = 0;
  795. for (int m = j; m < _recipeStepList.Count; m++)
  796. {
  797. lr1 += _recipeStepList[m].StepTime * 1000;
  798. if (_recipeStepList[m].IsLoopEndStep)
  799. {
  800. iNum2 = m;
  801. break;
  802. }
  803. }
  804. EstimatedTotalLeftTime = EstimatedTotalLeftTime + lr1 * _recipeStepList[iNum1].LoopCount;
  805. j = iNum2;
  806. }
  807. else
  808. {
  809. EstimatedTotalLeftTime += _recipeStepList[j].StepTime * 1000;
  810. }
  811. //END_WHILE
  812. }
  813. }
  814. catch (Exception ex)
  815. {
  816. LOG.Write(ex);
  817. }
  818. }
  819. }
  820. }