VpwVacuumPrewetRoutine.cs 19 KB

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