IoMfc3.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. using System;
  2. using System.Xml;
  3. using Aitex.Core.Common.DeviceData;
  4. using Aitex.Core.RT.DataCenter;
  5. using Aitex.Core.RT.Event;
  6. using Aitex.Core.RT.IOCore;
  7. using Aitex.Core.RT.Log;
  8. using Aitex.Core.RT.OperationCenter;
  9. using Aitex.Core.RT.SCCore;
  10. using Aitex.Core.RT.Tolerance;
  11. using Aitex.Core.Util;
  12. using MECF.Framework.Common.Event;
  13. using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.MFCs;
  14. namespace Aitex.Core.RT.Device.Unit
  15. {
  16. /// <summary>
  17. ///
  18. /// </summary>
  19. public class IoMfc3 : BaseDevice, IDevice, IMfc
  20. {
  21. public string Unit
  22. {
  23. get; set;
  24. }
  25. public double Scale
  26. {
  27. get
  28. {
  29. if (_scN2Scale == null || _scScaleFactor == null)
  30. return 0;
  31. return _scN2Scale.DoubleValue * _scScaleFactor.DoubleValue;
  32. }
  33. }
  34. public double SetPoint
  35. {
  36. get
  37. {
  38. if (_aoFlow != null)
  39. {
  40. return _isFloatAioType ? _aoFlow.FloatValue : _aoFlow.Value;
  41. }
  42. return 0;
  43. }
  44. set
  45. {
  46. if (_aoFlow != null)
  47. {
  48. if (_isFloatAioType)
  49. _aoFlow.FloatValue = (float)value;
  50. else
  51. _aoFlow.Value = (short)value;
  52. }
  53. }
  54. }
  55. public double DefaultSetPoint
  56. {
  57. get
  58. {
  59. if (_scDefaultSetPoint != null)
  60. return _scDefaultSetPoint.DoubleValue;
  61. return 0;
  62. }
  63. }
  64. public double FeedBack
  65. {
  66. get
  67. {
  68. if (_aiFlow != null)
  69. {
  70. double aiValue = _isFloatAioType ? _aiFlow.FloatValue : _aiFlow.Value;
  71. return (_scRegulationFactor != null && _scRegulationFactor.DoubleValue > 0.001) ? aiValue / _scRegulationFactor.DoubleValue : aiValue;
  72. }
  73. return 0;
  74. }
  75. }
  76. public bool EnableAlarm
  77. {
  78. get
  79. {
  80. if (_scEnableAlarm != null)
  81. return _scEnableAlarm.BoolValue;
  82. return false;
  83. }
  84. }
  85. public double AlarmRange
  86. {
  87. get
  88. {
  89. if (_scAlarmRange != null)
  90. return _scAlarmRange.DoubleValue;
  91. return 0;
  92. }
  93. }
  94. public double AlarmTime
  95. {
  96. get
  97. {
  98. if (_scAlarmTime != null)
  99. return _scAlarmTime.IntValue;
  100. return 0;
  101. }
  102. }
  103. public double WarningRange
  104. {
  105. get
  106. {
  107. if (_scWarningRange != null)
  108. return _scWarningRange.DoubleValue;
  109. return 0;
  110. }
  111. }
  112. public double WarningTime
  113. {
  114. get
  115. {
  116. if (_scWarningTime != null)
  117. return _scWarningTime.IntValue;
  118. return 0;
  119. }
  120. }
  121. private AITMfcData DeviceData
  122. {
  123. get
  124. {
  125. AITMfcData data = new AITMfcData()
  126. {
  127. UniqueName = $"{Module}.{Name}",
  128. Type = "MFC",
  129. Module = Module,
  130. DeviceName = Name,
  131. DeviceSchematicId = DeviceID,
  132. DisplayName = DisplayName,
  133. FeedBack = FeedBack,
  134. SetPoint = SetPoint,
  135. Scale = Scale,
  136. IsWarning = !AlarmToleranceWarning.IsAcknowledged,
  137. IsError = !AlarmToleranceAlarm.IsAcknowledged,
  138. };
  139. return data;
  140. }
  141. }
  142. public string DisplayName
  143. {
  144. get
  145. {
  146. if (_scGasName != null)
  147. return _scGasName.StringValue;
  148. return Display;
  149. }
  150. }
  151. private DeviceTimer _rampTimer = new DeviceTimer();
  152. private double _rampTarget;
  153. private double _rampInitValue;
  154. private int _rampTime;
  155. private ToleranceChecker _toleranceCheckerWarning = new ToleranceChecker();
  156. private ToleranceChecker _toleranceCheckerAlarm = new ToleranceChecker();
  157. private AIAccessor _aiFlow;
  158. private AOAccessor _aoFlow;
  159. private DOAccessor _doOpen;
  160. private DOAccessor _doClose;
  161. protected SCConfigItem _scGasName;
  162. protected SCConfigItem _scEnable;
  163. private SCConfigItem _scN2Scale;
  164. private SCConfigItem _scScaleFactor;
  165. private SCConfigItem _scAlarmRange;
  166. private SCConfigItem _scEnableAlarm;
  167. private SCConfigItem _scAlarmTime;
  168. private SCConfigItem _scDefaultSetPoint;
  169. private SCConfigItem _scRegulationFactor;
  170. protected SCConfigItem _scWarningTime;
  171. protected SCConfigItem _scWarningRange;
  172. public AlarmEventItem AlarmToleranceWarning { get; set; }
  173. public AlarmEventItem AlarmToleranceAlarm { get; set; }
  174. private bool _isFloatAioType = false;
  175. public IoMfc3(string module, XmlElement node, string ioModule = "")
  176. {
  177. Unit = node.GetAttribute("unit");
  178. base.Module = string.IsNullOrEmpty(node.GetAttribute("module")) ? module : node.GetAttribute("module");
  179. base.Name = node.GetAttribute("id");
  180. base.Display = node.GetAttribute("display");
  181. base.DeviceID = node.GetAttribute("schematicId");
  182. _aiFlow = ParseAiNode("aiFlow", node, ioModule);
  183. _aoFlow = ParseAoNode("aoFlow", node, ioModule);
  184. _doOpen = ParseDoNode("doOpen", node, ioModule);
  185. _doClose = ParseDoNode("doClose", node, ioModule);
  186. _isFloatAioType = !string.IsNullOrEmpty(node.GetAttribute("aioType")) && (node.GetAttribute("aioType")=="float");
  187. string scBasePath = node.GetAttribute("scBasePath");
  188. if (string.IsNullOrEmpty(scBasePath))
  189. scBasePath = $"{Module}.{Name}";
  190. else
  191. {
  192. scBasePath = scBasePath.Replace("{module}", Module);
  193. }
  194. _scGasName = SC.GetConfigItem($"{scBasePath}.{Name}.GasName");
  195. _scEnable = SC.GetConfigItem($"{scBasePath}.{Name}.Enable");
  196. _scN2Scale = ParseScNode("scN2Scale", node, ioModule, $"{scBasePath}.{Name}.N2Scale");
  197. _scScaleFactor = ParseScNode("scScaleFactor", node, ioModule, $"{scBasePath}.{Name}.ScaleFactor");
  198. _scAlarmRange = ParseScNode("scAlarmRange", node, ioModule, $"{scBasePath}.{Name}.AlarmRange");
  199. _scEnableAlarm = ParseScNode("scEnableAlarm", node, ioModule, $"{scBasePath}.{Name}.EnableAlarm");
  200. _scAlarmTime = ParseScNode("scAlarmTime", node, ioModule, $"{scBasePath}.{Name}.AlarmTime");
  201. _scDefaultSetPoint = ParseScNode("scDefaultSetPoint", node, ioModule, $"{scBasePath}.{Name}.DefaultSetPoint");
  202. _scWarningRange = SC.GetConfigItem($"{scBasePath}.{Name}.WarningRange");
  203. _scWarningTime = SC.GetConfigItem($"{scBasePath}.{Name}.WarningTime");
  204. _scRegulationFactor = ParseScNode("scFlowRegulationFactor", node, ioModule, $"{scBasePath}.{Name}.RegulationFactor");
  205. }
  206. public bool Initialize()
  207. {
  208. DATA.Subscribe($"{Module}.{Name}.DeviceData", () => DeviceData);
  209. DATA.Subscribe($"{Module}.{Name}.Feedback", () => FeedBack);
  210. DATA.Subscribe($"{Module}.{Name}.SetPoint", () => SetPoint);
  211. OP.Subscribe($"{Module}.{Name}.Ramp", (out string reason, int time, object[] param) =>
  212. {
  213. double target = Convert.ToDouble(param[0].ToString());
  214. if (target < 0 || target > Scale)
  215. {
  216. reason = $"set {Display} value {target} out of range [0, {Scale}] {Unit}";
  217. return false;
  218. }
  219. Ramp(target, time);
  220. if (time > 0)
  221. {
  222. reason = $"{Display} ramp to {target} {Unit} in {time} seconds";
  223. }
  224. else
  225. {
  226. reason = $"{Display} ramp to {target} {Unit}";
  227. }
  228. return true;
  229. });
  230. //for recipe
  231. OP.Subscribe($"{Module}.{Name}.SetMfcFlow", (out string reason, int time, object[] param) =>
  232. {
  233. reason = string.Empty;
  234. var paras = param[0].ToString().Split(';');
  235. if (paras.Length == 1)
  236. {
  237. Ramp(Convert.ToSingle(paras[0]), 0, out reason);
  238. }
  239. else
  240. {
  241. Ramp(Convert.ToSingle(paras[0]), (int)Convert.ToSingle(paras[1]), out reason);
  242. }
  243. return true;
  244. });
  245. AlarmToleranceWarning = SubscribeAlarm($"{Module}.{Name}.ToleranceWarning", "", ResetWarningChecker, EventLevel.Warning);
  246. AlarmToleranceAlarm = SubscribeAlarm($"{Module}.{Name}.ToleranceAlarm", "", ResetAlarmChecker);
  247. return true;
  248. }
  249. public void Monitor()
  250. {
  251. MonitorRamping();
  252. MonitorTolerance();
  253. }
  254. public bool ResetWarningChecker()
  255. {
  256. _toleranceCheckerWarning.Reset(WarningTime);
  257. return true;
  258. }
  259. public bool ResetAlarmChecker()
  260. {
  261. _toleranceCheckerAlarm.Reset(AlarmTime);
  262. return true;
  263. }
  264. public void Reset()
  265. {
  266. AlarmToleranceWarning.Reset();
  267. AlarmToleranceAlarm.Reset();
  268. }
  269. public void Terminate()
  270. {
  271. Ramp(DefaultSetPoint, 0);
  272. }
  273. public bool Ramp(double flowSetPoint, int time, out string reason)
  274. {
  275. if (HasAlarm)
  276. {
  277. reason = $"{DisplayName} in error status, can not flow";
  278. return false;
  279. }
  280. if (flowSetPoint < 0 || flowSetPoint > Scale)
  281. {
  282. reason = $"{DisplayName} range is [0, {Scale}], can not flow {flowSetPoint}";
  283. return false;
  284. }
  285. if (time > 0)
  286. {
  287. EV.PostInfoLog(Module, $"Set {DisplayName} flow to {flowSetPoint} {Unit} in {time/1000:F0} seconds");
  288. }
  289. else
  290. {
  291. EV.PostInfoLog(Module, $"Set {DisplayName} flow to {flowSetPoint} {Unit}");
  292. }
  293. Ramp(flowSetPoint, time);
  294. reason = string.Empty;
  295. return true;
  296. }
  297. public void Ramp(int time)
  298. {
  299. Ramp(DefaultSetPoint, time);
  300. }
  301. public void Ramp(double target, int time)
  302. {
  303. target = Math.Max(0, target);
  304. target = Math.Min(Scale, target);
  305. _rampInitValue = SetPoint; //ramp 初始值取当前设定值,而非实际读取值.零漂问题
  306. _rampTime = time;
  307. _rampTarget = target;
  308. _rampTimer.Start(_rampTime);
  309. }
  310. public void StopRamp()
  311. {
  312. Ramp(SetPoint, 0);
  313. }
  314. private void MonitorRamping()
  315. {
  316. if (!_rampTimer.IsIdle())
  317. {
  318. if (_rampTimer.IsTimeout() || _rampTime == 0)
  319. {
  320. _rampTimer.Stop();
  321. SetPoint = _rampTarget;
  322. }
  323. else
  324. {
  325. SetPoint = _rampInitValue + (_rampTarget - _rampInitValue) * _rampTimer.GetElapseTime() / _rampTime;
  326. }
  327. }
  328. }
  329. public bool SetOpen(bool isOpen, out string reason)
  330. {
  331. reason = string.Empty;
  332. if (_doOpen != null)
  333. {
  334. if (!_doOpen.SetValue(isOpen, out reason))
  335. {
  336. LOG.Write(reason);
  337. return false;
  338. }
  339. }
  340. if (_doClose != null)
  341. {
  342. if (!_doClose.SetValue(!isOpen, out reason))
  343. {
  344. LOG.Write(reason);
  345. return false;
  346. }
  347. }
  348. return true;
  349. }
  350. private void MonitorTolerance()
  351. {
  352. if (!EnableAlarm || SetPoint < 0.01)
  353. {
  354. _toleranceCheckerWarning.RST = true;
  355. _toleranceCheckerAlarm.RST = true;
  356. return;
  357. }
  358. _toleranceCheckerWarning.Monitor(FeedBack, (SetPoint - Math.Abs(WarningRange)), (SetPoint + Math.Abs(WarningRange)), WarningTime);
  359. if (_toleranceCheckerWarning.Trig)
  360. {
  361. AlarmToleranceWarning.Description = $"{Display} flow out of range {WarningRange} {Unit} in {WarningTime:F0} seconds";
  362. AlarmToleranceWarning.Set();
  363. }
  364. _toleranceCheckerAlarm.Monitor(FeedBack, (SetPoint - Math.Abs(AlarmRange)), (SetPoint + Math.Abs(AlarmRange)), AlarmTime);
  365. if (_toleranceCheckerAlarm.Trig)
  366. {
  367. AlarmToleranceAlarm.Description = $"{Display} flow out of range {AlarmRange} {Unit} in {AlarmTime:F0} seconds";
  368. AlarmToleranceAlarm.Set();
  369. }
  370. }
  371. }
  372. }