using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.RecipeCenter; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using MECF.Framework.Common.Beckhoff.ModuleIO; using MECF.Framework.Common.CommonData.Reservoir; using MECF.Framework.Common.Persistent.Reservoirs; using MECF.Framework.Common.TwinCat; using CyberX8_Core; using System; using System.Collections.Generic; using System.Reflection; using MECF.Framework.Common.RecipeCenter; using MECF.Framework.Common.ToolLayout; using CyberX8_RT.Devices.Facilities; using CyberX8_RT.Modules.Reservoir; using CyberX8_RT.Modules; using CyberX8_RT.Devices.Metal; using System.Collections.ObjectModel; using MECF.Framework.Common.CommonData; using MECF.Framework.Common.Beckhoff.IOAxis; using CyberX8_RT.Modules.Metal; using CyberX8_RT.Devices.Temperature; using CyberX8_RT.Devices.Safety; using System.Linq; using MECF.Framework.Common.IOCore; namespace CyberX8_RT.Devices.Reservoir { public class CompactMembranReservoirDevice : BaseDevice, IDevice { private enum ReservoirOperation { None, ManualANDiReplen, ManualCADiReplen, AutoANDiReplen, AutoCADiReplen } #region 常量 private const string PERSISTENT_VALUE = "PersistentValue"; private const string CA_DI_REPLEN = "CADiReplen"; private const string AN_DI_REPLEN = "ANDiReplen"; private const string CA_WATER_LEVEL = "CAWaterLevel"; private const string AN_WATER_LEVEL = "ANWaterLevel"; private const string AN_PUMP = "ANPump"; private const string CROSS_DOSE_ENABLE = "CrossDoseEnable"; private const string TRANSFER_PUMP_STM_STATUS = "TransferPumpSTMStatus"; private const string TRANSFER_PUMP_POS_STATUS = "TransferPumpPOSStatus"; private const string TRANSFER_ACTUAL_POSITION = "TransferActualPosition"; private const string TRANSFER_PUMP_ENABLE = "TransferPumpEnable"; private const string TRANSFER_PUMP_RESET = "TransferPumpReset"; private const string TRANSFER_PUMP_EXECUTE = "TransferPumpExecute"; private const string TRANSFER_PUMP_TARGET_POSITION = "TransferPumpTargetPosition"; private const string TRANSFER_PUMP_SPEED = "TransferPumpSpeed"; private const string TRANSFER_PUMP_START_TYPE = "TransferPumpStartType"; private const string TRANSFER_PUMP_ACCELERATION = "TransferPumpAcceleration"; private const string TRANSFER_PUMP_DECELERATION = "TransferPumpDeceleration"; private const string AN_BYPASS_FLOW = "ANBypassFlow"; private const string AN_A_DRAIN_PUMP = "ANADrainPump"; private const string AN_B_DRAIN_PUMP = "ANBDrainPump"; private const string AN_BY_PASS = "ANByPass"; //private const string AN_SLIP_STREAM_PUMP = "ANSlipStreamPump"; private const string AN_TRANSFER_FLOW = "ANTransferFlow"; //private const string CA_SLIP_STREAM_PUMP = "CASlipStreamPump"; private const string CA_PUMP_SPEED = "CAPumpSpeed"; private const string CA_PUMP_RUNNING = "CAPumpRunning"; private const string CA_HED_FLOW = "CAHedFlow"; private const string CDA_FLOW_VALVE = "CDAFlowValve"; private const string CA_BY_PASS = "CAByPass"; private const string CA_PUMP_ENABLE = "CAPumpEnable"; private const string EVAPORATORLEVEL = "EvaporatorLevel"; private const string AN_BYPASS_COUNTERFLOW = "ANBypassFlow"; private const string AN_SAMPLE_FLOW = "ANSampleFlow"; private const string CA_SAMPLE_FLOW = "CASampleFlow"; private const string STRATUS = "Stratus"; private const string AUTO = "Auto"; private const string COUNTER_VALUE = "CounterValue"; private const string COUNTER_START = "Start"; private const string COUNTER_STOP = "Stop"; private const string COUNTER_RESET = "Reset"; private const int ENABLE = 5; #endregion #region 内部变量 /// /// AN Level取样平均值 /// private double _avgANLevel; /// /// AN Level取样队列 /// private Queue _ANLevelSamples; /// /// CA Level取样平均值 /// private double _avgCALevel; /// /// CA Level取样队列 /// private Queue _CALevelSamples; /// /// AN/CA level计算平均值取样数 /// private int levelSampleCount; /// /// Prewet 持久性数值对象 /// private ReservoirsPersistentValue _persistentValue; /// /// 变量是否初始化字典 /// private Dictionary _variableInitializeDic = new Dictionary(); /// /// 数据 /// private CompactMembranReservoirData _reservoirData = new CompactMembranReservoirData(); /// /// Recipe /// private ResRecipe _resRecipe; /// /// 阳极Pump速度 /// private double _anPumpSpeed = 0; /// /// 阴极Pump速度 /// private double _caPumpSpeed = 0; /// /// 定时器 /// private PeriodicJob _periodicJob; /// /// 注水Helper /// private ReservoirDiReplenHelper _direplenHelper; /// /// 泵速Helper /// private ReservoirPumpSpeedHelper _pumpSpeedHelper; /// /// 当前操作 /// private ReservoirOperation _currentOperation; /// /// 手动注水时间(秒) /// private int _manualReplenSecond = 0; /// /// 注水是否出错 /// private bool _isDiReplenInFault = false; /// /// Fast leak Test时间间隔 /// private int _aNLeakOperatingUpdateTime; /// /// Fast leak Test Tolerance Value /// private double _aNFastLeakLevelTolerance; /// /// 计时器是否正在运行 /// private bool _isTestRunning = false; /// /// 是否检测到漏液 /// private bool _isLeakDetected = false; /// /// 漏液的体积 /// private double _leakVolume; /// /// 开始检测slow leak test时的ANLevel /// private double _StartSlowLeakTestANLevel; /// /// 配置的metal device集合 /// private ObservableCollection _metalDevices = new ObservableCollection(); /// /// 是否存在anflow有流量 /// private bool _isHasAnFlow; /// /// 是否存在metal 在auto模式 /// private bool _isHasMetalInAuto; /// /// 设备是否进行过初始化 /// private bool _isInitialized; /// /// 是否安装CrossDose /// private bool _isCrossDoseInstalled; /// /// fastleaktest的开始时间 /// private DateTime _fastLeakStartTime; /// /// slowleaktest的开始时间 /// private DateTime _slowLeakStartTime; /// /// fastleak 测试时间间隔 /// private TimeSpan _fastLeakTestSpan; /// /// slowleak 测试时间间隔 /// private TimeSpan _slowLeakTestSpan; /// /// clearLeakVolumeTime /// private double _clearLeakVolumeTime; /// /// ANTransferFlow(CrossDose Flow) /// private CounterFlowData _anTransferFlow = new CounterFlowData(); /// /// ReservoirANByPassCounterFlow /// private CounterFlowData _reservoirCounterByPassFlow = new CounterFlowData(); /// /// Counter字典 /// private Dictionary _nameCounterFlowData = new Dictionary(); /// /// CrossDoseHelper /// private CrossDoseHelper _crossDoseHelper; /// /// CrossDose是否初始化 /// private bool _isCrossDoseInitialized; /// /// WarningFlag /// private List _isCAFlowRateWARN; private List _isANAFlowRateWARN; private List _isANBFlowRateWARN; private bool _isTCControlWARN = false; /// /// flow fault hold off时长 /// private int _flowFaultHoldOffTime = 10; private DateTime _AnPumpSafeDetectTime; private double _metalTotalFlow; private bool _isAnPumpSafeDetectedActivate = false; private bool _isANAutoDIReplenError =false; private bool _isCAAutoDIReplenError =false; #endregion #region 属性 /// /// 数据 /// public CompactMembranReservoirData ReservoirData { get { return _reservoirData; } } /// /// 操作模式 /// public string OperationMode { get { return _persistentValue.OperatingMode; } } /// /// 工程模式 /// public string EngineerMode { get { return _persistentValue.RecipeOperatingMode; } } /// /// 阳极是否需要补水 /// public bool AnNeedDireplen { get { return CheckANNeedDiReplen(); } } /// /// 阴极是否需要补水 /// public bool CANeedDiReplen { get { return CheckCANeedDiReplen(); } } /// /// 检验阴极是否highlevel /// public bool IsCAHighLevel { get { return CheckCAHighLevelStatus(); } } /// /// 检验阴极是否lowlevel /// public bool IsCALowLevel { get { return CheckCALowLevelStatus(); } } /// /// 检验阳极是否highlevel /// public bool IsANHighLevel { get { return CheckANHighLevelStatus(); } } /// /// 检验阳极是否lowlevel /// public bool IsANLowLevel { get { return CheckANLowLevelStatus(); } } /// /// 正在补水 /// public bool IsDireplenOn { get { return _reservoirData.ANDiReplen || _reservoirData.CADiReplen; } } /// /// 当前Recipe /// public ResRecipe Recipe { get { return _resRecipe; } } /// /// 是否自动模式 /// public bool IsAuto { get { return _persistentValue.OperatingMode == AUTO; } } /// /// ANTransferFlow /// public CounterFlowData ANTransferFlow { get { return _anTransferFlow; } } /// /// ReservoirCounterByPassFlow /// public CounterFlowData ReservoirCounterByPassFlow { get { return _reservoirCounterByPassFlow; } } #endregion /// /// 构造函数 /// /// /// public CompactMembranReservoirDevice(string moduleName) : base(moduleName, moduleName, moduleName, moduleName) { _anPumpSpeed = SC.GetValue($"Reservoir.ANDefaultPumpSpeed"); _caPumpSpeed= SC.GetValue("Reservoir.CADefaultPumpSpeed"); _aNLeakOperatingUpdateTime = SC.GetValue($"Reservoir.{Module}.ANLeakOperatingUpdateTime"); _aNFastLeakLevelTolerance = SC.GetValue($"Reservoir.{Module}.ANFastLeakLevelTolerance"); _clearLeakVolumeTime = SC.GetValue($"Reservoir.{Module}.CleraLeakVolumeTime"); _flowFaultHoldOffTime = SC.GetValue($"Reservoir.{Module}.FlowFaultHoldOffTime")/1000; levelSampleCount = SC.GetValue("Reservoir.LevelAvgSamples"); levelSampleCount = levelSampleCount == 0 ? 20 : levelSampleCount; _ANLevelSamples = new Queue(levelSampleCount); _CALevelSamples = new Queue(levelSampleCount); _periodicJob = new PeriodicJob(200, OnTimer, $"{Module}.Timer", true, true); double updateTime = _aNLeakOperatingUpdateTime > 0 ? Convert.ToDouble(_aNLeakOperatingUpdateTime) : 3.00;//配置文件没有则默认3分钟 _fastLeakTestSpan = TimeSpan.FromMinutes(updateTime); //slow leak test 时间间隔一个小时,因为leak test开始后要等待clearleakvolumeTime重新开始,因此时间间隔就等于两者相加,第一次执行减掉就行。 _slowLeakTestSpan = TimeSpan.FromMinutes(60) + TimeSpan.FromMinutes(_clearLeakVolumeTime); } /// /// 初始化 /// /// public bool Initialize() { InitializeParameter(); InitializeRoutine(); SubscribeData(); InitializeOperation(); SubscribeValueAction(); return true; } /// /// 初始化Routine /// private void InitializeRoutine() { } /// /// 初始化参数 /// private void InitializeParameter() { _persistentValue = ReservoirsPersistentManager.Instance.GetReservoirsPersistentValue(Module); if (_persistentValue == null) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "Persistent Value Object is not exist"); } if (!string.IsNullOrEmpty(_persistentValue.Recipe)) { _resRecipe = RecipeFileManager.Instance.LoadGenericityRecipe(_persistentValue.Recipe); } _direplenHelper = new ReservoirDiReplenHelper(Module, _persistentValue); _pumpSpeedHelper = new ReservoirPumpSpeedHelper(Module,this); ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module); if (reservoirItem != null) { foreach (var item in reservoirItem.MetalCells) { if (item.ModuleName != Module) { CompactMembranMetalDevice metalDevice = DEVICE.GetDevice(item.ModuleName); if (metalDevice != null) { _metalDevices.Add(metalDevice); } } } if(reservoirItem.CrossDoseType != "" && reservoirItem.CrossDoseType != "None") { _isCrossDoseInstalled = true; _crossDoseHelper = new CrossDoseHelper(Module); _isCrossDoseInitialized = false; } _isCAFlowRateWARN = new List(new bool[_metalDevices.Count]); _isANAFlowRateWARN = new List(new bool[_metalDevices.Count]); _isANBFlowRateWARN = new List(new bool[_metalDevices.Count]); } } /// /// 订阅数据 /// private void SubscribeData() { ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module); DATA.Subscribe($"{Module}.ReservoirData", () => _reservoirData, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ReservoirAverageANLevel", () => _avgANLevel, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ReservoirAverageCALevel", () => _avgCALevel, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.{PERSISTENT_VALUE}", () => _persistentValue,SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ANPumpSpeed",()=>_anPumpSpeed, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.CAPumpSpeed", () => _caPumpSpeed, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.RecipeName", () => (_resRecipe != null?_resRecipe.Ppid : ""), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ANLevel", () => _reservoirData.ANLevel, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.CALevel", () => _reservoirData.CALevel, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ANBypassFlow",()=>_reservoirData.ANBypassFlow, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.HedFlow",()=>_reservoirData.CAHedFlow, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.CurrentRecipe", () => _resRecipe, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.DIValveMaxOnTime", () => SC.GetValue($"Reservoir.{Module}.DIValveMaxOnTime") * 60, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsManualCAReplen", () => { return _currentOperation == ReservoirOperation.ManualCADiReplen; }, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsManualANReplen", () => { return _currentOperation == ReservoirOperation.ManualANDiReplen; }, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsCAHighLevel", () => IsCAHighLevel, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsCALowLevel", () => IsCALowLevel, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsANHighLevel", () => IsANHighLevel, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsANLowLevel", () => IsANLowLevel, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsDIReplenInFault", () => _isDiReplenInFault, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.EvaporatorType", () => reservoirItem.EvaporatorType, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.CroseDoseType", () => reservoirItem.CrossDoseType, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsLeakDetected", () => _isLeakDetected, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsCrossDoseInstalled", () => _isCrossDoseInstalled, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ANBypassCounterFlow", () => ReservoirCounterByPassFlow.CounterValue, SubscriptionAttribute.FLAG.IgnoreSaveDB); if (_isCrossDoseInstalled) { DATA.Subscribe($"{Module}.ANTransferFlow", () => ANTransferFlow != null ? ANTransferFlow.CounterValue : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsCalibrateEnable", () => (_crossDoseHelper != null && _crossDoseHelper.CrossDoseState == RState.Running) ? false : true, SubscriptionAttribute.FLAG.IgnoreSaveDB); } } /// /// 初始化操作 /// private void InitializeOperation() { OP.Subscribe($"{Module}.DisabledAction", DisabledOperation); OP.Subscribe($"{Module}.ManualAction", ManualOperation); OP.Subscribe($"{Module}.AutoAction", AutoOperation); OP.Subscribe($"{Module}.EngineeringModeAction", EngineeringModeOperation); OP.Subscribe($"{Module}.ProductionModeAction", ProductionModeOperation); OP.Subscribe($"{Module}.LoadRecipe", LoadRecipeOperation); OP.Subscribe($"{Module}.AnPumpOn", AnPumpOnOperation); OP.Subscribe($"{Module}.ANPumpSpeed", ANPumpSpeed); OP.Subscribe($"{Module}.AnPumpOff", AnPumpOffOperation); OP.Subscribe($"{Module}.AnADrainPumpOn", AnADrainPumpOn); OP.Subscribe($"{Module}.AnADrainPumpOff", AnADrainPumpOff); OP.Subscribe($"{Module}.AnBDrainPumpOn", AnBDrainPumpOn); OP.Subscribe($"{Module}.AnBDrainPumpOff", AnBDrainPumpOff); OP.Subscribe($"{Module}.ANDiReplenOn", ANDiReplenOnOperation); OP.Subscribe($"{Module}.ANDiReplenOff", ANDiReplenOff); OP.Subscribe($"{Module}.ANByPassOn", ANByPassOn); OP.Subscribe($"{Module}.ANByPassOff", ANByPassOff); OP.Subscribe($"{Module}.CAPumpOn", CAPumpOn); OP.Subscribe($"{Module}.CAPumpSpeed", CAPumpSpeedOperation); OP.Subscribe($"{Module}.CAPumpOff", CAPumpOff); OP.Subscribe($"{Module}.CADiReplenOn", CADiReplenOnOperation); OP.Subscribe($"{Module}.CADiReplenOff", CADiReplenOff); OP.Subscribe($"{Module}.CDAFlowOn", CDAFlowOn); OP.Subscribe($"{Module}.CDAFlowOff", CDAFlowOff); OP.Subscribe($"{Module}.CAByPassOn", CAByPassOn); OP.Subscribe($"{Module}.CAByPassOff", CAByPassOff); OP.Subscribe($"{Module}.ANSampleOn", ANSampleOn); OP.Subscribe($"{Module}.ANSampleOff", ANSampleOff); OP.Subscribe($"{Module}.CASampleOn", CASampleOn); OP.Subscribe($"{Module}.CASampleOff", CASampleOff); OP.Subscribe($"{Module}.ManualANDiReplen", ManualANDiReplen); OP.Subscribe($"{Module}.ManualCADiReplen", ManualCADiReplen); OP.Subscribe($"{Module}.BaseLineKeyDown", BaseLineKeyDownAction); OP.Subscribe($"{Module}.StartLeakTest", StartLeakTestAction); OP.Subscribe($"{Module}.ResetTotalTime", ResetTotalTime); OP.Subscribe($"{Module}.ClearSlowLeak", ClearSlowLeak); if (_isCrossDoseInstalled) { OP.Subscribe($"{Module}.StartDosing", StartDosing); OP.Subscribe($"{Module}.HaltDosing", HaltDosing); OP.Subscribe($"{Module}.SetPumpFactor", SetPumpFactor); OP.Subscribe($"{Module}.CrossDoseOn", CrossDoseOn); OP.Subscribe($"{Module}.CrossDoseOff", CrossDoseOff); OP.Subscribe($"{Module}.ResetCrossDose", ResetCrossDose); } } #region Operation /// /// 重置时长 /// /// /// /// private bool ResetTotalTime(string cmd, object[] objs) { _persistentValue.TotalReplen = 0; _persistentValue.LastTotalReplen = 0; ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); return true; } /// /// DisabledAction /// /// /// /// private bool DisabledOperation(string cmd, object[] args) { string currentOperation = "Disabled"; if(_persistentValue!=null) { ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); if (reservoirEntity == null) return false; if (_persistentValue.OperatingMode == "Auto" && reservoirEntity.IsMetalBusy) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} is Busy, can't change to disable mode"); return false; } foreach (var metalDevice in _metalDevices) { metalDevice.DisabledOperation("", null); MetalEntity metalEntity = Singleton.Instance.GetModule(metalDevice.Module); metalEntity.AbortRecipe(null); metalDevice.EnterDisabledOperation(); } if(_isCrossDoseInstalled) HaltDosing("", null); EnterDisabledOperation(); if (_isCrossDoseInstalled && _persistentValue.OperatingMode != currentOperation) InitializeCrossDose(false); if (_persistentValue.OperatingMode != "Disabled") reservoirEntity.EnterInit(); _persistentValue.OperatingMode = currentOperation; } ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); _currentOperation = ReservoirOperation.None; return true; } /// /// ManualAction /// /// /// /// private bool ManualOperation(string cmd, object[] args) { string currentOperation = "Manual"; ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); if (_persistentValue != null) { if (_persistentValue.OperatingMode == "Auto" && reservoirEntity != null && reservoirEntity.IsMetalBusy) { string busymodule = ""; if (_metalDevices != null) { foreach (var item in _metalDevices) { MetalEntity metalEntity = Singleton.Instance.GetModule(item.Module.ToString()); if (metalEntity != null && metalEntity.IsBusy) { busymodule += metalEntity.Module.ToString() + "/"; } } } LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{busymodule} is Busy, can't change to manual mode"); return false; } foreach (var metalDevice in _metalDevices) { metalDevice.ManualOperation("", null); } if (_isCrossDoseInstalled && _persistentValue.OperatingMode != currentOperation) InitializeCrossDose(false); if (_persistentValue.OperatingMode != "Manual" && reservoirEntity != null) reservoirEntity.EnterInit(); _persistentValue.OperatingMode = currentOperation; } ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); _currentOperation = ReservoirOperation.None; return true; } /// /// AutoAction /// /// /// /// private bool AutoOperation(string cmd, object[] args) { if(IsANLowLevel || IsCALowLevel) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"LowLevel is Activate"); return false; } string currentOperation = "Auto"; if (_persistentValue != null) { if (_isCrossDoseInstalled && _persistentValue.OperatingMode != currentOperation) InitializeCrossDose(false); ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); if (_persistentValue.OperatingMode != "Auto" && reservoirEntity != null) reservoirEntity.EnterInit(); _persistentValue.OperatingMode = currentOperation; } ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); return true; } /// /// EngineeringModeAction /// /// /// /// private bool EngineeringModeOperation(string cmd, object[] args) { string currentRecipeOperation = "Engineering"; if (_persistentValue != null) { _persistentValue.RecipeOperatingMode = currentRecipeOperation; } ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); return true; } /// /// ProductionAction /// /// /// /// private bool ProductionModeOperation(string cmd, object[] args) { string currentRecipeOperation = "Production"; if (_persistentValue != null) { _persistentValue.RecipeOperatingMode = currentRecipeOperation; } ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); return true; } /// /// 加载Recipe /// /// /// /// private bool LoadRecipeOperation(string cmd, object[] args) { _persistentValue.Recipe = args[0].ToString(); string[] fileRoute = _persistentValue.Recipe.Split('\\'); string recipeRoute = ""; if (fileRoute.Length > 2) { recipeRoute = fileRoute[fileRoute.Length - 2]; } _resRecipe = RecipeFileManager.Instance.LoadGenericityRecipe(_persistentValue.Recipe); ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module.ToString()); LOG.WriteLog(eEvent.INFO_RESERVOIR, Module.ToString(), $"Load {recipeRoute} Recipe {_resRecipe.Ppid} Success"); return true; } /// /// Enter Disabled Operation /// /// private void EnterDisabledOperation() { if (_reservoirData.CAPumpEnable) { CAPumpOff("CAPumpOff", null); } if(_reservoirData.ANPump > 0) { AnPumpOffOperation("", null); } if(_reservoirData.ANADrainPump > 0) { AnADrainPumpOff("", null); } if (_reservoirData.ANBDrainPump > 0) { AnBDrainPumpOff("", null); } if (_reservoirData.ANByPass) { ANByPassOff("", null); } if (_reservoirData.ANDiReplen) { ANDiReplenOff("", null); } if (_reservoirData.CADiReplen) { CADiReplenOff("", null); } } #endregion #region AN DiReplen /// /// 阳极DI Replen On /// /// /// /// private bool ANDiReplenOnOperation(string cmd, object[] args) { return ANDiReplenOn(true); } /// /// 阳极DI Replen On /// /// /// public bool ANDiReplenOn(bool showError) { if (IsANHighLevel) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"ANHighLevel is activate,Can't do AN_DIReple"); return false; } if (IsANLowLevel) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"ANLowLevel is activate,Can't do AN_DIReple"); return false; } bool preCondition = CheckPreDiReplenCondition(showError); if (!preCondition) { return false; } if (ReservoirData.CADiReplen) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "CADiReplen is on"); return false; } string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_DI_REPLEN}"); return IOModuleManager.Instance.WriteIoValue(ioName, true); } /// /// 阳极DI Replen On /// /// /// /// private bool ANDiReplenOff(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_DI_REPLEN}"); bool result = IOModuleManager.Instance.WriteIoValue(ioName, false); if (result) { _persistentValue.IsDiReplenOn = false; if (_currentOperation == ReservoirOperation.ManualANDiReplen || _currentOperation == ReservoirOperation.AutoANDiReplen) { _currentOperation = ReservoirOperation.None; _persistentValue.LastTotalReplen = _persistentValue.TotalReplen; ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); } } return result; } /// /// 检验DiReplen前置条件 /// /// public bool CheckPreDiReplenCondition(bool showError) { if (!CheckFacilitiesDiReplenStatus()&&showError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "Facilities DiReplen is Off"); return false; } SafetyDevice safetyDevice = DEVICE.GetDevice("Safety"); if (safetyDevice != null && safetyDevice.SafetyData.ReservoirHighLevel) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Safety high is Activate"); return false; } if (CheckOtherReservoirDiReplenStatus(showError)) { return false; } return true; } /// /// 检验总Di有没有开 /// /// private bool CheckFacilitiesDiReplenStatus() { SystemFacilities systemFacilities = DEVICE.GetDevice("System.Facilities"); if (systemFacilities != null) { return systemFacilities.DIReplenEnable; } return false; } /// /// 检验是否其他Reservoir Direplen已经 /// /// private bool CheckOtherReservoirDiReplenStatus(bool showError) { List reservoirs = ReservoirItemManager.Instance.InstalledModules; foreach (string item in reservoirs) { if (item != Module) { ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(item); if (reservoirItem.SubType == STRATUS) { StandardHotReservoirDevice tmpDevice = DEVICE.GetDevice(item); if (tmpDevice.ReservoirData.DiReplen&&showError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{item} direplen valve is on"); return true; } } else { CompactMembranReservoirDevice tmpDevice = DEVICE.GetDevice(item); if (tmpDevice.ReservoirData.ANDiReplen&&showError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{item} ANDireplen valve is on"); return true; } if (tmpDevice.ReservoirData.CADiReplen&&showError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{item} CADireplen valve is on"); return true; } } } } return false; } #endregion #region AnPump /// /// AN Pump On 操作 /// /// /// /// public bool AnPumpOnOperation(string cmd, object[] args) { double anPumpSpeed = SC.GetValue($"Reservoir.ANDefaultPumpSpeed"); return AnPump(anPumpSpeed); } /// /// AN Pump Off操作 /// /// /// /// private bool AnPumpOffOperation(string cmd, object[] args) { return AnPump(0); } /// /// AN Pump /// /// /// public bool AnPump(double speed) { if (speed == 0) //关pump时关掉配置的metal的fill valve { ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module); if (reservoirItem != null) { List metalItems = reservoirItem.MetalCells; if (metalItems != null && metalItems.Count > 0) { foreach (MetalItem metalItem in metalItems) { if (metalItem.Installed) { CompactMembranMetalDevice metalDevice = DEVICE.GetDevice(metalItem.ModuleName); if (metalDevice != null) { metalDevice.AnSideAFillOff("ANAFillOff", null); metalDevice.AnSideBFillOff("ANBFillOff", null); } } } } } } SafetyDevice safetyDevice = DEVICE.GetDevice("Safety"); if (safetyDevice != null && !safetyDevice.SafetyData.PumpEdm) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Safety PumpEdm is Activate"); return false; } string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_PUMP}"); return IOModuleManager.Instance.WriteIoValue(ioName, speed); } /// /// AN Pump调整速度 /// /// /// /// public bool ANPumpSpeed(string cmd, object[] args) { if (double.TryParse(args[0].ToString(), out double speed)) { _anPumpSpeed = speed; if (_anPumpSpeed > 0) { _reservoirData.ANPump = _anPumpSpeed; } return AnPump(speed); } else { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{args[0]} is nor invalid speed"); return false; } } #endregion #region AN Drain Pump /// /// 阳极A面Drain Pump On /// /// /// /// public bool AnADrainPumpOn(string cmd, object[] args) { double speed = SC.GetValue($"Reservoir.DrainSpeed"); return AnADrainPump(speed); } /// /// 阳极A面Drain Pump Off /// /// /// /// private bool AnADrainPumpOff(string cmd, object[] args) { return AnADrainPump(0); } /// /// 阳极B面Drain Pump On /// /// /// /// public bool AnBDrainPumpOn(string cmd, object[] args) { double speed = SC.GetValue($"Reservoir.DrainSpeed"); return AnBDrainPump(speed); } /// /// 阳极B面Drain Pump Off /// /// /// /// private bool AnBDrainPumpOff(string cmd, object[] args) { return AnBDrainPump(0); } /// /// 阳极A Drain Pump /// /// /// public bool AnADrainPump(double speed) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_DRAIN_PUMP}"); return IOModuleManager.Instance.WriteIoValue(ioName, speed); } /// /// 阳极B Drain Pump /// /// /// public bool AnBDrainPump(double speed) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_B_DRAIN_PUMP}"); return IOModuleManager.Instance.WriteIoValue(ioName, speed); } #endregion #region AN ByPass /// /// 阳极ByPass On /// /// /// /// private bool ANByPassOn(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_BY_PASS}"); return IOModuleManager.Instance.WriteIoValue(ioName, true); } /// /// 阳极ByPass Off /// /// /// /// private bool ANByPassOff(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_BY_PASS}"); return IOModuleManager.Instance.WriteIoValue(ioName, false); } #endregion #region CA Pump /// /// CA Pump调速 /// /// /// /// private bool CAPumpSpeedOperation(string cmd, object[] args) { double caMaxPumpSpeed = 0; if (SC.ContainsItem("Reservoir.CAMaxPumpSpeed")) { caMaxPumpSpeed = SC.GetValue("Reservoir.CAMaxPumpSpeed"); } if (double.TryParse(args[0].ToString(), out double speed)) { _caPumpSpeed = speed; if(_caPumpSpeed > caMaxPumpSpeed) { LOG.WriteLog(eEvent.WARN_METAL, Module, $"CA pump speed:{_caPumpSpeed} is over CA max pump speed {caMaxPumpSpeed}!"); return false; } return CAPumpSpeed(_caPumpSpeed); } else { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{args[0]} is nor invalid speed"); return false; } } /// /// 设置阴极泵速 /// /// /// public bool CAPumpSpeed(double caPumpSpeed) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_PUMP_SPEED}"); return IOModuleManager.Instance.WriteIoValue(ioName, caPumpSpeed); } /// /// 阴极Pump On /// /// /// /// private bool CAPumpOn(string cmd, object[] args) { double caPumpSpeed = SC.GetValue("Reservoir.CADefaultPumpSpeed"); bool result= CAPumpSpeed(caPumpSpeed); if(result) { string enableIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_PUMP_ENABLE}"); return IOModuleManager.Instance.WriteIoValue(enableIOName, true); } else { return false; } } /// /// 阴极Pump Off /// /// /// /// private bool CAPumpOff(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_PUMP_ENABLE}"); return IOModuleManager.Instance.WriteIoValue(ioName, false); } #endregion #region CA DiReplen /// /// 阴极DI Replen On /// /// /// /// private bool CADiReplenOnOperation(string cmd, object[] args) { return CADiReplenOn(true); } /// /// 阴极DI Replen On /// /// /// private bool CADiReplenOn(bool showError) { bool preCondition = CheckPreDiReplenCondition(showError); if (!preCondition) { return false; } if (IsCAHighLevel) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"CAHighLevel is activate,Can't do CA_DIReple"); return false; } if (IsCALowLevel) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"CALowLevel is activate,Can't do CA_DIReple"); return false; } if (ReservoirData.ANDiReplen) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "ANDiReplen is on"); return false; } string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_DI_REPLEN}"); return IOModuleManager.Instance.WriteIoValue(ioName, true); } /// /// 阴极DI Replen Off /// /// /// /// private bool CADiReplenOff(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_DI_REPLEN}"); bool result = IOModuleManager.Instance.WriteIoValue(ioName, false); if (result) { _persistentValue.IsDiReplenOn = false; if (_currentOperation == ReservoirOperation.ManualCADiReplen || _currentOperation == ReservoirOperation.AutoCADiReplen) { _currentOperation = ReservoirOperation.None; _persistentValue.LastTotalReplen = _persistentValue.TotalReplen; ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); } } return result; } #endregion #region CDA Flow /// /// 阴极CDA Flow On /// /// /// /// private bool CDAFlowOn(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CDA_FLOW_VALVE}"); return IOModuleManager.Instance.WriteIoValue(ioName, true); } /// /// 阴极CDA Flow Off /// /// /// /// private bool CDAFlowOff(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CDA_FLOW_VALVE}"); return IOModuleManager.Instance.WriteIoValue(ioName, false); } #endregion #region CA ByPass /// /// 阴极ByPass On /// /// /// /// public bool CAByPassOn(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_BY_PASS}"); return IOModuleManager.Instance.WriteIoValue(ioName, true); } /// /// 阴极ByPass Off /// /// /// /// public bool CAByPassOff(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_BY_PASS}"); return IOModuleManager.Instance.WriteIoValue(ioName, false); } #endregion #region DiReplen Operation /// /// 手动阳极注水 /// /// /// /// private bool ManualANDiReplen(string cmd, object[] args) { return ManualDiReplen(ANDiReplenOnOperation, ReservoirOperation.ManualANDiReplen, args[0].ToString()); } /// /// 手动阴极注水 /// /// /// /// private bool ManualCADiReplen(string cmd, object[] args) { return ManualDiReplen(CADiReplenOnOperation,ReservoirOperation.ManualCADiReplen, args[0].ToString()); } /// /// 将前端输入的baseline更新到持久化文件 /// /// /// /// private bool BaseLineKeyDownAction(string cmd, object[] args) { string variableName = args[0].ToString(); //baseline输入了一个不同的值的话,将新值写入持久化文件 if (_persistentValue.ANBaseLineLevel.ToString() != args[1].ToString()) { PropertyInfo property = _persistentValue.GetType().GetProperty(variableName); if (property != null) { property.SetValue(_persistentValue, args[1]); } ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $" New ANBaseline {args[1]} was inputed"); _isTestRunning = false; } return true; } private bool StartLeakTestAction(string cmd, object[] args) { //前端重复点击start直接返回true; if (_isTestRunning) { LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $" Fast leak test has already started"); return true; } //判断是否启动fast leak test 参数【0】表示是否初始化,参数【1】表示是否有metal有流量 if ((bool)args[0] && (bool)args[1] ) { LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $" Fast leak test is start"); _isTestRunning = true; //记录fast leak test的开始时间 _fastLeakStartTime = DateTime.Now; //记录slow leak test的开始时间,第一次的开始时间需要加上这个配置时间,正好使第一次执行slow leak test的时间间隔使为1小时。 _slowLeakStartTime = DateTime.Now + TimeSpan.FromMinutes(_clearLeakVolumeTime); //记录slow leak test的开始液位 _StartSlowLeakTestANLevel = ReservoirData.ANLevel; } else { LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $" Leak test precondition not met, stoped"); _isTestRunning = false; } return true; } /// Fast leak test /// /// /// private bool FastLeakTestAction() { bool isHasMetalFlow = false; foreach (var metalDevice in _metalDevices) { if(metalDevice.ANACellFlow.CounterValue>0 || metalDevice.ANBCellFlow.CounterValue > 0) { isHasMetalFlow = true; } } if(!isHasMetalFlow) { LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $" No ANFLow in {Module}, current fast leak test is skiped"); //更新_faseLeak的启动时间,使其可以自动周期性检测 _fastLeakStartTime = DateTime.Now; return true ; } double aNBaseLineLevel = ReservoirsPersistentManager.Instance.GetReservoirsPersistentValue(Module).ANBaseLineLevel; if (_reservoirData.ANLevel < aNBaseLineLevel - _aNFastLeakLevelTolerance) { _isLeakDetected = true; //用于前端页面指示灯 LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $" Fast Leak was Detected,Current ANLevel is{_reservoirData.ANLevel},baseline is{aNBaseLineLevel}. Related pump and valve was closed"); AnPumpOffOperation($"{Module}.AnPumpOff", null); //关闭对应的anolyte flow valve foreach (var metalDevice in _metalDevices) { metalDevice.AnSideAFillOff($"{metalDevice.Name}.ANAFillOff", null); metalDevice.AnSideBFillOff($"{metalDevice.Name}.ANBFillOff", null); metalDevice.AnSideADrainOff($"{metalDevice.Name}.ANADrainOff", null); metalDevice.AnSideBDrainOff($"{metalDevice.Name}.ANBDrainOff", null); } } else { _isLeakDetected = false; string variableName = "ANBaseLineLevel"; PropertyInfo property = _persistentValue.GetType().GetProperty(variableName); if (property != null) { property.SetValue(_persistentValue, _reservoirData.ANLevel); } ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"No fast leak test was Detected, leak test baseLine was updated"); } //更新_faseLeak的启动时间,使其可以自动周期性检测 _fastLeakStartTime = DateTime.Now; return true; } /// Slow leak test /// /// /// private bool SlowLeakTestAction() { ReservoirEntity _reservoirEntity = Singleton.Instance.GetModule(Module); if (_reservoirEntity != null && _reservoirEntity.IsInitialized) { _isInitialized = true; } else { _isInitialized = false; } if (_persistentValue.OperatingMode == AUTO) { foreach (var metalDevice in _metalDevices) { if (metalDevice.ANACellFlow.CounterValue > 0 || metalDevice.ANBCellFlow.CounterValue > 0) { _isHasAnFlow = true; } if ("Auto".Equals(metalDevice.OperationMode)) { _isHasMetalInAuto = true; } } if (_isHasAnFlow && _isHasMetalInAuto && _isInitialized) { LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $" Slow leak test is start"); _leakVolume = ReservoirData.ANLevel - _StartSlowLeakTestANLevel; if (_leakVolume > SC.GetValue($"Reservoir.{Module}.MaxLeakVolume")) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, " Slow leak was detected"); } } } //更新当前液位 _StartSlowLeakTestANLevel = ReservoirData.ANLevel; //更新启动时间 _slowLeakStartTime = DateTime.Now; return true ; } /// /// 重新开始slow leak test /// /// /// /// private bool ClearSlowLeak(string cmd, object[] objs) { _StartSlowLeakTestANLevel = ReservoirData.ANLevel; _slowLeakStartTime = DateTime.Now; LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $" Slow leak test was reset"); return true; } /// /// 手动注水 /// /// /// /// private bool ManualDiReplen(Func direplenOn,ReservoirOperation direplenOperation,string timeLength) { if (_currentOperation != ReservoirOperation.None) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"current operation is {_currentOperation},cannot execute {direplenOperation}"); return false; } bool result = direplenOn("", null); if (result) { _currentOperation = direplenOperation; _persistentValue.DiReplenTime = DateTime.Now; ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); int.TryParse(timeLength, out _manualReplenSecond); } return result; } /// /// 阳极自动注水 /// /// public bool AutoANDiReplen() { if (IsANLowLevel) { if (!_isANAutoDIReplenError) { _isANAutoDIReplenError = true; LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"ANLowLevel is activate,Can't AutoANDireplen"); } return false; } else { _isANAutoDIReplenError = false ; } return AutoDireplen(ANDiReplenOn,ReservoirOperation.AutoANDiReplen); } /// /// 阴极自动流水 /// /// public bool AutoCADiReplen() { if (IsCALowLevel) { if (!_isCAAutoDIReplenError) { _isCAAutoDIReplenError = true; LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"CALowLevel is activate,Can't AutoANDireplen"); } return false; } else { _isCAAutoDIReplenError = false; } return AutoDireplen(CADiReplenOn, ReservoirOperation.AutoCADiReplen); } /// /// 自动注水 /// /// private bool AutoDireplen(Func direplenOn,ReservoirOperation reservoirOperation) { if (_currentOperation != ReservoirOperation.None) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"current operation is {_currentOperation},cannot execute {reservoirOperation}"); return false; } if (_resRecipe == null) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"recipe is null"); return false; } bool result = direplenOn(false); if (result) { _currentOperation = reservoirOperation; _persistentValue.DiReplenTime = DateTime.Now; } return result; } #endregion #region CrossDose /// /// CrossDose开阀 /// /// /// /// public bool CrossDoseOn(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CROSS_DOSE_ENABLE}"); return IOModuleManager.Instance.WriteIoValue(ioName, true); } /// /// CrossDose关阀 /// /// /// /// public bool CrossDoseOff(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CROSS_DOSE_ENABLE}"); return IOModuleManager.Instance.WriteIoValue(ioName, false); } /// /// 手动Dosing /// /// /// /// private bool StartDosing(string cmd, object[] args) { ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); if (!_isCrossDoseInitialized) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, "Please initialize Cross Dose"); return false; } double crossDoseVolume = (double)args[0]; _crossDoseHelper.SetManualDoseOperation(); return _crossDoseHelper.StartDosing(crossDoseVolume); } /// /// 停止Dosing /// /// /// /// private bool HaltDosing(string cmd, object[] args) { _crossDoseHelper.ResetDoseOperation(); _crossDoseHelper.HaltDosing(); string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CROSS_DOSE_ENABLE}"); return IOModuleManager.Instance.WriteIoValue(ioName, false); } /// /// Set Pump Factor /// /// /// /// private bool SetPumpFactor(string cmd, object[] args) { double targetPumpFactor = (double)args[0]; _crossDoseHelper.SetPumpfactor(targetPumpFactor); return true; } /// /// CrossDose初始化 /// /// public void InitializeCrossDose(bool isInitialized) { _isCrossDoseInitialized = isInitialized; } /// /// Reset CrossDose /// /// /// /// public bool ResetCrossDose(string cmd, object[] args) { return _crossDoseHelper.ResetCrossDose(); } /// /// Reset Monitor /// /// /// /// public bool ResetCrossDoseMonitor() { return _crossDoseHelper.ResetCrossDoseMonitor(); } #endregion #region Sample /// /// ANSample开阀 /// /// /// /// public bool ANSampleOn(string cmd, object[] args) { SystemFacilities systemFacility = DEVICE.GetDevice("System.Facilities"); if (systemFacility != null && !systemFacility.SampleFluidDetect) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "SampleFluidDetect is Activate. Can't open ANSample"); return false; } string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_SAMPLE_FLOW}"); return IOModuleManager.Instance.WriteIoValue(ioName, true); } /// /// ANSample关阀 /// /// /// /// public bool ANSampleOff(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_SAMPLE_FLOW}"); return IOModuleManager.Instance.WriteIoValue(ioName, false); } /// /// CASample开阀 /// /// /// /// public bool CASampleOn(string cmd, object[] args) { SystemFacilities systemFacility = DEVICE.GetDevice("System.Facilities"); if (systemFacility != null && !systemFacility.SampleFluidDetect) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "SampleFluidDetect is Activate. Can't open CASample"); return false; } string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_SAMPLE_FLOW}"); return IOModuleManager.Instance.WriteIoValue(ioName, true); } /// /// CASample关阀 /// /// /// /// public bool CASampleOff(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_SAMPLE_FLOW}"); return IOModuleManager.Instance.WriteIoValue(ioName, false); } #endregion /// /// 订阅变量数值发生变化 /// private void SubscribeValueAction() { BeckhoffIoSubscribeUpdateVariable(CA_DI_REPLEN); BeckhoffIoSubscribeUpdateVariable(AN_DI_REPLEN); BeckhoffIoSubscribeUpdateVariable(CA_WATER_LEVEL); BeckhoffIoSubscribeUpdateVariable(AN_WATER_LEVEL); BeckhoffIoSubscribeUpdateVariable(AN_PUMP); BeckhoffIoSubscribeUpdateVariable(CROSS_DOSE_ENABLE); BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_STM_STATUS); BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_POS_STATUS); BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_TARGET_POSITION); BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_ENABLE); BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_EXECUTE); BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_RESET); BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_SPEED); BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_START_TYPE); BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_ACCELERATION); BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_DECELERATION); BeckhoffIoSubscribeUpdateVariable(TRANSFER_ACTUAL_POSITION); BeckhoffIoSubscribeUpdateVariable(AN_BYPASS_FLOW); BeckhoffIoSubscribeUpdateVariable(AN_A_DRAIN_PUMP); BeckhoffIoSubscribeUpdateVariable(AN_B_DRAIN_PUMP); BeckhoffIoSubscribeUpdateVariable(AN_SAMPLE_FLOW); BeckhoffIoSubscribeUpdateVariable(CA_SAMPLE_FLOW); BeckhoffIoSubscribeUpdateVariable(CA_PUMP_SPEED); BeckhoffIoSubscribeUpdateVariable(CA_PUMP_RUNNING); BeckhoffIoSubscribeUpdateVariable(CA_HED_FLOW); BeckhoffIoSubscribeUpdateVariable(CDA_FLOW_VALVE); BeckhoffIoSubscribeUpdateVariable(AN_BY_PASS); BeckhoffIoSubscribeUpdateVariable(CA_BY_PASS); BeckhoffIoSubscribeUpdateVariable(CA_PUMP_ENABLE); BeckhoffIoSubscribeUpdateVariable(EVAPORATORLEVEL); BeckhoffCounterSubscribeUpdateVariable(AN_TRANSFER_FLOW, ANTransferFlow); BeckhoffCounter anTransferFlowCounter = BeckhoffCounterManager.Instance.GetBeckhoffCounter($"{Module}.{AN_TRANSFER_FLOW}"); if (anTransferFlowCounter != null) { ANTransferFlow.Period = anTransferFlowCounter.Period; } BeckhoffCounterSubscribeUpdateVariable(AN_BYPASS_COUNTERFLOW, ReservoirCounterByPassFlow); BeckhoffCounter reservoirCounterByPassFlow = BeckhoffCounterManager.Instance.GetBeckhoffCounter($"{Module}.{AN_BYPASS_COUNTERFLOW}"); if (reservoirCounterByPassFlow != null) { ReservoirCounterByPassFlow.Period = reservoirCounterByPassFlow.Period; } } /// /// 订阅IO变量 /// /// private void BeckhoffIoSubscribeUpdateVariable(string variable) { _variableInitializeDic[variable] = false; IOModuleManager.Instance.SubscribeModuleVariable(Module, variable, UpdateVariableValue); } /// /// 订阅Counter变量 /// /// private void BeckhoffCounterSubscribeUpdateVariable(string variable, CounterFlowData counterFlowData) { _nameCounterFlowData[$"{Module}.{variable}"] = counterFlowData; BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_VALUE, UpdateCounterVariableValue); BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_START, UpdateCounterVariableValue); BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_STOP, UpdateCounterVariableValue); BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_RESET, UpdateCounterVariableValue); } /// /// 更新变量数值 /// /// /// private void UpdateCounterVariableValue(string variable, object value) { string[] strAry = variable.Split('.'); string lastVariable = strAry[strAry.Length - 1]; PropertyInfo property = null; string key = variable.Replace($".{lastVariable}", ""); if (_nameCounterFlowData.ContainsKey(key)) { CounterFlowData counterFlowData = _nameCounterFlowData[key]; if (counterFlowData != null) { property = counterFlowData.GetType().GetProperty(lastVariable); if (property != null) { property.SetValue(counterFlowData, value); } } } } /// /// 更新变量数值 /// /// /// private void UpdateVariableValue(string variable, object value) { if (!ReservoirData.IsDataInitialized) { ReservoirData.IsDataInitialized = true; } PropertyInfo property = ReservoirData.GetType().GetProperty(variable); if (property != null) { property.SetValue(ReservoirData, value); if(variable==AN_WATER_LEVEL) { string anLevelCurve = SC.GetStringValue($"Reservoir.{Module}.ANLevelCurve"); ReservoirData.ANLevel = LevelCurveManager.Instance.CalculateLevelByWaterLevel(ReservoirData.ANWaterLevel, anLevelCurve); } else if(variable==CA_WATER_LEVEL) { string caLevelCurve = SC.GetStringValue($"Reservoir.{Module}.CALevelCurve"); ReservoirData.CALevel = LevelCurveManager.Instance.CalculateLevelByWaterLevel(ReservoirData.CAWaterLevel, caLevelCurve); } } if (_variableInitializeDic.ContainsKey(variable) && !_variableInitializeDic[variable]) { _variableInitializeDic[variable] = true; } } /// /// 是否所有IO变量初始化完成 /// /// private bool AllIoVariableInitialized() { foreach (string item in _variableInitializeDic.Keys) { if (!_variableInitializeDic[item]) { LOG.WriteLog(eEvent.ERR_RINSE, Module, $"{item} is not initialized"); return false; } } return true; } /// /// 检验阳极是否需要补水 /// /// private bool CheckANNeedDiReplen() { if(IsAuto&&_resRecipe!=null) { if (_resRecipe.ANDIReplenEnable&&_resRecipe.ANDIReplenCurrentRate==0&&_resRecipe.ANDIReplenTimeRate==0) { double levelHysteresis = SC.GetValue("Reservoir.LevelHysteresis"); return _reservoirData.ANLevel < _resRecipe.ReservoirANLevel - levelHysteresis; } return false; } else { return false; } } /// /// 检验CA是否需要注水 /// /// public bool CheckCANeedDiReplen() { if(IsAuto&&_resRecipe!=null) { if (_resRecipe.DIReplenEnable && _resRecipe.DIReplenTimeRate == 0 && _resRecipe.DIReplenCurrentRate == 0) { double levelHysteresis = SC.GetValue("Reservoir.LevelHysteresis"); return _reservoirData.CALevel < _resRecipe.ReservoirCALevel - levelHysteresis; } return false; } else { return false; } } /// /// 检验阴极是否highlevel /// public bool CheckCAHighLevelStatus() { return ReservoirData.CAWaterLevel > SC.GetValue($"Reservoir.{Module}.CAHighLevel") ? true : false; } /// /// 检验阴极是否lowlevel /// public bool CheckCALowLevelStatus() { return ReservoirData.CAWaterLevel < SC.GetValue($"Reservoir.{Module}.CALowLevel") ? true : false; } /// /// 检验阳极是否highlevel /// public bool CheckANHighLevelStatus() { return ReservoirData.ANWaterLevel > SC.GetValue($"Reservoir.{Module}.ANHighLevel") ? true : false; } /// /// 检验阳极是否lowlevel /// public bool CheckANLowLevelStatus() { return ReservoirData.ANWaterLevel < SC.GetValue($"Reservoir.{Module}.ANLowLevel") ? true : false; } /// /// CAFlowRate Check /// private void CAFlowRateCheck() { ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); if (_resRecipe == null) return; for (int i = 0; i < _metalDevices.Count; i++) { CompactMembranMetalDevice hotMetalDevice = _metalDevices[i]; if (hotMetalDevice != null && !hotMetalDevice.IsDisable && hotMetalDevice.IsAuto ) { MetalEntity metalEntity = Singleton.Instance.GetModule(hotMetalDevice.Name); if (hotMetalDevice.MetalDeviceData == null) continue ; if (!hotMetalDevice.FlowValveStable) continue; double cellFlow = hotMetalDevice.MetalDeviceData.CellFlow; if (cellFlow < _resRecipe.CAFlowRateErrorLow && !metalEntity.IsError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{hotMetalDevice.Name} cellflow:{cellFlow} is less than recipe's CAFlowRateErrorLow parameter:{_resRecipe.CAFlowRateErrorLow}"); metalEntity.PostMsg(MetalMsg.Error); } else if (cellFlow < _resRecipe.CAFlowRateWarningLow) { if (!_isCAFlowRateWARN[i]) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{hotMetalDevice.Name} cellflow:{cellFlow} is less than recipe's CAFlowRateWarningLow parameter:{_resRecipe.CAFlowRateWarningLow}"); _isCAFlowRateWARN[i] = true; } } else { _isCAFlowRateWARN[i] = false; } } } } /// /// ANFlowRate Check /// private void ANFlowRateCheck() { ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); if (_resRecipe == null) return; for (int i = 0; i < _metalDevices.Count; i++) { CompactMembranMetalDevice hotMetalDevice = _metalDevices[i]; if (hotMetalDevice != null && !hotMetalDevice.IsDisable && hotMetalDevice.IsAuto) { if (hotMetalDevice.MetalDeviceData == null) continue; //ANACellFlow MetalEntity metalEntity = Singleton.Instance.GetModule(hotMetalDevice.Name); if (hotMetalDevice.MetalDeviceData.ANAPinEnable) { double ANAcellFlow = hotMetalDevice.ANACellFlow.CounterValue; if (ANAcellFlow < _resRecipe.ANFlowRateErrorLow && !metalEntity.IsError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{hotMetalDevice.Name} ANASideflow:{ANAcellFlow} is less than recipe's ANFlowRateErrorLow parameter:{_resRecipe.ANFlowRateErrorLow}"); metalEntity.PostMsg(MetalMsg.Error); } else if (ANAcellFlow < _resRecipe.ANFlowRateWarningLow) { if (!_isANAFlowRateWARN[i]) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{hotMetalDevice.Name} ANASideflow:{ANAcellFlow} is less than recipe's ANFlowRateWarningLow parameter:{_resRecipe.ANFlowRateWarningLow}"); _isANAFlowRateWARN[i] = true; } } else { _isANAFlowRateWARN[i] = false; } } //ANBCellFlow if (hotMetalDevice.MetalDeviceData.ANBPinEnable) { double ANBcellFlow = hotMetalDevice.ANBCellFlow.CounterValue; if (ANBcellFlow < _resRecipe.ANFlowRateErrorLow && !metalEntity.IsError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{hotMetalDevice.Name} ANBSideflow:{ANBcellFlow} is less than recipe's ANFlowRateErrorLow parameter:{_resRecipe.ANFlowRateErrorLow}"); metalEntity.PostMsg(MetalMsg.Error); } else if (ANBcellFlow < _resRecipe.ANFlowRateWarningLow) { if (!_isANBFlowRateWARN[i]) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{hotMetalDevice.Name} ANBflow:{ANBcellFlow} is less than recipe's ANFlowRateWarningLow parameter:{_resRecipe.ANFlowRateWarningLow}"); _isANBFlowRateWARN[i] = true; } } else { _isANBFlowRateWARN[i] = false; } } } } } /// /// Temperature Check /// private void TemperatureCheck() { ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module); TemperatureController temperatureController = DEVICE.GetDevice(reservoirItem.TCID); if (temperatureController == null || temperatureController.TemperatureData == null || _resRecipe == null || temperatureController.TemperatureData.ControlOperationModel != ENABLE) return; double tempValue = temperatureController.TemperatureData.ReserviorTemperature; if (tempValue > _resRecipe.TemperatureErrorHigh && !reservoirEntity.IsError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{temperatureController.Name} temperature:{tempValue} is over recipe's TemperatureErrorHigh parameter:{_resRecipe.TemperatureErrorHigh}"); reservoirEntity.PostMsg(ReservoirMsg.Error); } else if (tempValue < _resRecipe.TemperatureErrorLow && !reservoirEntity.IsError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{temperatureController.Name} temperature:{tempValue} is less than recipe's TemperatureErrorLow parameter:{_resRecipe.TemperatureErrorLow}"); reservoirEntity.PostMsg(ReservoirMsg.Error); } else if (tempValue > _resRecipe.TemperatureWarningHigh) { if (!_isTCControlWARN) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{temperatureController.Name} temperature:{tempValue} is over recipe's TemperatureWarningHigh parameter:{_resRecipe.TemperatureWarningHigh}"); _isTCControlWARN = true; } } else if (tempValue < _resRecipe.TemperatureWarningLow) { if (!_isTCControlWARN) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{temperatureController.Name} temperature;{tempValue} is less than recipe's TemperatureWarningLow parameter:{_resRecipe.TemperatureWarningLow}"); _isTCControlWARN = true; } } else { _isTCControlWARN = false; } } /// /// 定时器 /// /// private bool OnTimer() { //补水监控 if(_direplenHelper != null) { _direplenHelper.MonitorPeriodTime(); if (_currentOperation == ReservoirOperation.ManualANDiReplen) { bool result = _direplenHelper.MonitorManualDiReplenComplete(_manualReplenSecond, ANDiReplenOff); if (result) { _currentOperation = ReservoirOperation.None; } } if (_currentOperation == ReservoirOperation.ManualCADiReplen) { bool result = _direplenHelper.MonitorManualDiReplenComplete(_manualReplenSecond, CADiReplenOff); if (result) { _currentOperation = ReservoirOperation.None; } } if (_currentOperation == ReservoirOperation.AutoANDiReplen) { AutoDiReplenMonitor(ANDiReplenOff, _reservoirData.ANLevel, _resRecipe.ReservoirANLevel); } if (_currentOperation == ReservoirOperation.AutoCADiReplen) { AutoDiReplenMonitor(CADiReplenOff, _reservoirData.CALevel, _resRecipe.ReservoirCALevel); } } //计算AN/CA level的平均值 if (ReservoirData != null) { //AN if(_ANLevelSamples.Count >= levelSampleCount) { _ANLevelSamples.Dequeue(); _ANLevelSamples.Enqueue(ReservoirData.ANLevel); } else { _ANLevelSamples.Enqueue(ReservoirData.ANLevel); } //CA if (_CALevelSamples.Count >= levelSampleCount) { _CALevelSamples.Dequeue(); _CALevelSamples.Enqueue(ReservoirData.CALevel); } else { _CALevelSamples.Enqueue(ReservoirData.CALevel); } _avgANLevel = _ANLevelSamples.Count > 0 ? _ANLevelSamples.Average() : 0; _avgCALevel = _CALevelSamples.Count > 0 ? _CALevelSamples.Average() : 0; } _metalTotalFlow = 0; ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module); if (reservoirItem != null) { List metalItems = reservoirItem.MetalCells; if (metalItems != null && metalItems.Count > 0) { foreach (MetalItem metalItem in metalItems) { if (metalItem.Installed) { CompactMembranMetalDevice metalDevice = DEVICE.GetDevice(metalItem.ModuleName); if (metalDevice != null) { _metalTotalFlow += metalDevice.ANACellFlow.CounterValue; _metalTotalFlow += metalDevice.ANBCellFlow.CounterValue; } } } } } //pump安全性检验 if (_reservoirData.ANPump > 0 && (_reservoirData.ANBypassFlow + ReservoirCounterByPassFlow.CounterValue + _metalTotalFlow)< SC.GetValue($"Reservoir.{Module}.ByPassMetalTotalFlowMinLimit")) { if (!_isAnPumpSafeDetectedActivate) { _isAnPumpSafeDetectedActivate = true; _AnPumpSafeDetectTime = DateTime.Now; } if ((DateTime.Now - _AnPumpSafeDetectTime).TotalSeconds > _flowFaultHoldOffTime && _isAnPumpSafeDetectedActivate) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Total flow is less than configuration item ByPassMetalTotalFlowMinLimit :{SC.GetValue($"Reservoir.{Module}.ByPassMetalTotalFlowMinLimit")}, AN Pump off"); _isAnPumpSafeDetectedActivate = false; AnPump(0); } } else { _isAnPumpSafeDetectedActivate = false; } foreach(CompactMembranMetalDevice device in _metalDevices) { device.OnTimer(_periodicJob.Interval); } ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); if(reservoirEntity != null && reservoirEntity.IsError && _isCrossDoseInstalled && _reservoirData.TransferPumpEnable && _reservoirData.TransferPumpExecute) { _crossDoseHelper.HaltDosing(); } // 判断排气是否触发漏液警报 if (_reservoirData!=null && _reservoirData.EvaporatorLevel && "STD".Equals(reservoirItem.EvaporatorType)) //_reservoirData.EvaporatorLevel true表示触发漏液 { if (_reservoirData.CDAFlowValve) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"EvaporatorLevel is Activate"); CDAFlowOff("CDAFlowOff", null); } if (_reservoirData.CAPumpEnable) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"EvaporatorLevel is Activate"); CAPumpOff("CAPumpOff", null); } } //触发low将对应的reservoir和对应metal切成error if (IsANLowLevel || IsCALowLevel) { if (IsANLowLevel && !reservoirEntity.IsError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current ANWaterlevel:{ReservoirData.ANWaterLevel} is lower than ANLowLevel Config:{SC.GetValue($"Reservoir.{Module}.ANLowLevel")}"); } if (IsCALowLevel && !reservoirEntity.IsError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current CAWaterlevel:{ReservoirData.ANWaterLevel} is lower than CALowLevel Config:{SC.GetValue($"Reservoir.{Module}.CALowLevel")}"); } foreach (var metalDevice in _metalDevices) { MetalEntity metalEntity = Singleton.Instance.GetModule(metalDevice.DeviceID); if (metalEntity != null && !metalEntity.IsError) { metalEntity.PostMsg(MetalMsg.Error); } } reservoirEntity.PostMsg(ReservoirMsg.Error); } //触发high将reservoir切成error if (IsANHighLevel || IsCAHighLevel) { if (IsANHighLevel && !reservoirEntity.IsError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current ANWaterlevel:{ReservoirData.ANWaterLevel} is larger than ANHighLevel Config:{SC.GetValue($"Reservoir.{Module}.ANHighLevel")}"); } if (IsCAHighLevel && !reservoirEntity.IsError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current CAWaterlevel:{ReservoirData.CAWaterLevel} is large than CAHighLevel Config:{SC.GetValue($"Reservoir.{Module}.CAHighLevel")}"); } SystemFacilities systemFacilities = DEVICE.GetDevice("System.Facilities"); if(systemFacilities != null && !reservoirEntity.IsError) { systemFacilities.DiFillDisableOperation("DIFillDisableOpeartion", null); systemFacilities.DiReplenDisableOperation("DiReplenDisableOperation", null); if (_reservoirData.ANDiReplen) { _currentOperation = ReservoirOperation.None; ANDiReplenOff("", null); } if (_reservoirData.CADiReplen) { _currentOperation = ReservoirOperation.None; CADiReplenOff("", null); } } reservoirEntity.PostMsg(ReservoirMsg.Error); } //触发Safetyhigh将reservoir切成error SafetyDevice safetyDevice = DEVICE.GetDevice("Safety"); if (safetyDevice != null && safetyDevice.SafetyData.ReservoirHighLevel && !reservoirEntity.IsError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Safety high is Activate"); reservoirEntity.PostMsg(ReservoirMsg.Error); } //判断high/low等指示灯是否触发并执行对应的操作 if (IsANLowLevel) { if (_reservoirData.ANPump > 0) { AnPumpOffOperation("ANPumpOff", null); LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"ANLowLevel is Activate"); } foreach (var metalDevice in _metalDevices) { if (metalDevice.MetalDeviceData.ANAPinEnable) { metalDevice.AnSideAFillOff($"{metalDevice.Name}.ANAFillOff", null); } if (metalDevice.MetalDeviceData.ANBPinEnable) { metalDevice.AnSideBFillOff($"{metalDevice.Name}.ANBFillOff", null); } } } if (IsCALowLevel) { if (_reservoirData.CAPumpEnable) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"CALowLevel is Activate"); CAPumpOff("CAPumpOff", null); } foreach (var metalDevice in _metalDevices) { if(metalDevice.MetalDeviceData.CellFlowValve) { metalDevice.CellFlowValveOff($"{metalDevice.Name}.FlowOff", null); } } //禁用TC if (!String.IsNullOrEmpty(reservoirItem.TCID)) { TemperatureController temperatureController = DEVICE.GetDevice(reservoirItem.TCID); if (temperatureController != null && temperatureController.TemperatureData.ControlOperationModel == 5) { temperatureController.DisableOperation("", null); } } } //水位触发recipe里面的high/low参数将对应的reservoir切成error if (_resRecipe != null && (ReservoirData.ANLevel < _resRecipe.ANLevelErrorLow || ReservoirData.ANLevel > _resRecipe.ANLevelErrorHigh || ReservoirData.CALevel < _resRecipe.CALevelErrorLow || ReservoirData.CALevel > _resRecipe.CALevelErrorHigh)) { if (ReservoirData.ANLevel < _resRecipe.ANLevelErrorLow && !reservoirEntity.IsError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current ANlevel:{ReservoirData.ANLevel} is lower than ResRecipe.ANLevelErrorLow:{_resRecipe.ANLevelErrorLow}"); } if (ReservoirData.ANLevel > _resRecipe.ANLevelErrorHigh && !reservoirEntity.IsError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current ANlevel:{ReservoirData.ANLevel} is larger than ResRecipe.ANLevelErrorHigh:{_resRecipe.ANLevelErrorHigh}"); } if (ReservoirData.CALevel < _resRecipe.CALevelErrorLow && !reservoirEntity.IsError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current CAlevel:{ReservoirData.CALevel} is lower than ResRecipe.CALevelErrorLow:{_resRecipe.CALevelErrorLow}"); } if (ReservoirData.CALevel > _resRecipe.CALevelErrorHigh && !reservoirEntity.IsError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current CAlevel:{ReservoirData.CALevel} is larger than ResRecipe.CALevelErrorHigh:{_resRecipe.CALevelErrorHigh}"); } reservoirEntity.PostMsg(ReservoirMsg.Error); } //Sample检测 SystemFacilities systemFacility = DEVICE.GetDevice("System.Facilities"); if (systemFacility != null && !systemFacility.SampleFluidDetect) { if(ReservoirData.ANSampleFlow) ANSampleOff("", null); if(ReservoirData.CASampleFlow) CASampleOff("", null); } if (reservoirEntity == null || !reservoirEntity.IsInitialized) { return true; } if (_isCrossDoseInstalled) { if (_crossDoseHelper.CrossDoseState == RState.Running) { _crossDoseHelper.CrossDoseStatusMonitor(); } if(_crossDoseHelper.ResetState == RState.Running) { _crossDoseHelper.ResetCrossDoseMonitor(); } if (_persistentValue.OperatingMode == "Auto") { _crossDoseHelper.AutoCrossDoseMonitor(_isCrossDoseInitialized); } else { _crossDoseHelper.CrossDoseOperationMonitor(); } } if (_persistentValue.OperatingMode == AUTO) { _pumpSpeedHelper.Monitor(_resRecipe); //CAFlowRate判断 CAFlowRateCheck(); //ANFlowRate判断 ANFlowRateCheck(); //Temperature判断 TemperatureCheck(); } //判断是否到启动fast leak test的时间 if(DateTime.Now - _fastLeakStartTime >= _fastLeakTestSpan - TimeSpan.FromMilliseconds(200) && DateTime.Now - _fastLeakStartTime <= _fastLeakTestSpan + TimeSpan.FromMilliseconds(200)) { FastLeakTestAction(); } //判断是否到启动slow leak test的时间 if (DateTime.Now - _slowLeakStartTime >= _slowLeakTestSpan - TimeSpan.FromMilliseconds(200) && DateTime.Now - _slowLeakStartTime <= _slowLeakTestSpan + TimeSpan.FromMilliseconds(200)) { SlowLeakTestAction(); } return true; } /// /// 自动注水监控 /// /// /// /// private void AutoDiReplenMonitor(Func direplenOff,double level,double recipeLevel) { bool result = _direplenHelper.AutoDiReplenMonitorTimeOut(direplenOff); if (result) { _currentOperation = ReservoirOperation.None; //触发注水异常信号 _isDiReplenInFault = true; } else { //按液位补水 result = _direplenHelper.AutoDiReplenMonitorComplete(level, recipeLevel,_resRecipe, direplenOff); if (result) { _currentOperation = ReservoirOperation.None; } } } public void Monitor() { } public void Reset() { } public void Terminate() { } } }