IoMfc1.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. using Aitex.Core.Common.DeviceData;
  2. using Aitex.Core.RT.DataCenter;
  3. using Aitex.Core.RT.Device;
  4. using Aitex.Core.RT.Event;
  5. using Aitex.Core.RT.IOCore;
  6. using Aitex.Core.RT.OperationCenter;
  7. using Aitex.Core.RT.SCCore;
  8. using Aitex.Core.RT.Tolerance;
  9. using Aitex.Core.Util;
  10. using MECF.Framework.Common.DBCore;
  11. using SorterRT.Modules;
  12. using System;
  13. using System.Diagnostics;
  14. using System.Xml;
  15. using Aitex.Core.RT.Log;
  16. namespace VirgoRT.Devices.IODevices
  17. {
  18. public class IoMfc1 : MfcBase1
  19. {
  20. public string Unit
  21. {
  22. get; set;
  23. }
  24. [Subscription(AITMfcDataPropertyName.Scale)]
  25. public override double Scale
  26. {
  27. get
  28. {
  29. if (_scN2Scale == null || _scScaleFactor == null)
  30. return 0;
  31. return _scN2Scale.IntValue * _scScaleFactor.DoubleValue;
  32. }
  33. }
  34. [Subscription(AITMfcDataPropertyName.SetPoint)]
  35. public override double SetPoint
  36. {
  37. get
  38. {
  39. if (_aoFlow != null)
  40. {
  41. byte[] high = BitConverter.GetBytes(_aoFlow.Buffer[_aoFlow.Index]);
  42. byte[] low = BitConverter.GetBytes(_aoFlow.Buffer[_aoFlow.Index + 1]);
  43. float flow = BitConverter.ToSingle(new[] { high[0], high[1], low[0], low[1] }, 0);
  44. return flow * Scale / _ANALOG_TRANS_RANGE;
  45. }
  46. return 0;
  47. }
  48. set
  49. {
  50. if (_aoFlow != null)
  51. {
  52. byte[] flow = BitConverter.GetBytes((float)(value * _ANALOG_TRANS_RANGE / Scale));
  53. _aoFlow.Buffer[_aoFlow.Index] = BitConverter.ToInt16(flow, 0);
  54. _aoFlow.Buffer[_aoFlow.Index + 1] = BitConverter.ToInt16(flow, 2);
  55. }
  56. }
  57. }
  58. [Subscription(AITMfcDataPropertyName.DefaultSetPoint)]
  59. public double DefaultSetPoint
  60. {
  61. get
  62. {
  63. if (_scDefaultSetPoint != null)
  64. return _scDefaultSetPoint.IntValue;
  65. return 0;
  66. }
  67. }
  68. [Subscription(AITMfcDataPropertyName.FeedBack)]
  69. public override double FeedBack
  70. {
  71. get
  72. {
  73. if (_aiFlow != null)
  74. {
  75. byte[] high = BitConverter.GetBytes(_aiFlow.Buffer[_aiFlow.Index]);
  76. byte[] low = BitConverter.GetBytes(_aiFlow.Buffer[_aiFlow.Index + 1]);
  77. float flow = BitConverter.ToSingle(new[] { high[0], high[1], low[0], low[1] }, 0);
  78. return (_scRegulationFactor != null && _scRegulationFactor.IntValue > 0) ? flow * Scale / _ANALOG_TRANS_RANGE / _scRegulationFactor.IntValue
  79. : flow * Scale / _ANALOG_TRANS_RANGE;
  80. }
  81. return 0;
  82. }
  83. }
  84. [Subscription(AITMfcDataPropertyName.IsOutOfTolerance)]
  85. public override bool IsOutOfTolerance
  86. {
  87. get
  88. {
  89. return _alarmChecker.Result;
  90. }
  91. }
  92. [Subscription(AITMfcDataPropertyName.IsEnableAlarm)]
  93. public bool EnableAlarm
  94. {
  95. get
  96. {
  97. if (_scEnableAlarm != null)
  98. return _scEnableAlarm.BoolValue;
  99. return false;
  100. }
  101. }
  102. [Subscription(AITMfcDataPropertyName.AlarmRange)]
  103. public double AlarmRange
  104. {
  105. get
  106. {
  107. if (_scAlarmRange != null)
  108. return _scAlarmRange.IntValue;
  109. return 0;
  110. }
  111. }
  112. [Subscription(AITMfcDataPropertyName.AlarmTime)]
  113. public double AlarmTime
  114. {
  115. get
  116. {
  117. if (_scAlarmTime != null)
  118. return _scAlarmTime.IntValue;
  119. return 0;
  120. }
  121. }
  122. public double WarningRange
  123. {
  124. get
  125. {
  126. if (_scWarningRange != null)
  127. return _scWarningRange.IntValue;
  128. return 0;
  129. }
  130. }
  131. public double WarningTime
  132. {
  133. get
  134. {
  135. if (_scWarningTime != null)
  136. return _scWarningTime.IntValue;
  137. return 0;
  138. }
  139. }
  140. [Subscription(AITMfcDataPropertyName.PressureAlarm)]
  141. public bool PressureAlarm
  142. {
  143. get { return _diPressureAlarm != null ? _diPressureAlarm.Value : true; }
  144. }
  145. [Subscription(AITMfcDataPropertyName.MfcAlarm)]
  146. public bool MfcAlarm
  147. {
  148. get
  149. {
  150. return _bMfcAlarm;
  151. }
  152. }
  153. [Subscription(AITMfcDataPropertyName.IsEnable)]
  154. public bool Enable
  155. {
  156. get
  157. {
  158. if (_scEnable != null)
  159. return _scEnable.BoolValue;
  160. return false;
  161. }
  162. }
  163. [Subscription(AITMfcDataPropertyName.IsOffline)]
  164. public bool IsOffline
  165. {
  166. get
  167. {
  168. if (_diOffline != null)
  169. return _diOffline.Value;
  170. return false;
  171. }
  172. }
  173. public override string DisplayName
  174. {
  175. get
  176. {
  177. if (_scGasName != null)
  178. return _scGasName.StringValue;
  179. return Display;
  180. }
  181. }
  182. private DeviceTimer rampTimer = new DeviceTimer();
  183. private double rampTarget;
  184. private double rampInitValue;
  185. private int rampTime;
  186. private bool _bMfcAlarm = false;
  187. private ToleranceChecker _alarmChecker = new ToleranceChecker();
  188. private ToleranceChecker _warningChecker = new ToleranceChecker();
  189. private AIAccessor _aiFlow;
  190. private AOAccessor _aoFlow;
  191. private AOAccessor _aoRange;
  192. private DIAccessor _diOffline;
  193. private DIAccessor _diPressureAlarm;
  194. private SCConfigItem _scGasName;
  195. private SCConfigItem _scEnable;
  196. private SCConfigItem _scN2Scale;
  197. private SCConfigItem _scScaleFactor;
  198. private SCConfigItem _scAlarmRange;
  199. private SCConfigItem _scEnableAlarm;
  200. private SCConfigItem _scAlarmTime;
  201. private SCConfigItem _scDefaultSetPoint;
  202. private SCConfigItem _scRegulationFactor;
  203. private SCConfigItem _scWarningRange;
  204. private SCConfigItem _scWarningTime;
  205. public bool Recipetolerance;
  206. private R_TRIG _trigOffline = new R_TRIG();
  207. private R_TRIG _trigPressureAlarm = new R_TRIG();
  208. private string _uniqueName;
  209. private string GasFlowOutOfTolerance = "GasFlowOutOfTolerance";
  210. private float _recipeAlarmRange;
  211. private float _recipeWarningRange;
  212. private int _recipeIgnoreTimeMS;
  213. private ToleranceChecker _recipeAlarmChecker = new ToleranceChecker();
  214. private ToleranceChecker _recipeWarningChecker = new ToleranceChecker();
  215. private DeviceTimer _recipeIgnoreTimer = new DeviceTimer();
  216. private object _lockerTolerance = new object();
  217. private ushort _ANALOG_TRANS_RANGE = 8000;
  218. public IoMfc1(string module, XmlElement node, string ioModule = "")
  219. {
  220. Unit = node.GetAttribute("unit");
  221. base.Module = module;
  222. base.Name = node.GetAttribute("id");
  223. base.Display = node.GetAttribute("display");
  224. base.DeviceID = node.GetAttribute("schematicId");
  225. _aoRange = ParseAoNode("aoRange", node, ioModule);
  226. _diOffline = ParseDiNode("diOffline", node, ioModule);
  227. _aiFlow = ParseAiNode("aiFlow", node, ioModule);
  228. _aoFlow = ParseAoNode("aoFlow", node, ioModule);
  229. _diPressureAlarm = ParseDiNode("diPressureAlarm", node, ioModule);
  230. _scGasName = SC.GetConfigItem($"{Module}.{Name}.GasName");
  231. _scEnable = SC.GetConfigItem($"{Module}.{Name}.Enable");
  232. _scN2Scale = SC.GetConfigItem($"{Module}.{Name}.MfcN2Scale");
  233. _scScaleFactor = SC.GetConfigItem($"{Module}.{Name}.MfcScaleFactor");
  234. _scAlarmRange = SC.GetConfigItem($"{Module}.{Name}.MfcAlarmRange");
  235. _scEnableAlarm = SC.GetConfigItem($"{Module}.{Name}.MfcEnableAlarm");
  236. _scAlarmTime = SC.GetConfigItem($"{Module}.{Name}.MfcAlarmTime");
  237. _scDefaultSetPoint = SC.GetConfigItem($"{Module}.{Name}.DefaultSetPoint");
  238. _scRegulationFactor = SC.GetConfigItem($"{Module}.{Name}.FlowRegulationFactor");
  239. _scWarningRange = SC.GetConfigItem($"{Module}.{Name}.MfcWarningRange");
  240. _scWarningTime = SC.GetConfigItem($"{Module}.{Name}.MfcWarningTime");
  241. if (SC.ContainsItem("System.ANALOG_TRANS_RANGE"))
  242. {
  243. _ANALOG_TRANS_RANGE = Convert.ToUInt16(SC.GetValue<int>("System.ANALOG_TRANS_RANGE"));
  244. }
  245. Recipetolerance = SC.GetValue<bool>($"System.Recipetolerance");
  246. _uniqueName = $"{Module}.{Name}";
  247. if (_scGasName != null)
  248. Display = _scGasName.StringValue;
  249. #if DEBUG
  250. Debug.Assert(!string.IsNullOrWhiteSpace(_scGasName.StringValue));
  251. Debug.Assert(null != _scN2Scale);
  252. Debug.Assert(null != _aoFlow);
  253. Debug.Assert(null != _aiFlow);
  254. #endif
  255. }
  256. public override bool Initialize()
  257. {
  258. EV.Subscribe(new EventItem("Event", GasFlowOutOfTolerance, "Gas Flow Out Of Tolerance", EventLevel.Alarm, EventType.HostNotification));
  259. DATA.Subscribe($"{Module}.{Name}", () =>
  260. {
  261. AITMfcData data = new AITMfcData
  262. {
  263. Type = "MFC",
  264. UniqueName = _uniqueName,
  265. DeviceName = Name,
  266. DeviceSchematicId = DeviceID,
  267. DisplayName = DisplayName,
  268. FeedBack = FeedBack,
  269. SetPoint = SetPoint,
  270. Scale = Scale,
  271. IsOffline = IsOffline,
  272. };
  273. return data;
  274. }, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  275. OP.Subscribe($"{Module}.{Name}.{AITMfcOperation.Ramp}", (name, args) =>
  276. {
  277. double target = (double)args[0];
  278. target = Math.Min(target, Scale);
  279. target = Math.Max(target, 0);
  280. Ramp(target, 0);
  281. EV.PostInfoLog(Module, $"Ramp to {target}{Unit}");
  282. return true;
  283. });
  284. DEVICE.Register($"{Module}.{Name}.{AITMfcOperation.Ramp}", (out string reason, int time, object[] param) =>
  285. {
  286. double target = Convert.ToDouble((string)param[0]);
  287. target = Math.Min(target, Scale);
  288. target = Math.Max(target, 0);
  289. Ramp(target, time);
  290. reason = $"{Display} ramp to {target}{Unit}";
  291. return true;
  292. });
  293. //@AAA use recipe
  294. DEVICE.Register($"{Module}.{Name}", (out string reason, int time, object[] param) =>
  295. {
  296. double target = Convert.ToDouble((string)param[0]);
  297. target = Math.Min(target, Scale);
  298. target = Math.Max(target, 0);
  299. Ramp(target, time);
  300. reason = $"{Display} ramp to {target}{Unit}";
  301. return true;
  302. });
  303. OP.Subscribe($"{Module}.{Name}.SetRecipeTolerance", (out string reason, int time, object[] param) =>
  304. {
  305. reason = string.Empty;
  306. lock (_lockerTolerance)
  307. {
  308. _recipeIgnoreTimer.Stop();
  309. _recipeIgnoreTimeMS = Convert.ToInt32(param[0]) * 1000;
  310. _recipeWarningRange = Convert.ToSingle(param[1]);
  311. _recipeAlarmRange = Convert.ToSingle(param[2]);
  312. _recipeAlarmChecker.RST = true;
  313. _recipeWarningChecker.RST = true;
  314. _alarmChecker.RST = true;
  315. _warningChecker.RST = true;
  316. _recipeIgnoreTimer.Start(0);
  317. }
  318. return true;
  319. });
  320. return base.Initialize();
  321. }
  322. public override void Monitor()
  323. {
  324. if (Enable)
  325. {
  326. Ramping();
  327. CheckTolerance();
  328. if (_aoRange != null)
  329. _aoRange.Value = (short)Scale;
  330. _trigOffline.CLK = IsOffline;
  331. if (_trigOffline.Q)
  332. {
  333. EV.PostAlarmLog(Module, string.Format("{0} is offline", DisplayName));
  334. _bMfcAlarm = true;
  335. }
  336. _trigPressureAlarm.CLK = PressureAlarm == false;
  337. if (_trigPressureAlarm.Q)
  338. EV.PostAlarmLog(Module, $"{Name}, {DisplayName} Pressure Alarm");
  339. if (PressureAlarm)
  340. {
  341. _trigPressureAlarm.RST = true;
  342. }
  343. }
  344. }
  345. public override void Reset()
  346. {
  347. _bMfcAlarm = false;
  348. _trigPressureAlarm.RST = true;
  349. _trigOffline.RST = true;
  350. _alarmChecker.RST = true;
  351. _warningChecker.RST = true;
  352. _recipeWarningChecker.RST = true;
  353. _recipeAlarmChecker.RST = true;
  354. }
  355. public override void Terminate()
  356. {
  357. Ramp(DefaultSetPoint, 0);
  358. }
  359. public override void Ramp(int time)
  360. {
  361. Ramp(DefaultSetPoint, time);
  362. }
  363. public override void Ramp(double target, int time)
  364. {
  365. target = Math.Max(0, target);
  366. target = Math.Min(Scale, target);
  367. rampInitValue = SetPoint; //ramp 初始值取当前设定值,而非实际读取值。零漂问题
  368. rampTime = time;
  369. rampTarget = target;
  370. rampTimer.Start(rampTime);
  371. }
  372. public override void StopRamp()
  373. {
  374. Ramp(SetPoint, 0);
  375. }
  376. private void Ramping()
  377. {
  378. if (rampTimer.IsTimeout() || rampTime == 0)
  379. {
  380. SetPoint = rampTarget;
  381. }
  382. else
  383. {
  384. SetPoint = rampInitValue + (rampTarget - rampInitValue) * rampTimer.GetElapseTime() / rampTime;
  385. }
  386. }
  387. private void CheckTolerance()
  388. {
  389. lock (_lockerTolerance)
  390. {
  391. if (!Enable)
  392. return;
  393. if (Math.Abs(SetPoint) < 0.01)
  394. return;
  395. double alarmRange = _scAlarmRange.IntValue;
  396. double alarmTime = _scAlarmTime.IntValue;
  397. ToleranceChecker alarmChecker = _alarmChecker;
  398. if ((_recipeAlarmRange > 0) && (_recipeAlarmRange / 100.0 * SetPoint < _scAlarmRange.IntValue) && Recipetolerance)
  399. {
  400. alarmRange = _recipeAlarmRange / 100.0 * SetPoint;
  401. alarmChecker = _recipeAlarmChecker;
  402. _alarmChecker.RST = true;
  403. }
  404. else
  405. {
  406. if (!EnableAlarm || Math.Abs(alarmRange) < 0.01)
  407. {
  408. alarmChecker = null;
  409. }
  410. _recipeAlarmChecker.RST = true;
  411. }
  412. if (_recipeIgnoreTimer.GetElapseTime() > _recipeIgnoreTimeMS && alarmChecker != null)
  413. {
  414. alarmChecker.Monitor(FeedBack, SetPoint - Math.Abs(alarmRange), SetPoint + Math.Abs(alarmRange), alarmTime);
  415. if (alarmChecker.Trig)
  416. {
  417. LOG.Write($"_recipeIgnoreTimer Elapse time : {_recipeIgnoreTimer.GetElapseTime()}ms , _recipeIgnoreTimeMS :{_recipeIgnoreTimeMS}ms");
  418. EV.PostAlarmLog(Module, $" flow={FeedBack}, setpoint={SetPoint}, out of tolerance({SetPoint - Math.Abs(alarmRange)},{SetPoint + Math.Abs(alarmRange)}) in {alarmTime:0} seconds");
  419. EV.Notify(GasFlowOutOfTolerance);
  420. }
  421. }
  422. double warningRange = _scWarningRange.IntValue;
  423. double warningTime = _scWarningTime.IntValue;
  424. ToleranceChecker warningChecker = _warningChecker;
  425. if ((_recipeWarningRange > 0) && (_recipeWarningRange / 100.0 * SetPoint < _scWarningRange.IntValue) && Recipetolerance)
  426. {
  427. warningRange = _recipeWarningRange / 100.0 * SetPoint;
  428. warningChecker = _recipeWarningChecker;
  429. _warningChecker.RST = true;
  430. }
  431. else
  432. {
  433. if (!EnableAlarm || Math.Abs(warningRange) < 0.01)
  434. {
  435. warningChecker = null;
  436. }
  437. _recipeWarningChecker.RST = true;
  438. }
  439. if (_recipeIgnoreTimer.GetElapseTime() > _recipeIgnoreTimeMS && warningChecker != null)
  440. {
  441. warningChecker.Monitor(FeedBack, SetPoint - Math.Abs(warningRange), SetPoint + Math.Abs(warningRange), warningTime);
  442. if (warningChecker.Trig)
  443. {
  444. EV.PostWarningLog(Module, $" flow={FeedBack}, setpoint={SetPoint}, out of tolerance({SetPoint - Math.Abs(warningRange)},{SetPoint + Math.Abs(warningRange)}) in {warningTime:0} seconds");
  445. }
  446. }
  447. }
  448. }
  449. }
  450. }