IoMfc.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  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.Device;
  7. using Aitex.Core.RT.Event;
  8. using Aitex.Core.RT.IOCore;
  9. using Aitex.Core.RT.OperationCenter;
  10. using Aitex.Core.RT.SCCore;
  11. using Aitex.Core.RT.Tolerance;
  12. using Aitex.Core.Util;
  13. using SorterRT.Modules;
  14. namespace Virgo_DRT.Devices.IODevices
  15. {
  16. //will be upgrade later
  17. public class MfcBase1 : BaseDevice, IDevice
  18. {
  19. public virtual double SetPoint { get; set; }
  20. public virtual bool IsOutOfTolerance { get; }
  21. public MfcBase1()
  22. {
  23. }
  24. public virtual bool Initialize()
  25. {
  26. return true;
  27. }
  28. public virtual void Monitor()
  29. {
  30. }
  31. public virtual void Reset()
  32. {
  33. }
  34. public virtual void Terminate()
  35. {
  36. }
  37. public virtual void Ramp(int time)
  38. {
  39. }
  40. public virtual void Ramp(double target, int time)
  41. {
  42. }
  43. public virtual void StopRamp()
  44. {
  45. }
  46. }
  47. public class IoMfc : MfcBase1
  48. {
  49. public string Unit
  50. {
  51. get; set;
  52. }
  53. [Subscription(AITMfcDataPropertyName.Scale)]
  54. public double Scale
  55. {
  56. get
  57. {
  58. if (_scN2Scale == null || _scScaleFactor == null)
  59. return 0;
  60. return _scN2Scale.IntValue * _scScaleFactor.DoubleValue;
  61. }
  62. }
  63. [Subscription(AITMfcDataPropertyName.IsEnable)]
  64. public bool Enable
  65. {
  66. get
  67. {
  68. if (_scEnable != null)
  69. return _scEnable.BoolValue;
  70. return false;
  71. }
  72. }
  73. [Subscription(AITMfcDataPropertyName.SetPoint)]
  74. public override double SetPoint
  75. {
  76. get
  77. {
  78. if (_aoFlow != null)
  79. {
  80. byte[] high = BitConverter.GetBytes(_aoFlow.Buffer[_aoFlow.Index]);
  81. byte[] low = BitConverter.GetBytes(_aoFlow.Buffer[_aoFlow.Index + 1]);
  82. float flow = BitConverter.ToSingle(new[] { high[0], high[1], low[0], low[1] }, 0);
  83. return flow * Scale / RtInstance.ANALOG_TRANS_RANGE;
  84. }
  85. return 0;
  86. }
  87. set
  88. {
  89. if (_aoFlow != null)
  90. {
  91. byte[] flow = BitConverter.GetBytes((float)(value * RtInstance.ANALOG_TRANS_RANGE / Scale));
  92. _aoFlow.Buffer[_aoFlow.Index] = BitConverter.ToInt16(flow, 0);
  93. _aoFlow.Buffer[_aoFlow.Index + 1] = BitConverter.ToInt16(flow, 2);
  94. }
  95. }
  96. }
  97. [Subscription(AITMfcDataPropertyName.DefaultSetPoint)]
  98. public double DefaultSetPoint
  99. {
  100. get
  101. {
  102. if (_scDefaultSetPoint != null)
  103. return _scDefaultSetPoint.IntValue;
  104. return 0;
  105. }
  106. }
  107. [Subscription(AITMfcDataPropertyName.FeedBack)]
  108. public double FeedBack
  109. {
  110. get
  111. {
  112. if (_aiFlow != null)
  113. {
  114. byte[] high = BitConverter.GetBytes(_aiFlow.Buffer[_aiFlow.Index]);
  115. byte[] low = BitConverter.GetBytes(_aiFlow.Buffer[_aiFlow.Index + 1]);
  116. float flow = BitConverter.ToSingle(new[] { high[0], high[1], low[0], low[1] }, 0);
  117. return (_scRegulationFactor != null && _scRegulationFactor.IntValue > 0) ? flow * Scale / RtInstance.ANALOG_TRANS_RANGE / _scRegulationFactor.IntValue
  118. : flow * Scale / RtInstance.ANALOG_TRANS_RANGE;
  119. }
  120. return 0;
  121. }
  122. }
  123. [Subscription(AITMfcDataPropertyName.IsOutOfTolerance)]
  124. public override bool IsOutOfTolerance
  125. {
  126. get
  127. {
  128. return _toleranceChecker.Result;
  129. }
  130. }
  131. [Subscription(AITMfcDataPropertyName.IsEnableAlarm)]
  132. public bool EnableAlarm
  133. {
  134. get
  135. {
  136. if (_scEnableAlarm != null)
  137. return _scEnableAlarm.BoolValue;
  138. return false;
  139. }
  140. }
  141. [Subscription(AITMfcDataPropertyName.AlarmRange)]
  142. public double AlarmRange
  143. {
  144. get
  145. {
  146. if (_scAlarmRange != null)
  147. return _scAlarmRange.IntValue;
  148. return 0;
  149. }
  150. }
  151. [Subscription(AITMfcDataPropertyName.AlarmTime)]
  152. public double AlarmTime
  153. {
  154. get
  155. {
  156. if (_scAlarmTime != null)
  157. return _scAlarmTime.IntValue;
  158. return 0;
  159. }
  160. }
  161. [Subscription(AITMfcDataPropertyName.MfcAlarm)]
  162. public bool MfcAlarm
  163. {
  164. get
  165. {
  166. return _bMfcAlarm;
  167. }
  168. }
  169. [Subscription(AITMfcDataPropertyName.PressureAlarm)]
  170. public bool PressureAlarm
  171. {
  172. get { return _diPressureAlarm != null ? _diPressureAlarm.Value : true; }
  173. }
  174. [Subscription(AITMfcDataPropertyName.IsOffline)]
  175. public bool IsOffline
  176. {
  177. get
  178. {
  179. if (_diOffline != null)
  180. return _diOffline.Value;
  181. return false;
  182. }
  183. }
  184. public string DisplayName
  185. {
  186. get
  187. {
  188. if (_scGasName != null)
  189. return _scGasName.StringValue;
  190. return Display;
  191. }
  192. }
  193. private DeviceTimer rampTimer = new DeviceTimer();
  194. private double rampTarget;
  195. private double rampInitValue;
  196. private int rampTime;
  197. private bool _bMfcAlarm = false;
  198. private ToleranceChecker _toleranceChecker = new ToleranceChecker();
  199. private AIAccessor _aiFlow;
  200. private AOAccessor _aoFlow;
  201. private AOAccessor _aoRange;
  202. private DIAccessor _diOffline;
  203. private DIAccessor _diPressureAlarm;
  204. private SCConfigItem _scGasName;
  205. private SCConfigItem _scEnable;
  206. private SCConfigItem _scN2Scale;
  207. private SCConfigItem _scScaleFactor;
  208. private SCConfigItem _scAlarmRange;
  209. private SCConfigItem _scEnableAlarm;
  210. private SCConfigItem _scAlarmTime;
  211. private SCConfigItem _scDefaultSetPoint;
  212. private SCConfigItem _scRegulationFactor;
  213. private R_TRIG _trigOffline = new R_TRIG();
  214. private F_TRIG _trigPressureAlarm = new F_TRIG();
  215. private string _uniqueName;
  216. public IoMfc(string module, XmlElement node, string ioModule = "")
  217. {
  218. Unit = node.GetAttribute("unit");
  219. base.Module = module;
  220. base.Name = node.GetAttribute("id");
  221. base.Display = node.GetAttribute("display");
  222. base.DeviceID = node.GetAttribute("schematicId");
  223. _aoRange = ParseAoNode("aoRange", node, ioModule);
  224. _diOffline = ParseDiNode("diOffline", node, ioModule);
  225. _aiFlow = ParseAiNode("aiFlow", node, ioModule);
  226. _aoFlow = ParseAoNode("aoFlow", node, ioModule);
  227. _diPressureAlarm = ParseDiNode("diPressureAlarm", node, ioModule);
  228. _scGasName = SC.GetConfigItem($"{Module}.{Name}.GasName");
  229. _scEnable = SC.GetConfigItem($"{Module}.{Name}.Enable");
  230. _scN2Scale = SC.GetConfigItem($"{Module}.{Name}.MfcN2Scale");
  231. _scScaleFactor = SC.GetConfigItem($"{Module}.{Name}.MfcScaleFactor");
  232. _scAlarmRange = SC.GetConfigItem($"{Module}.{Name}.MfcAlarmRange");
  233. _scEnableAlarm = SC.GetConfigItem($"{Module}.{Name}.MfcEnableAlarm");
  234. _scAlarmTime = SC.GetConfigItem($"{Module}.{Name}.MfcAlarmTime");
  235. _scDefaultSetPoint = SC.GetConfigItem($"{Module}.{Name}.DefaultSetPoint");
  236. _scRegulationFactor = SC.GetConfigItem($"{module}.{Name}.FlowRegulationFactor");
  237. _uniqueName = $"{Module}.{Name}";
  238. #if DEBUG
  239. Debug.Assert(!string.IsNullOrWhiteSpace(_scGasName.StringValue));
  240. Debug.Assert(null != _scN2Scale);
  241. Debug.Assert(null != _aoFlow);
  242. Debug.Assert(null != _aiFlow);
  243. #endif
  244. }
  245. public override bool Initialize()
  246. {
  247. DATA.Subscribe($"{Module}.{Name}", () =>
  248. {
  249. AITMfcData data = new AITMfcData
  250. {
  251. Type = "MFC",
  252. UniqueName = _uniqueName,
  253. DeviceName = Name,
  254. DeviceSchematicId = DeviceID,
  255. DisplayName = DisplayName,
  256. FeedBack = FeedBack,
  257. SetPoint = SetPoint,
  258. Scale = Scale,
  259. IsOffline = IsOffline,
  260. };
  261. return data;
  262. }, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  263. OP.Subscribe($"{Module}.{Name}.{AITMfcOperation.Ramp}", (name, args) =>
  264. {
  265. double target = (double)args[0];
  266. target = Math.Min(target, Scale);
  267. target = Math.Max(target, 0);
  268. Ramp(target, 0);
  269. EV.PostInfoLog(Module, $"Ramp to {target}{Unit}");
  270. return true;
  271. });
  272. DEVICE.Register($"{Module}.{Name}.{AITMfcOperation.Ramp}", (out string reason, int time, object[] param) =>
  273. {
  274. double target = Convert.ToDouble((string)param[0]);
  275. target = Math.Min(target, Scale);
  276. target = Math.Max(target, 0);
  277. Ramp(target, time);
  278. reason = $"{Display} ramp to {target}{Unit}";
  279. return true;
  280. });
  281. //@AAA use recipe
  282. DEVICE.Register($"{Module}.{Name}", (out string reason, int time, object[] param) =>
  283. {
  284. double target = Convert.ToDouble((string)param[0]);
  285. target = Math.Min(target, Scale);
  286. target = Math.Max(target, 0);
  287. Ramp(target, time);
  288. reason = $"{Display} ramp to {target}{Unit}";
  289. return true;
  290. });
  291. return true;
  292. }
  293. public override void Monitor()
  294. {
  295. if (Enable)
  296. {
  297. Ramping();
  298. CheckTolerance();
  299. if (_aoRange != null)
  300. _aoRange.Value = (short)Scale;
  301. _trigOffline.CLK = IsOffline;
  302. if (_trigOffline.Q)
  303. {
  304. EV.PostAlarmLog(Module, string.Format("{0} is offline", DisplayName));
  305. _bMfcAlarm = true;
  306. }
  307. _trigPressureAlarm.CLK = PressureAlarm;
  308. if (_trigPressureAlarm.Q)
  309. EV.PostAlarmLog(Module, $"{Name} Pressure Alarm");
  310. }
  311. }
  312. public override void Reset()
  313. {
  314. _bMfcAlarm = false;
  315. _toleranceChecker.Reset(AlarmTime);
  316. _trigPressureAlarm.RST = true;
  317. _trigOffline.RST = true;
  318. }
  319. public override void Terminate()
  320. {
  321. Ramp(DefaultSetPoint, 0);
  322. }
  323. public override void Ramp(int time)
  324. {
  325. Ramp(DefaultSetPoint, time);
  326. }
  327. public override void Ramp(double target, int time)
  328. {
  329. target = Math.Max(0, target);
  330. target = Math.Min(Scale, target);
  331. rampInitValue = SetPoint; //ramp 初始值取当前设定值,而非实际读取值。零漂问题
  332. rampTime = time;
  333. rampTarget = target;
  334. rampTimer.Start(rampTime);
  335. }
  336. public override void StopRamp()
  337. {
  338. Ramp(SetPoint, 0);
  339. }
  340. private void Ramping()
  341. {
  342. if (rampTimer.IsTimeout() || rampTime == 0)
  343. {
  344. SetPoint = rampTarget;
  345. }
  346. else
  347. {
  348. SetPoint = rampInitValue + (rampTarget - rampInitValue) * rampTimer.GetElapseTime() / rampTime;
  349. }
  350. }
  351. private void CheckTolerance()
  352. {
  353. if (!EnableAlarm)
  354. return;
  355. // 流率检查
  356. _toleranceChecker.Monitor(FeedBack, SetPoint - Math.Abs(AlarmRange), SetPoint + Math.Abs(AlarmRange), AlarmTime);
  357. if (_toleranceChecker.Trig)
  358. {
  359. EV.PostAlarmLog(Module, Display + $" 越界 in {AlarmTime:0} seconds");
  360. _bMfcAlarm = true;
  361. }
  362. }
  363. }
  364. }