IoCylinder.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  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. string operation = isOpen ? "开" : "关";
  192. if (Name == "SlitDoor")
  193. {
  194. bool tmIsOnline = (bool)DATA.Poll("TM.IsOnline");
  195. if (tmIsOnline == true)
  196. {
  197. int difference = SC.GetValue<int>($"TM.WithPMPressureDifference");
  198. int tmPressure = Convert.ToInt32(DATA.Poll("TM.TMProcessGauge.Value"));
  199. int pmPressure = Convert.ToInt32(DATA.Poll($"{Module}.ProcessHighPressure"));
  200. if (Math.Abs(tmPressure - pmPressure) > difference)
  201. {
  202. LOG.Write(eEvent.ERR_TM, Module, $"TM正在控压,{Module}与TM压差过大,不可以{operation}{Module}腔体SlitDoor");
  203. return true;
  204. }
  205. }
  206. }
  207. if (Name == "LLATSlitDoor")
  208. {
  209. bool tmIsOnline = (bool)DATA.Poll("TM.IsOnline");
  210. if (tmIsOnline == true)
  211. {
  212. int difference = SC.GetValue<int>($"TM.WithPMPressureDifference");
  213. int tmPressure = Convert.ToInt32(DATA.Poll("TM.TMProcessGauge.Value"));
  214. int llPressure = Convert.ToInt32(DATA.Poll("TM.LLAPressureGauge.Value"));
  215. if (Math.Abs(tmPressure - llPressure) > difference)
  216. {
  217. LOG.Write(eEvent.ERR_TM, Module, $"TM正在控压,LLA与TM压差过大,不可以{operation}LLATSlitDoor");
  218. return true;
  219. }
  220. }
  221. }
  222. if (Name == "LLBTSlitDoor")
  223. {
  224. bool tmIsOnline = (bool)DATA.Poll("TM.IsOnline");
  225. if (tmIsOnline == true)
  226. {
  227. int difference = SC.GetValue<int>($"TM.WithPMPressureDifference");
  228. int tmPressure = Convert.ToInt32(DATA.Poll("TM.TMProcessGauge.Value"));
  229. int llPressure = Convert.ToInt32(DATA.Poll("TM.LLBPressureGauge.Value"));
  230. if (Math.Abs(tmPressure - llPressure) > difference)
  231. {
  232. LOG.Write(eEvent.ERR_TM, Module, $"TM正在控压,LLB与TM压差过大,不可以{operation}LLBTSlitDoor");
  233. return true;
  234. }
  235. }
  236. }
  237. ONSetPoint = isOpen;
  238. reason += _error;
  239. reason += " ";
  240. OFFSetPoint = !isOpen;
  241. reason += _error;
  242. _operation = isOpen ? CylinderState.Open : CylinderState.Close;
  243. LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"{(isOpen ? "打开" : "关闭")} 气缸 {Name}");
  244. if (Name == "LoadLockArm")
  245. _timer.Start(10 * 1000);
  246. else if (Name == "SlitDoor")
  247. _timer.Start(5 * 1000);
  248. else
  249. _timer.Start(2000);
  250. return true;
  251. }
  252. public void Monitor()
  253. {
  254. try
  255. {
  256. if (_timer.IsTimeout())
  257. {
  258. _timer.Stop();
  259. if (State != _operation)
  260. {
  261. if (_operation == CylinderState.Open)
  262. {
  263. if (!_doON.Check(true, out var reason))
  264. LOG.Write(eEvent.ERR_DEVICE_INFO, Module, $"{Name}气缸信号无法打开, interlock, " + reason);
  265. else
  266. LOG.Write(eEvent.ERR_DEVICE_INFO, Module, $"{Name}气缸信号仍然关闭");
  267. }
  268. else
  269. {
  270. if (!_doON.Check(false, out var reason))
  271. LOG.Write(eEvent.ERR_DEVICE_INFO, Module, $"{Name}气缸信号无法关闭, interlock, " + reason);
  272. else
  273. LOG.Write(eEvent.ERR_DEVICE_INFO, Module, $"{Name}气缸信号仍然打开");
  274. }
  275. }
  276. _operation = (CylinderState)SetPoint;
  277. }
  278. else if (_timer.IsIdle())
  279. {
  280. _trigReset.CLK = SetPoint != (int)_operation; // fire event only check at first, SetPoint set by interlock
  281. m_SetPoint = SetPoint;
  282. if (_trigReset.Q)
  283. {
  284. if (_operation == CylinderState.Open)
  285. {
  286. LOG.Write(eEvent.ERR_DEVICE_INFO, Module, !_doON.Check(true, out var reason)
  287. ? $"气缸信号 {Display} was Close,Reason:{reason}"
  288. : $"气缸信号 {Display} was Close,Reason PLC kept");
  289. }
  290. else
  291. {
  292. LOG.Write(eEvent.ERR_DEVICE_INFO, Module, !_doON.Check(false, out var reason)
  293. ? $"气缸信号 {Display} was Open,Reason:{reason}"
  294. : $"气缸信号 {Display} was Open,Reason PLC Kept");
  295. }
  296. _operation = (CylinderState)SetPoint;
  297. }
  298. }
  299. _trigError.CLK = State == CylinderState.Error;
  300. if (_trigError.Q)
  301. {
  302. //EV.PostAlarmLog(Module, "气缸状态错误");
  303. }
  304. //if ((SetPoint == (int)State) && (SetPoint == (int)CylinderState.Open || SetPoint == (int)CylinderState.Close))
  305. //{
  306. // OFFSetPoint = false;
  307. // ONSetPoint = false;
  308. //}
  309. }
  310. catch (Exception ex)
  311. {
  312. LOG.WriteExeption(ex);
  313. }
  314. }
  315. public void Reset()
  316. {
  317. _trigReset.RST = true;
  318. _trigError.RST = true;
  319. SetOtherCylinderStateRst(null);
  320. }
  321. }
  322. }