VpwVacuumPrewetRoutine.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  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. if (_recipe.VacuumPrewetLargeEnable)
  308. {
  309. count += _vpwCellDevice.FlowLargeOn() ? 1 : 0;
  310. enableCount++;
  311. }
  312. if (_recipe.VacuumPrewetSmallEnable)
  313. {
  314. count += _vpwCellDevice.FlowSmallOn() ? 1 : 0;
  315. enableCount++;
  316. }
  317. bool result= count == enableCount;
  318. if (!result)
  319. {
  320. NotifyError(eEvent.ERR_VPW, "open cell valve failed", 0);
  321. }
  322. //boost pump
  323. _mainDevice.VPWBoostPumpTarget = VPWBoostPumpTarget.CellFlow;
  324. _mainDevice.BoostTargetFlow = _recipe.VacuumPrewetFlowSetPoint;
  325. _mainDevice.CommonData.BoosterPumpSpeedAuto = true;
  326. _mainDevice.CellFlow = _vpwCellDevice.CommonData.DiwFlow;
  327. if (!_mainDevice.BoosterPumpSpeed())
  328. {
  329. NotifyError(eEvent.ERR_VPW, "boost pump speed failed", 0);
  330. return false;
  331. }
  332. if (!_mainDevice.BoosterPumpEnableOperation("",null))
  333. {
  334. NotifyError(eEvent.ERR_VPW, "pump enable error",0);
  335. return false;
  336. }
  337. _mainDevice.CommonData.BoosterPumpStatusContent = "Auto:On";
  338. result = StartRotation();
  339. if (!result)
  340. {
  341. NotifyError(eEvent.ERR_VPW, "start rotation failed", 0);
  342. return false;
  343. }
  344. _startStepTime = DateTime.Now;
  345. _stepIndex = 0;
  346. return result;
  347. }
  348. /// <summary>
  349. /// 同时旋转
  350. /// </summary>
  351. /// <returns></returns>
  352. private bool StartRotation()
  353. {
  354. int targetPosition = 0;
  355. int maxSpeed = 0;
  356. int second = 0;
  357. foreach(var item in _recipe.VacuumRinseStep)
  358. {
  359. second += item.DurationSeconds;
  360. _totalMicrosecond += second * 1000;
  361. int speed = item.RotationSpeed;
  362. if (maxSpeed < speed)
  363. {
  364. maxSpeed = speed;
  365. }
  366. }
  367. foreach(var item in _recipe.VentRinseStep)
  368. {
  369. second += item.DurationSeconds;
  370. int speed = item.RotationSpeed;
  371. if (maxSpeed < speed)
  372. {
  373. maxSpeed = speed;
  374. }
  375. }
  376. foreach(var item in _recipe.ExtendCleanRinseStep)
  377. {
  378. second += item.DurationSeconds;
  379. int speed = item.RotationSpeed;
  380. if (maxSpeed < speed)
  381. {
  382. maxSpeed = speed;
  383. }
  384. }
  385. second += _recipe.SpinTime;
  386. if (maxSpeed < _recipe.SpinSpeed)
  387. {
  388. maxSpeed= _recipe.SpinSpeed;
  389. }
  390. targetPosition = maxSpeed * (second + 60);//按最大速度*(时间+多出一分钟)
  391. _vpwCellDevice.SetRotationSpeed(_recipe.VacuumRinseStep[0].RotationSpeed * 6);
  392. return _vpwCellDevice.RotationProfilePosition(targetPosition);
  393. }
  394. /// <summary>
  395. /// 检验步骤是否完成
  396. /// </summary>
  397. /// <returns></returns>
  398. private bool CheckStepComplete()
  399. {
  400. _mainDevice.CellFlow = _vpwCellDevice.CommonData.DiwFlow;
  401. if (_stepIndex >= _recipe.VacuumRinseStep.Count)
  402. {
  403. LOG.WriteLog(eEvent.INFO_METAL, Module, $"vacuum step {_stepIndex} is over step count {_recipe.VacuumRinseStep.Count}");
  404. return true;
  405. }
  406. int length = _recipe.VacuumRinseStep[_stepIndex].DurationSeconds;
  407. if (DateTime.Now.Subtract(_startStepTime).TotalSeconds >= length)
  408. {
  409. _stepIndex++;
  410. _startStepTime = DateTime.Now;
  411. if (_stepIndex >= _recipe.VacuumRinseStep.Count)
  412. {
  413. LOG.WriteLog(eEvent.INFO_METAL, Module, $"vaccum step {_stepIndex} is over step count {_recipe.VacuumRinseStep.Count}");
  414. return true;
  415. }
  416. bool result = _vpwCellDevice.ChangeRotationSpeed(_recipe.VacuumRinseStep[_stepIndex].RotationSpeed*6);
  417. if (result)
  418. {
  419. LOG.WriteLog(eEvent.INFO_METAL, Module, $"vacuum step {_stepIndex} complete");
  420. }
  421. return result;
  422. }
  423. int firstDelay = SC.GetValue<int>($"{Module}.FlowCheckDelay") * 1000;
  424. if (DateTime.Now.Subtract(_startStepTime).TotalMilliseconds >= firstDelay)
  425. {
  426. bool abnormal = CheckDisable();
  427. if (abnormal)
  428. {
  429. return false;
  430. }
  431. }
  432. return false;
  433. }
  434. /// <summary>
  435. /// 检验数据
  436. /// </summary>
  437. /// <returns></returns>
  438. private bool CheckDisable()
  439. {
  440. double flow = _vpwCellDevice.CommonData.DiwFlow;
  441. double lowError = _recipe.VacuumPrewetFlowSetPoint * (1 - (double)_recipe.VacuumPrewetFlowErrorPercent / 100);
  442. double upError = _recipe.VacuumPrewetFlowSetPoint * (1 + (double)_recipe.VacuumPrewetFlowErrorPercent / 100);
  443. double lowWarn = _recipe.VacuumPrewetFlowSetPoint * (1 - (double)_recipe.VacuumPrewetFlowWarningPercent / 100);
  444. double upWarn = _recipe.VacuumPrewetFlowSetPoint * (1 + (double)_recipe.VacuumPrewetFlowWarningPercent / 100);
  445. if (flow<lowError)
  446. {
  447. NotifyError(eEvent.ERR_VPW, $"{Module} cell flow {flow} is less than {lowError} ", 0);
  448. Abort();
  449. return true;
  450. }
  451. if (flow > upError)
  452. {
  453. NotifyError(eEvent.ERR_VPW, $"{Module} cell flow {flow} is up than {upError} ", 0);
  454. Abort();
  455. return true;
  456. }
  457. if ((flow <= upError && flow >= upWarn) || (flow >= lowError && flow <= lowWarn))
  458. {
  459. string str = $"{Module} cell flow {flow} is in warning";
  460. if (AlarmListManager.Instance.AddWarn(Module, $"{Module} cell flow", str))
  461. {
  462. LOG.WriteLog(eEvent.WARN_VPW, Module, str);
  463. }
  464. }
  465. bool isSimulatorMode = SC.GetValue<bool>("System.IsSimulatorMode");
  466. if (!isSimulatorMode)
  467. {
  468. if (!_vpwCellDevice.CheckRotationRunning())
  469. {
  470. NotifyError(eEvent.ERR_VPW, $"{Module} rotation is stopped", 0);
  471. Abort();
  472. return true;
  473. }
  474. }
  475. return false;
  476. }
  477. /// <summary>
  478. /// 启动
  479. /// </summary>
  480. /// <param name="objs"></param>
  481. /// <returns></returns>
  482. public RState Start(params object[] objs)
  483. {
  484. _recipe=(VpwRecipe)objs[0];
  485. _vpwCellDevice = DEVICE.GetDevice<VpwCellDevice>(Module);
  486. _mainDevice = DEVICE.GetDevice<VpwMainDevice>(ModuleName.VPWMain1.ToString());
  487. _pumpDownWarningTime = SC.GetValue<int>($"{Module}.PumpDownWarningTime")*1000;
  488. _pumpDownTimeOut = SC.GetValue<int>($"{Module}.PumpDownTimeout")*1000;
  489. _lidReleasePressure = SC.GetValue<int>($"{Module}.LidReleasePressure");
  490. _lidReleasePressureTimeout = SC.GetValue<int>($"{Module}.LidReleasePressureTimeout");
  491. _isNeedRetry = false;
  492. _totalMicrosecond = 0;
  493. _stepIndex = 0;
  494. return Runner.Start(Module, $"{Module} vacuum prewet");
  495. }
  496. /// <summary>
  497. /// 重试
  498. /// </summary>
  499. /// <param name="step"></param>
  500. public RState Retry(int step)
  501. {
  502. if (_recipe == null)
  503. {
  504. NotifyError(eEvent.ERR_VPW, "recipe is null", -1);
  505. return RState.Failed;
  506. }
  507. List<Enum> preStepIds = new List<Enum>();
  508. return Runner.Retry(PrepareStep.OpenVacuumValve, preStepIds, Module, "Vacuum Prewet Retry");
  509. }
  510. }
  511. }