IoValve.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. using System;
  2. using System.Diagnostics;
  3. using System.Xml;
  4. using Aitex.Core.Common.DeviceData;
  5. using Aitex.Core.RT.DataCenter;
  6. using Aitex.Core.RT.Event;
  7. using Aitex.Core.RT.IOCore;
  8. using Aitex.Core.RT.Log;
  9. using Aitex.Core.RT.OperationCenter;
  10. using Aitex.Core.RT.SCCore;
  11. using Aitex.Core.Util;
  12. using MECF.Framework.Common.Event;
  13. namespace Aitex.Core.RT.Device.Unit
  14. {
  15. public interface IValve
  16. {
  17. bool TurnValve(bool isOn, out string reason);
  18. }
  19. public class IoValve : BaseDevice, IDevice, IValve
  20. {
  21. public string GVName { get { return Name; } }
  22. public string GVDeviceID { get { return DeviceID; } }
  23. public bool GVIsDefaultOpen { get { return _isDefaultOpen; } }
  24. public AlarmEventItem InterlockAlarm;
  25. public AlarmEventItem InterlockWarning;
  26. public DOAccessor DOOpen => _doOpen;
  27. public DOAccessor DOClose => _doClose;
  28. private bool _setPoint;
  29. public bool IsILKOK = true;
  30. [Subscription(AITValveDataPropertyName.SetPoint)]
  31. public bool SetPoint //True:open| False:close
  32. {
  33. get
  34. {
  35. return _setPoint;
  36. //if (_doOpen == null)
  37. // return false;
  38. //return _isNc ? _doOpen.Value : !_doOpen.Value;
  39. }
  40. set
  41. {
  42. if (_doOpen != null)
  43. {
  44. if (_doOpen.SetValue(_isNc ? value : !value, out _, false))
  45. {
  46. _setPoint = value;
  47. }
  48. }
  49. if (_doClose != null)
  50. {
  51. if (_doClose.SetValue(_isNc ? !value : value, out _, false))
  52. {
  53. _setPoint = value;
  54. }
  55. }
  56. }
  57. }
  58. [Subscription(AITValveDataPropertyName.Status)]
  59. public bool Status //True:open | False:close
  60. {
  61. get
  62. {
  63. if (_diOpenSensor != null && _diCloseSensor != null)
  64. return _diOpenSensor.Value && !_diCloseSensor.Value;
  65. if (_diCloseSensor != null)
  66. return !_diCloseSensor.Value;
  67. if (_diOpen != null)
  68. return _isNc ? _diOpen.Value : !_diOpen.Value;
  69. if (_doOpen != null)
  70. return _isNc ? _doOpen.Value : !_doOpen.Value;
  71. if (_doClose != null)
  72. return _isNc ? !_doClose.Value : _doClose.Value;
  73. return false;
  74. }
  75. }
  76. private AITValveData DeviceData
  77. {
  78. get
  79. {
  80. AITValveData data = new AITValveData()
  81. {
  82. UniqueName = _uniqueName,
  83. DeviceName = GVName,
  84. DefaultValue = GVIsDefaultOpen,
  85. DeviceSchematicId = DeviceID,
  86. DisplayName = Display,
  87. Feedback = Status,
  88. SetPoint = SetPoint,
  89. ILKDiValue = ILKDiSensor == null ? true : ILKDiSensor.Value,
  90. IsILKOK = this.IsILKOK,
  91. VirtualFeedback = VirtualStatus,
  92. };
  93. return data;
  94. }
  95. }
  96. /// <summary>
  97. /// normal closed, 0 关闭,1打开
  98. /// </summary>
  99. public bool _isNc;
  100. /// <summary>
  101. /// default open
  102. /// </summary>
  103. public bool _isDefaultOpen;
  104. private DIAccessor _diOpenSensor;
  105. private DIAccessor _diCloseSensor;
  106. private DIAccessor _diOpen;
  107. private DOAccessor _doOpen;
  108. private DOAccessor _doClose;
  109. private DIAccessor ILKDiSensor;
  110. private bool _operation;
  111. public bool IsILKNot { get; set; } = false;
  112. R_TRIG eventTrigger = new R_TRIG();
  113. R_TRIG _mutexSignalTrigger = new R_TRIG();
  114. DeviceTimer _timer = new DeviceTimer();
  115. DeviceTimer _mutexSignalTimer = new DeviceTimer();
  116. private string _uniqueName;
  117. public bool VirtualStatus;
  118. private string _writeLog = "";
  119. private SCConfigItem _interlockNoneOrExist;
  120. private SCConfigItem _interlockNormaly0nOrOff;
  121. private SCConfigItem _interlockDelayOnTime;
  122. private SCConfigItem _interlockDelayOffTime;
  123. private SCConfigItem _interlockILKTime;
  124. private float _interlockDelayTimeInMS;
  125. private float _ilkDelayTimeInMS;
  126. private Stopwatch _interlockDelayTimer = new Stopwatch();
  127. private Stopwatch _ilkDelayTimer = new Stopwatch();
  128. public IoValve(string module, XmlElement node, string ioModule = "")
  129. {
  130. var attrModule = node.GetAttribute("module");
  131. base.Module = string.IsNullOrEmpty(attrModule) ? module : attrModule;
  132. base.Name = node.GetAttribute("id");
  133. base.Display = node.GetAttribute("display");
  134. base.DeviceID = node.GetAttribute("schematicId");
  135. _isNc = Convert.ToBoolean(node.GetAttribute("isNc"));
  136. _isDefaultOpen = Convert.ToBoolean(node.GetAttribute("isDefaultOpen"));
  137. _diOpenSensor = ParseDiNode("diOpenSensor", node, ioModule);
  138. _diCloseSensor = ParseDiNode("diCloseSensor", node, ioModule);
  139. _doOpen = ParseDoNode("doOpen", node, ioModule);
  140. _diOpen = ParseDiNode("diOpen", node, ioModule);
  141. _doClose = ParseDoNode("doClose", node, ioModule);
  142. ILKDiSensor = ParseDiNode("ILKDi", node, ioModule);
  143. var attIsILKNot = node.GetAttribute("IsILKNot");
  144. IsILKNot = string.IsNullOrEmpty(attIsILKNot) ? false : Convert.ToBoolean(attIsILKNot);
  145. _uniqueName = $"{Module}.{Name}";
  146. InterlockAlarm= SubscribeAlarm(new AlarmEventItem()
  147. {
  148. EventEnum = $"{Module}.{Name} InterlockAlarm",
  149. Description = $"{Name} Interlock alarm",
  150. Solution = "No information available. Press[Clear] to delete alarm message.",
  151. Explaination = "No information available.",
  152. AutoRecovery = false,
  153. Level = EventLevel.Alarm,
  154. Action = EventAction.Clear,
  155. Category = "TubeAlarm",
  156. }, () => { Reset(); return true; });
  157. }
  158. public bool Initialize()
  159. {
  160. _operation = _isNc ? false : true;
  161. if (_isNc == false && _isDefaultOpen == false)
  162. {
  163. TurnValve(_isDefaultOpen, out string tempReason);
  164. }
  165. DATA.Subscribe($"Device.{Module}.{GVName}", () => DeviceData);
  166. DATA.Subscribe($"{_uniqueName}.DeviceData", () => DeviceData);
  167. DATA.Subscribe($"{Module}.{Name}.SetPoint", () => SetPoint);
  168. DATA.Subscribe($"{Module}.{Name}.Feedback", () => Status);
  169. OP.Subscribe($"{_uniqueName}.{AITValveOperation.GVTurnValve}", InvokeOpenCloseValve);
  170. OP.Subscribe($"{_uniqueName}.{AITValveOperation.GVVirtualTurnValve}", InvokeOpenCloseVirtualValve);
  171. DEVICE.Register(String.Format("{0}.{1}", Name, AITValveOperation.GVTurnValve), (out string reason, int time, object[] param) =>
  172. {
  173. bool bOn = Convert.ToBoolean((string)param[0]);
  174. bool ret = TurnValve(bOn, out reason);
  175. if (ret)
  176. {
  177. reason = string.Format("Valve {0}{1}", Name, bOn ? "Open" : "Close");
  178. return true;
  179. }
  180. return false;
  181. });
  182. //for recipe
  183. DEVICE.Register(String.Format("{0}", Name), (out string reason, int time, object[] param) =>
  184. {
  185. bool bOn = Convert.ToBoolean((string)param[0]);
  186. bool ret = TurnValve(bOn, out reason);
  187. if (ret)
  188. {
  189. reason = string.Format("Valve {0}{1}", Name, bOn ? "Open" : "Close");
  190. return true;
  191. }
  192. return false;
  193. });
  194. //for recipe
  195. OP.Subscribe($"{Module}.{Name}", (out string reason, int time, object[] param) =>
  196. {
  197. reason = string.Empty;
  198. if (param[0].ToString() == "Continue")
  199. {
  200. EV.PostInfoLog(Module, $"Turn {Display} Continue");
  201. return true;
  202. }
  203. bool bOn = Convert.ToBoolean((string)param[0]);
  204. bool ret = TurnValve(bOn, out reason);
  205. if (!ret)
  206. {
  207. reason = string.Format("Valve {0}{1} failed", Name, bOn ? "Open" : "Close");
  208. return false;
  209. }
  210. return true;
  211. });
  212. var valveIndex = Name.Replace("ValveAV", "");
  213. _interlockNoneOrExist = SC.GetConfigItem($"PM1.RecipeEditParameter.InterLock.{valveIndex}.NoneOrExist");
  214. _interlockNormaly0nOrOff = SC.GetConfigItem($"PM1.RecipeEditParameter.InterLock.{valveIndex}.Normaly0nOrOff");
  215. _interlockDelayOnTime = SC.GetConfigItem($"PM1.RecipeEditParameter.InterLock.{valveIndex}.DelayOnTime");
  216. _interlockDelayOffTime = SC.GetConfigItem($"PM1.RecipeEditParameter.InterLock.{valveIndex}.DelayOffTime");
  217. _interlockILKTime = SC.GetConfigItem($"PM1.RecipeEditParameter.InterLock.{valveIndex}.ILKTime");
  218. return true;
  219. }
  220. public void Terminate()
  221. {
  222. string reason;
  223. TurnValve(_isDefaultOpen, out reason);
  224. }
  225. public bool InvokeOpenCloseValve(string method, object[] args)
  226. {
  227. string reason;
  228. bool op = Convert.ToBoolean(args[0]);
  229. string name = op ? "Open" : "Close";
  230. if (!TurnValve(op, out reason))
  231. {
  232. if (InterlockWarning != null)
  233. {
  234. InterlockWarning.Description = $"{reason}";
  235. InterlockWarning.Set();
  236. }
  237. else
  238. {
  239. EV.PostWarningLog(Module, $"Can not {name} valve {Module}.{Name}, {reason}");
  240. }
  241. return false;
  242. }
  243. EV.PostInfoLog(Module, $"{name} valve {Module}.{Name}");
  244. return true;
  245. }
  246. public bool InvokeOpenCloseVirtualValve(string method, object[] args)
  247. {
  248. bool op = Convert.ToBoolean(args[0]);
  249. VirtualStatus = op;
  250. return true;
  251. }
  252. private bool _openOperation;
  253. public void Monitor()
  254. {
  255. if (!string.IsNullOrEmpty(_writeLog))
  256. {
  257. LOG.Write(_writeLog);
  258. _writeLog = "";
  259. }
  260. if (_interlockDelayTimer.IsRunning)
  261. {
  262. if (_interlockDelayTimer.ElapsedMilliseconds >= _interlockDelayTimeInMS)
  263. {
  264. _interlockDelayTimer.Stop();
  265. _interlockDelayTimer.Reset();
  266. bool bValue = _operation;
  267. _openOperation = _operation;
  268. if (_doOpen != null)
  269. {
  270. if (!_doOpen.Check(bValue, out var reason))
  271. {
  272. if (!_doOpen.SetValue(bValue, out reason, false))
  273. {
  274. EV.PostWarningLog("System", $"interlock set DO {Module} to {bValue}:{reason}, {reason}");
  275. }
  276. // EV.PostMessage(Module, EventEnum.ValveOperationFail, Module, Display, $"{(_operation ? "Open" : "Close")}", ":Failed for interlock " + reason);
  277. _operation = SetPoint; //还原状态 防止定时检查状态再次写日志
  278. return;
  279. }
  280. }
  281. if (_doClose != null)
  282. {
  283. if (!_doClose.Check(bValue, out var reason))
  284. {
  285. if (!_doClose.SetValue(bValue, out reason, false))
  286. {
  287. EV.PostWarningLog("System", $"interlock set DO {Module} to {bValue}:{reason}, {reason}");
  288. }
  289. //EV.PostMessage(Module, EventEnum.ValveOperationFail, Module, Display, $"{(_operation ? "Open" : "Close")}", ":Failed for interlock " + reason); ;
  290. _operation = SetPoint;//还原状态 防止定时检查状态再次写日志
  291. return;
  292. }
  293. }
  294. SetPoint = _isNc ? _operation : !_operation;
  295. }
  296. else
  297. {
  298. return;
  299. }
  300. }
  301. try
  302. {
  303. if (_diOpenSensor != null && _diCloseSensor != null && _doOpen != null)
  304. {
  305. if (_diOpenSensor.Value != _diCloseSensor.Value)
  306. {
  307. _mutexSignalTimer.Start(2000);
  308. }
  309. _mutexSignalTrigger.CLK = _mutexSignalTimer.IsTimeout();
  310. if (_mutexSignalTrigger.Q)
  311. {
  312. EV.PostWarningLog(Module, $"Valve {Name} was abnormal,Reason:diOpenSensor's value is {_diOpenSensor.Value} and diCloseSensor's value is {_diCloseSensor.Value} too.");
  313. }
  314. }
  315. if (_timer.IsTimeout() && _doOpen != null)
  316. {
  317. _timer.Stop();
  318. if (Status != _operation)
  319. {
  320. if (_operation)
  321. {
  322. string reason;
  323. if (!_doOpen.Check(_isNc ? true : false, out reason))
  324. EV.PostMessage(Module, EventEnum.ValveOperationFail, Module, Display, "Open", ":Failed for interlock " + reason);
  325. else
  326. EV.PostMessage(Module, EventEnum.ValveOperationFail, Module, Display, "Open", $":Valve {Name} keep closed ");
  327. }
  328. else
  329. {
  330. string reason;
  331. if (!_doOpen.Check(_isNc ? true : false, out reason))
  332. EV.PostMessage(Module, EventEnum.ValveOperationFail, Module, Display, "Close", ":Failed for interlock " + reason);
  333. else
  334. EV.PostMessage(Module, EventEnum.ValveOperationFail, Module, Display, "Close", $":Valve {Name} keep open");
  335. }
  336. }
  337. _operation = SetPoint;
  338. }
  339. else if (_timer.IsIdle() && _doOpen != null)
  340. {
  341. eventTrigger.CLK = SetPoint != _operation; // fire event only check at first, SetPoint set by interlock
  342. if (eventTrigger.Q)
  343. {
  344. if (_operation)
  345. {
  346. string reason;
  347. if (!_doOpen.Check(_isNc ? true : false, out reason))
  348. EV.PostMessage(Module, EventEnum.SwInterlock, Module, string.Format("Valve {0} was {1},Reason:{2}", Display, "Close", reason));
  349. else
  350. EV.PostMessage(Module, EventEnum.SwInterlock, Module, string.Format("Valve {0} was {1},Reason {2}", Display, "Close", "PLC kept"));
  351. }
  352. else
  353. {
  354. string reason;
  355. if (!_doOpen.Check(_isNc ? true : false, out reason))
  356. EV.PostMessage(Module, EventEnum.SwInterlock, Module, string.Format("Valve {0} was {1},Reason:{2}", Display, "Open", reason));
  357. else
  358. EV.PostMessage(Module, EventEnum.SwInterlock, Module, string.Format("Valve {0} was {1},Reason {2}", Display, "Open", "PLC Kept"));
  359. }
  360. _operation = SetPoint;
  361. }
  362. }
  363. }
  364. catch (Exception ex)
  365. {
  366. LOG.Write(ex);
  367. }
  368. if (ILKDiSensor == null)
  369. {
  370. IsILKOK = true;
  371. }
  372. else
  373. {
  374. if (!_isNc)
  375. {
  376. IsILKOK = true;
  377. return;
  378. }
  379. if (ILKDiSensor.Value)
  380. {
  381. IsILKOK = true;
  382. }
  383. else if (!ILKDiSensor.Value)
  384. {
  385. if (!IsILKNot)
  386. {
  387. IsILKOK = false;
  388. }
  389. }
  390. }
  391. //ILK判断
  392. if (_ilkDelayTimer.IsRunning)
  393. {
  394. if (_ilkDelayTimer.ElapsedMilliseconds >= _ilkDelayTimeInMS)
  395. {
  396. _ilkDelayTimer.Stop();
  397. _ilkDelayTimer.Reset();
  398. if (_doOpen != null)
  399. {
  400. if (!ILKDiSensor.Value)
  401. {
  402. InterlockAlarm.Set($"interlock delay ends. The value of the {Name} valve is incorrect.");
  403. // EV.PostWarningLog(Module, $"interlock delay ends. The value of the {Name} valve is incorrect.");
  404. return;
  405. }
  406. }
  407. }
  408. else
  409. {
  410. return;
  411. }
  412. }
  413. }
  414. public bool TurnValve(bool isOn, out string reason)
  415. {
  416. bool bValue = _isNc ? isOn : !isOn;
  417. var stringOnOff = isOn ? "On" : "Off";
  418. //EV.PostInfoLog(Module, $"Turn {Display} {stringOnOff}");
  419. _writeLog = $"Turn {Display} {stringOnOff}";
  420. reason = "";
  421. _interlockDelayTimeInMS = 0;
  422. _ilkDelayTimeInMS = 0;
  423. //开始计时ILK
  424. if (_interlockNoneOrExist != null && _interlockILKTime != null && _interlockNoneOrExist.BoolValue && bValue)
  425. {
  426. var timeParas = _interlockILKTime.StringValue.Split(':');//00:00.0
  427. if (timeParas.Length > 1)
  428. {
  429. float.TryParse(timeParas[0], out float min);
  430. float.TryParse(timeParas[1], out float sec);
  431. _ilkDelayTimeInMS = min * 60 * 1000 + sec * 1000;
  432. }
  433. _ilkDelayTimer.Restart();
  434. _operation = bValue;
  435. if (_ilkDelayTimeInMS > 0)
  436. {
  437. _writeLog += $"ilk delay time={_ilkDelayTimeInMS} ms";
  438. _timer.Start(2000 + _ilkDelayTimeInMS);
  439. }
  440. }
  441. if (_interlockNoneOrExist != null && _interlockDelayOnTime != null && _interlockNoneOrExist.BoolValue && bValue)
  442. {
  443. var timeParas = _interlockDelayOnTime.StringValue.Split(':');//00:00.0
  444. if (timeParas.Length > 1)
  445. {
  446. float.TryParse(timeParas[0], out float min);
  447. float.TryParse(timeParas[1], out float sec);
  448. _interlockDelayTimeInMS = min * 60 * 1000 + sec * 1000;
  449. }
  450. _interlockDelayTimer.Restart();
  451. _operation = bValue;
  452. if (_interlockDelayTimeInMS > 0)
  453. {
  454. _writeLog += $" delay time={_interlockDelayTimeInMS} ms";
  455. _timer.Start(2000 + _interlockDelayTimeInMS);
  456. }
  457. else
  458. {
  459. _timer.Start(2000); //2 seconds to monitor
  460. }
  461. }
  462. else if (_interlockNoneOrExist != null && _interlockDelayOffTime != null && _interlockNoneOrExist.BoolValue && !bValue)
  463. {
  464. var timeParas = _interlockDelayOffTime.StringValue.Split(':');//00:00.0
  465. if (timeParas.Length > 1)
  466. {
  467. float.TryParse(timeParas[0], out float min);
  468. float.TryParse(timeParas[1], out float sec);
  469. _interlockDelayTimeInMS = min * 60 * 1000 + sec * 1000;
  470. }
  471. _interlockDelayTimer.Restart();
  472. _operation = bValue;
  473. if (_interlockDelayTimeInMS > 0)
  474. {
  475. _writeLog += $" delay time={_interlockDelayTimeInMS} ms";
  476. _timer.Start(2000 + _interlockDelayTimeInMS);
  477. }
  478. else
  479. {
  480. _timer.Start(2000); //2 seconds to monitor
  481. }
  482. }
  483. else
  484. {
  485. if (_doOpen != null)
  486. {
  487. if (!_doOpen.Check(bValue, out reason))
  488. {
  489. if (!_isNc && !IsILKNot)
  490. {
  491. IsILKOK = false;
  492. }
  493. _doOpen.SetValue(bValue, out reason, false);
  494. //EV.PostMessage(Module, EventEnum.ValveOperationFail, Module, Display, $"{(isOn ? "Open" : "Close")}", ":Failed for interlock " + reason); ;
  495. return false;
  496. }
  497. }
  498. if (_doClose != null)
  499. {
  500. if (!_doClose.Check(!bValue, out reason))
  501. {
  502. _doClose.SetValue(bValue, out reason, false);
  503. //EV.PostMessage(Module, EventEnum.ValveOperationFail, Module, Display, $"{(isOn ? "Open" : "Close")}", ":Failed for interlock " + reason); ;
  504. return false;
  505. }
  506. }
  507. SetPoint = isOn;
  508. _operation = isOn;
  509. _timer.Start(2000); //2 seconds to monitor
  510. }
  511. return true;
  512. }
  513. public void Reset()
  514. {
  515. eventTrigger.RST = true;
  516. }
  517. }
  518. }