123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- 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,
- }
- /// <summary>
- /// 补液体积(固定10mL)
- /// </summary>
- private const double DOSING_VOLUME = 10;
- #endregion
- #region 内部变量
- /// <summary>
- /// ModuleName
- /// </summary>
- private string _moduleName;
- /// <summary>
- /// ANTransferPumpOnRoutine
- /// </summary>
- private ANTransferPumpOnRoutine _anTransferPumpOnRoutine;
- /// <summary>
- /// CrossDoseResetRoutine
- /// </summary>
- private CrossDoseResetRoutine _crossDoseResetRoutine;
- /// <summary>
- /// ReservoirsPersistentValue
- /// </summary>
- private ReservoirsPersistentValue _persistentValue;
- /// <summary>
- /// CompactMembranReservoirDevice
- /// </summary>
- private CompactMembranReservoirDevice _cmReservoirDevice;
- /// <summary>
- /// CrossDoseVolume
- /// </summary>
- private double _crossDoseVolume;
- /// <summary>
- /// 当前CrossDose模式
- /// </summary>
- private CrossDoseOperation _currentCrossDoseOperation;
- /// <summary>
- /// Reservoir Usage
- /// </summary>
- private ReservoirUsage _reservoirUsage;
- private bool _flag;
- #endregion
- #region 属性
- /// <summary>
- /// 当前Dose模式
- /// </summary>
- public CrossDoseOperation CurrentDoseOperation{ get {return _currentCrossDoseOperation; } }
- /// <summary>
- /// CrossDose当前的RState
- /// </summary>
- public RState CrossDoseState { get { return _anTransferPumpOnRoutine.CurrentState; } }
- /// <summary>
- /// ResetRoutine当前的RState
- /// </summary>
- 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<CompactMembranReservoirDevice>($"{_moduleName}");
- _currentCrossDoseOperation = CrossDoseOperation.None;
- }
- #region Operation
- /// <summary>
- /// 开始Dosing
- /// </summary>
- /// <returns></returns>
- public bool StartDosing(double crossDoseVolume)
- {
- _crossDoseVolume = crossDoseVolume;
- return _anTransferPumpOnRoutine.Start(crossDoseVolume) == RState.Running;
- }
- /// <summary>
- /// 停止Dosing
- /// </summary>
- /// <returns></returns>
- public bool HaltDosing()
- {
- _anTransferPumpOnRoutine.Abort();
- EnterError();
- return true;
- }
- /// <summary>
- /// CrossDosing监控
- /// </summary>
- 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);
- }
- }
- /// <summary>
- /// 自动CrossDose监控
- /// </summary>
- 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);
- }
- }
- /// <summary>
- /// CrossDoseOperation状态监控
- /// </summary>
- public bool CrossDoseOperationMonitor()
- {
- if (_currentCrossDoseOperation == CrossDoseOperation.ManualDosing && CrossDoseState != RState.Running)
- {
- _currentCrossDoseOperation = CrossDoseOperation.None;
- }
- if (_currentCrossDoseOperation == CrossDoseOperation.AutoDosing)
- {
- _currentCrossDoseOperation = CrossDoseOperation.None;
- }
- return true;
- }
- /// <summary>
- /// 自动补液触发时机判断
- /// </summary>
- /// <returns></returns>
- 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;
- }
- /// <summary>
- /// 设置手动Dose模式
- /// </summary>
- public void SetManualDoseOperation()
- {
- _currentCrossDoseOperation = CrossDoseOperation.ManualDosing;
- }
- /// <summary>
- /// 设置自动Dose模式
- /// </summary>
- public void SetAutoDoseOperation()
- {
- _currentCrossDoseOperation = CrossDoseOperation.AutoDosing;
- }
- /// <summary>
- /// 重置Dose模式
- /// </summary>
- public void ResetDoseOperation()
- {
- _currentCrossDoseOperation = CrossDoseOperation.None;
- }
- /// <summary>
- /// EnterError
- /// </summary>
- 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;
- }
- /// <summary>
- /// 记录AutoCrossDose开始时的时间和电量
- /// </summary>
- private void RecordStartData()
- {
- _reservoirUsage = ReservoirUsageManager.Instance.GetReservoirUsage(_moduleName);
- _persistentValue.AutoCrossDoseStartTime = DateTime.Now;
- if (_reservoirUsage != null) _persistentValue.AutoCrossDoseStartAmpHour = _reservoirUsage.TotalUsage;
- ReservoirsPersistentManager.Instance.UpdatePersistentValue(_moduleName);
- }
- /// <summary>
- /// 设置PumpFactor
- /// </summary>
- public void SetPumpfactor(double targetPumpFactor)
- {
- _persistentValue.CrossDosePumpFactor = targetPumpFactor;
- ReservoirsPersistentManager.Instance.UpdatePersistentValue(_moduleName);
- }
- /// <summary>
- /// Reset Start
- /// </summary>
- public bool ResetCrossDose()
- {
- return _crossDoseResetRoutine.Start() == RState.Running;
- }
- /// <summary>
- /// Reset Start Monitor
- /// </summary>
- /// <returns></returns>
- 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
- }
- }
|