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
}
}