using Aitex.Core.RT.Device; using Aitex.Core.RT.Log; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using CyberX8_Core; using CyberX8_RT.Devices.Dose; using CyberX8_RT.Modules; using CyberX8_RT.Modules.Reservoir; using MECF.Framework.Common.Beckhoff.ModuleIO; using MECF.Framework.Common.IOCore; using MECF.Framework.Common.Persistent.Reservoirs; using MECF.Framework.Common.ProcessCell; using MECF.Framework.Common.RecipeCenter; using MECF.Framework.Common.ToolLayout; using MECF.Framework.Common.TwinCat; using System; using System.Reflection; using System.Windows; using static CyberX8_RT.Devices.Reservoir.DosingSystemHelper; namespace CyberX8_RT.Devices.Reservoir { public class CrossDoseHelper { #region 常量 public enum CrossDoseOperation { None, ManualDosing, AutoDosing, } /// /// 补液体积(固定10mL) /// private const double DOSING_VOLUME = 10; #endregion #region 内部变量 /// /// ModuleName /// private string _moduleName; /// /// ANTransferPumpOnRoutine /// private ANTransferPumpOnRoutine _anTransferPumpOnRoutine; /// /// CrossDoseResetRoutine /// private CrossDoseResetRoutine _crossDoseResetRoutine; /// /// ReservoirsPersistentValue /// private ReservoirsPersistentValue _persistentValue; /// /// CompactMembranReservoirDevice /// private CompactMembranReservoirDevice _cmReservoirDevice; /// /// CrossDoseVolume /// private double _crossDoseVolume; /// /// 当前CrossDose模式 /// private CrossDoseOperation _currentCrossDoseOperation; /// /// Reservoir Usage /// private ReservoirUsage _reservoirUsage; private bool _flag; #endregion #region 属性 /// /// 当前Dose模式 /// public CrossDoseOperation CurrentDoseOperation{ get {return _currentCrossDoseOperation; } } /// /// CrossDose当前的RState /// public RState CrossDoseState { get { return _anTransferPumpOnRoutine.CurrentState; } } /// /// ResetRoutine当前的RState /// public RState ResetState { get { return _crossDoseResetRoutine.CurrentState; } } #endregion public CrossDoseHelper(string moduleName) { _moduleName = moduleName; _anTransferPumpOnRoutine = new ANTransferPumpOnRoutine(_moduleName); _crossDoseResetRoutine = new CrossDoseResetRoutine(_moduleName); _persistentValue = ReservoirsPersistentManager.Instance.GetReservoirsPersistentValue(_moduleName); _cmReservoirDevice = DEVICE.GetDevice($"{_moduleName}"); _currentCrossDoseOperation = CrossDoseOperation.None; } #region Operation /// /// 开始Dosing /// /// public bool StartDosing(double crossDoseVolume) { _crossDoseVolume = crossDoseVolume; return _anTransferPumpOnRoutine.Start(crossDoseVolume) == RState.Running; } /// /// 停止Dosing /// /// public bool HaltDosing() { _anTransferPumpOnRoutine.Abort(); EnterError(); return true; } /// /// CrossDosing监控 /// public void CrossDoseStatusMonitor() { RState result = _anTransferPumpOnRoutine.Monitor(); //监控Pump if (result == RState.Failed || result == RState.Timeout) { EnterError(); LOG.WriteLog(eEvent.WARN_RESERVOIR, _moduleName, "Open AN Transfer Pump failed"); _cmReservoirDevice.InitializeCrossDose(false); } } /// /// 自动CrossDose监控 /// public void AutoCrossDoseMonitor(bool isInitialized) { if (!isInitialized) { if (!_flag) { LOG.WriteLog(eEvent.WARN_RESERVOIR, _moduleName, "Please initialize Cross Dose"); _flag = true; } return; } _flag = false; if (_cmReservoirDevice.Recipe != null && (_cmReservoirDevice.Recipe.CurrentBased || _cmReservoirDevice.Recipe.TimeBased)) { //非AutoDosing模式下进入AutoDosing模式,并记录开始数据 if (_currentCrossDoseOperation != CrossDoseOperation.AutoDosing) { LOG.WriteLog(eEvent.INFO_RESERVOIR, _moduleName, $"Timing of AutoCrossDose has started now"); RecordStartData(); SetAutoDoseOperation(); } else { //AutoDosing模式下,若上一次Dosing完成则再次记录数据 if (_persistentValue.AutoCrossDoseStartTime == DateTime.MinValue && _persistentValue.AutoCrossDoseStartAmpHour == 0) { LOG.WriteLog(eEvent.INFO_RESERVOIR, _moduleName, $"Timing of AutoCrossDose has started again now"); RecordStartData(); } } } else { ResetDoseOperation(); } //AutoDosing监控 if (CrossDoseState != RState.Running && _currentCrossDoseOperation == CrossDoseOperation.AutoDosing && AutoDosingMonitor()) { StartDosing(DOSING_VOLUME); } } /// /// CrossDoseOperation状态监控 /// public bool CrossDoseOperationMonitor() { if (_currentCrossDoseOperation == CrossDoseOperation.ManualDosing && CrossDoseState != RState.Running) { _currentCrossDoseOperation = CrossDoseOperation.None; } if (_currentCrossDoseOperation == CrossDoseOperation.AutoDosing) { _currentCrossDoseOperation = CrossDoseOperation.None; } return true; } /// /// 自动补液触发时机判断 /// /// private bool AutoDosingMonitor() { ResRecipe recipe = _cmReservoirDevice.Recipe; bool result = false; double targetVolume = 0; double currentDosingAmpHour = 0; _reservoirUsage = ReservoirUsageManager.Instance.GetReservoirUsage(_moduleName); //当前电量 if (_reservoirUsage != null) currentDosingAmpHour = _reservoirUsage.TotalUsage; //累计电量(Ah) double deltAmpHour = currentDosingAmpHour - _persistentValue.AutoCrossDoseStartAmpHour; //累计时间(Day) double deltDay = DateTime.Now.Subtract(_persistentValue.AutoCrossDoseStartTime).TotalDays; if (recipe.CurrentBased) { //基于电量补液 targetVolume = deltAmpHour * recipe.CrossDoseCurrentRate; _persistentValue.TargetDosingVolume = Math.Round(targetVolume, 2); if (targetVolume >= DOSING_VOLUME) { result = true; } } else if (recipe.TimeBased) { //基于时间则开始补液 targetVolume = deltDay * recipe.CrossDoseTimeRate; _persistentValue.TargetDosingVolume = Math.Round(targetVolume, 2); if (targetVolume >= DOSING_VOLUME) { result = true; } } ReservoirsPersistentManager.Instance.UpdatePersistentValue(_moduleName); return result; } /// /// 设置手动Dose模式 /// public void SetManualDoseOperation() { _currentCrossDoseOperation = CrossDoseOperation.ManualDosing; } /// /// 设置自动Dose模式 /// public void SetAutoDoseOperation() { _currentCrossDoseOperation = CrossDoseOperation.AutoDosing; } /// /// 重置Dose模式 /// public void ResetDoseOperation() { _currentCrossDoseOperation = CrossDoseOperation.None; } /// /// EnterError /// private bool EnterError() { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{_moduleName}.TransferPumpExecute"); bool result = IOModuleManager.Instance.WriteIoValue(ioName, false); if (!result) { return false; } ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{_moduleName}.TransferPumpEnable"); result = IOModuleManager.Instance.WriteIoValue(ioName, false); if (!result) { return false; } if (!_cmReservoirDevice.CrossDoseOff("", null)) { LOG.WriteLog(eEvent.WARN_RESERVOIR, _moduleName, $"Close CrossDose Valve failed"); return false; } return true; } /// /// 记录AutoCrossDose开始时的时间和电量 /// private void RecordStartData() { _reservoirUsage = ReservoirUsageManager.Instance.GetReservoirUsage(_moduleName); _persistentValue.AutoCrossDoseStartTime = DateTime.Now; if (_reservoirUsage != null) _persistentValue.AutoCrossDoseStartAmpHour = _reservoirUsage.TotalUsage; ReservoirsPersistentManager.Instance.UpdatePersistentValue(_moduleName); } /// /// 设置PumpFactor /// public void SetPumpfactor(double targetPumpFactor) { _persistentValue.CrossDosePumpFactor = targetPumpFactor; ReservoirsPersistentManager.Instance.UpdatePersistentValue(_moduleName); } /// /// Reset Start /// public bool ResetCrossDose() { return _crossDoseResetRoutine.Start() == RState.Running; } /// /// Reset Start Monitor /// /// public bool ResetCrossDoseMonitor() { RState result = _crossDoseResetRoutine.Monitor(); if (result == RState.Failed || result == RState.Timeout) { LOG.WriteLog(eEvent.WARN_RESERVOIR, _moduleName, "Reset Cross Dose failed"); return false; } return result == RState.End; } #endregion } }