IoValve.cs 16 KB

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