ReservoirRunRecipeRoutine.cs 51 KB

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