IoValve.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  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. [Subscription(AITValveDataPropertyName.SetPoint)]
  30. public bool SetPoint //True:open| False:close
  31. {
  32. get
  33. {
  34. return _setPoint;
  35. //if (_doOpen == null)
  36. // return false;
  37. //return _isNc ? _doOpen.Value : !_doOpen.Value;
  38. }
  39. set
  40. {
  41. if (_doOpen != null)
  42. {
  43. if (_doOpen.SetValue(_isNc ? value : !value, out _, false))
  44. {
  45. _setPoint = value;
  46. }
  47. }
  48. if (_doClose != null)
  49. {
  50. if (_doClose.SetValue(_isNc ? !value : value, out _, false))
  51. {
  52. _setPoint = value;
  53. }
  54. }
  55. }
  56. }
  57. [Subscription(AITValveDataPropertyName.Status)]
  58. public bool Status //True:open | False:close
  59. {
  60. get
  61. {
  62. if (_diOpenSensor != null && _diCloseSensor != null)
  63. return _diOpenSensor.Value && !_diCloseSensor.Value;
  64. if (_diCloseSensor != null)
  65. return !_diCloseSensor.Value;
  66. if (_diOpen != null)
  67. return _isNc ? _diOpen.Value : !_diOpen.Value;
  68. if (_doOpen != null)
  69. return _isNc ? _doOpen.Value : !_doOpen.Value;
  70. if (_doClose != null)
  71. return _isNc ? !_doClose.Value : _doClose.Value;
  72. return false;
  73. }
  74. }
  75. private AITValveData DeviceData
  76. {
  77. get
  78. {
  79. AITValveData data = new AITValveData()
  80. {
  81. UniqueName = _uniqueName,
  82. DeviceName = GVName,
  83. DefaultValue = GVIsDefaultOpen,
  84. DeviceSchematicId = DeviceID,
  85. DisplayName = Display,
  86. Feedback = Status,
  87. SetPoint = SetPoint,
  88. ILKDiValue = ILKDiSensor == null ? true : ILKDiSensor.Value,
  89. VirtualFeedback = VirtualStatus,
  90. };
  91. return data;
  92. }
  93. }
  94. /// <summary>
  95. /// normal closed, 0 关闭,1打开
  96. /// </summary>
  97. public bool _isNc;
  98. /// <summary>
  99. /// default open
  100. /// </summary>
  101. public bool _isDefaultOpen;
  102. private DIAccessor _diOpenSensor;
  103. private DIAccessor _diCloseSensor;
  104. private DIAccessor _diOpen;
  105. private DOAccessor _doOpen;
  106. private DOAccessor _doClose;
  107. private DIAccessor ILKDiSensor;
  108. private bool _operation;
  109. R_TRIG eventTrigger = new R_TRIG();
  110. R_TRIG _mutexSignalTrigger = new R_TRIG();
  111. DeviceTimer _timer = new DeviceTimer();
  112. DeviceTimer _mutexSignalTimer = new DeviceTimer();
  113. private string _uniqueName;
  114. public bool VirtualStatus;
  115. private string _writeLog = "";
  116. private SCConfigItem _interlockNoneOrExist;
  117. private SCConfigItem _interlockNormaly0nOrOff;
  118. private SCConfigItem _interlockDelayTime;
  119. private float _interlockDelayTimeInMS;
  120. private Stopwatch _interlockDelayTimer = new Stopwatch();
  121. public IoValve(string module, XmlElement node, string ioModule = "")
  122. {
  123. var attrModule = node.GetAttribute("module");
  124. base.Module = string.IsNullOrEmpty(attrModule) ? module : attrModule;
  125. base.Name = node.GetAttribute("id");
  126. base.Display = node.GetAttribute("display");
  127. base.DeviceID = node.GetAttribute("schematicId");
  128. _isNc = Convert.ToBoolean(node.GetAttribute("isNc"));
  129. _isDefaultOpen = Convert.ToBoolean(node.GetAttribute("isDefaultOpen"));
  130. _diOpenSensor = ParseDiNode("diOpenSensor", node, ioModule);
  131. _diCloseSensor = ParseDiNode("diCloseSensor", node, ioModule);
  132. _doOpen = ParseDoNode("doOpen", node, ioModule);
  133. _diOpen = ParseDiNode("diOpen", node, ioModule);
  134. _doClose = ParseDoNode("doClose", node, ioModule);
  135. ILKDiSensor = ParseDiNode("ILKDi", node, ioModule);
  136. _uniqueName = $"{Module}.{Name}";
  137. }
  138. public bool Initialize()
  139. {
  140. _operation = _isNc ? false : true;
  141. if (_isNc == false && _isDefaultOpen == false)
  142. {
  143. TurnValve(_isDefaultOpen, out string tempReason);
  144. }
  145. DATA.Subscribe($"Device.{Module}.{GVName}", () => DeviceData);
  146. DATA.Subscribe($"{_uniqueName}.DeviceData", () => DeviceData);
  147. DATA.Subscribe($"{Module}.{Name}.SetPoint", () => SetPoint);
  148. DATA.Subscribe($"{Module}.{Name}.Feedback", () => Status);
  149. OP.Subscribe($"{_uniqueName}.{AITValveOperation.GVTurnValve}", InvokeOpenCloseValve);
  150. OP.Subscribe($"{_uniqueName}.{AITValveOperation.GVVirtualTurnValve}", InvokeOpenCloseVirtualValve);
  151. DEVICE.Register(String.Format("{0}.{1}", Name, AITValveOperation.GVTurnValve), (out string reason, int time, object[] param) =>
  152. {
  153. bool bOn = Convert.ToBoolean((string)param[0]);
  154. bool ret = TurnValve(bOn, out reason);
  155. if (ret)
  156. {
  157. reason = string.Format("Valve {0}{1}", Name, bOn ? "Open" : "Close");
  158. return true;
  159. }
  160. return false;
  161. });
  162. //for recipe
  163. DEVICE.Register(String.Format("{0}", Name), (out string reason, int time, object[] param) =>
  164. {
  165. bool bOn = Convert.ToBoolean((string)param[0]);
  166. bool ret = TurnValve(bOn, out reason);
  167. if (ret)
  168. {
  169. reason = string.Format("Valve {0}{1}", Name, bOn ? "Open" : "Close");
  170. return true;
  171. }
  172. return false;
  173. });
  174. //for recipe
  175. OP.Subscribe($"{Module}.{Name}", (out string reason, int time, object[] param) =>
  176. {
  177. reason = string.Empty;
  178. if (param[0].ToString() == "Continue")
  179. {
  180. EV.PostInfoLog(Module, $"Turn {Display} Continue");
  181. return true;
  182. }
  183. bool bOn = Convert.ToBoolean((string)param[0]);
  184. bool ret = TurnValve(bOn, out reason);
  185. if (!ret)
  186. {
  187. reason = string.Format("Valve {0}{1} failed", Name, bOn ? "Open" : "Close");
  188. return false;
  189. }
  190. return true;
  191. });
  192. var valveIndex = Name.Replace("ValveAV", "");
  193. _interlockNoneOrExist = SC.GetConfigItem($"PM1.RecipeEditParameter.InterLock.{valveIndex}.NoneOrExist");
  194. _interlockNormaly0nOrOff = SC.GetConfigItem($"PM1.RecipeEditParameter.InterLock.{valveIndex}.Normaly0nOrOff");
  195. _interlockDelayTime = SC.GetConfigItem($"PM1.RecipeEditParameter.InterLock.{valveIndex}.DelayTime");
  196. return true;
  197. }
  198. public void Terminate()
  199. {
  200. string reason;
  201. TurnValve(_isDefaultOpen, out reason);
  202. }
  203. public bool InvokeOpenCloseValve(string method, object[] args)
  204. {
  205. string reason;
  206. bool op = Convert.ToBoolean(args[0]);
  207. string name = op ? "Open" : "Close";
  208. if (!TurnValve(op, out reason))
  209. {
  210. if (InterlockWarning != null)
  211. {
  212. InterlockWarning.Description = $"{reason}";
  213. InterlockWarning.Set();
  214. }
  215. else
  216. {
  217. EV.PostWarningLog(Module, $"Can not {name} valve {Module}.{Name}, {reason}");
  218. }
  219. return false;
  220. }
  221. EV.PostInfoLog(Module, $"{name} valve {Module}.{Name}");
  222. return true;
  223. }
  224. public bool InvokeOpenCloseVirtualValve(string method, object[] args)
  225. {
  226. bool op = Convert.ToBoolean(args[0]);
  227. VirtualStatus = op;
  228. return true;
  229. }
  230. public void Monitor()
  231. {
  232. if (!string.IsNullOrEmpty(_writeLog))
  233. {
  234. LOG.Write(_writeLog);
  235. _writeLog = "";
  236. }
  237. if (_interlockDelayTimer.IsRunning)
  238. {
  239. if (_interlockDelayTimer.ElapsedMilliseconds >= _interlockDelayTimeInMS)
  240. {
  241. _interlockDelayTimer.Stop();
  242. SetPoint = _setPoint;
  243. }
  244. else
  245. {
  246. return;
  247. }
  248. }
  249. try
  250. {
  251. if (_diOpenSensor != null && _diCloseSensor != null && _doOpen != null)
  252. {
  253. if (_diOpenSensor.Value != _diCloseSensor.Value)
  254. {
  255. _mutexSignalTimer.Start(2000);
  256. }
  257. _mutexSignalTrigger.CLK = _mutexSignalTimer.IsTimeout();
  258. if (_mutexSignalTrigger.Q)
  259. {
  260. EV.PostWarningLog(Module, $"Valve {Name} was abnormal,Reason:diOpenSensor's value is {_diOpenSensor.Value} and diCloseSensor's value is {_diCloseSensor.Value} too.");
  261. }
  262. }
  263. if (_timer.IsTimeout() && _doOpen != null)
  264. {
  265. _timer.Stop();
  266. if (Status != _operation)
  267. {
  268. if (_operation)
  269. {
  270. string reason;
  271. if (!_doOpen.Check(_isNc ? true : false, out reason))
  272. EV.PostMessage(Module, EventEnum.ValveOperationFail, Module, Display, "Open", ":Failed for interlock " + reason);
  273. else
  274. EV.PostMessage(Module, EventEnum.ValveOperationFail, Module, Display, "Open", $":Valve {Name} keep closed ");
  275. }
  276. else
  277. {
  278. string reason;
  279. if (!_doOpen.Check(_isNc ? true : false, out reason))
  280. EV.PostMessage(Module, EventEnum.ValveOperationFail, Module, Display, "Close", ":Failed for interlock " + reason);
  281. else
  282. EV.PostMessage(Module, EventEnum.ValveOperationFail, Module, Display, "Close", $":Valve {Name} keep open");
  283. }
  284. }
  285. _operation = SetPoint;
  286. }
  287. else if (_timer.IsIdle() && _doOpen != null)
  288. {
  289. eventTrigger.CLK = SetPoint != _operation; // fire event only check at first, SetPoint set by interlock
  290. if (eventTrigger.Q)
  291. {
  292. if (_operation)
  293. {
  294. string reason;
  295. if (!_doOpen.Check(_isNc ? true : false, out reason))
  296. EV.PostMessage(Module, EventEnum.SwInterlock, Module, string.Format("Valve {0} was {1},Reason:{2}", Display, "Close", reason));
  297. else
  298. EV.PostMessage(Module, EventEnum.SwInterlock, Module, string.Format("Valve {0} was {1},Reason {2}", Display, "Close", "PLC kept"));
  299. }
  300. else
  301. {
  302. string reason;
  303. if (!_doOpen.Check(_isNc ? true : false, out reason))
  304. EV.PostMessage(Module, EventEnum.SwInterlock, Module, string.Format("Valve {0} was {1},Reason:{2}", Display, "Open", reason));
  305. else
  306. EV.PostMessage(Module, EventEnum.SwInterlock, Module, string.Format("Valve {0} was {1},Reason {2}", Display, "Open", "PLC Kept"));
  307. }
  308. _operation = SetPoint;
  309. }
  310. }
  311. }
  312. catch (Exception ex)
  313. {
  314. LOG.Write(ex);
  315. }
  316. }
  317. public bool TurnValve(bool isOn, out string reason)
  318. {
  319. bool bValue = _isNc ? isOn : !isOn;
  320. if (_doOpen != null)
  321. {
  322. if (!_doOpen.Check(bValue, out reason))
  323. {
  324. EV.PostMessage(Module, EventEnum.ValveOperationFail, Module, Display, $"{(isOn ? "Open" : "Close")}", ":Failed for interlock " + reason); ;
  325. return false;
  326. }
  327. }
  328. if (_doClose != null)
  329. {
  330. if (!_doClose.Check(!bValue, out reason))
  331. {
  332. EV.PostMessage(Module, EventEnum.ValveOperationFail, Module, Display, $"{(isOn ? "Open" : "Close")}", ":Failed for interlock " + reason); ;
  333. return false;
  334. }
  335. }
  336. var stringOnOff = isOn ? "On" : "Off";
  337. //EV.PostInfoLog(Module, $"Turn {Display} {stringOnOff}");
  338. _writeLog = $"Turn {Display} {stringOnOff}";
  339. reason = "";
  340. if (_interlockNoneOrExist != null && _interlockDelayTime != null && _interlockNoneOrExist.BoolValue)
  341. {
  342. var timeParas = _interlockDelayTime.StringValue.Split(':');//00:00.0
  343. _interlockDelayTimeInMS = 0;
  344. if (timeParas.Length > 1)
  345. {
  346. float.TryParse(timeParas[0], out float min);
  347. float.TryParse(timeParas[1], out float sec);
  348. _interlockDelayTimeInMS = min * 60 * 1000 + sec * 1000;
  349. }
  350. if (_interlockDelayTimeInMS > 0)
  351. {
  352. _writeLog += $" delay time={_interlockDelayTimeInMS} ms";
  353. _interlockDelayTimer.Restart();
  354. _operation = isOn;
  355. _timer.Start(2000 + _interlockDelayTimeInMS); //2 seconds to monitor
  356. }
  357. else
  358. {
  359. SetPoint = isOn;
  360. _operation = isOn;
  361. _timer.Start(2000); //2 seconds to monitor
  362. }
  363. }
  364. else
  365. {
  366. SetPoint = isOn;
  367. _operation = isOn;
  368. _timer.Start(2000); //2 seconds to monitor
  369. }
  370. return true;
  371. }
  372. public void Reset()
  373. {
  374. eventTrigger.RST = true;
  375. }
  376. }
  377. }