EdwardsPump.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. using System;
  2. using System.Collections;
  3. using System.Diagnostics;
  4. using System.Text;
  5. using System.Xml;
  6. using Aitex.Core.Common.DeviceData;
  7. using Aitex.Core.RT.DataCenter;
  8. using Aitex.Core.RT.Device;
  9. using Aitex.Core.RT.Event;
  10. using Aitex.Core.RT.IOCore;
  11. using Aitex.Core.RT.Log;
  12. using Aitex.Core.RT.OperationCenter;
  13. using Aitex.Core.RT.SCCore;
  14. using Aitex.Core.RT.Tolerance;
  15. using Aitex.Core.Util;
  16. using MECF.Framework.Common.Communications;
  17. using MECF.Framework.Common.DataCenter;
  18. using MECF.Framework.Common.Device.Bases;
  19. using MECF.Framework.Common.Equipment;
  20. using Venus_Core;
  21. namespace Venus_RT.Devices
  22. {
  23. public enum EdwardsPumpState { ON = 0, OFF, Connected, Disconnected, Unknown, ERROR }
  24. static class EdwardsPumpControlSystemParameters
  25. {
  26. public const int System_Node = 1;
  27. public const int Dry_Pump_Current = 3;
  28. public const int Dry_Pump_Power = 4;
  29. public const int Booster_Current = 7;
  30. public const int Booster_Power = 8;
  31. public const int Dry_Pump_Control = 11;
  32. public const int Dry_Pump_Run_hours = 14;
  33. public const int Number_of_pump_starts = 20;
  34. }
  35. static class EdwardsPumpMessage
  36. {
  37. public const string EOF = "\r\n";
  38. public const string RESET = "/";
  39. public const string QUERY_Alarm_Status = "?A";
  40. public const string QUERY_Bitfield_Status = "?B";
  41. public const string QUERY_Control_Status = "?C";
  42. public const string QUERY_Gas_ballast_Status = "?D";
  43. public const string QUERY_Gate_valve_Status = "?G";
  44. public const string QUERY_Nitrogen_supply_Status = "?N";
  45. public const string QUERY_On_process_Status = "?O";
  46. public const string QUERY_Pump_Status = "?P";
  47. public const string QUERY_Run_til_crash_Status = "?R";
  48. public const string QUERY_Inlet_purge_Status = "?U";
  49. public const string QUERY_Pump_node_type = "?T";
  50. public const string QUERY_Value = "?V";
  51. public const string QUERY_Serial_Number = "?S";
  52. public const string QUERY_Information = "?I";
  53. public const string QUERY_Format_mode = "?F";
  54. public const string COMMAND_Release_Control = "!C0";
  55. public const string COMMAND_Take_Control = "!C1";
  56. public const string COMMAND_Gas_ballast = "!D";
  57. public const string COMMAND_Equipment = "!E";
  58. public const string COMMAND_Format_mode = "!F";
  59. public const string COMMAND_Gate_valve = "!G";
  60. public const string COMMAND_Reserved = "!L";
  61. public const string COMMAND_Simulation_mode = "!M";
  62. public const string COMMAND_Nitrogen_supply = "!N";
  63. public const string COMMAND_On_process = "!O";
  64. public const string COMMAND_Switch_on_Pump = "!P1";
  65. public const string COMMAND_Switch_off_Pump_Auto_shut_down = "!P0";
  66. public const string COMMAND_Switch_off_Pump_Fast_shut_down = "!P2";
  67. public const string COMMAND_Run_til_crash = "!R";
  68. public const string COMMAND_Reserved_do_not_use = "!T";
  69. public const string COMMAND_Inlet_purge = "!U";
  70. public const string COMMAND_Terminate_protocol = "!XO";
  71. public const string SET_SHORT_REPLY = "!F0";
  72. public const string SET_LONG_REPLY = "!F1";
  73. }
  74. class EdwardsPump : PumpBase
  75. {
  76. // ----------------------------Fields--------------------------
  77. //
  78. private const ushort CHK_ST_INTERVAL = 1000;
  79. private const ushort CHK_CONTROL_INTERVAL = 3 * 1000;
  80. private const ushort CHK_REC_INTERVAL = 20 * 1000;
  81. private const ushort CHK_PUMP_REC_INTERVAL = 10 * 1000;
  82. private double _total;
  83. private double _fromLast;
  84. private const string EOF = "\r";
  85. private const char MSG_DELIMITER = ' ';
  86. private readonly string _PortNum = "COM91";
  87. private const int _counterMax = 30;
  88. //private int _counter = 0;
  89. private static string SendData;
  90. private readonly AsyncSerialPort _serial;
  91. private readonly DeviceTimer _timerQueryStatus = new DeviceTimer();
  92. private readonly DeviceTimer _timerControlStatus = new DeviceTimer();
  93. private readonly DeviceTimer _timerReceiveStatus = new DeviceTimer();
  94. private readonly DeviceTimer _timerPumpOn = new DeviceTimer();
  95. private readonly DeviceTimer _timerPumpOff = new DeviceTimer();
  96. private readonly DeviceTimer _timerTotal = new DeviceTimer();
  97. private readonly DeviceTimer _timerFromLast = new DeviceTimer();
  98. private readonly R_TRIG _trigPumpOn = new R_TRIG();
  99. private readonly R_TRIG _trigPumpOff = new R_TRIG();
  100. private readonly R_TRIG _trigReceiveStatus = new R_TRIG();
  101. private readonly RD_TRIG _trigOnOff = new RD_TRIG();
  102. private readonly R_TRIG _trigPMNeeded = new R_TRIG();
  103. private StatsDataItemRFAndPump _statPumpOnTime;
  104. // --------------------------Properties------------------------
  105. //
  106. private Stopwatch _pumpOnTimeWatch = new Stopwatch();
  107. public EdwardsPumpState StatusDry { get; set; }
  108. public string LastPMTime
  109. {
  110. get
  111. {
  112. return _statPumpOnTime != null ? _statPumpOnTime.LastPMTime.ToString() : "";
  113. }
  114. }
  115. public float DaysFromLastPM
  116. {
  117. get
  118. {
  119. return _statPumpOnTime == null ? 0 : _statPumpOnTime.fromLastPM;
  120. }
  121. set
  122. {
  123. if (_statPumpOnTime != null)
  124. _statPumpOnTime.fromLastPM = value;
  125. }
  126. }
  127. public float TotalDays
  128. {
  129. get
  130. {
  131. return _statPumpOnTime != null ? _statPumpOnTime.Total : 0;
  132. }
  133. set
  134. {
  135. if (_statPumpOnTime != null)
  136. _statPumpOnTime.Total = value;
  137. }
  138. }
  139. public double PMIntervalDays
  140. {
  141. get
  142. {
  143. return _statPumpOnTime != null ? _statPumpOnTime.PMInterval : 0;
  144. }
  145. }
  146. public bool IsPMNeeded
  147. {
  148. get
  149. {
  150. return DaysFromLastPM > PMIntervalDays;
  151. }
  152. }
  153. public bool EnableAlarm
  154. {
  155. get
  156. {
  157. return _statPumpOnTime == null || _statPumpOnTime.AlarmEnable;
  158. }
  159. }
  160. [Subscription(AITPumpProperty.IsRunning)]
  161. public override bool IsRunning
  162. {
  163. get
  164. {
  165. return StatusDry == EdwardsPumpState.ON;
  166. }
  167. }
  168. [Subscription(AITPumpProperty.IsError)]
  169. public override bool IsError
  170. {
  171. get
  172. {
  173. return StatusDry == EdwardsPumpState.ERROR || StatusDry == EdwardsPumpState.Disconnected;
  174. }
  175. }
  176. public override AITPumpData DeviceData
  177. {
  178. get
  179. {
  180. AITPumpData deviceData = new AITPumpData
  181. {
  182. DeviceName = Name,
  183. DeviceModule = Module,
  184. DeviceSchematicId = DeviceID,
  185. DisplayName = Display,
  186. IsError = false,
  187. IsWarning = false,
  188. IsOn = IsRunning,
  189. //WaterFlow = WaterFlowValue,
  190. IsDryPumpEnable = true,
  191. IsN2PressureEnable = false,
  192. IsWaterFlowEnable = false,
  193. //WaterFlowWarning = WaterFlowWarning,
  194. //WaterFlowAlarm = WaterFlowAlarm,
  195. //N2PressureAlarm = N2PressureAlarm,
  196. //N2PressureWarning = N2PressureWarning,
  197. };
  198. return deviceData;
  199. }
  200. }
  201. // --------------------------Constructor-----------------------
  202. //
  203. public EdwardsPump(ModuleName mod) : base(mod.ToString(), VenusDevice.MainPump.ToString(), "Edwards Pump", "")
  204. {
  205. _PortNum = SC.GetStringValue($"{mod}.DryPump.Port");
  206. StatusDry = EdwardsPumpState.Unknown;
  207. _serial = new AsyncSerialPort(_PortNum, 9600, 8, System.IO.Ports.Parity.None, System.IO.Ports.StopBits.One, "\r\n", true);
  208. }
  209. public EdwardsPump(ModuleName mod, string name) : base(mod.ToString(), VenusDevice.MainPump.ToString(), "Edwards Pump", "")
  210. {
  211. _PortNum = SC.GetStringValue($"{mod.ToString()}.{name}.Port");
  212. StatusDry = EdwardsPumpState.Unknown;
  213. _serial = new AsyncSerialPort(_PortNum, 9600, 8, System.IO.Ports.Parity.None, System.IO.Ports.StopBits.One, "\r\n", true);
  214. }
  215. public override bool Initialize()
  216. {
  217. base.Initialize();
  218. if (!_serial.Open())
  219. {
  220. StatusDry = EdwardsPumpState.Disconnected;
  221. LOG.Write(eEvent.ERR_DRY_PUMP, Module, "Edwards Pump串口无法打开");
  222. return false;
  223. }
  224. _statPumpOnTime = StatsDataManager.Instance.GetItemRFAndPump($"{Module}.PumpOnTime");
  225. StatusDry = EdwardsPumpState.Connected;
  226. _trigPumpOn.RST = true;
  227. _trigPumpOff.RST = true;
  228. _trigReceiveStatus.RST = true;
  229. _serial.OnDataChanged += OnPortDataChanged;
  230. _serial.OnErrorHappened += OnErrorOccurred;
  231. SendCmd(EdwardsPumpMessage.RESET);
  232. SendCmd(EdwardsPumpMessage.SET_SHORT_REPLY);
  233. SendCmd(EdwardsPumpMessage.COMMAND_Take_Control);
  234. _timerQueryStatus.Start(CHK_ST_INTERVAL);
  235. _timerControlStatus.Start(CHK_CONTROL_INTERVAL);
  236. _timerReceiveStatus.Start(CHK_REC_INTERVAL);
  237. DATA.Subscribe($"{Module}.PumpOnTime",()=>DaysFromLastPM);
  238. return true;
  239. }
  240. private void OnErrorOccurred(string obj)
  241. {
  242. StatusDry = EdwardsPumpState.ERROR;
  243. LOG.Write(eEvent.ERR_DRY_PUMP, Module, $"[{Module}] edwards pump error: [{obj}]");
  244. }
  245. private void OnPortDataChanged(string obj)
  246. {
  247. if (string.IsNullOrEmpty(obj))
  248. LOG.Write(eEvent.WARN_DEVICE_INFO, Module, "edwards pump message IsNullOrEmpty");
  249. try
  250. {
  251. _timerReceiveStatus.Stop();
  252. _timerReceiveStatus.Start(CHK_REC_INTERVAL);
  253. string cmd = obj.ToString().Split('\n')[0].Split('\r')[0];
  254. switch (SendData)
  255. {
  256. case EdwardsPumpMessage.RESET:
  257. break;
  258. case EdwardsPumpMessage.COMMAND_Take_Control:
  259. LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"Take Control Edwards Pump {QueryCmdReply(cmd)}");
  260. break;
  261. case EdwardsPumpMessage.COMMAND_Release_Control:
  262. LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"Release Control Edwards Pump {QueryCmdReply(cmd)}");
  263. break;
  264. case EdwardsPumpMessage.COMMAND_Switch_on_Pump:
  265. LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"Switch on Edwards Pump {QueryCmdReply(cmd)}");
  266. break;
  267. case EdwardsPumpMessage.COMMAND_Switch_off_Pump_Fast_shut_down:
  268. LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"Switch off Edwards Pump {QueryCmdReply(cmd)}");
  269. break;
  270. case EdwardsPumpMessage.QUERY_Pump_Status:
  271. if (cmd == "0")
  272. {
  273. StatusDry = EdwardsPumpState.OFF;
  274. if (_trigPumpOn.Q && _timerPumpOn.IsTimeout())
  275. {
  276. _trigPumpOn.RST = true;
  277. LOG.Write(eEvent.WARN_DEVICE_INFO, Module, "Edwards Pump 无法打开");
  278. }
  279. if (_trigPumpOff.Q)
  280. {
  281. LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"Edwards Pump关闭");
  282. }
  283. _trigPumpOff.RST = true;
  284. }
  285. else if (cmd == "4")
  286. {
  287. StatusDry = EdwardsPumpState.ON;
  288. if (_trigPumpOff.Q && _timerPumpOff.IsTimeout())
  289. {
  290. _trigPumpOff.RST = true;
  291. LOG.Write(eEvent.WARN_DEVICE_INFO, Module, "Edwards Pump 无法关闭");
  292. }
  293. if (_trigPumpOn.Q)
  294. {
  295. LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"Edwards Pump打开");
  296. }
  297. _trigPumpOn.RST = true;
  298. }
  299. break;
  300. default:
  301. LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"Edwards Pump {SendData} {QueryCmdReply(cmd)}");
  302. break;
  303. }
  304. }
  305. catch (Exception ex)
  306. {
  307. LOG.WriteExeption($"[{Module}] edwards pump error: ", ex);
  308. }
  309. }
  310. public string QueryCmdReply(string cmd)
  311. {
  312. if (cmd == "ERR 0")
  313. {
  314. return "No error";
  315. }
  316. else if (cmd == "ERR 1")
  317. {
  318. return "Invalid message";
  319. }
  320. else if (cmd == "ERR 2")
  321. {
  322. return "Number not found";
  323. }
  324. else if (cmd == "ERR 3")
  325. {
  326. return "Number Invalid";
  327. }
  328. else if (cmd == "ERR 4")
  329. {
  330. return "Parameter’s value not received";
  331. }
  332. else if (cmd == "ERR 5")
  333. {
  334. return "Command not possible";
  335. }
  336. else
  337. {
  338. return cmd;
  339. }
  340. }
  341. public override void Monitor()
  342. {
  343. try
  344. {
  345. // 状态查询
  346. if (_timerQueryStatus.IsTimeout())
  347. {
  348. this.SendCmd(EdwardsPumpMessage.QUERY_Pump_Status);
  349. _timerQueryStatus.Start(CHK_ST_INTERVAL);
  350. }
  351. if (_timerReceiveStatus.IsTimeout())
  352. {
  353. _trigReceiveStatus.CLK = true;
  354. if (_trigReceiveStatus.Q)
  355. {
  356. //EV.PostMessage(Module, EventEnum.DefaultWarning, "Edwards Pump 没有回复");
  357. //EV.PostAlarmLog(Module, "Edwards Pump 没有回复",)
  358. }
  359. }
  360. _trigOnOff.CLK = IsRunning;
  361. //第一次检测到打开了,开始计时
  362. if (_trigOnOff.R)
  363. {
  364. _total = TotalDays;
  365. _fromLast = DaysFromLastPM;
  366. _timerTotal.Start(0);
  367. _timerFromLast.Start(0);
  368. _pumpOnTimeWatch.Start();
  369. }
  370. //第一次检测到从打开到关闭状态
  371. if (_trigOnOff.T)
  372. {
  373. }
  374. //如果开着,就更新SC
  375. if (_trigOnOff.M && _pumpOnTimeWatch.ElapsedMilliseconds > 1000)
  376. {
  377. TotalDays = (float)1 / 60 / 60;
  378. DaysFromLastPM = (float)1 / 60 / 60;
  379. _pumpOnTimeWatch.Restart();
  380. //_timerTotal.Restart(0);
  381. //_timerFromLast.Restart(0);
  382. if (ModuleHelper.IsPm(Module))
  383. {
  384. StatsDataManager.Instance.Increase($"{Module}.PumpOnTime", $"{Module} PumpOnTime", DaysFromLastPM, TotalDays);
  385. }
  386. }
  387. if (PMIntervalDays > 0)
  388. {
  389. _trigPMNeeded.CLK = IsPMNeeded;
  390. if (_trigPMNeeded.Q)
  391. {
  392. if (EnableAlarm)
  393. {
  394. EV.PostAlarmLog(Module, "pump on time value larger than setting interval days");
  395. }
  396. }
  397. }
  398. //if (ModuleHelper.IsPm(Module))
  399. // StatsDataManager.Instance.Increase($"{Module}.PumpOnTime", $"{Module} PumpOnTime", DaysFromLastPM, TotalDays);
  400. }
  401. catch (Exception ex)
  402. {
  403. throw ex;
  404. }
  405. }
  406. private bool SendCmd(string str)
  407. {
  408. SendData = str;
  409. if (SendData == "!P1")
  410. {
  411. _trigPumpOn.CLK = true;
  412. _timerPumpOn.Start(CHK_PUMP_REC_INTERVAL);
  413. LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"[{Module}] Switch on Edwards Pump");
  414. }
  415. else if (SendData == "!P2")
  416. {
  417. _trigPumpOff.CLK = true;
  418. _timerPumpOff.Start(CHK_PUMP_REC_INTERVAL);
  419. LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"[{Module}] Switch off Edwards Pump");
  420. }
  421. return _serial.Write(str + "\r");
  422. }
  423. public override void Reset()
  424. {
  425. _trigPumpOn.RST = true;
  426. _trigPumpOff.RST = true;
  427. _trigReceiveStatus.RST = true;
  428. _trigPMNeeded.RST = true;
  429. SendCmd(EdwardsPumpMessage.RESET);
  430. }
  431. public override void Terminate()
  432. {
  433. //if (StatusDry == EdwardsPumpState.ON)
  434. // SetPumpOnOff(false);
  435. _serial?.Close();
  436. }
  437. public override void ResetPumpStats()
  438. {
  439. _statPumpOnTime = StatsDataManager.Instance.GetItemRFAndPump($"{Module}.PumpOnTime");
  440. }
  441. public override void SetPumpOnOff(bool on)
  442. {
  443. SendCmd(on ? EdwardsPumpMessage.COMMAND_Switch_on_Pump : EdwardsPumpMessage.COMMAND_Switch_off_Pump_Fast_shut_down);
  444. }
  445. public override bool ReConnect()
  446. {
  447. return _serial.ReConnect();
  448. }
  449. }
  450. }