using Aitex.Core.RT.Device; using Aitex.Core.RT.Log; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using CyberX8_Core; using CyberX8_RT.Devices.Reservoir; using MECF.Framework.Common.Persistent.Reservoirs; using MECF.Framework.Common.RecipeCenter; using MECF.Framework.Common.Routine; using System; namespace CyberX8_RT.Modules.Reservoir { public class ReservoirDosingRoutine : RoutineBase, IRoutine { private enum DosingStep { Dosing_Check_Status, Dosing_Dispensing, Dosing_Wait_Complete, Dosing_Done, End } #region 内部变量 /// /// 模块名称 /// private string _moduleName; /// /// Replen名称 /// private string _replenName; /// /// Replen ID /// private int _replenId; /// /// SHReservoirDevice /// private StandardHotReservoirDevice _standardHotReservoirdevice; /// /// 本次需要补充的液体体积(mL) /// private double _targetVolume; /// /// RDS Recipe /// private RdsRecipe _rdsRecipe; /// /// 补液开始时间(ms) /// private int _dosingStartTime; /// /// 补液需要消耗的时间(ms) /// private int _dosingTime; /// /// InitialDosingSpeed(mL/min) /// private double _initialDosingSpeed; /// /// Replen Persistent Value /// private ReplenPersistentValue _persistentValue; /// /// 是否为Auto模式 /// private bool _isAutoMode; /// /// Dosing超时时间 /// private int _dosingOutTime; #endregion #region 属性 /// /// 状态 /// public string State { get { return Runner.CurrentStep.ToString(); } } #endregion /// /// 构造函数 /// /// public ReservoirDosingRoutine(string module, string replenName) : base(module) { _moduleName = module; _replenName = replenName; _replenId = int.Parse(_replenName.Substring(6, 1)); } public void Abort() { if (_standardHotReservoirdevice.ReplenDatas[_replenId - 1].ReplenPumpEnable) { //关闭Replen Pump Object[] args = new object[1]; args[0] = _replenName; bool result = _standardHotReservoirdevice.ReplenPumpOffOperation("", args); if (result) { LOG.WriteLog(eEvent.INFO_RESERVOIR, _moduleName, "Replen Pump Off"); } else { LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Replen Pump Off is failed"); } _persistentValue.RemainDosingVolume -= _persistentValue.CurrentDosingVolume; } Runner.Stop($"{_moduleName}_{_replenName} Stop Dosing"); } public RState Monitor() { Runner.Run(DosingStep.Dosing_Check_Status, CheckStatus, _delay_1ms) .Run(DosingStep.Dosing_Dispensing, Dispensing, _delay_1ms) .WaitWithStopCondition(DosingStep.Dosing_Wait_Complete, WaitCompleteEndStatus, WaitCompleteErrorStatus, _dosingTime + _dosingOutTime) .End(DosingStep.Dosing_Done, DoneOperation, _delay_1ms); return Runner.Status; } /// /// 启动 /// /// /// public RState Start(params object[] objs) { _targetVolume = (double)objs[0]; _isAutoMode = (bool)objs[1]; //加载Reservoir设备 _standardHotReservoirdevice = DEVICE.GetDevice($"{_moduleName}"); if (_standardHotReservoirdevice == null) { LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Reservoir Device is not exist"); return RState.Failed; } //加载持久化文件 _persistentValue = ReplenPersistentManager.Instance.GetReplenPersistentValue(_moduleName, _replenName); if (_persistentValue == null) { LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Replen Persistent Value Object is not exist"); return RState.Failed; } //加载Recipe _rdsRecipe = _standardHotReservoirdevice.RdsRecipe[_replenId - 1]; //手动模式下无需Recipe if (_isAutoMode && _rdsRecipe == null) { LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "RDS recipe is null"); return RState.Failed; } if (SC.ContainsItem($"Reservoir.{_moduleName}.DosingOutTime")) { _dosingOutTime = (int)SC.GetValue($"Reservoir.{_moduleName}.DosingOutTime") * 60 * 1000; } return Runner.Start(_moduleName +"_"+_replenName, "Dosing"); } #region Operation /// /// Check Status /// /// /// private bool CheckStatus() { if (!_standardHotReservoirdevice.CheckandUpdateBottleLevel(_replenName, _targetVolume)) { LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, $"Current Bottle is not in Full Level!"); return false; } return true; } /// /// Dispensing /// /// /// private bool Dispensing() { //计算Dosing时间 if (SC.ContainsItem($"Reservoir.{_moduleName}.InitialDosingSpeed")) { _initialDosingSpeed = SC.GetValue($"Reservoir.{_moduleName}.InitialDosingSpeed"); double pumpFactor = _persistentValue.ReplenPumpFactor; double adjustSpeed = pumpFactor * _initialDosingSpeed; SCConfigItem item = SC.GetConfigItem($"Reservoir.{Module}.InitialDosingSpeed"); double speedMax = double.Parse(item.Max); if(adjustSpeed > speedMax) { _dosingTime = (int)((pumpFactor * _targetVolume / speedMax) * 60 * 1000); _initialDosingSpeed = speedMax / pumpFactor; } else { _dosingTime = (int)((_targetVolume / _initialDosingSpeed) * 60 * 1000); } } //记录Dosing开始时刻 _dosingStartTime = Environment.TickCount; //打开Replen Pump Object[] args = new object[1]; args[0] = _replenName; bool result = _standardHotReservoirdevice.ReplenPumpOnOperation("", args); if (result) { LOG.WriteLog(eEvent.INFO_RESERVOIR, _moduleName, "Replen Pump On"); } else { LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Replen Pump On is failed"); } return result; } /// /// WaitComplete End /// /// private bool WaitCompleteEndStatus() { int tick = Environment.TickCount - _dosingStartTime; //更新实时DosingVolume _persistentValue.CurrentDosingVolume = Math.Round(tick * (_initialDosingSpeed / 1000 / 60), 2); ReplenPersistentManager.Instance.UpdatePersistentValue(_moduleName, _replenName); if (tick >= _dosingTime) { //关闭Replen Pump Object[] args = new object[1]; args[0] = _replenName; bool result = _standardHotReservoirdevice.ReplenPumpOffOperation("", args); if (result) { LOG.WriteLog(eEvent.INFO_RESERVOIR, _moduleName, "Replen Pump Off"); } else { LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Replen Pump Off is failed"); } return true; } return false; } /// /// WaitComplete Error /// /// private bool WaitCompleteErrorStatus() { //若Pump被关闭则报错 if (!_standardHotReservoirdevice.ReplenDatas[_replenId - 1].ReplenPumpEnable) { _persistentValue.RemainDosingVolume = Math.Round(_persistentValue.RemainDosingVolume - _persistentValue.CurrentDosingVolume, 2); ReplenPersistentManager.Instance.UpdatePersistentValue(_moduleName, _replenName); LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Replen Pump is off. Stop Dosing"); return true; } //若BottleLevel not full则报错 if (!_standardHotReservoirdevice.CheckandUpdateBottleLevel(_replenName, _targetVolume)) { _persistentValue.RemainDosingVolume = Math.Round(_persistentValue.RemainDosingVolume - _persistentValue.CurrentDosingVolume, 2); ReplenPersistentManager.Instance.UpdatePersistentValue(_moduleName, _replenName); return true; } return false; } /// /// Done Operation /// /// /// private bool DoneOperation() { //数据清零 _persistentValue.CurrentDosingVolume = 0; _persistentValue.IsDosingRunning = false; _persistentValue.AutoDosingStartAmpHour = 0; _persistentValue.AutoDosingStartTime = DateTime.MinValue; _persistentValue.RemainDosingVolume = Math.Round(_persistentValue.RemainDosingVolume - _targetVolume, 2); ReplenPersistentManager.Instance.UpdatePersistentValue(_moduleName, _replenName); _targetVolume = 0; _dosingTime = 0; _dosingStartTime = 0; return true; } #endregion } }