IoCylinder.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Xml;
  4. using Aitex.Core.Common.DeviceData;
  5. using Aitex.Core.RT.DataCenter;
  6. using Aitex.Core.RT.Device;
  7. using Aitex.Core.RT.Event;
  8. using Aitex.Core.RT.IOCore;
  9. using Aitex.Core.RT.Log;
  10. using Aitex.Core.RT.OperationCenter;
  11. using Aitex.Core.RT.SCCore;
  12. using Aitex.Core.Util;
  13. namespace Venus_RT.Devices
  14. {
  15. public class IoCylinder : BaseDevice, IDevice
  16. {
  17. private readonly DIAccessor _diON;
  18. private readonly DIAccessor _diOFF;
  19. private readonly DOAccessor _doON;
  20. private readonly DOAccessor _doOFF;
  21. private CylinderState _operation;
  22. private readonly DeviceTimer _timer = new DeviceTimer();
  23. private readonly R_TRIG _trigReset = new R_TRIG();
  24. private readonly R_TRIG _trigError = new R_TRIG();
  25. private readonly R_TRIG _trigCylinderStateError = new R_TRIG();
  26. private readonly R_TRIG _trigCylinderStateOpen = new R_TRIG();
  27. private readonly R_TRIG _trigCylinderStateClose = new R_TRIG();
  28. private readonly R_TRIG _trigCylinderStateUnknown = new R_TRIG();
  29. private int m_SetPoint;
  30. public bool EnableOpen { get; set; }
  31. public bool EnableClose { get; set; }
  32. private string _error = null;
  33. public int SetPoint
  34. {
  35. get
  36. {
  37. if (_doON.Value && _doOFF.Value) return (int)CylinderState.Error;
  38. if (_doON.Value && !_doOFF.Value) return (int)CylinderState.Open;
  39. if (!_doON.Value && _doOFF.Value) return (int)CylinderState.Close;
  40. if (!_doON.Value && !_doOFF.Value) return (int)CylinderState.Unknown;
  41. return (int)CylinderState.Unknown;
  42. }
  43. }
  44. private void SetOtherCylinderStateRst(R_TRIG curTrig)
  45. {
  46. List<R_TRIG> list = new List<R_TRIG>() { _trigCylinderStateError, _trigCylinderStateOpen, _trigCylinderStateClose, _trigCylinderStateUnknown };
  47. if (curTrig != null)
  48. {
  49. list.Remove(curTrig);
  50. }
  51. list.ForEach(p => p.RST = true);
  52. }
  53. public CylinderState State
  54. {
  55. get
  56. {
  57. if (_diON != null && _diOFF != null)
  58. {
  59. if (ONFeedback && _diOFF.Value)
  60. {
  61. _trigCylinderStateError.CLK = ONFeedback && _diOFF.Value;
  62. if (_trigCylinderStateError.Q) LOG.Write(eEvent.INFO_IOCYLINDER, Module, $"{Module} {Name} cylinder state error");
  63. SetOtherCylinderStateRst(_trigCylinderStateError);
  64. return CylinderState.Error;
  65. }
  66. if (ONFeedback && !_diOFF.Value)
  67. {
  68. _trigCylinderStateOpen.CLK = ONFeedback && !_diOFF.Value;
  69. if (_trigCylinderStateOpen.Q) LOG.Write(eEvent.INFO_IOCYLINDER, Module, $"{Module} {Name} cylinder state open");
  70. SetOtherCylinderStateRst(_trigCylinderStateOpen);
  71. return CylinderState.Open;
  72. }
  73. if (!ONFeedback && _diOFF.Value)
  74. {
  75. _trigCylinderStateClose.CLK = !ONFeedback && _diOFF.Value;
  76. if (_trigCylinderStateClose.Q) LOG.Write(eEvent.INFO_IOCYLINDER, Module, $"{Module} {Name} cylinder state close");
  77. SetOtherCylinderStateRst(_trigCylinderStateClose);
  78. return CylinderState.Close;
  79. }
  80. if (!ONFeedback && !_diOFF.Value)
  81. {
  82. _trigCylinderStateUnknown.CLK = !ONFeedback && !_diOFF.Value;
  83. if (_trigCylinderStateUnknown.Q) LOG.Write(eEvent.INFO_IOCYLINDER, Module, $"{Module} {Name} cylinder state unknown");
  84. SetOtherCylinderStateRst(_trigCylinderStateUnknown);
  85. return CylinderState.Unknown;
  86. }
  87. }
  88. return CylinderState.Unknown;
  89. }
  90. }
  91. public bool ONFeedback
  92. {
  93. get { return _diON != null && _diON.Value; }
  94. }
  95. public bool OFFFeedback
  96. {
  97. get { return _diOFF != null && _diOFF.Value; }
  98. }
  99. public bool ONSetPoint
  100. {
  101. get
  102. {
  103. return _doON != null && _doON.Value;
  104. }
  105. private set
  106. {
  107. if (_doON != null && _doON.Check(value, out _error))
  108. _doON.Value = value;
  109. }
  110. }
  111. public bool OFFSetPoint
  112. {
  113. get
  114. {
  115. return _doOFF != null && _doOFF.Value;
  116. }
  117. private set
  118. {
  119. if (_doOFF != null && _doOFF.Check(value, out _error))
  120. _doOFF.Value = value;
  121. }
  122. }
  123. private AITCylinderData DeviceData
  124. {
  125. get
  126. {
  127. return new AITCylinderData
  128. {
  129. Module = Module,
  130. DeviceName = Name,
  131. DeviceSchematicId = DeviceID,
  132. DisplayName = Display,
  133. OpenFeedback = ONFeedback,
  134. CloseFeedback = OFFFeedback,
  135. OpenSetPoint = ONSetPoint,
  136. CloseSetPoint = OFFSetPoint
  137. };
  138. }
  139. }
  140. public IoCylinder(string module, XmlElement node, string ioModule = "")
  141. {
  142. base.Module = module;
  143. base.Name = node.GetAttribute("id");
  144. base.Display = node.GetAttribute("display");
  145. base.DeviceID = node.GetAttribute("schematicId");
  146. _operation = CylinderState.Close;
  147. _diON = ParseDiNode("diON", node, ioModule);
  148. _diOFF = ParseDiNode("diOFF", node, ioModule);
  149. _doON = ParseDoNode("doON", node, ioModule);
  150. _doOFF = ParseDoNode("doOFF", node, ioModule);
  151. }
  152. public bool Initialize()
  153. {
  154. DATA.Subscribe($"{Module}.{Name}.DeviceData", () => DeviceData);
  155. DATA.Subscribe($"{Module}.{Name}.IsClosed", () => OFFFeedback);
  156. OP.Subscribe($"{Module}.{Name}.{AITCylinderOperation.Open}", (s, objects) => SetCylinder(true, out _));
  157. OP.Subscribe($"{Module}.{Name}.{AITCylinderOperation.Close}", (s, objects) => SetCylinder(false, out _));
  158. OP.Subscribe($"{Module}.{Name}.{AITCylinderOperation.SetState}", (out string reason, int time, object[] param) =>
  159. {
  160. bool isUp = (string)param[0] == "Up" ? true : false;
  161. SetCylinder(isUp, out reason);
  162. return true;
  163. });
  164. DEVICE.Register($"{Module}.{Name}.{AITCylinderOperation.Open}",
  165. (out string reason, int time, object[] param) => SetCylinder(true, out reason));
  166. DEVICE.Register($"{Module}.{Name}.{AITCylinderOperation.Close}",
  167. (out string reason, int time, object[] param) => SetCylinder(false, out reason));
  168. return true;
  169. }
  170. public void Terminate()
  171. {
  172. OFFSetPoint = false;
  173. ONSetPoint = false;
  174. }
  175. public bool SetCylinder(bool isOpen, out string reason)
  176. {
  177. reason = "";
  178. if (Name == "LoadLockArm")
  179. {
  180. if (isOpen && State == CylinderState.Open)
  181. {
  182. LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"检查到气缸 {Name} 已经开");
  183. return true;
  184. }
  185. if (!isOpen && State == CylinderState.Close)
  186. {
  187. LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"检查到气缸 {Name} 已经关");
  188. return true;
  189. }
  190. }
  191. ONSetPoint = isOpen;
  192. reason += _error;
  193. reason += " ";
  194. OFFSetPoint = !isOpen;
  195. reason += _error;
  196. _operation = isOpen ? CylinderState.Open : CylinderState.Close;
  197. LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"{(isOpen ? "打开" : "关闭")} 气缸 {Name}");
  198. if (Name == "LoadLockArm")
  199. _timer.Start(10 * 1000);
  200. else if (Name == "SlitDoor")
  201. _timer.Start(5 * 1000);
  202. else
  203. _timer.Start(2000);
  204. return true;
  205. }
  206. public void Monitor()
  207. {
  208. try
  209. {
  210. if (_timer.IsTimeout())
  211. {
  212. _timer.Stop();
  213. if (State != _operation)
  214. {
  215. if (_operation == CylinderState.Open)
  216. {
  217. if (!_doON.Check(true, out var reason))
  218. LOG.Write(eEvent.ERR_DEVICE_INFO, Module, $"{Name}气缸信号无法打开, interlock, " + reason);
  219. else
  220. LOG.Write(eEvent.ERR_DEVICE_INFO, Module, $"{Name}气缸信号仍然关闭");
  221. }
  222. else
  223. {
  224. if (!_doON.Check(false, out var reason))
  225. LOG.Write(eEvent.ERR_DEVICE_INFO, Module, $"{Name}气缸信号无法关闭, interlock, " + reason);
  226. else
  227. LOG.Write(eEvent.ERR_DEVICE_INFO, Module, $"{Name}气缸信号仍然打开");
  228. }
  229. }
  230. _operation = (CylinderState)SetPoint;
  231. }
  232. else if (_timer.IsIdle())
  233. {
  234. _trigReset.CLK = SetPoint != (int)_operation; // fire event only check at first, SetPoint set by interlock
  235. m_SetPoint = SetPoint;
  236. if (_trigReset.Q)
  237. {
  238. if (_operation == CylinderState.Open)
  239. {
  240. LOG.Write(eEvent.ERR_DEVICE_INFO, Module, !_doON.Check(true, out var reason)
  241. ? $"气缸信号 {Display} was Close,Reason:{reason}"
  242. : $"气缸信号 {Display} was Close,Reason PLC kept");
  243. }
  244. else
  245. {
  246. LOG.Write(eEvent.ERR_DEVICE_INFO, Module, !_doON.Check(false, out var reason)
  247. ? $"气缸信号 {Display} was Open,Reason:{reason}"
  248. : $"气缸信号 {Display} was Open,Reason PLC Kept");
  249. }
  250. _operation = (CylinderState)SetPoint;
  251. }
  252. }
  253. _trigError.CLK = State == CylinderState.Error;
  254. if (_trigError.Q)
  255. {
  256. //EV.PostAlarmLog(Module, "气缸状态错误");
  257. }
  258. //if ((SetPoint == (int)State) && (SetPoint == (int)CylinderState.Open || SetPoint == (int)CylinderState.Close))
  259. //{
  260. // OFFSetPoint = false;
  261. // ONSetPoint = false;
  262. //}
  263. }
  264. catch (Exception ex)
  265. {
  266. LOG.WriteExeption(ex);
  267. }
  268. }
  269. public void Reset()
  270. {
  271. _trigReset.RST = true;
  272. _trigError.RST = true;
  273. SetOtherCylinderStateRst(null);
  274. }
  275. }
  276. }