ReservoirDosingRoutine.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. using Aitex.Core.RT.Device;
  2. using Aitex.Core.RT.Log;
  3. using Aitex.Core.RT.Routine;
  4. using Aitex.Core.RT.SCCore;
  5. using CyberX8_Core;
  6. using CyberX8_RT.Devices.Reservoir;
  7. using MECF.Framework.Common.Persistent.Reservoirs;
  8. using MECF.Framework.Common.RecipeCenter;
  9. using MECF.Framework.Common.Routine;
  10. using System;
  11. namespace CyberX8_RT.Modules.Reservoir
  12. {
  13. public class ReservoirDosingRoutine : RoutineBase, IRoutine
  14. {
  15. private enum DosingStep
  16. {
  17. Dosing_Check_Status,
  18. Dosing_Dispensing,
  19. Dosing_Wait_Complete,
  20. Dosing_Done,
  21. End
  22. }
  23. #region 内部变量
  24. /// <summary>
  25. /// 模块名称
  26. /// </summary>
  27. private string _moduleName;
  28. /// <summary>
  29. /// Replen名称
  30. /// </summary>
  31. private string _replenName;
  32. /// <summary>
  33. /// Replen ID
  34. /// </summary>
  35. private int _replenId;
  36. /// <summary>
  37. /// SHReservoirDevice
  38. /// </summary>
  39. private StandardHotReservoirDevice _standardHotReservoirdevice;
  40. /// <summary>
  41. /// 本次需要补充的液体体积(mL)
  42. /// </summary>
  43. private double _targetVolume;
  44. /// <summary>
  45. /// RDS Recipe
  46. /// </summary>
  47. private RdsRecipe _rdsRecipe;
  48. /// <summary>
  49. /// 补液开始时间(ms)
  50. /// </summary>
  51. private int _dosingStartTime;
  52. /// <summary>
  53. /// 补液需要消耗的时间(ms)
  54. /// </summary>
  55. private int _dosingTime;
  56. /// <summary>
  57. /// InitialDosingSpeed(mL/min)
  58. /// </summary>
  59. private double _initialDosingSpeed;
  60. /// <summary>
  61. /// Replen Persistent Value
  62. /// </summary>
  63. private ReplenPersistentValue _persistentValue;
  64. /// <summary>
  65. /// 是否为Auto模式
  66. /// </summary>
  67. private bool _isAutoMode;
  68. /// <summary>
  69. /// Dosing超时时间
  70. /// </summary>
  71. private int _dosingOutTime;
  72. #endregion
  73. #region 属性
  74. /// <summary>
  75. /// 状态
  76. /// </summary>
  77. public string State { get { return Runner.CurrentStep.ToString(); } }
  78. #endregion
  79. /// <summary>
  80. /// 构造函数
  81. /// </summary>
  82. /// <param name="name"></param>
  83. public ReservoirDosingRoutine(string module, string replenName) : base(module)
  84. {
  85. _moduleName = module;
  86. _replenName = replenName;
  87. _replenId = int.Parse(_replenName.Substring(6, 1));
  88. }
  89. public void Abort()
  90. {
  91. if (_standardHotReservoirdevice.ReplenDatas[_replenId - 1].ReplenPumpEnable)
  92. {
  93. //关闭Replen Pump
  94. Object[] args = new object[1];
  95. args[0] = _replenName;
  96. bool result = _standardHotReservoirdevice.ReplenPumpOffOperation("", args);
  97. if (result)
  98. {
  99. LOG.WriteLog(eEvent.INFO_RESERVOIR, _moduleName, "Replen Pump Off");
  100. }
  101. else
  102. {
  103. LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Replen Pump Off is failed");
  104. }
  105. _persistentValue.RemainDosingVolume -= _persistentValue.CurrentDosingVolume;
  106. }
  107. Runner.Stop($"{_moduleName}_{_replenName} Stop Dosing");
  108. }
  109. public RState Monitor()
  110. {
  111. Runner.Run(DosingStep.Dosing_Check_Status, CheckStatus, _delay_1ms)
  112. .Run(DosingStep.Dosing_Dispensing, Dispensing, _delay_1ms)
  113. .WaitWithStopCondition(DosingStep.Dosing_Wait_Complete, WaitCompleteEndStatus, WaitCompleteErrorStatus, _dosingTime + _dosingOutTime)
  114. .End(DosingStep.Dosing_Done, DoneOperation, _delay_1ms);
  115. return Runner.Status;
  116. }
  117. /// <summary>
  118. /// 启动
  119. /// </summary>
  120. /// <param name="objs"></param>
  121. /// <returns></returns>
  122. public RState Start(params object[] objs)
  123. {
  124. _targetVolume = (double)objs[0];
  125. _isAutoMode = (bool)objs[1];
  126. //加载Reservoir设备
  127. _standardHotReservoirdevice = DEVICE.GetDevice<StandardHotReservoirDevice>($"{_moduleName}");
  128. if (_standardHotReservoirdevice == null)
  129. {
  130. LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Reservoir Device is not exist");
  131. return RState.Failed;
  132. }
  133. //加载持久化文件
  134. _persistentValue = ReplenPersistentManager.Instance.GetReplenPersistentValue(_moduleName, _replenName);
  135. if (_persistentValue == null)
  136. {
  137. LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Replen Persistent Value Object is not exist");
  138. return RState.Failed;
  139. }
  140. //加载Recipe
  141. _rdsRecipe = _standardHotReservoirdevice.RdsRecipe[_replenId - 1];
  142. //手动模式下无需Recipe
  143. if (_isAutoMode && _rdsRecipe == null)
  144. {
  145. LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "RDS recipe is null");
  146. return RState.Failed;
  147. }
  148. if (SC.ContainsItem($"Reservoir.{_moduleName}.DosingOutTime"))
  149. {
  150. _dosingOutTime = (int)SC.GetValue<double>($"Reservoir.{_moduleName}.DosingOutTime") * 60 * 1000;
  151. }
  152. return Runner.Start(_moduleName +"_"+_replenName, "Dosing");
  153. }
  154. #region Operation
  155. /// <summary>
  156. /// Check Status
  157. /// </summary>
  158. /// <param name="param"></param>
  159. /// <returns></returns>
  160. private bool CheckStatus()
  161. {
  162. if (!_standardHotReservoirdevice.CheckandUpdateBottleLevel(_replenName, _targetVolume))
  163. {
  164. LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, $"Current Bottle is not in Full Level!");
  165. return false;
  166. }
  167. return true;
  168. }
  169. /// <summary>
  170. /// Dispensing
  171. /// </summary>
  172. /// <param name="param"></param>
  173. /// <returns></returns>
  174. private bool Dispensing()
  175. {
  176. //计算Dosing时间
  177. if (SC.ContainsItem($"Reservoir.{_moduleName}.InitialDosingSpeed"))
  178. {
  179. _initialDosingSpeed = SC.GetValue<double>($"Reservoir.{_moduleName}.InitialDosingSpeed");
  180. double pumpFactor = _persistentValue.ReplenPumpFactor;
  181. double adjustSpeed = pumpFactor * _initialDosingSpeed;
  182. SCConfigItem item = SC.GetConfigItem($"Reservoir.{Module}.InitialDosingSpeed");
  183. double speedMax = double.Parse(item.Max);
  184. if(adjustSpeed > speedMax)
  185. {
  186. _dosingTime = (int)((pumpFactor * _targetVolume / speedMax) * 60 * 1000);
  187. _initialDosingSpeed = speedMax / pumpFactor;
  188. }
  189. else
  190. {
  191. _dosingTime = (int)((_targetVolume / _initialDosingSpeed) * 60 * 1000);
  192. }
  193. }
  194. //记录Dosing开始时刻
  195. _dosingStartTime = Environment.TickCount;
  196. //打开Replen Pump
  197. Object[] args = new object[1];
  198. args[0] = _replenName;
  199. bool result = _standardHotReservoirdevice.ReplenPumpOnOperation("", args);
  200. if (result)
  201. {
  202. LOG.WriteLog(eEvent.INFO_RESERVOIR, _moduleName, "Replen Pump On");
  203. }
  204. else
  205. {
  206. LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Replen Pump On is failed");
  207. }
  208. return result;
  209. }
  210. /// <summary>
  211. /// WaitComplete End
  212. /// </summary>
  213. /// <returns></returns>
  214. private bool WaitCompleteEndStatus()
  215. {
  216. int tick = Environment.TickCount - _dosingStartTime;
  217. //更新实时DosingVolume
  218. _persistentValue.CurrentDosingVolume = Math.Round(tick * (_initialDosingSpeed / 1000 / 60), 2);
  219. ReplenPersistentManager.Instance.UpdatePersistentValue(_moduleName, _replenName);
  220. if (tick >= _dosingTime)
  221. {
  222. //关闭Replen Pump
  223. Object[] args = new object[1];
  224. args[0] = _replenName;
  225. bool result = _standardHotReservoirdevice.ReplenPumpOffOperation("", args);
  226. if (result)
  227. {
  228. LOG.WriteLog(eEvent.INFO_RESERVOIR, _moduleName, "Replen Pump Off");
  229. }
  230. else
  231. {
  232. LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Replen Pump Off is failed");
  233. }
  234. return true;
  235. }
  236. return false;
  237. }
  238. /// <summary>
  239. /// WaitComplete Error
  240. /// </summary>
  241. /// <returns></returns>
  242. private bool WaitCompleteErrorStatus()
  243. {
  244. //若Pump被关闭则报错
  245. if (!_standardHotReservoirdevice.ReplenDatas[_replenId - 1].ReplenPumpEnable)
  246. {
  247. _persistentValue.RemainDosingVolume = Math.Round(_persistentValue.RemainDosingVolume - _persistentValue.CurrentDosingVolume, 2);
  248. ReplenPersistentManager.Instance.UpdatePersistentValue(_moduleName, _replenName);
  249. LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Replen Pump is off. Stop Dosing");
  250. return true;
  251. }
  252. //若BottleLevel not full则报错
  253. if (!_standardHotReservoirdevice.CheckandUpdateBottleLevel(_replenName, _targetVolume))
  254. {
  255. _persistentValue.RemainDosingVolume = Math.Round(_persistentValue.RemainDosingVolume - _persistentValue.CurrentDosingVolume, 2);
  256. ReplenPersistentManager.Instance.UpdatePersistentValue(_moduleName, _replenName);
  257. return true;
  258. }
  259. return false;
  260. }
  261. /// <summary>
  262. /// Done Operation
  263. /// </summary>
  264. /// <param name="param"></param>
  265. /// <returns></returns>
  266. private bool DoneOperation()
  267. {
  268. //数据清零
  269. _persistentValue.CurrentDosingVolume = 0;
  270. _persistentValue.IsDosingRunning = false;
  271. _persistentValue.AutoDosingStartAmpHour = 0;
  272. _persistentValue.AutoDosingStartTime = DateTime.MinValue;
  273. _persistentValue.RemainDosingVolume = Math.Round(_persistentValue.RemainDosingVolume - _targetVolume, 2);
  274. ReplenPersistentManager.Instance.UpdatePersistentValue(_moduleName, _replenName);
  275. _targetVolume = 0;
  276. _dosingTime = 0;
  277. _dosingStartTime = 0;
  278. return true;
  279. }
  280. #endregion
  281. }
  282. }