ReservoirRunRecipeRoutine.cs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  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 CyberX8_Core;
  7. using CyberX8_RT.Devices.Facilities;
  8. using CyberX8_RT.Devices.Metal;
  9. using CyberX8_RT.Devices.PowerSupplier;
  10. using CyberX8_RT.Devices.Reservoir;
  11. using CyberX8_RT.Devices.Temperature;
  12. using CyberX8_RT.Modules.Metal;
  13. using CyberX8_RT.Modules;
  14. using MECF.Framework.Common.Alarm;
  15. using MECF.Framework.Common.CommonData;
  16. using MECF.Framework.Common.CommonData.Metal;
  17. using MECF.Framework.Common.CommonData.PowerSupplier;
  18. using MECF.Framework.Common.Persistent.Reservoirs;
  19. using MECF.Framework.Common.RecipeCenter;
  20. using MECF.Framework.Common.Routine;
  21. using MECF.Framework.Common.ToolLayout;
  22. using System;
  23. using System.Collections.Generic;
  24. using System.Diagnostics;
  25. namespace CyberX8_RT.Modules.Metal
  26. {
  27. public class ReservoirRunRecipeRoutine : RoutineBase, IRoutine
  28. {
  29. #region 常量
  30. private const int LOTTRACK_TIME = 1000;
  31. private const string CDA_1_PRESSURE_VALUE = "CDA1Pressure";
  32. private const string CDA_2_PRESSURE_VALUE = "CDA2Pressure";
  33. private const string STRATUS = "Stratus";
  34. #endregion
  35. private enum RecipeStep
  36. {
  37. PlatingDelay,
  38. PlatingDelayCheck,
  39. HotPlating,
  40. WaitPlatingDelay,
  41. RunPowerStep,
  42. RunPowerStepWait,
  43. LoopStart,
  44. LoopCheckRun,
  45. LoopEnd,
  46. StopLinmot,
  47. StopPowerSuppliers,
  48. SwitchToNormal,
  49. WaferHolderUnclampOn,
  50. End
  51. }
  52. #region 常量
  53. private const string SIDE_A = "SideA";
  54. private const string SIDE_B = "SideB";
  55. #endregion
  56. #region 内部变量
  57. /// <summary>
  58. /// recipe
  59. /// </summary>
  60. private DepRecipe _recipe;
  61. /// <summary>
  62. /// Plate Delay时间
  63. /// </summary>
  64. private DateTime _platingDelayTime = DateTime.Now;
  65. /// <summary>
  66. /// 启动步骤时间
  67. /// </summary>
  68. private DateTime _startStepTime = DateTime.Now;
  69. /// <summary>
  70. /// 电量步骤计数
  71. /// </summary>
  72. private Stopwatch _stepWatch = new Stopwatch();
  73. /// <summary>
  74. /// Power 集合
  75. /// </summary>
  76. List<PowerSupplierStepPeriodData> _powerSupplierStepPeriodDatas = new List<PowerSupplierStepPeriodData>();
  77. /// <summary>
  78. /// 单面
  79. /// </summary>
  80. private string _side;
  81. /// <summary>
  82. /// 步骤索引
  83. /// </summary>
  84. private int _stepIndex = 0;
  85. /// <summary>
  86. /// 设备
  87. /// </summary>
  88. private MetalCellDevice _device;
  89. /// <summary>
  90. /// 设备Entity
  91. /// </summary>
  92. private MetalEntity _metalEntity;
  93. /// <summary>
  94. /// A面电量
  95. /// </summary>
  96. private double _anodeAUsage;
  97. /// <summary>
  98. /// B面电量
  99. /// </summary>
  100. private double _anodeBUsage;
  101. /// <summary>
  102. /// 是否启动recipe步骤
  103. /// </summary>
  104. private bool _startRecipeStep = false;
  105. /// <summary>
  106. /// lock track time
  107. /// </summary>
  108. private DateTime _lotTackTime = DateTime.Now;
  109. /// <summary>
  110. /// LotTrack数据
  111. /// </summary>
  112. private List<MetalLotTrackData> _datas = new List<MetalLotTrackData>();
  113. /// <summary>
  114. /// LotTrack文件头数据
  115. /// </summary>
  116. private LotTrackFileHeaderCommonData _header = new LotTrackFileHeaderCommonData();
  117. /// <summary>
  118. /// Facilities
  119. /// </summary>
  120. private SystemFacilities _facilities;
  121. /// <summary>
  122. /// StandardHot Reservoir Device
  123. /// </summary>
  124. private StandardHotReservoirDevice _standardHotReservoirDevice;
  125. /// <summary>
  126. /// StandardHot Metal Device
  127. /// </summary>
  128. private StandardHotMetalDevice _standardHotMetalDevice;
  129. /// <summary>
  130. /// CompactMembran Reservoir Device
  131. /// </summary>
  132. private CompactMembranReservoirDevice _compactMembranReservoirDevice;
  133. /// <summary>
  134. /// CompactMembran Reservoir Metal
  135. /// </summary>
  136. private CompactMembranMetalDevice _compactMembranMetalDevice;
  137. /// <summary>
  138. /// MetalType
  139. /// </summary>
  140. private string _metalType;
  141. /// <summary>
  142. /// TC device
  143. /// </summary>
  144. private TemperatureController _temperatureController;
  145. /// <summary>
  146. /// Persistent value
  147. /// </summary>
  148. private MetalPersistentValue _persistentValue;
  149. /// <summary>
  150. /// PlatingDelay计时
  151. /// </summary>
  152. private DateTime _hotPlatingRunTime;
  153. /// <summary>
  154. /// 是否处于warning状态
  155. /// </summary>
  156. private bool _isVotlageWarningA = false;
  157. private bool _isVotlageWarningB = false;
  158. private bool _isCurrentWarningA = false;
  159. private bool _isCurrentWarningB = false;
  160. private bool _isZeroCurrent = false;
  161. private int _totalMicrosecond = 0;
  162. #endregion
  163. #region 属性
  164. /// <summary>
  165. /// A面电量
  166. /// </summary>
  167. public double AnodeAUsage { get { return _anodeAUsage; } }
  168. /// <summary>
  169. /// B面电量
  170. /// </summary>
  171. public double AnodeBUsage { get { return _anodeBUsage; } }
  172. /// <summary>
  173. /// LotTrack数据
  174. /// </summary>
  175. public List<MetalLotTrackData> MetalLotTrackDatas { get { return _datas; } }
  176. /// <summary>
  177. /// LotTrack文件头数据
  178. /// </summary>
  179. public LotTrackFileHeaderCommonData MetalLotTrackHeaderDatas { get { return _header; } }
  180. #endregion
  181. /// <summary>
  182. /// 构造函数
  183. /// </summary>
  184. public ReservoirRunRecipeRoutine(string moduleName) : base(moduleName)
  185. {
  186. }
  187. /// <summary>
  188. /// 中止
  189. /// </summary>
  190. public void Abort()
  191. {
  192. if (_device != null)
  193. {
  194. _device.SideAPowerSupplier.DisableOperation("", null);
  195. _device.SideBPowerSupplier.DisableOperation("", null);
  196. _device.SideAPowerSupplier.SwitchPowerRunModel((int)PowerRunModelEnum.Normal);
  197. _device.SideBPowerSupplier.SwitchPowerRunModel((int)PowerRunModelEnum.Normal);
  198. if (_device.IsLinmotMotorOn)
  199. {
  200. _device.StopLinmot();
  201. }
  202. }
  203. Runner.Stop("Manual Abort");
  204. }
  205. /// <summary>
  206. /// 监控
  207. /// </summary>
  208. /// <returns></returns>
  209. public RState Monitor()
  210. {
  211. LottrackRecord();
  212. Runner.Run(RecipeStep.PlatingDelay, PlatingDelay, _delay_1ms)
  213. .WaitWithStopCondition(RecipeStep.PlatingDelayCheck, () => { return _device.CheckLinmotRoutineEnd(); }, () => { return _device.CheckLinmotRoutineError(); })
  214. .RunIf(RecipeStep.HotPlating, _recipe.HotPlatingCurrentOn, HotPlating, _delay_1ms)
  215. .RunIf(RecipeStep.WaitPlatingDelay, !_recipe.HotPlatingCurrentOn, NullFun, WaitPlatingDelay, _recipe.PlatingDelaySeconds * 1000 + 10000)
  216. .RunIf(RecipeStep.RunPowerStep, !_recipe.HotPlatingCurrentOn, StartPowerStep, _delay_1ms)
  217. .WaitWithStopCondition(RecipeStep.RunPowerStepWait, CheckRecipeStepEndStatus, CheckRecipeStepStopStatus, _delay_5s)
  218. .LoopStart(RecipeStep.LoopStart, "Loop update linmot speed", _powerSupplierStepPeriodDatas.Count, NullFun, _delay_1ms)
  219. .LoopRunWithStopStatus(RecipeStep.LoopCheckRun, CheckStepComplete, () => { return false; }, 24 * 60 * 60 * 1000)
  220. .LoopEnd(RecipeStep.LoopEnd, NullFun, _delay_1ms)
  221. .Run(RecipeStep.StopLinmot, StopLinmot, _delay_1ms)
  222. .Run(RecipeStep.StopPowerSuppliers, StopPowerSupplier, _delay_1ms)
  223. .Run(RecipeStep.SwitchToNormal, SwitchToNormal, _delay_1ms)
  224. .End(RecipeStep.End, NullFun, _delay_1ms);
  225. return Runner.Status;
  226. }
  227. /// <summary>
  228. /// 记录Lottrack
  229. /// </summary>
  230. private void LottrackRecord()
  231. {
  232. //记录Lottrack
  233. if (DateTime.Now.Subtract(_lotTackTime).TotalMilliseconds >= LOTTRACK_TIME)
  234. {
  235. AddLotTrackData();
  236. _lotTackTime = DateTime.Now;
  237. }
  238. }
  239. /// <summary>
  240. /// 获取Lot Track数据
  241. /// </summary>
  242. /// <returns></returns>
  243. public void AddLotTrackData()
  244. {
  245. MetalLotTrackData data = new MetalLotTrackData();
  246. if (_metalType == STRATUS)
  247. {
  248. data.Flow = _standardHotMetalDevice.MetalDeviceData.CellFlow;
  249. data.ANLevel = 0;
  250. data.CALevel = _standardHotReservoirDevice.ReservoirData.Level;
  251. data.CAPumpSpeed = 0;
  252. }
  253. else
  254. {
  255. data.Flow = _compactMembranMetalDevice.MetalDeviceData.CellFlow;
  256. data.ANLevel = _compactMembranReservoirDevice.ReservoirData.ANLevel;
  257. data.CALevel = _compactMembranReservoirDevice.ReservoirData.CALevel;
  258. data.CAPumpSpeed = _compactMembranReservoirDevice.ReservoirData.CAPumpSpeed;
  259. }
  260. data.RunTime = 0;
  261. data.ClampCycleEngaged = _recipe.CycleClampsEnable;
  262. data.Temperature = _temperatureController.TemperatureData.ReserviorTemperature;
  263. data.TimeStamp = DateTime.Now;
  264. data.PowerSupplyA = _device.SideAPowerSupplier.Name;
  265. data.PowerSupplyB = _device.SideBPowerSupplier.Name;
  266. data.PosVoltageA = _device.SideAPowerSupplier.PowerSupplierData.Voltage;
  267. data.PosCurrentA = _device.SideAPowerSupplier.PowerSupplierData.Current;
  268. data.PosVoltageB = _device.SideBPowerSupplier.PowerSupplierData.Voltage;
  269. data.PosCurrentB = _device.SideBPowerSupplier.PowerSupplierData.Current;
  270. data.CDA_1_Pressure = _facilities.GetCommonLimitDataByName(CDA_1_PRESSURE_VALUE).Value;
  271. data.CDA_2_Pressure = _facilities.GetCommonLimitDataByName(CDA_2_PRESSURE_VALUE).Value;
  272. int maxStep = _powerSupplierStepPeriodDatas.Count;
  273. if (_stepIndex < maxStep)
  274. {
  275. data.StepNum = _stepIndex + 1;
  276. int length = _powerSupplierStepPeriodDatas[_stepIndex].Hour * 3600 + _powerSupplierStepPeriodDatas[_stepIndex].Minute * 60 +
  277. _powerSupplierStepPeriodDatas[_stepIndex].Second;
  278. data.DurationRef = length;
  279. data.ShearPlateSpeed = _recipe.CurrentRampProfileSteps[_stepIndex].ShearPlateSpeed;
  280. data.CurrentSP = _recipe.CurrentRampProfileSteps[_stepIndex].ForwardAmps;
  281. }
  282. else
  283. {
  284. data.StepNum = maxStep;
  285. int length = _powerSupplierStepPeriodDatas[maxStep - 1].Hour * 3600 + _powerSupplierStepPeriodDatas[maxStep - 1].Minute * 60 +
  286. _powerSupplierStepPeriodDatas[maxStep - 1].Second;
  287. data.DurationRef = length;
  288. data.ShearPlateSpeed = _recipe.CurrentRampProfileSteps[maxStep - 1].ShearPlateSpeed;
  289. data.CurrentSP = _recipe.CurrentRampProfileSteps[maxStep - 1].ForwardAmps;
  290. }
  291. RecipeStep step = (RecipeStep)Runner.CurrentStep;
  292. if (step <= RecipeStep.WaitPlatingDelay)
  293. {
  294. if (!_recipe.HotPlatingCurrentOn)
  295. {
  296. data.RunTime = DateTime.Now.Subtract(_hotPlatingRunTime).TotalSeconds;
  297. data.DurationRef = _recipe.PlatingDelaySeconds;
  298. data.StepNum = 0;
  299. }
  300. else
  301. {
  302. data.RunTime = 0;
  303. data.DurationRef = _recipe.PlatingDelaySeconds;
  304. data.StepNum = 0;
  305. }
  306. }
  307. else
  308. {
  309. if (_recipe.HotPlatingCurrentOn)
  310. {
  311. if (DateTime.Now.Subtract(_hotPlatingRunTime).TotalSeconds <= _recipe.PlatingDelaySeconds)
  312. {
  313. data.RunTime = DateTime.Now.Subtract(_hotPlatingRunTime).TotalSeconds;
  314. data.DurationRef = _recipe.PlatingDelaySeconds;
  315. data.StepNum = 0;
  316. }
  317. else
  318. {
  319. if (data.StepNum == 1) data.DurationRef -= _recipe.PlatingDelaySeconds;
  320. data.RunTime = (data.StepNum == 1) ? (DateTime.Now.Subtract(_startStepTime).TotalSeconds - _recipe.PlatingDelaySeconds) : DateTime.Now.Subtract(_startStepTime).TotalSeconds;
  321. }
  322. }
  323. else
  324. {
  325. data.RunTime = DateTime.Now.Subtract(_startStepTime).TotalSeconds;
  326. }
  327. }
  328. _datas.Add(data);
  329. }
  330. /// <summary>
  331. /// Plate Delay
  332. /// </summary>
  333. /// <returns></returns>
  334. private bool PlatingDelay()
  335. {
  336. double speed = _recipe.CurrentRampProfileSteps[0].ShearPlateSpeed;
  337. bool result = _device.StartCurveMotion((int)speed);
  338. if (result)
  339. {
  340. _platingDelayTime = DateTime.Now;
  341. if (!_recipe.HotPlatingCurrentOn) _hotPlatingRunTime = DateTime.Now;
  342. }
  343. return result;
  344. }
  345. /// <summary>
  346. /// Hot Plating
  347. /// </summary>
  348. /// <returns></returns>
  349. private bool HotPlating()
  350. {
  351. UpdateHotPlatingStepDatas();
  352. return StartPowerStep();
  353. }
  354. /// <summary>
  355. /// 启动PowerSupplier
  356. /// </summary>
  357. /// <returns></returns>
  358. private bool StartPowerStep()
  359. {
  360. if (_isZeroCurrent)
  361. {
  362. _startStepTime = DateTime.Now;
  363. return true;
  364. }
  365. if (string.IsNullOrEmpty(_side))
  366. {
  367. bool result = StartPowerStep(_device.SideAPowerSupplier);
  368. if (result)
  369. {
  370. result = StartPowerStep(_device.SideBPowerSupplier);
  371. if (!result)
  372. {
  373. _device.SideAPowerSupplier.DisableOperation("", null);
  374. _device.SideBPowerSupplier.DisableOperation("", null);
  375. return false;
  376. }
  377. else
  378. {
  379. _startStepTime = DateTime.Now;
  380. _hotPlatingRunTime = DateTime.Now;
  381. _stepWatch.Restart();
  382. _startRecipeStep = true;
  383. return true;
  384. }
  385. }
  386. else
  387. {
  388. _device.SideAPowerSupplier.DisableOperation("", null);
  389. return false;
  390. }
  391. }
  392. else
  393. {
  394. CellPowerSupplier cellPowerSupplier = GetSidePowerSupplier();
  395. bool result = StartPowerStep(cellPowerSupplier);
  396. if (!result)
  397. {
  398. cellPowerSupplier.DisableOperation("", null);
  399. _stepWatch.Restart();
  400. return false;
  401. }
  402. _startStepTime = DateTime.Now;
  403. _hotPlatingRunTime = DateTime.Now;
  404. _startRecipeStep = true;
  405. return true;
  406. }
  407. }
  408. /// <summary>
  409. /// 检验Powerstep是否启动完成
  410. /// </summary>
  411. /// <returns></returns>
  412. private bool CheckRecipeStepEndStatus()
  413. {
  414. if (_isZeroCurrent)
  415. {
  416. return true;
  417. }
  418. if (_startRecipeStep)
  419. {
  420. if (string.IsNullOrEmpty(_side))
  421. {
  422. bool resultA = _device.SideAPowerSupplier.Status == RState.End;
  423. bool resultB = _device.SideBPowerSupplier.Status == RState.End;
  424. return resultA && resultB;
  425. }
  426. else
  427. {
  428. CellPowerSupplier cellPowerSupplier = GetSidePowerSupplier();
  429. return cellPowerSupplier.Status == RState.End;
  430. }
  431. }
  432. return true;
  433. }
  434. /// <summary>
  435. /// 检验Powerstep是否启动完成
  436. /// </summary>
  437. /// <returns></returns>
  438. private bool CheckRecipeStepStopStatus()
  439. {
  440. if (_isZeroCurrent)
  441. {
  442. return false;
  443. }
  444. if (_startRecipeStep)
  445. {
  446. if (string.IsNullOrEmpty(_side))
  447. {
  448. bool resultA = _device.SideAPowerSupplier.Status == RState.Failed || _device.SideAPowerSupplier.Status == RState.Timeout;
  449. bool resultB = _device.SideBPowerSupplier.Status == RState.Failed || _device.SideBPowerSupplier.Status == RState.Timeout;
  450. return resultA && resultB;
  451. }
  452. else
  453. {
  454. CellPowerSupplier cellPowerSupplier = GetSidePowerSupplier();
  455. return cellPowerSupplier.Status == RState.Failed || cellPowerSupplier.Status == RState.Timeout;
  456. }
  457. }
  458. return false;
  459. }
  460. /// <summary>
  461. /// 获取单面PowerSupplier
  462. /// </summary>
  463. /// <returns></returns>
  464. private CellPowerSupplier GetSidePowerSupplier()
  465. {
  466. if (_side == SIDE_A)
  467. {
  468. return _device.SideAPowerSupplier;
  469. }
  470. else
  471. {
  472. return _device.SideBPowerSupplier;
  473. }
  474. }
  475. /// <summary>
  476. /// 启动
  477. /// </summary>
  478. /// <returns></returns>
  479. private bool StartPowerStep(CellPowerSupplier cellPowerSupplier)
  480. {
  481. bool result = cellPowerSupplier.StartSetStepPeriodNoWaitEnd(_powerSupplierStepPeriodDatas);
  482. if (!result)
  483. {
  484. cellPowerSupplier.DisableOperation("", null);
  485. return false;
  486. }
  487. return true;
  488. }
  489. /// <summary>
  490. /// 更新HotPlating step数据
  491. /// </summary>
  492. private void UpdateHotPlatingStepDatas()
  493. {
  494. ushort second = _powerSupplierStepPeriodDatas[0].Second;
  495. ushort minute = _powerSupplierStepPeriodDatas[0].Minute;
  496. ushort hour = _powerSupplierStepPeriodDatas[0].Hour;
  497. if (second + _recipe.PlatingDelaySeconds >= 60)
  498. {
  499. if (minute + 1 < 60)
  500. {
  501. _powerSupplierStepPeriodDatas[0].Minute = (ushort)(minute + 1);
  502. }
  503. else
  504. {
  505. _powerSupplierStepPeriodDatas[0].Minute = 0;
  506. _powerSupplierStepPeriodDatas[0].Hour = (ushort)(hour + 1);
  507. }
  508. _powerSupplierStepPeriodDatas[0].Second = (ushort)(second + _recipe.PlatingDelaySeconds - 60);
  509. }
  510. else
  511. {
  512. _powerSupplierStepPeriodDatas[0].Second = (ushort)(second + _recipe.PlatingDelaySeconds);
  513. }
  514. }
  515. /// <summary>
  516. /// 更新Power step步骤
  517. /// </summary>
  518. private void UpdatePowerStepDatas()
  519. {
  520. _isZeroCurrent = false;
  521. double current = 0;
  522. _totalMicrosecond = 0;
  523. _powerSupplierStepPeriodDatas.Clear();
  524. foreach (var item in _recipe.CurrentRampProfileSteps)
  525. {
  526. PowerSupplierStepPeriodData step = new PowerSupplierStepPeriodData();
  527. step.Current = item.ForwardAmps;
  528. step.Hour = (ushort)(item.CurrentRampDurartionSeconds / 3600);
  529. step.Minute = (ushort)((item.CurrentRampDurartionSeconds - step.Hour * 3600) / 60);
  530. step.Second = (ushort)(item.CurrentRampDurartionSeconds % 60);
  531. step.Microsecond = 0;
  532. step.Voltage = _recipe.VoltageWarningLevel;
  533. _powerSupplierStepPeriodDatas.Add(step);
  534. current += step.Current;
  535. _totalMicrosecond += item.CurrentRampDurartionSeconds * 1000;
  536. }
  537. if (current == 0)
  538. {
  539. _isZeroCurrent = true;
  540. }
  541. }
  542. /// <summary>
  543. /// 等待Plating Delay结束
  544. /// </summary>
  545. /// <returns></returns>
  546. private bool WaitPlatingDelay()
  547. {
  548. if (DateTime.Now.Subtract(_platingDelayTime).TotalSeconds >= _recipe.PlatingDelaySeconds)
  549. {
  550. return true;
  551. }
  552. return false;
  553. }
  554. /// <summary>
  555. /// 检验步骤是否完成
  556. /// </summary>
  557. /// <returns></returns>
  558. private bool CheckStepComplete()
  559. {
  560. if (_stepIndex >= _powerSupplierStepPeriodDatas.Count)
  561. {
  562. _stepWatch.Stop();
  563. LOG.WriteLog(eEvent.INFO_METAL, Module, $"step {_stepIndex} is over step count {_powerSupplierStepPeriodDatas.Count}");
  564. return true;
  565. }
  566. int firstDelay = 2000;
  567. if (_stepIndex == 0)
  568. {
  569. firstDelay = SC.GetValue<int>("Metal.CurrentCheckDelay") * 1000;
  570. }
  571. if (DateTime.Now.Subtract(_startStepTime).TotalMilliseconds >= firstDelay)
  572. {
  573. bool abnormal = CheckMetalDisable();
  574. if (abnormal)
  575. {
  576. return false;
  577. }
  578. }
  579. int length = _powerSupplierStepPeriodDatas[_stepIndex].Hour * 3600 + _powerSupplierStepPeriodDatas[_stepIndex].Minute * 60 +
  580. _powerSupplierStepPeriodDatas[_stepIndex].Second;
  581. if (DateTime.Now.Subtract(_startStepTime).TotalSeconds >= length)
  582. {
  583. _stepIndex++;
  584. if (_stepIndex >= _powerSupplierStepPeriodDatas.Count)
  585. {
  586. _stepWatch.Stop();
  587. LOG.WriteLog(eEvent.INFO_METAL, Module, $"step {_stepIndex} is over step count {_powerSupplierStepPeriodDatas.Count}");
  588. return true;
  589. }
  590. bool result = _device.ChangeCurveSpeedMotion((int)_recipe.CurrentRampProfileSteps[_stepIndex].ShearPlateSpeed);
  591. if (result)
  592. {
  593. LOG.WriteLog(eEvent.INFO_METAL, Module, $"step {_stepIndex} complete");
  594. _startStepTime = DateTime.Now;
  595. }
  596. return result;
  597. }
  598. double second = (double)_stepWatch.ElapsedMilliseconds / 1000;
  599. if (string.IsNullOrEmpty(_side))
  600. {
  601. _anodeAUsage += _device.SideAPowerSupplier.PowerSupplierData.Current * second / 3600;
  602. _anodeBUsage += _device.SideBPowerSupplier.PowerSupplierData.Current * second / 3600;
  603. }
  604. else if (_side == SIDE_A)
  605. {
  606. _anodeAUsage += _device.SideAPowerSupplier.PowerSupplierData.Current * second / 3600;
  607. }
  608. else
  609. {
  610. _anodeBUsage += _device.SideBPowerSupplier.PowerSupplierData.Current * second / 3600;
  611. }
  612. _stepWatch.Restart();
  613. return false;
  614. }
  615. /// <summary>
  616. /// 检验Power是否Disable
  617. /// </summary>
  618. /// <returns></returns>
  619. private bool CheckMetalDisable()
  620. {
  621. if (!_device.IsLinmotMotorOn)
  622. {
  623. LOG.WriteLog(eEvent.ERR_METAL, Module, "Linmot is not motor on");
  624. Abort();
  625. return true;
  626. }
  627. //CheckVotlageAndCurrent();
  628. if (!CheckVoltageAndCurrentValid())
  629. {
  630. Abort();
  631. return true;
  632. }
  633. return false;
  634. }
  635. /// <summary>
  636. /// 检验电压电流的合理性
  637. /// </summary>
  638. /// <returns></returns>
  639. private bool CheckVoltageAndCurrentValid()
  640. {
  641. //零电流不检验
  642. if (_isZeroCurrent)
  643. {
  644. return true;
  645. }
  646. if (string.IsNullOrEmpty(_side))
  647. {
  648. if (!_device.SideAPowerSupplier.PowerSupplierData.Enabled)
  649. {
  650. LOG.WriteLog(eEvent.ERR_METAL, Module, "PowerA disable");
  651. return false;
  652. }
  653. if (!_device.SideBPowerSupplier.PowerSupplierData.Enabled)
  654. {
  655. LOG.WriteLog(eEvent.ERR_METAL, Module, "PowerB disable");
  656. return false;
  657. }
  658. }
  659. else
  660. {
  661. if (_side == SIDE_A && !_device.SideAPowerSupplier.PowerSupplierData.Enabled)
  662. {
  663. LOG.WriteLog(eEvent.ERR_METAL, Module, "PowerA disable");
  664. return false;
  665. }
  666. if (_side == SIDE_B && !_device.SideBPowerSupplier.PowerSupplierData.Enabled)
  667. {
  668. LOG.WriteLog(eEvent.ERR_METAL, Module, "PowerB disable");
  669. return false;
  670. }
  671. }
  672. double sideACurrent = _device.SideAPowerSupplier.PowerSupplierData.Current;
  673. double sideAVoltage = _device.SideAPowerSupplier.PowerSupplierData.Voltage;
  674. double sideBCurrent = _device.SideBPowerSupplier.PowerSupplierData.Current;
  675. double sideBVoltage = _device.SideBPowerSupplier.PowerSupplierData.Voltage;
  676. if (string.IsNullOrEmpty(_side))
  677. {
  678. bool sideAValid = CheckSidePowerInvalid(sideACurrent, sideAVoltage, SIDE_A);
  679. if (sideAValid)
  680. {
  681. return false;
  682. }
  683. bool sideBValid = CheckSidePowerInvalid(sideBCurrent, sideBVoltage, SIDE_B);
  684. if (sideBValid)
  685. {
  686. return false;
  687. }
  688. }
  689. else
  690. {
  691. if (_side == SIDE_A)
  692. {
  693. bool sideAValid = CheckSidePowerInvalid(sideACurrent, sideAVoltage, SIDE_A);
  694. if (sideAValid)
  695. {
  696. return false;
  697. }
  698. }
  699. else
  700. {
  701. bool sideBValid = CheckSidePowerInvalid(sideBCurrent, sideBVoltage, SIDE_B);
  702. if (sideBValid)
  703. {
  704. return false;
  705. }
  706. }
  707. }
  708. return true;
  709. }
  710. /// <summary>
  711. /// 检验电流和电压合理性
  712. /// </summary>
  713. /// <param name="current"></param>
  714. /// <param name="voltage"></param>
  715. /// <param name="side"></param>
  716. /// <returns></returns>
  717. private bool CheckSidePowerInvalid(double current, double voltage, string side)
  718. {
  719. double maxVoltage = _recipe.VolatageLimitMax;
  720. double warnVoltage = _recipe.VoltageWarningLevel;
  721. double minVoltage = _recipe.VolatageLimitMin;
  722. if (voltage > maxVoltage)
  723. {
  724. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{side} voltage {voltage} is large than recipe max voltage {maxVoltage}");
  725. return true;
  726. }
  727. if (voltage < minVoltage)
  728. {
  729. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{side} voltage {voltage} is less than recipe min voltage {minVoltage}");
  730. return true;
  731. }
  732. if (voltage > warnVoltage)
  733. {
  734. string str = $"{side} voltage is {voltage} in warning";
  735. if (AlarmListManager.Instance.AddWarn(Module, $"{side} voltage", str))
  736. {
  737. LOG.WriteLog(eEvent.WARN_PREWET, Module, str);
  738. }
  739. }
  740. double maxErrorCurrent = _powerSupplierStepPeriodDatas[_stepIndex].Current * (double)(1 + _recipe.FaultPercent * 0.01);
  741. double minErrorCurrent = _powerSupplierStepPeriodDatas[_stepIndex].Current * (double)(1 - _recipe.FaultPercent * 0.01);
  742. double maxWarnCurrent = _powerSupplierStepPeriodDatas[_stepIndex].Current * (double)(1 + _recipe.CurrentWarningLevel * 0.01);
  743. double minWarnCurrent = _powerSupplierStepPeriodDatas[_stepIndex].Current * (double)(1 - _recipe.CurrentWarningLevel * 0.01);
  744. if (current > maxErrorCurrent)
  745. {
  746. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{side} current {current} is large than recipe max current {maxErrorCurrent}");
  747. return true;
  748. }
  749. if (current < minErrorCurrent)
  750. {
  751. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{side} current {current} is less than recipe min current {minErrorCurrent}");
  752. return true;
  753. }
  754. if ((current <= maxErrorCurrent && current >= maxWarnCurrent) || (current >= minErrorCurrent && current <= minWarnCurrent))
  755. {
  756. string str = $"{side} current {current} is in warning";
  757. if (AlarmListManager.Instance.AddWarn(Module, $"{side} current", str))
  758. {
  759. LOG.WriteLog(eEvent.WARN_PREWET, Module, str);
  760. }
  761. }
  762. return false;
  763. }
  764. /// <summary>
  765. /// 停止Linmot
  766. /// </summary>
  767. /// <returns></returns>
  768. private bool StopLinmot()
  769. {
  770. return _device.StopLinmot();
  771. }
  772. /// <summary>
  773. /// 停止电源
  774. /// </summary>
  775. /// <returns></returns>
  776. private bool StopPowerSupplier()
  777. {
  778. if (string.IsNullOrEmpty(_side))
  779. {
  780. _device.SideAPowerSupplier.DisableOperation("", null);
  781. _device.SideBPowerSupplier.DisableOperation("", null);
  782. }
  783. else
  784. {
  785. CellPowerSupplier cellPowerSupplier = GetSidePowerSupplier();
  786. cellPowerSupplier.DisableOperation("", null);
  787. }
  788. return true;
  789. }
  790. /// <summary>
  791. /// 切换成正常模式
  792. /// </summary>
  793. /// <returns></returns>
  794. private bool SwitchToNormal()
  795. {
  796. if (string.IsNullOrEmpty(_side))
  797. {
  798. _device.SideAPowerSupplier.SwitchPowerRunModel((int)PowerRunModelEnum.Normal);
  799. _device.SideBPowerSupplier.SwitchPowerRunModel((int)PowerRunModelEnum.Normal);
  800. }
  801. else
  802. {
  803. CellPowerSupplier cellPowerSupplier = GetSidePowerSupplier();
  804. cellPowerSupplier.SwitchPowerRunModel((int)PowerRunModelEnum.Normal);
  805. }
  806. return true;
  807. }
  808. /// <summary>
  809. /// 启动
  810. /// </summary>
  811. /// <param name="objs"></param>
  812. /// <returns></returns>
  813. public RState Start(params object[] objs)
  814. {
  815. _isVotlageWarningA = false;
  816. _isVotlageWarningB = false;
  817. _isCurrentWarningA = false;
  818. _isCurrentWarningB = false;
  819. _recipe = objs[0] as DepRecipe;
  820. if (_recipe == null)
  821. {
  822. LOG.WriteLog(eEvent.ERR_METAL, Module, "recipe is null");
  823. return RState.Failed;
  824. }
  825. if (objs.Length > 1)
  826. {
  827. _side = objs[1].ToString();
  828. }
  829. _startRecipeStep = false;
  830. _anodeAUsage = 0;
  831. _anodeBUsage = 0;
  832. _device = DEVICE.GetDevice<MetalCellDevice>(Module);
  833. _metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(Module);
  834. UpdatePowerStepDatas();
  835. _stepIndex = 0;
  836. _header.SoftWareVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
  837. _header.Recipe = $"{_recipe.Ppid}.dep.rcp";
  838. if (SC.ContainsItem("System.ToolID")) _header.ToolID = SC.GetStringValue("System.ToolID");
  839. //lotTract记录SequenceRecipe
  840. MetalEntity metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(Module);
  841. if (metalEntity.WaferHolderInfo != null && metalEntity.WaferHolderInfo.SequenceRecipe != null && !String.IsNullOrEmpty(metalEntity.WaferHolderInfo.SequenceRecipe.Ppid.ToString()))
  842. {
  843. _header.SequenceRecipe = metalEntity.WaferHolderInfo.SequenceRecipe.Ppid.ToString();
  844. _header.ProcessTransferList = new List<string>();
  845. _header.ProcessTransferList.AddRange(metalEntity.WaferHolderInfo.SchedulerModules);
  846. metalEntity.WaferHolderInfo.SchedulerModules.Clear();
  847. }
  848. _facilities = DEVICE.GetDevice<SystemFacilities>("System.Facilities");
  849. if (_facilities == null)
  850. {
  851. LOG.WriteLog(eEvent.ERR_METAL, Module, "Facility is null");
  852. return RState.Failed;
  853. }
  854. string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module);
  855. MetalItem metalItem = MetalItemManager.Instance.GetMetalItem(Module);
  856. _metalType = metalItem.SubType;
  857. if (_metalType == STRATUS)
  858. {
  859. _standardHotReservoirDevice = DEVICE.GetDevice<StandardHotReservoirDevice>(reservoirName);
  860. _standardHotMetalDevice = DEVICE.GetDevice<StandardHotMetalDevice>(Module);
  861. if (_standardHotReservoirDevice == null || _standardHotMetalDevice == null)
  862. {
  863. LOG.WriteLog(eEvent.ERR_METAL, Module, $"metal or reservoir device is null");
  864. return RState.Failed;
  865. }
  866. if (_standardHotMetalDevice.MetalDeviceData.CellFlow <= 0) //检查cell flow
  867. {
  868. LOG.WriteLog(eEvent.ERR_METAL, Module, $"reservoir metal cell flow is 0");
  869. return RState.Failed;
  870. }
  871. }
  872. else
  873. {
  874. _compactMembranReservoirDevice = DEVICE.GetDevice<CompactMembranReservoirDevice>(reservoirName);
  875. _compactMembranMetalDevice = DEVICE.GetDevice<CompactMembranMetalDevice>(Module);
  876. if (_compactMembranMetalDevice == null || _compactMembranReservoirDevice == null)
  877. {
  878. LOG.WriteLog(eEvent.ERR_METAL, Module, $"metal or reservoir device is null");
  879. return RState.Failed;
  880. }
  881. if (_compactMembranMetalDevice.MetalDeviceData.CellFlow <= 0) //检查cell flow
  882. {
  883. LOG.WriteLog(eEvent.ERR_METAL, Module, $"reservoir metal cell flow is 0");
  884. return RState.Failed;
  885. }
  886. if (_compactMembranMetalDevice.ANACellFlow.CounterValue <= 0) //检查hold flow
  887. {
  888. LOG.WriteLog(eEvent.ERR_METAL, Module, $"reservoir metal AnodeA flow is 0");
  889. return RState.Failed;
  890. }
  891. if (_compactMembranMetalDevice.ANBCellFlow.CounterValue <= 0)
  892. {
  893. LOG.WriteLog(eEvent.ERR_METAL, Module, $"reservoir metal AnodeB flow is 0");
  894. return RState.Failed;
  895. }
  896. }
  897. ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(reservoirName);
  898. _temperatureController = DEVICE.GetDevice<TemperatureController>(reservoirItem.TCID);
  899. if (_temperatureController == null)
  900. {
  901. LOG.WriteLog(eEvent.ERR_METAL, Module, $"Temperature controller is null");
  902. return RState.Failed;
  903. }
  904. _persistentValue = MetalPersistentManager.Instance.GetMetalPersistentValue(Module);
  905. if (_persistentValue == null)
  906. {
  907. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} Persistent Value Object is not exist");
  908. return RState.Failed;
  909. }
  910. _lotTackTime = DateTime.Now;
  911. return Runner.Start(Module, "Metal run recipe");
  912. }
  913. public void clearLotTrack()
  914. {
  915. _datas.Clear();
  916. }
  917. public void resetMetalUsage()
  918. {
  919. _anodeAUsage = 0;
  920. _anodeBUsage = 0;
  921. }
  922. }
  923. }