VpwVacuumPrewetRoutine.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  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)
  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. AlarmListManager.Instance.AddWarn(Module, "vacuum value", $"vacuum value {vacuumValue} is less than {_recipe.VacuumTarget}");
  193. }
  194. if (DateTime.Now.Subtract(_pumpDownTime).TotalMilliseconds >= _pumpDownTimeOut)
  195. {
  196. _isNeedRetry = true;
  197. }
  198. return false;
  199. }
  200. /// <summary>
  201. /// 检验Lid Release真空数值
  202. /// </summary>
  203. /// <returns></returns>
  204. private bool CheckLidReleaseVacuum()
  205. {
  206. double vacuumValue = _vpwCellDevice.CommonData.VacuumPressure;
  207. return vacuumValue <= _lidReleasePressure;
  208. }
  209. /// <summary>
  210. /// open vent valve
  211. /// </summary>
  212. /// <returns></returns>
  213. private bool OpenVentValve()
  214. {
  215. bool result = _vpwCellDevice.VentValveOn();
  216. if (!result)
  217. {
  218. NotifyError(eEvent.ERR_VPW, "open vent valve failed", 0);
  219. }
  220. return result;
  221. }
  222. /// <summary>
  223. /// close vent valve
  224. /// </summary>
  225. /// <returns></returns>
  226. private bool CloseVentValve()
  227. {
  228. bool result = _vpwCellDevice.VentValveOff();
  229. if (!result)
  230. {
  231. NotifyError(eEvent.ERR_VPW, "close vent valve failed", 0);
  232. }
  233. return result;
  234. }
  235. /// <summary>
  236. /// Chamber down
  237. /// </summary>
  238. /// <returns></returns>
  239. private bool ChamberDown()
  240. {
  241. bool result= _mainDevice.ChamberDown();
  242. if (!result)
  243. {
  244. NotifyError(eEvent.ERR_VPW, "chamber down failed",0);
  245. }
  246. return result;
  247. }
  248. /// <summary>
  249. /// 检验Chamber是否打开
  250. /// </summary>
  251. /// <returns></returns>
  252. private bool CheckChamberOpened()
  253. {
  254. return _mainDevice.CommonData.ChamberOpened && !_mainDevice.CommonData.ChamberClosed;
  255. }
  256. /// <summary>
  257. /// Chamber up
  258. /// </summary>
  259. /// <returns></returns>
  260. private bool ChamberUp()
  261. {
  262. bool result = _mainDevice.ChamberUp();
  263. if (!result)
  264. {
  265. NotifyError(eEvent.ERR_VPW, "chamber up failed", 0);
  266. }
  267. return result;
  268. }
  269. /// <summary>
  270. /// 检验Chamber是否关闭
  271. /// </summary>
  272. /// <returns></returns>
  273. private bool CheckChamberClosed()
  274. {
  275. return !_mainDevice.CommonData.ChamberOpened && _mainDevice.CommonData.ChamberClosed;
  276. }
  277. /// <summary>
  278. /// 检验真空
  279. /// </summary>
  280. /// <returns></returns>
  281. private bool LastCheckVacuumValue()
  282. {
  283. double vacuumValue = _vpwCellDevice.CommonData.VacuumPressure;
  284. if (vacuumValue >= _recipe.VacuumTarget)
  285. {
  286. return true;
  287. }
  288. if (DateTime.Now.Subtract(_pumpDownTime).TotalMilliseconds >= _pumpDownWarningTime)
  289. {
  290. AlarmListManager.Instance.AddWarn(Module, "vacuum value", $"vacuum value {vacuumValue} is less than {_recipe.VacuumTarget}");
  291. }
  292. return false;
  293. }
  294. /// <summary>
  295. /// 打开相应的cell valve
  296. /// </summary>
  297. /// <returns></returns>
  298. private bool OpenCellValve()
  299. {
  300. int count = 0;
  301. int enableCount = 0;
  302. if (_recipe.VacuumPrewetDripEnable)
  303. {
  304. count += _vpwCellDevice.FlowDripOn()?1:0;
  305. enableCount++;
  306. }
  307. else
  308. {
  309. _vpwCellDevice.FlowDripOff();
  310. }
  311. if (_recipe.VacuumPrewetLargeEnable)
  312. {
  313. count += _vpwCellDevice.FlowLargeOn() ? 1 : 0;
  314. enableCount++;
  315. }
  316. else
  317. {
  318. _vpwCellDevice.FlowLargeOff();
  319. }
  320. if (_recipe.VacuumPrewetSmallEnable)
  321. {
  322. count += _vpwCellDevice.FlowSmallOn() ? 1 : 0;
  323. enableCount++;
  324. }
  325. else
  326. {
  327. _vpwCellDevice.FlowSmallOff();
  328. }
  329. bool result = count == enableCount;
  330. if (!result)
  331. {
  332. NotifyError(eEvent.ERR_VPW, "open cell valve failed", 0);
  333. }
  334. //boost pump
  335. _mainDevice.VPWBoostPumpTarget = VPWBoostPumpTarget.CellFlow;
  336. _mainDevice.BoostTargetFlow = _recipe.VacuumPrewetFlowSetPoint;
  337. _mainDevice.CommonData.BoosterPumpSpeedAuto = true;
  338. _mainDevice.CellFlow = _vpwCellDevice.CommonData.DiwFlow;
  339. if (!_mainDevice.BoosterPumpSpeed())
  340. {
  341. NotifyError(eEvent.ERR_VPW, "boost pump speed failed", 0);
  342. return false;
  343. }
  344. if (!_mainDevice.BoosterPumpEnableOperation("",null))
  345. {
  346. NotifyError(eEvent.ERR_VPW, "pump enable error",0);
  347. return false;
  348. }
  349. _mainDevice.CommonData.BoosterPumpStatusContent = "Auto:On";
  350. result = StartRotation();
  351. if (!result)
  352. {
  353. NotifyError(eEvent.ERR_VPW, "start rotation failed", 0);
  354. return false;
  355. }
  356. _startStepTime = DateTime.Now;
  357. _stepIndex = 0;
  358. return result;
  359. }
  360. /// <summary>
  361. /// 同时旋转
  362. /// </summary>
  363. /// <returns></returns>
  364. private bool StartRotation()
  365. {
  366. int targetPosition = 0;
  367. int maxSpeed = 0;
  368. int second = 0;
  369. foreach(var item in _recipe.VacuumRinseStep)
  370. {
  371. second += item.DurationSeconds;
  372. _totalMicrosecond += second * 1000;
  373. int speed = item.RotationSpeed;
  374. if (maxSpeed < speed)
  375. {
  376. maxSpeed = speed;
  377. }
  378. }
  379. foreach(var item in _recipe.VentRinseStep)
  380. {
  381. second += item.DurationSeconds;
  382. int speed = item.RotationSpeed;
  383. if (maxSpeed < speed)
  384. {
  385. maxSpeed = speed;
  386. }
  387. }
  388. foreach(var item in _recipe.ExtendCleanRinseStep)
  389. {
  390. second += item.DurationSeconds;
  391. int speed = item.RotationSpeed;
  392. if (maxSpeed < speed)
  393. {
  394. maxSpeed = speed;
  395. }
  396. }
  397. second += _recipe.SpinTime;
  398. if (maxSpeed < _recipe.SpinSpeed)
  399. {
  400. maxSpeed= _recipe.SpinSpeed;
  401. }
  402. targetPosition = maxSpeed * (second + 60);//按最大速度*(时间+多出一分钟)
  403. _vpwCellDevice.SetRotationSpeed(_recipe.VacuumRinseStep[0].RotationSpeed * 6);
  404. return _vpwCellDevice.RotationProfilePosition(targetPosition);
  405. }
  406. /// <summary>
  407. /// 检验步骤是否完成
  408. /// </summary>
  409. /// <returns></returns>
  410. private bool CheckStepComplete()
  411. {
  412. _mainDevice.CellFlow = _vpwCellDevice.CommonData.DiwFlow;
  413. if (_stepIndex >= _recipe.VacuumRinseStep.Count)
  414. {
  415. LOG.WriteLog(eEvent.INFO_METAL, Module, $"vacuum step {_stepIndex} is over step count {_recipe.VacuumRinseStep.Count}");
  416. return true;
  417. }
  418. int length = _recipe.VacuumRinseStep[_stepIndex].DurationSeconds;
  419. if (DateTime.Now.Subtract(_startStepTime).TotalSeconds >= length)
  420. {
  421. _stepIndex++;
  422. _startStepTime = DateTime.Now;
  423. if (_stepIndex >= _recipe.VacuumRinseStep.Count)
  424. {
  425. LOG.WriteLog(eEvent.INFO_METAL, Module, $"vaccum step {_stepIndex} is over step count {_recipe.VacuumRinseStep.Count}");
  426. return true;
  427. }
  428. bool result = _vpwCellDevice.ChangeRotationSpeed(_recipe.VacuumRinseStep[_stepIndex].RotationSpeed*6);
  429. if (result)
  430. {
  431. LOG.WriteLog(eEvent.INFO_METAL, Module, $"vacuum step {_stepIndex} complete");
  432. }
  433. return result;
  434. }
  435. int firstDelay = SC.GetValue<int>($"{Module}.FlowCheckDelay") * 1000;
  436. if (DateTime.Now.Subtract(_startStepTime).TotalMilliseconds >= firstDelay)
  437. {
  438. bool abnormal = CheckDisable();
  439. if (abnormal)
  440. {
  441. return false;
  442. }
  443. }
  444. return false;
  445. }
  446. /// <summary>
  447. /// 检验数据
  448. /// </summary>
  449. /// <returns></returns>
  450. private bool CheckDisable()
  451. {
  452. double flow = _vpwCellDevice.CommonData.DiwFlow;
  453. double lowError = _recipe.VacuumPrewetFlowSetPoint * (1 - (double)_recipe.VacuumPrewetFlowErrorPercent / 100);
  454. double upError = _recipe.VacuumPrewetFlowSetPoint * (1 + (double)_recipe.VacuumPrewetFlowErrorPercent / 100);
  455. double lowWarn = _recipe.VacuumPrewetFlowSetPoint * (1 - (double)_recipe.VacuumPrewetFlowWarningPercent / 100);
  456. double upWarn = _recipe.VacuumPrewetFlowSetPoint * (1 + (double)_recipe.VacuumPrewetFlowWarningPercent / 100);
  457. if (flow<lowError)
  458. {
  459. NotifyError(eEvent.ERR_VPW, $"{Module} cell flow {flow} is less than {lowError} ", 0);
  460. Abort();
  461. return true;
  462. }
  463. if (flow > upError)
  464. {
  465. NotifyError(eEvent.ERR_VPW, $"{Module} cell flow {flow} is up than {upError} ", 0);
  466. Abort();
  467. return true;
  468. }
  469. if ((flow <= upError && flow >= upWarn) || (flow >= lowError && flow <= lowWarn))
  470. {
  471. string str = $"{Module} cell flow {flow} is in warning";
  472. if (AlarmListManager.Instance.AddWarn(Module, $"{Module} cell flow", str))
  473. {
  474. LOG.WriteLog(eEvent.WARN_VPW, Module, str);
  475. }
  476. }
  477. bool isSimulatorMode = SC.GetValue<bool>("System.IsSimulatorMode");
  478. if (!isSimulatorMode)
  479. {
  480. if (!_vpwCellDevice.CheckRotationRunning())
  481. {
  482. NotifyError(eEvent.ERR_VPW, $"{Module} rotation is stopped", 0);
  483. Abort();
  484. return true;
  485. }
  486. }
  487. return false;
  488. }
  489. /// <summary>
  490. /// 启动
  491. /// </summary>
  492. /// <param name="objs"></param>
  493. /// <returns></returns>
  494. public RState Start(params object[] objs)
  495. {
  496. _recipe=(VpwRecipe)objs[0];
  497. _vpwCellDevice = DEVICE.GetDevice<VpwCellDevice>(Module);
  498. _mainDevice = DEVICE.GetDevice<VpwMainDevice>(ModuleName.VPWMain1.ToString());
  499. _pumpDownWarningTime = SC.GetValue<int>($"{Module}.PumpDownWarningTime")*1000;
  500. _pumpDownTimeOut = SC.GetValue<int>($"{Module}.PumpDownTimeout")*1000;
  501. _lidReleasePressure = SC.GetValue<int>($"{Module}.LidReleasePressure");
  502. _lidReleasePressureTimeout = SC.GetValue<int>($"{Module}.LidReleasePressureTimeout");
  503. _isNeedRetry = false;
  504. _totalMicrosecond = 0;
  505. _stepIndex = 0;
  506. return Runner.Start(Module, $"{Module} vacuum prewet");
  507. }
  508. /// <summary>
  509. /// 重试
  510. /// </summary>
  511. /// <param name="step"></param>
  512. public RState Retry(int step)
  513. {
  514. if (_recipe == null)
  515. {
  516. NotifyError(eEvent.ERR_VPW, "recipe is null", -1);
  517. return RState.Failed;
  518. }
  519. List<Enum> preStepIds = new List<Enum>();
  520. return Runner.Retry(PrepareStep.OpenVacuumValve, preStepIds, Module, "Vacuum Prewet Retry");
  521. }
  522. }
  523. }