ReservoirDevice.cs 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071
  1. using Aitex.Core.RT.DataCenter;
  2. using Aitex.Core.RT.Device;
  3. using Aitex.Core.RT.Log;
  4. using Aitex.Core.RT.OperationCenter;
  5. using Aitex.Core.RT.RecipeCenter;
  6. using Aitex.Core.RT.SCCore;
  7. using Aitex.Core.Util;
  8. using MECF.Framework.Common.Alarm;
  9. using MECF.Framework.Common.Beckhoff.ModuleIO;
  10. using MECF.Framework.Common.CommonData.Reservoir;
  11. using MECF.Framework.Common.IOCore;
  12. using MECF.Framework.Common.Persistent.Reservoirs;
  13. using MECF.Framework.Common.RecipeCenter;
  14. using MECF.Framework.Common.ToolLayout;
  15. using MECF.Framework.Common.TwinCat;
  16. using MECF.Framework.Common.Utilities;
  17. using PunkHPX8_Core;
  18. using PunkHPX8_RT.Devices.Facilities;
  19. using PunkHPX8_RT.Devices.Safety;
  20. using PunkHPX8_RT.Devices.Temperature;
  21. using PunkHPX8_RT.Modules;
  22. using PunkHPX8_RT.Modules.Reservoir;
  23. using System;
  24. using System.Collections.Generic;
  25. using System.Linq;
  26. using System.Reflection;
  27. using System.ServiceModel.Security;
  28. using System.Text;
  29. using System.Threading.Tasks;
  30. namespace PunkHPX8_RT.Devices.Reservoir
  31. {
  32. public class ReservoirDevice : BaseDevice, IDevice
  33. {
  34. #region 常量
  35. protected const string AUTO = "Auto";
  36. protected const string MANUAL = "Manual";
  37. protected const string DISABLE = "Disable";
  38. protected const string CA_PUMP_RUNNING="CaPumpRunning";
  39. protected const string AN_TOWER_HIGH="AnTowerHigh";
  40. protected const string AN_TOWER_LOW="AnTowerLow";
  41. protected const string CA_LEVEL="CaLevel";
  42. protected const string CA_WATER_LEVEL="CaWaterLevel";
  43. protected const string AN_FLOW="AnFlow";
  44. protected const string AN_PUMP_ENABLE="AnPumpEnable";
  45. protected const string AN_PUMP_SPEED="AnPumpSpeed";
  46. protected const string CA_FLOW="CaFlow";
  47. protected const string CA_PUMP_ENABLE="CaPumpEnable";
  48. protected const string CA_PUMP_SPEED="CaPumpSpeed";
  49. protected const string RETURN_VALVE_OPENING="ReturnValveOpening";
  50. protected const string RETURN_VALVE="ReturnValve";
  51. protected const string RETURN_VALVE_PERCENT="ReturnValvePercent";
  52. protected const string CA_DI_REPLEN="CaDiReplen";
  53. protected const string AN_DI_REPLEN="AnDiReplen";
  54. protected const string SAMPLE_OUT="SampleOut";
  55. protected const string DEGAS_ENABLE="DegasEnable";
  56. protected const string HED_FLOW="HedFlow";
  57. protected const string HED_FLOW_ENABLE="HedFlowEnable";
  58. protected const string PH_FLOW_VALVE="PhFlowValve";
  59. protected const string PH_VALUE="PhValue";
  60. #endregion
  61. #region 内部变量
  62. /// <summary>
  63. /// Prewet 持久性数值对象
  64. /// </summary>
  65. private ReservoirsPersistentValue _persistentValue;
  66. /// <summary>
  67. /// 变量是否初始化字典
  68. /// </summary>
  69. private Dictionary<string, bool> _variableInitializeDic = new Dictionary<string, bool>();
  70. /// <summary>
  71. /// 数据
  72. /// </summary>
  73. private ReservoirData _reservoirData = new ReservoirData();
  74. /// <summary>
  75. /// 定时器
  76. /// </summary>
  77. private PeriodicJob _periodicJob;
  78. /// <summary>
  79. /// 阴极Pump速度
  80. /// </summary>
  81. private double _caPumpSpeed = 0;
  82. /// <summary>
  83. /// Return Valve比例
  84. /// </summary>
  85. private double _returnValvePercent = 0.5;
  86. /// <summary>
  87. /// CA Level取样平均值
  88. /// </summary>
  89. private double _avgCALevel;
  90. /// <summary>
  91. /// CA Level取样队列
  92. /// </summary>
  93. private Queue<double> _CALevelSamples;
  94. /// <summary>
  95. /// CA level计算平均值取样数
  96. /// </summary>
  97. private int _levelSampleCount;
  98. /// <summary>
  99. /// Recipe
  100. /// </summary>
  101. private ResRecipe _resRecipe;
  102. /// <summary>
  103. /// 累计补水是否超时
  104. /// </summary>
  105. private bool _isDIReplenMaxTimeOut = false;
  106. /// <summary>
  107. /// 单次补水是否超时
  108. /// </summary>
  109. private bool _isDIReplenPerfillTimeOut = false;
  110. /// <summary>
  111. /// 注水Helper
  112. /// </summary>
  113. private ReservoirDiReplenHelper _direplenHelper;
  114. #endregion
  115. #region Trigger
  116. /// <summary>
  117. /// low WaterLevel trigger
  118. /// </summary>
  119. private R_TRIG _caWaterLevelLowerTrigger=new R_TRIG();
  120. /// <summary>
  121. /// low WaterLevel trigger
  122. /// </summary>
  123. private R_TRIG _caWaterLevelHighTrigger = new R_TRIG();
  124. #endregion
  125. #region 共享变量
  126. protected DiReplenOperation _currentDireplenOperation = DiReplenOperation.None;
  127. /// <summary>
  128. /// 手动注水时间(秒)
  129. /// </summary>
  130. protected int _manualReplenSecond = 0;
  131. #endregion
  132. #region 属性
  133. /// <summary>
  134. /// 操作模式
  135. /// </summary>
  136. public string OperationMode { get { return _persistentValue.OperatingMode; } }
  137. /// <summary>
  138. /// 工程模式
  139. /// </summary>
  140. public string EngineerMode { get { return _persistentValue.RecipeOperatingMode; } }
  141. /// <summary>
  142. /// 是否自动
  143. /// </summary>
  144. public bool IsAuto { get { return _persistentValue.OperatingMode == AUTO; } }
  145. /// <summary>
  146. /// 数据
  147. /// </summary>
  148. public ReservoirData ReservoirData { get { return _reservoirData; } }
  149. /// <summary>
  150. /// 检验阴极是否highlevel
  151. /// </summary>
  152. public bool IsCAHighLevel { get { return CheckCAHighLevelStatus(); } }
  153. /// <summary>
  154. /// 检验阴极是否lowlevel
  155. /// </summary>
  156. public bool IsCALowLevel { get { return CheckCALowLevelStatus(); } }
  157. /// <summary>
  158. /// 检验阳极是否highlevel
  159. /// </summary>
  160. public bool IsANHighLevel { get { return _reservoirData.AnTowerHigh; } }
  161. /// <summary>
  162. /// 检验阳极是否lowlevel
  163. /// </summary>
  164. public bool IsANLowLevel { get { return _reservoirData.AnTowerLow; } }
  165. /// <summary>
  166. /// 当前Recipe
  167. /// </summary>
  168. public ResRecipe Recipe { get { return _resRecipe; } }
  169. #endregion
  170. /// <summary>
  171. /// 构造函数
  172. /// </summary>
  173. /// <param name="moduleName"></param>
  174. /// <param name="name"></param>
  175. public ReservoirDevice(string moduleName) : base(moduleName, moduleName, moduleName, moduleName)
  176. {
  177. _levelSampleCount = SC.GetValue<int>("Reservoir.LevelAvgSamples");
  178. _levelSampleCount = _levelSampleCount == 0 ? 20 : _levelSampleCount;
  179. _CALevelSamples = new Queue<double>(_levelSampleCount);
  180. }
  181. /// <summary>
  182. /// 初始化
  183. /// </summary>
  184. /// <returns></returns>
  185. public bool Initialize()
  186. {
  187. InitializeParameter();
  188. InitializeRoutine();
  189. SubscribeData();
  190. InitializeOperation();
  191. SubscribeValueAction();
  192. _periodicJob = new PeriodicJob(200, OnTimer, $"{Module}.Timer", true, true);
  193. return true;
  194. }
  195. /// <summary>
  196. /// 初始化参数
  197. /// </summary>
  198. private void InitializeParameter()
  199. {
  200. _persistentValue = ReservoirsPersistentManager.Instance.GetReservoirsPersistentValue(Module.ToString());
  201. if (_persistentValue == null)
  202. {
  203. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module.ToString(), "Persistent Value Object is not exist");
  204. }
  205. _persistentValue = ReservoirsPersistentManager.Instance.GetReservoirsPersistentValue(Module);
  206. if (_persistentValue == null)
  207. {
  208. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "Persistent Value Object is not exist");
  209. }
  210. if (!string.IsNullOrEmpty(_persistentValue.Recipe))
  211. {
  212. _resRecipe = RecipeFileManager.Instance.LoadGenericityRecipe<ResRecipe>(_persistentValue.Recipe);
  213. }
  214. _direplenHelper = new ReservoirDiReplenHelper(Module, _persistentValue);
  215. }
  216. /// <summary>
  217. /// 初始化Routine
  218. /// </summary>
  219. private void InitializeRoutine()
  220. {
  221. }
  222. /// <summary>
  223. /// 订阅数据
  224. /// </summary>
  225. private void SubscribeData()
  226. {
  227. DATA.Subscribe($"{Module}.ReservoirData", () => _reservoirData, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  228. }
  229. /// <summary>
  230. /// 初始化Operation
  231. /// </summary>
  232. protected virtual void InitializeOperation()
  233. {
  234. OP.Subscribe($"{Module}.DisabledAction", DisabledOperation);
  235. OP.Subscribe($"{Module}.ManualAction", ManualOperation);
  236. OP.Subscribe($"{Module}.AutoAction", AutoOperation);
  237. OP.Subscribe($"{Module}.EngineeringModeAction", EngineeringModeOperation);
  238. OP.Subscribe($"{Module}.ProductionModeAction", ProductionModeOperation);
  239. OP.Subscribe($"{Module}.CAPumpOn", CAPumpOn);
  240. OP.Subscribe($"{Module}.CAPumpSpeed", CAPumpSpeedOperation);
  241. OP.Subscribe($"{Module}.CAPumpOff", CAPumpOff);
  242. }
  243. /// <summary>
  244. /// 订阅变量数值发生变化
  245. /// </summary>
  246. protected virtual void SubscribeValueAction()
  247. {
  248. IoSubscribeUpdateVariable(CA_PUMP_RUNNING);
  249. IoSubscribeUpdateVariable(AN_TOWER_HIGH);
  250. IoSubscribeUpdateVariable(AN_TOWER_LOW);
  251. IoSubscribeUpdateVariable(CA_LEVEL);
  252. IoSubscribeUpdateVariable(CA_WATER_LEVEL);
  253. IoSubscribeUpdateVariable(CA_PUMP_ENABLE);
  254. IoSubscribeUpdateVariable(CA_PUMP_SPEED);
  255. IoSubscribeUpdateVariable(CA_DI_REPLEN);
  256. IoSubscribeUpdateVariable(RETURN_VALVE);
  257. IoSubscribeUpdateVariable(RETURN_VALVE_OPENING);
  258. IoSubscribeUpdateVariable(RETURN_VALVE_PERCENT);
  259. IoSubscribeUpdateVariable(SAMPLE_OUT);
  260. }
  261. /// <summary>
  262. /// 订阅IO变量
  263. /// </summary>
  264. /// <param name="variable"></param>
  265. protected void IoSubscribeUpdateVariable(string variable)
  266. {
  267. _variableInitializeDic[variable] = false;
  268. IOModuleManager.Instance.SubscribeModuleVariable(Module, variable, UpdateVariableValue);
  269. }
  270. /// <summary>
  271. /// 更新变量数值
  272. /// </summary>
  273. /// <param name="variable"></param>
  274. /// <param name="value"></param>
  275. private void UpdateVariableValue(string variable, object value)
  276. {
  277. if (!_reservoirData.IsDataInitialized)
  278. {
  279. _reservoirData.IsDataInitialized = true;
  280. }
  281. PropertyInfo property = _reservoirData.GetType().GetProperty(variable);
  282. if (property != null)
  283. {
  284. property.SetValue(_reservoirData, value);
  285. if (variable == CA_WATER_LEVEL)
  286. {
  287. string caLevelCurve = SC.GetStringValue($"Reservoir.{Module}.CALevelCurve");
  288. ReservoirData.CaLevel = LevelCurveManager.Instance.CalculateLevelByWaterLevel(ReservoirData.CaWaterLevel, caLevelCurve);
  289. }
  290. }
  291. if (_variableInitializeDic.ContainsKey(variable) && !_variableInitializeDic[variable])
  292. {
  293. _variableInitializeDic[variable] = true;
  294. }
  295. }
  296. /// <summary>
  297. /// 定时器
  298. /// </summary>
  299. /// <returns></returns>
  300. protected virtual bool OnTimer()
  301. {
  302. CalculateCALevel();
  303. WaterLevelMonitor();
  304. DireplenMonitor();
  305. return true;
  306. }
  307. #region timer
  308. /// <summary>
  309. /// 计算CA
  310. /// </summary>
  311. private void CalculateCALevel()
  312. {
  313. if (ReservoirData != null)
  314. {
  315. if (_CALevelSamples.Count >= _levelSampleCount)
  316. {
  317. _CALevelSamples.Dequeue();
  318. _CALevelSamples.Enqueue(ReservoirData.CaLevel);
  319. }
  320. else
  321. {
  322. _CALevelSamples.Enqueue(ReservoirData.CaLevel);
  323. }
  324. _avgCALevel = _CALevelSamples.Count > 0 ? _CALevelSamples.Average() : 0;
  325. }
  326. }
  327. /// <summary>
  328. /// WaterLevel监控
  329. /// </summary>
  330. protected virtual void WaterLevelMonitor()
  331. {
  332. _caWaterLevelLowerTrigger.CLK = IsCALowLevel;
  333. if (_caWaterLevelLowerTrigger.Q)
  334. {
  335. ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(Module);
  336. string reason = $"Current CAWaterlevel:{ReservoirData.CaWaterLevel} is lower than CALowLevel Config:{SC.GetValue<double>($"Reservoir.{Module}.CALowLevel")}";
  337. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, reason);
  338. CALowLevelOperation();
  339. if (reservoirEntity.IsAuto && !AlarmListManager.Instance.IsContainDataError(Module, "CAWaterLevel"))
  340. {
  341. AlarmListManager.Instance.AddDataError(Module,
  342. $"CAWaterLevel", $"Current CAWaterlevel:{ReservoirData.CaWaterLevel} is lower than CALowLevel Config:{SC.GetValue<double>($"Reservoir.{Module}.CALowLevel")}");
  343. }
  344. if (!reservoirEntity.IsError) reservoirEntity.PostMsg(ReservoirMsg.Error);
  345. }
  346. _caWaterLevelLowerTrigger.CLK = IsCAHighLevel;
  347. if (_caWaterLevelHighTrigger.Q)
  348. {
  349. HighLevelOperation();
  350. }
  351. }
  352. /// <summary>
  353. /// CA Low Level触发对应操作
  354. /// </summary>
  355. private void CALowLevelOperation()
  356. {
  357. ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module);
  358. if (_reservoirData.CaPumpEnable)
  359. {
  360. CAPumpOff("", null);
  361. }
  362. //禁用TC
  363. if (!string.IsNullOrEmpty(reservoirItem.TCID))
  364. {
  365. TemperatureController temperatureController = DEVICE.GetDevice<TemperatureController>(reservoirItem.TCID);
  366. if (temperatureController != null && temperatureController.TemperatureData.ControlOperationModel == (int)TemperatureEnumData.ENABLE)
  367. {
  368. temperatureController.DisableOperation("", null);
  369. }
  370. }
  371. ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(Module);
  372. if (!reservoirEntity.IsError) reservoirEntity.PostMsg(ReservoirMsg.Error);
  373. }
  374. /// <summary>
  375. /// High Level Common Operation
  376. /// </summary>
  377. private void HighLevelOperation()
  378. {
  379. ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(Module);
  380. SystemFacilities systemFacilities = DEVICE.GetDevice<SystemFacilities>("System.Facilities");
  381. if (systemFacilities != null)
  382. {
  383. if (systemFacilities.DIFillEnable) systemFacilities.DiFillDisableOperation("DIFillDisableOpeartion", null);
  384. if (systemFacilities.DIReplenEnable) systemFacilities.DiReplenDisableOperation("DiReplenDisableOperation", null);
  385. if (_reservoirData.CaDiReplen)
  386. {
  387. _currentDireplenOperation = DiReplenOperation.None;
  388. CADiReplenOff("", null);
  389. }
  390. }
  391. if (!reservoirEntity.IsError) reservoirEntity.PostMsg(ReservoirMsg.Error);
  392. if (reservoirEntity.IsAuto && !AlarmListManager.Instance.IsContainDataError(Module, "CAWaterLevel"))
  393. {
  394. AlarmListManager.Instance.AddDataError(Module,
  395. $"CAWaterLevel", $"Current CAWaterlevel:{ReservoirData.CaWaterLevel} is large than CAHighLevel Config:{SC.GetValue<double>($"Reservoir.{Module}.CAHighLevel")}");
  396. }
  397. }
  398. /// <summary>
  399. /// Direplen监控
  400. /// </summary>
  401. private void DireplenMonitor()
  402. {
  403. var facilities = DEVICE.GetDevice<SystemFacilities>("System.Facilities");
  404. //补水监控
  405. if (_direplenHelper != null)
  406. {
  407. _direplenHelper.MonitorPeriodTime(ref _isDIReplenMaxTimeOut);
  408. if (!_isDIReplenMaxTimeOut && !_isDIReplenPerfillTimeOut && facilities.DIFillEnable)
  409. {
  410. AutoDireplenMonitor();
  411. }
  412. }
  413. }
  414. /// <summary>
  415. /// 自动补水
  416. /// </summary>
  417. protected virtual void AutoDireplenMonitor()
  418. {
  419. if (_currentDireplenOperation == DiReplenOperation.ManualCADiReplen)
  420. {
  421. bool result = _direplenHelper.MonitorManualDiReplenComplete(_manualReplenSecond, CADiReplenOff, ref _isDIReplenMaxTimeOut);
  422. if (result)
  423. {
  424. _currentDireplenOperation = DiReplenOperation.None;
  425. }
  426. }
  427. if (_currentDireplenOperation == DiReplenOperation.ManualANDiReplen)
  428. {
  429. bool result = _direplenHelper.MonitorManualDiReplenComplete(_manualReplenSecond, ANDiReplenOff, ref _isDIReplenMaxTimeOut);
  430. if (result)
  431. {
  432. _currentDireplenOperation = DiReplenOperation.None;
  433. }
  434. }
  435. if (_currentDireplenOperation == DiReplenOperation.AutoCADiReplen)
  436. {
  437. AutoDiReplenMonitor(CADiReplenOff, _reservoirData.CaLevel, _resRecipe.ReservoirCALevel, _resRecipe.DIReplenEnable,
  438. _resRecipe.DIReplenTimeRate, _resRecipe.DIReplenCurrentRate);
  439. }
  440. if (_currentDireplenOperation == DiReplenOperation.AutoANDiReplen) //阳极没有水位,自动补水监控逻辑待修正
  441. {
  442. }
  443. }
  444. /// <summary>
  445. /// 自动注水监控
  446. /// </summary>
  447. /// <param name="direplenOff"></param>
  448. /// <param name="level"></param>
  449. /// <param name="recipeLevel"></param>
  450. private void AutoDiReplenMonitor(Func<string, object[], bool> direplenOff, double level, double recipeLevel, bool replenEnable,
  451. int direplenTimeRate, int direplenCurrentRate)
  452. {
  453. bool result = _direplenHelper.AutoDiReplenMonitorTimeOut(direplenOff, ref _isDIReplenMaxTimeOut, ref _isDIReplenPerfillTimeOut);
  454. if (result)
  455. {
  456. _currentDireplenOperation = DiReplenOperation.None;
  457. }
  458. else
  459. {
  460. //按液位补水
  461. result = _direplenHelper.AutoDiReplenMonitorComplete(level, recipeLevel, replenEnable, direplenTimeRate, direplenCurrentRate, direplenOff);
  462. if (result)
  463. {
  464. _currentDireplenOperation = DiReplenOperation.None;
  465. }
  466. }
  467. }
  468. #endregion
  469. #region Mode switch
  470. /// <summary>
  471. /// DisabledAction
  472. /// </summary>
  473. /// <param name="cmd"></param>
  474. /// <param name="param"></param>
  475. /// <returns></returns>
  476. private bool DisabledOperation(string cmd, object[] args)
  477. {
  478. string currentOperation = "Disabled";
  479. string preOperation = _persistentValue.OperatingMode;
  480. _persistentValue.OperatingMode = currentOperation;
  481. LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"Operating mode is switched from {preOperation} to {currentOperation}");
  482. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  483. return true;
  484. }
  485. /// <summary>
  486. /// ManualAction
  487. /// </summary>
  488. /// <param name="cmd"></param>
  489. /// <param name="param"></param>
  490. /// <returns></returns>
  491. private bool ManualOperation(string cmd, object[] args)
  492. {
  493. string currentOperation = "Manual";
  494. string preOperation = _persistentValue.OperatingMode;
  495. _persistentValue.OperatingMode = currentOperation;
  496. LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"Operating mode is switched from {preOperation} to {currentOperation}");
  497. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  498. return true;
  499. }
  500. /// <summary>
  501. /// AutoAction
  502. /// </summary>
  503. /// <param name="cmd"></param>
  504. /// <param name="param"></param>
  505. /// <returns></returns>
  506. private bool AutoOperation(string cmd, object[] args)
  507. {
  508. string currentOperation = "Auto";
  509. string preOperation = _persistentValue.OperatingMode;
  510. _persistentValue.OperatingMode = currentOperation;
  511. LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"Operating mode is switched from {preOperation} to {currentOperation}");
  512. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  513. return true;
  514. }
  515. /// <summary>
  516. /// EngineeringModeAction
  517. /// </summary>
  518. /// <param name="cmd"></param>
  519. /// <param name="param"></param>
  520. /// <returns></returns>
  521. private bool EngineeringModeOperation(string cmd, object[] args)
  522. {
  523. string currentRecipeOperation = "Engineering";
  524. if (_persistentValue != null)
  525. {
  526. _persistentValue.RecipeOperatingMode = currentRecipeOperation;
  527. }
  528. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  529. return true;
  530. }
  531. /// <summary>
  532. /// ProductionAction
  533. /// </summary>
  534. /// <param name="cmd"></param>
  535. /// <param name="param"></param>
  536. /// <returns></returns>
  537. private bool ProductionModeOperation(string cmd, object[] args)
  538. {
  539. string currentRecipeOperation = "Production";
  540. if (_persistentValue != null)
  541. {
  542. _persistentValue.RecipeOperatingMode = currentRecipeOperation;
  543. }
  544. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  545. return true;
  546. }
  547. #endregion
  548. /// <summary>
  549. /// 监控
  550. /// </summary>
  551. public void Monitor()
  552. {
  553. }
  554. #region CA Pump
  555. /// <summary>
  556. /// CA Pump调速
  557. /// </summary>
  558. /// <param name="cmd"></param>
  559. /// <param name="args"></param>
  560. /// <returns></returns>
  561. private bool CAPumpSpeedOperation(string cmd, object[] args)
  562. {
  563. double caMaxPumpSpeed = 0;
  564. if (SC.ContainsItem("Reservoir.CAMaxPumpSpeed"))
  565. {
  566. caMaxPumpSpeed = SC.GetValue<double>("Reservoir.CAMaxPumpSpeed");
  567. }
  568. if (double.TryParse(args[0].ToString(), out double speed))
  569. {
  570. _caPumpSpeed = speed;
  571. if (_caPumpSpeed > caMaxPumpSpeed)
  572. {
  573. LOG.WriteLog(eEvent.WARN_METAL, Module, $"CA pump speed:{_caPumpSpeed} is over CA max pump speed {caMaxPumpSpeed}!");
  574. return false;
  575. }
  576. return CAPumpSpeed(_caPumpSpeed);
  577. }
  578. else
  579. {
  580. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{args[0]} is nor invalid speed");
  581. return false;
  582. }
  583. }
  584. /// <summary>
  585. /// 设置阴极泵速
  586. /// </summary>
  587. /// <param name="caPumpSpeed"></param>
  588. /// <returns></returns>
  589. public bool CAPumpSpeed(double caPumpSpeed)
  590. {
  591. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_PUMP_SPEED}");
  592. return BeckhoffIOManager.Instance.WriteIoValue(ioName, caPumpSpeed);
  593. }
  594. /// <summary>
  595. /// 阴极Pump On
  596. /// </summary>
  597. /// <param name="cmd"></param>
  598. /// <param name="args"></param>
  599. /// <returns></returns>
  600. private bool CAPumpOn(string cmd, object[] args)
  601. {
  602. double caPumpSpeed = SC.GetValue<double>("Reservoir.CADefaultPumpSpeed");
  603. bool result = CAPumpSpeed(caPumpSpeed);
  604. if (result)
  605. {
  606. string enableIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_PUMP_ENABLE}");
  607. return BeckhoffIOManager.Instance.WriteIoValue(enableIOName, true);
  608. }
  609. else
  610. {
  611. return false;
  612. }
  613. }
  614. /// <summary>
  615. /// 阴极Pump Off
  616. /// </summary>
  617. /// <param name="cmd"></param>
  618. /// <param name="args"></param>
  619. /// <returns></returns>
  620. private bool CAPumpOff(string cmd, object[] args)
  621. {
  622. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_PUMP_ENABLE}");
  623. return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
  624. }
  625. #endregion
  626. #region Return Valve
  627. /// <summary>
  628. /// Return Valve
  629. /// </summary>
  630. /// <param name="cmd"></param>
  631. /// <param name="args"></param>
  632. /// <returns></returns>
  633. private bool ReturnValvePercentOperation(string cmd, object[] args)
  634. {
  635. if (double.TryParse(args[0].ToString(), out double percent))
  636. {
  637. _returnValvePercent = percent;
  638. return CAPumpSpeed(_caPumpSpeed);
  639. }
  640. else
  641. {
  642. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{args[0]} is nor invalid speed");
  643. return false;
  644. }
  645. }
  646. /// <summary>
  647. /// 设置比例
  648. /// </summary>
  649. /// <param name="caPumpSpeed"></param>
  650. /// <returns></returns>
  651. public bool ReturnValvePercent(double percent)
  652. {
  653. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{RETURN_VALVE_PERCENT}");
  654. return BeckhoffIOManager.Instance.WriteIoValue(ioName, percent);
  655. }
  656. /// <summary>
  657. /// Return Valve On
  658. /// </summary>
  659. /// <param name="cmd"></param>
  660. /// <param name="args"></param>
  661. /// <returns></returns>
  662. private bool ReturnValveOn(string cmd, object[] args)
  663. {
  664. double percent = SC.GetValue<double>("Reservoir.ReturnOpenDefaultPercentage");
  665. bool result = ReturnValvePercent(percent);
  666. if (result)
  667. {
  668. string enableIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{RETURN_VALVE}");
  669. return BeckhoffIOManager.Instance.WriteIoValue(enableIOName, true);
  670. }
  671. else
  672. {
  673. return false;
  674. }
  675. }
  676. /// <summary>
  677. /// Return Valve Off
  678. /// </summary>
  679. /// <param name="cmd"></param>
  680. /// <param name="args"></param>
  681. /// <returns></returns>
  682. private bool ReturnValveOff(string cmd, object[] args)
  683. {
  684. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{RETURN_VALVE}");
  685. return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
  686. }
  687. #endregion
  688. #region CA DiReplen
  689. /// <summary>
  690. /// 阴极DI Replen On
  691. /// </summary>
  692. /// <param name="cmd"></param>
  693. /// <param name="args"></param>
  694. /// <returns></returns>
  695. private bool CADiReplenOnOperation(string cmd, object[] args)
  696. {
  697. return CADiReplenOn();
  698. }
  699. /// <summary>
  700. /// 阴极DI Replen On
  701. /// </summary>
  702. /// <param name="showError"></param>
  703. /// <returns></returns>
  704. private bool CADiReplenOn()
  705. {
  706. bool preCondition = CheckPreDiReplenCondition();
  707. if (!preCondition)
  708. {
  709. return false;
  710. }
  711. if (IsCAHighLevel)
  712. {
  713. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"CAHighLevel is activate,Can't do CA_DIReple");
  714. return false;
  715. }
  716. if (IsCALowLevel)
  717. {
  718. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"CALowLevel is activate,Can't do CA_DIReple");
  719. return false;
  720. }
  721. if (ReservoirData.AnDiReplen)
  722. {
  723. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "ANDiReplen is on");
  724. return false;
  725. }
  726. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_DI_REPLEN}");
  727. return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
  728. }
  729. /// <summary>
  730. /// 阴极DI Replen Off
  731. /// </summary>
  732. /// <param name="cmd"></param>
  733. /// <param name="args"></param>
  734. /// <returns></returns>
  735. private bool CADiReplenOff(string cmd, object[] args)
  736. {
  737. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_DI_REPLEN}");
  738. bool result = BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
  739. if (result)
  740. {
  741. _persistentValue.IsDiReplenOn = false;
  742. if (_currentDireplenOperation == DiReplenOperation.ManualCADiReplen || _currentDireplenOperation == DiReplenOperation.AutoCADiReplen)
  743. {
  744. _currentDireplenOperation = DiReplenOperation.None;
  745. _persistentValue.LastTotalReplen = _persistentValue.TotalReplen;
  746. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  747. }
  748. }
  749. return result;
  750. }
  751. /// <summary>
  752. /// 检验DiReplen前置条件
  753. /// </summary>
  754. /// <returns></returns>
  755. public bool CheckPreDiReplenCondition()
  756. {
  757. if (!CheckFacilitiesDiReplenStatus())
  758. {
  759. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "Facilities DiReplen is Off, can't start auto diReplen");
  760. return false;
  761. }
  762. SafetyDevice safetyDevice = DEVICE.GetDevice<SafetyDevice>("Safety");
  763. if (safetyDevice != null && safetyDevice.SafetyData.Reservoir1CALevelHigh)
  764. {
  765. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Safety high is Activate, can't start auto diReplen");
  766. return false;
  767. }
  768. if (CheckOtherReservoirDiReplenStatus())
  769. {
  770. return false;
  771. }
  772. return true;
  773. }
  774. /// <summary>
  775. /// 检验总Di有没有开
  776. /// </summary>
  777. /// <returns></returns>
  778. private bool CheckFacilitiesDiReplenStatus()
  779. {
  780. SystemFacilities systemFacilities = DEVICE.GetDevice<SystemFacilities>("System.Facilities");
  781. if (systemFacilities != null)
  782. {
  783. return systemFacilities.DIReplenEnable;
  784. }
  785. return false;
  786. }
  787. /// <summary>
  788. /// 检验是否其他Reservoir Direplen已经
  789. /// </summary>
  790. /// <returns></returns>
  791. protected bool CheckOtherReservoirDiReplenStatus()
  792. {
  793. List<string> reservoirs = ReservoirItemManager.Instance.InstalledModules;
  794. foreach (string item in reservoirs)
  795. {
  796. if (item != Module)
  797. {
  798. ReservoirDevice tmpDevice = DEVICE.GetDevice<ReservoirDevice>(item);
  799. if (tmpDevice.ReservoirData.CaDiReplen)
  800. {
  801. return true;
  802. }
  803. ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(item);
  804. if (reservoirItem.SubType == ReservoirType.DegasMembrance.ToString())
  805. {
  806. if (tmpDevice.ReservoirData.AnDiReplen)
  807. {
  808. return true;
  809. }
  810. }
  811. }
  812. }
  813. return false;
  814. }
  815. #endregion
  816. #region AN DiReplen
  817. /// <summary>
  818. /// 阳极DI Replen On
  819. /// </summary>
  820. /// <param name="cmd"></param>
  821. /// <param name="args"></param>
  822. /// <returns></returns>
  823. private bool ANDiReplenOnOperation(string cmd, object[] args)
  824. {
  825. return ANDiReplenOn();
  826. }
  827. /// <summary>
  828. /// 阳极DI Replen On
  829. /// </summary>
  830. /// <param name="showError"></param>
  831. /// <returns></returns>
  832. private bool ANDiReplenOn()
  833. {
  834. bool preCondition = CheckPreDiReplenCondition();
  835. if (!preCondition)
  836. {
  837. return false;
  838. }
  839. if (IsANHighLevel)
  840. {
  841. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"ANHighLevel is activate,Can't do AN_DIReple");
  842. return false;
  843. }
  844. if (IsANLowLevel)
  845. {
  846. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"ANLowLevel is activate,Can't do AN_DIReple");
  847. return false;
  848. }
  849. if (ReservoirData.CaDiReplen)
  850. {
  851. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "CADiReplen is on");
  852. return false;
  853. }
  854. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_DI_REPLEN}");
  855. return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
  856. }
  857. /// <summary>
  858. /// 阳极DI Replen Off
  859. /// </summary>
  860. /// <param name="cmd"></param>
  861. /// <param name="args"></param>
  862. /// <returns></returns>
  863. private bool ANDiReplenOff(string cmd, object[] args)
  864. {
  865. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_DI_REPLEN}");
  866. bool result = BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
  867. if (result)
  868. {
  869. _persistentValue.IsDiReplenOn = false;
  870. if (_currentDireplenOperation == DiReplenOperation.ManualANDiReplen || _currentDireplenOperation == DiReplenOperation.AutoANDiReplen)
  871. {
  872. _currentDireplenOperation = DiReplenOperation.None;
  873. _persistentValue.LastTotalReplen = _persistentValue.TotalReplen;
  874. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  875. }
  876. }
  877. return result;
  878. }
  879. #endregion
  880. #region DiReplen Operation
  881. /// <summary>
  882. /// 重置时长
  883. /// </summary>
  884. /// <param name="cmd"></param>
  885. /// <param name="objs"></param>
  886. /// <returns></returns>
  887. private bool ResetTotalTime(string cmd, object[] objs)
  888. {
  889. _isDIReplenMaxTimeOut = false;
  890. _persistentValue.TotalReplen = 0;
  891. _persistentValue.LastTotalReplen = 0;
  892. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  893. return true;
  894. }
  895. /// <summary>
  896. /// 手动阴极注水
  897. /// </summary>
  898. /// <param name="cmd"></param>
  899. /// <param name="args"></param>
  900. /// <returns></returns>
  901. private bool ManualCADiReplen(string cmd, object[] args)
  902. {
  903. return ManualDiReplen(CADiReplenOnOperation, DiReplenOperation.ManualCADiReplen, args[0].ToString());
  904. }
  905. /// <summary>
  906. /// 手动阳极注水
  907. /// </summary>
  908. /// <param name="cmd"></param>
  909. /// <param name="args"></param>
  910. /// <returns></returns>
  911. private bool ManualANDiReplen(string cmd, object[] args)
  912. {
  913. return ManualDiReplen(ANDiReplenOnOperation, DiReplenOperation.ManualANDiReplen, args[0].ToString());
  914. }
  915. /// <summary>
  916. /// 手动注水
  917. /// </summary>
  918. /// <param name="direplenOn"></param>
  919. /// <param name="direplenOperation"></param>
  920. /// <returns></returns>
  921. private bool ManualDiReplen(Func<string, object[], bool> direplenOn, DiReplenOperation direplenOperation, string timeLength)
  922. {
  923. if (_currentDireplenOperation != DiReplenOperation.None)
  924. {
  925. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"current operation is {_currentDireplenOperation},cannot execute {direplenOperation}");
  926. return false;
  927. }
  928. ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(Module);
  929. if (!reservoirEntity.IsInitialized)
  930. {
  931. LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} is not initialized. Can't start DiReplen");
  932. return false;
  933. }
  934. if (_isDIReplenMaxTimeOut)
  935. {
  936. double diValveMaxOnTime = SC.GetValue<double>($"Reservoir.{Module}.DIValveMaxOnTime");
  937. LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"Direplen time over conifg's DIValveMaxOnTime:{diValveMaxOnTime} min");
  938. return false;
  939. }
  940. if (_isDIReplenPerfillTimeOut)
  941. {
  942. double diValveMaxOnTimePerFill = SC.GetValue<double>($"Reservoir.{Module}.DIValveMaxOnTimePerFill");
  943. LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"Direplen time over conifg's DIValveMaxOnTimePerFill:{diValveMaxOnTimePerFill} min");
  944. return false;
  945. }
  946. bool result = direplenOn("", null);
  947. if (result)
  948. {
  949. _currentDireplenOperation = direplenOperation;
  950. _persistentValue.DiReplenTime = DateTime.Now;
  951. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  952. int.TryParse(timeLength, out _manualReplenSecond);
  953. }
  954. return result;
  955. }
  956. /// <summary>
  957. /// 阴极自动流水
  958. /// </summary>
  959. /// <returns></returns>
  960. public bool AutoCADiReplen()
  961. {
  962. if (IsCALowLevel)
  963. {
  964. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"CALowLevel is activate,Can't AutoANDireplen");
  965. return false;
  966. }
  967. return AutoDireplen(CADiReplenOn, DiReplenOperation.AutoCADiReplen);
  968. }
  969. /// <summary>
  970. /// 自动注水
  971. /// </summary>
  972. /// <returns></returns>
  973. protected bool AutoDireplen(Func<bool> direplenOn, DiReplenOperation reservoirOperation)
  974. {
  975. if (_currentDireplenOperation != DiReplenOperation.None)
  976. {
  977. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"current operation is {_currentDireplenOperation},cannot execute {reservoirOperation}");
  978. return false;
  979. }
  980. if (_resRecipe == null)
  981. {
  982. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"recipe is null");
  983. return false;
  984. }
  985. bool result = direplenOn();
  986. if (result)
  987. {
  988. _currentDireplenOperation = reservoirOperation;
  989. _persistentValue.DiReplenTime = DateTime.Now;
  990. }
  991. return result;
  992. }
  993. #endregion
  994. /// <summary>
  995. /// 检验阴极是否highlevel
  996. /// </summary>
  997. public bool CheckCAHighLevelStatus()
  998. {
  999. return ReservoirData.CaWaterLevel > SC.GetValue<double>($"Reservoir.{Module}.CAHighLevel") ? true : false;
  1000. }
  1001. /// <summary>
  1002. /// 检验阴极是否lowlevel
  1003. /// </summary>
  1004. public bool CheckCALowLevelStatus()
  1005. {
  1006. return ReservoirData.CaWaterLevel < SC.GetValue<double>($"Reservoir.{Module}.CALowLevel") ? true : false;
  1007. }
  1008. public void Reset()
  1009. {
  1010. }
  1011. public void Terminate()
  1012. {
  1013. }
  1014. protected enum DiReplenOperation
  1015. {
  1016. None,
  1017. ManualANDiReplen,
  1018. ManualCADiReplen,
  1019. AutoANDiReplen,
  1020. AutoCADiReplen
  1021. }
  1022. }
  1023. }