VpwVacuumPrewetRoutine.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. using Aitex.Core.RT.Device;
  2. using Aitex.Core.RT.Log;
  3. using Aitex.Core.RT.Routine;
  4. using Aitex.Core.RT.SCCore;
  5. using Aitex.Core.Util;
  6. using MECF.Framework.Common.Alarm;
  7. using MECF.Framework.Common.Equipment;
  8. using MECF.Framework.Common.RecipeCenter;
  9. using MECF.Framework.Common.Routine;
  10. using MECF.Framework.Common.SubstrateTrackings;
  11. using PunkHPX8_Core;
  12. using PunkHPX8_RT.Devices.AXIS;
  13. using PunkHPX8_RT.Devices.VpwCell;
  14. using PunkHPX8_RT.Devices.VpwMain;
  15. using PunkHPX8_RT.Modules.VpwMain;
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Diagnostics;
  19. using System.Linq;
  20. using System.Text;
  21. using System.Threading.Tasks;
  22. namespace PunkHPX8_RT.Modules.VpwCell
  23. {
  24. public class VpwVacuumPrewetRoutine : RoutineBase, IRoutine
  25. {
  26. private enum PrepareStep
  27. {
  28. OpenVacuumValve,
  29. EnableVacuumPump,
  30. CheckVacuum,
  31. CloseVacuumValve,
  32. OpenVentValve,
  33. CheckLidReleaseVacuum,
  34. ChamberDown,
  35. CloseVentValve,
  36. ChamberUp,
  37. LastOpenVacuumValve,
  38. LastCheckVacuum,
  39. DryerHoldTime,
  40. OpenCellValve,
  41. LoopStart,
  42. LoopRun,
  43. LoopEnd,
  44. End
  45. }
  46. #region 内部变量
  47. /// <summary>
  48. /// recipe
  49. /// </summary>
  50. private VpwRecipe _recipe;
  51. /// <summary>
  52. /// 设备
  53. /// </summary>
  54. private VpwCellDevice _vpwCellDevice;
  55. /// <summary>
  56. /// Main设备
  57. /// </summary>
  58. private VpwMainDevice _mainDevice;
  59. /// <summary>
  60. /// Pump DownWarn时间
  61. /// </summary>
  62. private int _pumpDownWarningTime = 60000;
  63. /// <summary>
  64. /// Pump Down超时
  65. /// </summary>
  66. private int _pumpDownTimeOut = 80000;
  67. /// <summary>
  68. /// 开始Pump Down时间
  69. /// </summary>
  70. private DateTime _pumpDownTime=DateTime.MinValue;
  71. /// <summary>
  72. /// 是否需要重试
  73. /// </summary>
  74. private bool _isNeedRetry = false;
  75. /// <summary>
  76. /// Lid Release Pressure
  77. /// </summary>
  78. private int _lidReleasePressure = 730;
  79. /// <summary>
  80. /// Lid Release Pressure
  81. /// </summary>
  82. private int _lidReleasePressureTimeout = 10000;
  83. /// <summary>
  84. /// 总时长
  85. /// </summary>
  86. private int _totalMicrosecond = 0;
  87. /// <summary>
  88. /// 步骤
  89. /// </summary>
  90. private int _stepIndex = 0;
  91. /// <summary>
  92. /// 启动步骤时间
  93. /// </summary>
  94. private DateTime _startStepTime = DateTime.Now;
  95. #endregion
  96. /// <summary>
  97. /// 构造函数
  98. /// </summary>
  99. /// <param name="module"></param>
  100. public VpwVacuumPrewetRoutine(string module) : base(module)
  101. {
  102. }
  103. /// <summary>
  104. /// 中止
  105. /// </summary>
  106. public void Abort()
  107. {
  108. Runner.Stop("Manual abort");
  109. _mainDevice.VPWBoostPumpTarget = VPWBoostPumpTarget.Pressure;
  110. }
  111. /// <summary>
  112. /// 监控
  113. /// </summary>
  114. /// <returns></returns>
  115. public RState Monitor()
  116. {
  117. Runner.Run(PrepareStep.OpenVacuumValve, PumpValveOn, _delay_1ms)
  118. .Run(PrepareStep.EnableVacuumPump, PumpEnable, _delay_1ms)
  119. .Wait(PrepareStep.CheckVacuum, CheckVacuumValue, _pumpDownTimeOut + 1000)
  120. .RunIf(PrepareStep.CloseVacuumValve, _isNeedRetry, PumpValveOff, _delay_1ms)
  121. .RunIf(PrepareStep.OpenVentValve, _isNeedRetry, OpenVentValve, _delay_1ms)
  122. .WaitIf(PrepareStep.CheckLidReleaseVacuum, _isNeedRetry, CheckLidReleaseVacuum, _lidReleasePressureTimeout*1000)
  123. .RunIf(PrepareStep.ChamberDown, _isNeedRetry, ChamberDown, CheckChamberOpened, _delay_10s)
  124. .RunIf(PrepareStep.CloseVentValve, _isNeedRetry, CloseVentValve, _delay_1ms)
  125. .RunIf(PrepareStep.ChamberUp, _isNeedRetry, ChamberUp, CheckChamberClosed, _delay_10s)
  126. .RunIf(PrepareStep.LastOpenVacuumValve, _isNeedRetry, PumpValveOn, _delay_1ms)
  127. .WaitIf(PrepareStep.LastCheckVacuum, _isNeedRetry,LastCheckVacuumValue, _pumpDownTimeOut)
  128. .Delay(PrepareStep.DryerHoldTime,_recipe.DryHoldTime*1000)
  129. .Run(PrepareStep.OpenCellValve,OpenCellValve,_delay_1ms)
  130. .LoopStart(PrepareStep.LoopStart,"Loop Step",_recipe.VacuumRinseStep.Count,NullFun,_delay_1ms)
  131. .LoopRunWithStopStatus(PrepareStep.LoopRun, CheckStepComplete, () => { return false; }, _totalMicrosecond + 60 * 1000)//总时长再延迟1分种
  132. .LoopEnd(PrepareStep.LoopEnd,NullFun,_delay_1ms)
  133. .End(PrepareStep.End,NullFun,_delay_1ms);
  134. return Runner.Status;
  135. }
  136. /// <summary>
  137. /// pump valve on
  138. /// </summary>
  139. /// <returns></returns>
  140. private bool PumpValveOn()
  141. {
  142. bool result = _vpwCellDevice.VacuumValveOn();
  143. if (!result)
  144. {
  145. NotifyError(eEvent.ERR_VPW, "pump valve on failed", 0);
  146. }
  147. return result;
  148. }
  149. /// <summary>
  150. /// Pump valve off
  151. /// </summary>
  152. /// <returns></returns>
  153. private bool PumpValveOff()
  154. {
  155. bool result = _vpwCellDevice.VacuumValveOff();
  156. if (!result)
  157. {
  158. NotifyError(eEvent.ERR_VPW, "pump valve off failed", 0);
  159. }
  160. return result;
  161. }
  162. /// <summary>
  163. /// Pump Enable
  164. /// </summary>
  165. /// <returns></returns>
  166. private bool PumpEnable()
  167. {
  168. bool result =_mainDevice.VacuumPumpEnable();
  169. if (!result)
  170. {
  171. NotifyError(eEvent.ERR_VPW, "pump enable failed", 0);
  172. }
  173. else
  174. {
  175. _pumpDownTime = DateTime.Now;
  176. }
  177. return result;
  178. }
  179. /// <summary>
  180. /// 检验真空
  181. /// </summary>
  182. /// <returns></returns>
  183. private bool CheckVacuumValue()
  184. {
  185. double vacuumValue = _vpwCellDevice.CommonData.VacuumPressure;
  186. if (vacuumValue <= _recipe.VacuumTarget)
  187. {
  188. return true;
  189. }
  190. if (DateTime.Now.Subtract(_pumpDownTime).TotalMilliseconds >= _pumpDownWarningTime)
  191. {
  192. LOG.WriteLog(eEvent.WARN_VPW, Module, $"vacuum value {vacuumValue} is less than {_recipe.VacuumTarget} in PumpDownWarningTime");
  193. //AlarmListManager.Instance.AddWarn(Module, "vacuum value", $"vacuum value {vacuumValue} is less than {_recipe.VacuumTarget}");
  194. }
  195. if (DateTime.Now.Subtract(_pumpDownTime).TotalMilliseconds >= _pumpDownTimeOut)
  196. {
  197. _isNeedRetry = true;
  198. LOG.WriteLog(eEvent.INFO_VPW, Module, $"Check Vacuum failed, Pump down retry start!");
  199. return true;
  200. }
  201. return false;
  202. }
  203. /// <summary>
  204. /// 检验Lid Release真空数值
  205. /// </summary>
  206. /// <returns></returns>
  207. private bool CheckLidReleaseVacuum()
  208. {
  209. double vacuumValue = _vpwCellDevice.CommonData.VacuumPressure;
  210. return vacuumValue >= _lidReleasePressure;
  211. }
  212. /// <summary>
  213. /// open vent valve
  214. /// </summary>
  215. /// <returns></returns>
  216. private bool OpenVentValve()
  217. {
  218. bool result = _vpwCellDevice.VentValveOn();
  219. if (!result)
  220. {
  221. NotifyError(eEvent.ERR_VPW, "open vent valve failed", 0);
  222. }
  223. return result;
  224. }
  225. /// <summary>
  226. /// close vent valve
  227. /// </summary>
  228. /// <returns></returns>
  229. private bool CloseVentValve()
  230. {
  231. bool result = _vpwCellDevice.VentValveOff();
  232. if (!result)
  233. {
  234. NotifyError(eEvent.ERR_VPW, "close vent valve failed", 0);
  235. }
  236. return result;
  237. }
  238. /// <summary>
  239. /// Chamber down
  240. /// </summary>
  241. /// <returns></returns>
  242. private bool ChamberDown()
  243. {
  244. bool result= _mainDevice.ChamberDown();
  245. if (!result)
  246. {
  247. NotifyError(eEvent.ERR_VPW, "chamber down failed",0);
  248. }
  249. return result;
  250. }
  251. /// <summary>
  252. /// 检验Chamber是否打开
  253. /// </summary>
  254. /// <returns></returns>
  255. private bool CheckChamberOpened()
  256. {
  257. return _mainDevice.CommonData.ChamberOpened && !_mainDevice.CommonData.ChamberClosed;
  258. }
  259. /// <summary>
  260. /// Chamber up
  261. /// </summary>
  262. /// <returns></returns>
  263. private bool ChamberUp()
  264. {
  265. bool result = _mainDevice.ChamberUp();
  266. if (!result)
  267. {
  268. NotifyError(eEvent.ERR_VPW, "chamber up failed", 0);
  269. }
  270. return result;
  271. }
  272. /// <summary>
  273. /// 检验Chamber是否关闭
  274. /// </summary>
  275. /// <returns></returns>
  276. private bool CheckChamberClosed()
  277. {
  278. return !_mainDevice.CommonData.ChamberOpened && _mainDevice.CommonData.ChamberClosed;
  279. }
  280. /// <summary>
  281. /// 检验真空
  282. /// </summary>
  283. /// <returns></returns>
  284. private bool LastCheckVacuumValue()
  285. {
  286. double vacuumValue = _vpwCellDevice.CommonData.VacuumPressure;
  287. if (vacuumValue <= _recipe.VacuumTarget)
  288. {
  289. return true;
  290. }
  291. if (DateTime.Now.Subtract(_pumpDownTime).TotalMilliseconds >= _pumpDownWarningTime)
  292. {
  293. AlarmListManager.Instance.AddWarn(Module, "vacuum value", $"vacuum value {vacuumValue} is less than {_recipe.VacuumTarget}");
  294. }
  295. return false;
  296. }
  297. /// <summary>
  298. /// 打开相应的cell valve
  299. /// </summary>
  300. /// <returns></returns>
  301. private bool OpenCellValve()
  302. {
  303. int count = 0;
  304. int enableCount = 0;
  305. if (_recipe.VacuumPrewetDripEnable)
  306. {
  307. count += _vpwCellDevice.FlowDripOn()?1:0;
  308. enableCount++;
  309. }
  310. else
  311. {
  312. _vpwCellDevice.FlowDripOff();
  313. }
  314. if (_recipe.VacuumPrewetLargeEnable)
  315. {
  316. count += _vpwCellDevice.FlowLargeOn() ? 1 : 0;
  317. enableCount++;
  318. }
  319. else
  320. {
  321. _vpwCellDevice.FlowLargeOff();
  322. }
  323. if (_recipe.VacuumPrewetSmallEnable)
  324. {
  325. count += _vpwCellDevice.FlowSmallOn() ? 1 : 0;
  326. enableCount++;
  327. }
  328. else
  329. {
  330. _vpwCellDevice.FlowSmallOff();
  331. }
  332. bool result = count == enableCount;
  333. if (!result)
  334. {
  335. NotifyError(eEvent.ERR_VPW, "open cell valve failed", 0);
  336. }
  337. //boost pump
  338. _mainDevice.VPWBoostPumpTarget = VPWBoostPumpTarget.CellFlow;
  339. _mainDevice.BoostTargetFlow = _recipe.VacuumPrewetFlowSetPoint;
  340. _mainDevice.CommonData.BoosterPumpSpeedAuto = true;
  341. _mainDevice.CellFlow = _vpwCellDevice.CommonData.DiwFlow;
  342. if (!_mainDevice.BoosterPumpSpeed())
  343. {
  344. NotifyError(eEvent.ERR_VPW, "boost pump speed failed", 0);
  345. return false;
  346. }
  347. if (!_mainDevice.BoosterPumpEnableOperation("",null))
  348. {
  349. NotifyError(eEvent.ERR_VPW, "pump enable error",0);
  350. return false;
  351. }
  352. _mainDevice.CommonData.BoosterPumpStatusContent = "Auto:On";
  353. result = StartRotation();
  354. if (!result)
  355. {
  356. NotifyError(eEvent.ERR_VPW, "start rotation failed", 0);
  357. return false;
  358. }
  359. _startStepTime = DateTime.Now;
  360. _stepIndex = 0;
  361. return result;
  362. }
  363. /// <summary>
  364. /// 同时旋转
  365. /// </summary>
  366. /// <returns></returns>
  367. private bool StartRotation()
  368. {
  369. int targetPosition = 0;
  370. int maxSpeed = 0;
  371. int second = 0;
  372. foreach(var item in _recipe.VacuumRinseStep)
  373. {
  374. second += item.DurationSeconds;
  375. _totalMicrosecond += second * 1000;
  376. int speed = item.RotationSpeed;
  377. if (maxSpeed < speed)
  378. {
  379. maxSpeed = speed;
  380. }
  381. }
  382. foreach(var item in _recipe.VentRinseStep)
  383. {
  384. second += item.DurationSeconds;
  385. int speed = item.RotationSpeed;
  386. if (maxSpeed < speed)
  387. {
  388. maxSpeed = speed;
  389. }
  390. }
  391. foreach(var item in _recipe.ExtendCleanRinseStep)
  392. {
  393. second += item.DurationSeconds;
  394. int speed = item.RotationSpeed;
  395. if (maxSpeed < speed)
  396. {
  397. maxSpeed = speed;
  398. }
  399. }
  400. second += _recipe.SpinTime;
  401. if (maxSpeed < _recipe.SpinSpeed)
  402. {
  403. maxSpeed= _recipe.SpinSpeed;
  404. }
  405. targetPosition = maxSpeed * (second + 60);//按最大速度*(时间+多出一分钟)
  406. _vpwCellDevice.SetRotationSpeed(_recipe.VacuumRinseStep[0].RotationSpeed * 6);
  407. return _vpwCellDevice.RotationProfilePosition(targetPosition);
  408. }
  409. /// <summary>
  410. /// 检验步骤是否完成
  411. /// </summary>
  412. /// <returns></returns>
  413. private bool CheckStepComplete()
  414. {
  415. _mainDevice.CellFlow = _vpwCellDevice.CommonData.DiwFlow;
  416. if (_stepIndex >= _recipe.VacuumRinseStep.Count)
  417. {
  418. LOG.WriteLog(eEvent.INFO_VPW, Module, $"vacuum step {_stepIndex} is over step count {_recipe.VacuumRinseStep.Count}");
  419. return true;
  420. }
  421. int length = _recipe.VacuumRinseStep[_stepIndex].DurationSeconds;
  422. if (DateTime.Now.Subtract(_startStepTime).TotalSeconds >= length)
  423. {
  424. _stepIndex++;
  425. _startStepTime = DateTime.Now;
  426. if (_stepIndex >= _recipe.VacuumRinseStep.Count)
  427. {
  428. LOG.WriteLog(eEvent.INFO_VPW, Module, $"vaccum step {_stepIndex} is over step count {_recipe.VacuumRinseStep.Count}");
  429. return true;
  430. }
  431. bool result = _vpwCellDevice.ChangeRotationSpeed(_recipe.VacuumRinseStep[_stepIndex].RotationSpeed*6);
  432. if (result)
  433. {
  434. LOG.WriteLog(eEvent.INFO_VPW, Module, $"vacuum step {_stepIndex} complete");
  435. }
  436. return result;
  437. }
  438. int firstDelay = SC.GetValue<int>($"{Module}.FlowCheckDelay") * 1000;
  439. if (DateTime.Now.Subtract(_startStepTime).TotalMilliseconds >= firstDelay)
  440. {
  441. bool abnormal = CheckDisable();
  442. if (abnormal)
  443. {
  444. return false;
  445. }
  446. }
  447. return false;
  448. }
  449. /// <summary>
  450. /// 检验数据
  451. /// </summary>
  452. /// <returns></returns>
  453. private bool CheckDisable()
  454. {
  455. double flow = _vpwCellDevice.CommonData.DiwFlow;
  456. double lowError = _recipe.VacuumPrewetFlowSetPoint * (1 - (double)_recipe.VacuumPrewetFlowErrorPercent / 100);
  457. double upError = _recipe.VacuumPrewetFlowSetPoint * (1 + (double)_recipe.VacuumPrewetFlowErrorPercent / 100);
  458. double lowWarn = _recipe.VacuumPrewetFlowSetPoint * (1 - (double)_recipe.VacuumPrewetFlowWarningPercent / 100);
  459. double upWarn = _recipe.VacuumPrewetFlowSetPoint * (1 + (double)_recipe.VacuumPrewetFlowWarningPercent / 100);
  460. if (flow<lowError)
  461. {
  462. NotifyError(eEvent.ERR_VPW, $"{Module} cell flow {flow} is less than {lowError} ", 0);
  463. Abort();
  464. return true;
  465. }
  466. if (flow > upError)
  467. {
  468. NotifyError(eEvent.ERR_VPW, $"{Module} cell flow {flow} is up than {upError} ", 0);
  469. Abort();
  470. return true;
  471. }
  472. if ((flow <= upError && flow >= upWarn) || (flow >= lowError && flow <= lowWarn))
  473. {
  474. string str = $"{Module} cell flow {flow} is in warning";
  475. if (AlarmListManager.Instance.AddWarn(Module, $"{Module} cell flow", str))
  476. {
  477. LOG.WriteLog(eEvent.WARN_VPW, Module, str);
  478. }
  479. }
  480. bool isSimulatorMode = SC.GetValue<bool>("System.IsSimulatorMode");
  481. if (!isSimulatorMode)
  482. {
  483. if (!_vpwCellDevice.CheckRotationRunning())
  484. {
  485. NotifyError(eEvent.ERR_VPW, $"{Module} rotation is stopped", 0);
  486. Abort();
  487. return true;
  488. }
  489. }
  490. return false;
  491. }
  492. /// <summary>
  493. /// 启动
  494. /// </summary>
  495. /// <param name="objs"></param>
  496. /// <returns></returns>
  497. public RState Start(params object[] objs)
  498. {
  499. _recipe=(VpwRecipe)objs[0];
  500. _vpwCellDevice = DEVICE.GetDevice<VpwCellDevice>(Module);
  501. _mainDevice = DEVICE.GetDevice<VpwMainDevice>(ModuleName.VPWMain1.ToString());
  502. _pumpDownWarningTime = SC.GetValue<int>($"{Module}.PumpDownWarningTime")*1000;
  503. _pumpDownTimeOut = SC.GetValue<int>($"{Module}.PumpDownTimeout")*1000;
  504. _lidReleasePressure = SC.GetValue<int>($"{Module}.LidReleasePressure");
  505. _lidReleasePressureTimeout = SC.GetValue<int>($"{Module}.LidReleasePressureTimeout");
  506. _isNeedRetry = false;
  507. _totalMicrosecond = 0;
  508. _stepIndex = 0;
  509. return Runner.Start(Module, $"{Module} vacuum prewet");
  510. }
  511. /// <summary>
  512. /// 重试
  513. /// </summary>
  514. /// <param name="step"></param>
  515. public RState Retry(int step)
  516. {
  517. if (_recipe == null)
  518. {
  519. NotifyError(eEvent.ERR_VPW, "recipe is null", -1);
  520. return RState.Failed;
  521. }
  522. List<Enum> preStepIds = new List<Enum>();
  523. return Runner.Retry(PrepareStep.OpenVacuumValve, preStepIds, Module, "Vacuum Prewet Retry");
  524. }
  525. }
  526. }