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.Alarm;
using MECF.Framework.Common.Algorithm;
using MECF.Framework.Common.Beckhoff.ModuleIO;
using MECF.Framework.Common.CommonData.PlatingCell;
using MECF.Framework.Common.CommonData.Prewet;
using MECF.Framework.Common.CommonData.Reservoir;
using MECF.Framework.Common.IOCore;
using MECF.Framework.Common.Persistent.Reservoirs;
using MECF.Framework.Common.RecipeCenter;
using MECF.Framework.Common.ToolLayout;
using MECF.Framework.Common.TwinCat;
using MECF.Framework.Common.Utilities;
using PunkHPX8_Core;
using PunkHPX8_RT.Devices.Facilities;
using PunkHPX8_RT.Devices.PlatingCell;
using PunkHPX8_RT.Devices.Safety;
using PunkHPX8_RT.Devices.Temperature;
using PunkHPX8_RT.Modules;
using PunkHPX8_RT.Modules.Reservoir;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.ServiceModel.Security;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Documents;
namespace PunkHPX8_RT.Devices.Reservoir
{
public class ReservoirDevice : BaseDevice, IDevice
{
protected enum DiReplenOperation
{
None,
ManualANDiReplen,
ManualCADiReplen,
AutoANDiReplen,
AutoCADiReplen
}
#region 常量
protected const string AUTO = "Auto";
protected const string MANUAL = "Manual";
protected const string DISABLE = "Disable";
protected const string CA_PUMP_RUNNING="CaPumpRunning";
protected const string AN_TOWER_HIGH="AnTowerHigh";
protected const string AN_TOWER_LOW="AnTowerLow";
protected const string CA_LEVEL="CaLevel";
protected const string CA_WATER_LEVEL="CaWaterLevel";
protected const string AN_FLOW="AnFlow";
protected const string AN_PUMP_ENABLE="AnPumpEnable";
protected const string AN_PUMP_SPEED="AnPumpSpeed";
protected const string CA_FLOW="CaFlow";
protected const string CA_PUMP_ENABLE="CaPumpEnable";
protected const string CA_PUMP_SPEED="CaPumpSpeed";
protected const string RETURN_VALVE_OPENING="ReturnValveOpening";
protected const string CA_DI_REPLEN="CaDiReplen";
protected const string AN_DI_REPLEN="AnDiReplen";
protected const string SAMPLE_OUT="SampleOut";
protected const string DEGAS_ENABLE="DegasEnable";
protected const string CA_ISOLATION="CaIsolation";
protected const string AN_ISOLATION="AnIsolation";
protected const string HED_FLOW="HedFlow";
protected const string HED_FLOW_ENABLE="HedFlowEnable";
protected const string PH_FLOW_VALVE="PhFlowValve";
protected const string PH_VALUE="PhValue";
private const int ENABLE = 5;
#endregion
#region 内部变量
///
/// 变量是否初始化字典
///
private Dictionary _variableInitializeDic = new Dictionary();
///
/// 定时器
///
private PeriodicJob _periodicJob;
///
/// 阴极Pump速度
///
private double _caPumpSpeed = 0;
///
/// Return Valve比例
///
private double _returnValvePercent = 0.5;
///
/// CA Level取样平均值
///
private double _avgCALevel;
///
/// CA Level取样队列
///
private Queue _CALevelSamples;
///
/// CA level计算平均值取样数
///
private int _levelSampleCount;
///
/// 上一时刻platingcell的overflow level
///
private double _lastOverFlow;
///
/// 当前调节return valve的时间
///
private DateTime _adjustReturnvalveStartTime = DateTime.Now;
///
/// 首次发现ca flow 满足条件的时间,用于自动打开degas valve
///
private DateTime _caFlowOKTime = DateTime.Now;
///
/// ca flow 是否首次达到条件
///
private bool _isFirstCaFlowOK = false;
///
/// ca泵速Helper
///
private ReservoirCAPumpSpeedHelper _caPumpSpeedHelper;
//TC是否报警
private bool _isTCControlWARN = false;
#endregion
#region Trigger
///
/// Low WaterLevel trigger
///
private R_TRIG _caWaterLevelLowerTrigger=new R_TRIG();
///
/// High WaterLevel trigger
///
private R_TRIG _caWaterLevelHighTrigger = new R_TRIG();
#endregion
#region 共享变量
protected DiReplenOperation _currentDireplenOperation = DiReplenOperation.None;
///
/// 手动注水时间(秒)
///
protected int _manualReplenSecond = 0;
///
/// 数据
///
protected ReservoirData _reservoirData = new ReservoirData();
///
/// Prewet 持久性数值对象
///
protected ReservoirsPersistentValue _persistentValue;
///
/// platingcellData
///
protected PlatingCellDevice _platingCellDevice;
///
/// Recipe
///
protected ResRecipe _resRecipe;
///
/// 注水Helper
///
protected ReservoirDiReplenHelper _direplenHelper;
///
/// 累计补水是否超时
///
protected bool _isDIReplenMaxTimeOut = false;
///
/// 单次补水是否超时
///
protected bool _isDIReplenPerfillTimeOut = false;
#endregion
#region 属性
///
/// 操作模式
///
public string OperationMode { get { return _persistentValue.OperatingMode; } }
///
/// 工程模式
///
public string EngineerMode { get { return _persistentValue.RecipeOperatingMode; } }
///
/// 是否自动
///
public bool IsAuto { get { return _persistentValue.OperatingMode == AUTO; } }
///
/// 数据
///
public ReservoirData ReservoirData { get { return _reservoirData; } }
///
/// 检验阴极是否highlevel
///
public bool IsCAHighLevel { get { return CheckCAHighLevelStatus(); } }
///
/// 检验阴极是否lowlevel
///
public bool IsCALowLevel { get { return CheckCALowLevelStatus(); } }
///
/// 当前Recipe
///
public ResRecipe Recipe { get { return _resRecipe; } }
///
/// 阴极是否需要补水
///
public bool CANeedDiReplen { get { return CheckCANeedDiReplen(); } }
///
/// 正在补水
///
public bool IsDireplenOn { get { return _reservoirData.AnDiReplen || _reservoirData.CaDiReplen; } }
///
/// 单次补水是否超时
///
public bool IsDIReplenPerfillTimeOut { get { return _isDIReplenPerfillTimeOut; } }
///
/// 累计补水是否超时
///
public bool IsDIReplenMaxTimeOut { get { return _isDIReplenMaxTimeOut; } }
///
/// 是否启动retrun valve自动调节开闭
///
public bool IsStartAutoReturnValve { get; set; }
#endregion
///
/// 构造函数
///
///
///
public ReservoirDevice(string moduleName) : base(moduleName, moduleName, moduleName, moduleName)
{
_levelSampleCount = SC.GetValue("Reservoir.LevelAvgSamples");
_levelSampleCount = _levelSampleCount == 0 ? 20 : _levelSampleCount;
_CALevelSamples = new Queue(_levelSampleCount);
}
///
/// 初始化
///
///
public bool Initialize()
{
InitializeParameter();
InitializeRoutine();
SubscribeData();
InitializeOperation();
SubscribeValueAction();
_periodicJob = new PeriodicJob(200, OnTimer, $"{Module}.Timer", true, true);
return true;
}
///
/// 初始化参数
///
private void InitializeParameter()
{
_persistentValue = ReservoirsPersistentManager.Instance.GetReservoirsPersistentValue(Module.ToString());
if (_persistentValue == null)
{
LOG.WriteLog(eEvent.ERR_RESERVOIR, Module.ToString(), "Persistent Value Object is not exist");
}
if (!string.IsNullOrEmpty(_persistentValue.Recipe))
{
_resRecipe = RecipeFileManager.Instance.LoadGenericityRecipe(_persistentValue.Recipe);
}
_direplenHelper = new ReservoirDiReplenHelper(Module, _persistentValue);
_caPumpSpeedHelper = new ReservoirCAPumpSpeedHelper(Module, this);
ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module);
if (reservoirItem!=null)
{
List platingCellItems = reservoirItem.PlatingCells;
if (platingCellItems != null && platingCellItems.Count > 0)
{
if (platingCellItems[0].Installed)
{
_platingCellDevice = DEVICE.GetDevice(platingCellItems[0].ModuleName);
}
}
}
}
///
/// 初始化Routine
///
private void InitializeRoutine()
{
}
///
/// 订阅数据
///
protected virtual void SubscribeData()
{
DATA.Subscribe($"{Module}.ReservoirData", () => _reservoirData, SubscriptionAttribute.FLAG.IgnoreSaveDB);
DATA.Subscribe($"{Module}.PersistentValue", () => _persistentValue, SubscriptionAttribute.FLAG.IgnoreSaveDB);
DATA.Subscribe($"{Module}.CurrentRecipe", () => _resRecipe, SubscriptionAttribute.FLAG.IgnoreSaveDB);
DATA.Subscribe($"{Module}.IsCAHighLevel", () => IsCAHighLevel, SubscriptionAttribute.FLAG.IgnoreSaveDB);
DATA.Subscribe($"{Module}.IsCALowLevel", () => IsCALowLevel, SubscriptionAttribute.FLAG.IgnoreSaveDB);
DATA.Subscribe($"{Module}.AvgCALevel", () => _avgCALevel, SubscriptionAttribute.FLAG.IgnoreSaveDB);
DATA.Subscribe($"{Module}.DIValveMaxOnTime", () => SC.GetValue($"Reservoir.{Module}.DIValveMaxOnTime") * 60, SubscriptionAttribute.FLAG.IgnoreSaveDB);
DATA.Subscribe($"{Module}.IsManualCAReplen", () => { return _currentDireplenOperation == DiReplenOperation.ManualCADiReplen; }, SubscriptionAttribute.FLAG.IgnoreSaveDB);
DATA.Subscribe($"{Module}.IsDIReplenPerfillTimeOut", () => _isDIReplenPerfillTimeOut, SubscriptionAttribute.FLAG.IgnoreSaveDB);
DATA.Subscribe($"{Module}.IsDIReplenMaxTimeOut", () => _isDIReplenMaxTimeOut, SubscriptionAttribute.FLAG.IgnoreSaveDB);
}
///
/// 初始化Operation
///
protected virtual 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}.CAPumpEnable", CAPumpOn);
OP.Subscribe($"{Module}.CAPumpSpeed", CAPumpSpeedOperation);
OP.Subscribe($"{Module}.CAPumpDisable", CAPumpOff);
OP.Subscribe($"{Module}.LoadRecipe", LoadRecipeOperation);
OP.Subscribe($"{Module}.ReturnValveOn", ReturnValveOn);
OP.Subscribe($"{Module}.ReturnValveOff", (cmd, para) => { return ReturnValveOff();});
OP.Subscribe($"{Module}.ReturnValvePercent", ReturnValvePercentOperation);
OP.Subscribe($"{Module}.CAIsolationOn", (cmd, para) => { return CAIsolationOn(); });
OP.Subscribe($"{Module}.CAIsolationOff", (cmd, para) => { return CAIsolationOff(); });
OP.Subscribe($"{Module}.SampleOutValveOn", (cmd, para) => { return SampleOutValveOn(); });
OP.Subscribe($"{Module}.SampleOutValveOff", (cmd, para) => { return SampleOutValveOff(); });
OP.Subscribe($"{Module}.DegasValveOn", (cmd, para) => { return DegasValveOn(); });
OP.Subscribe($"{Module}.DegasValveOff", (cmd, para) => { return DegasValveOff(); });
OP.Subscribe($"{Module}.PhValveOn", (cmd, para) => { return PhValveOn(); });
OP.Subscribe($"{Module}.PhValveOff", (cmd, para) => { return PhValveOff(); });
OP.Subscribe($"{Module}.HedValveOn", (cmd, para) => { return HedValveOn(); });
OP.Subscribe($"{Module}.HedValveOff", (cmd, para) => { return HedValveOff(); });
OP.Subscribe($"{Module}.ResetTotalTime", ResetTotalTime);
OP.Subscribe($"{Module}.ManualCADiReplen", ManualCADiReplen);
}
///
/// 订阅变量数值发生变化
///
protected virtual void SubscribeValueAction()
{
IoSubscribeUpdateVariable(CA_PUMP_RUNNING);
IoSubscribeUpdateVariable(AN_TOWER_HIGH);
IoSubscribeUpdateVariable(AN_TOWER_LOW);
IoSubscribeUpdateVariable(CA_LEVEL);
IoSubscribeUpdateVariable(CA_WATER_LEVEL);
IoSubscribeUpdateVariable(CA_PUMP_ENABLE);
IoSubscribeUpdateVariable(CA_PUMP_SPEED);
IoSubscribeUpdateVariable(CA_DI_REPLEN);
IoSubscribeUpdateVariable(RETURN_VALVE_OPENING);
IoSubscribeUpdateVariable(SAMPLE_OUT);
IoSubscribeUpdateVariable(CA_ISOLATION);
IoSubscribeUpdateVariable(AN_ISOLATION);
IoSubscribeUpdateVariable(DEGAS_ENABLE);
IoSubscribeUpdateVariable(CA_FLOW);
}
///
/// 订阅IO变量
///
///
protected void IoSubscribeUpdateVariable(string variable)
{
_variableInitializeDic[variable] = false;
IOModuleManager.Instance.SubscribeModuleVariable(Module, variable, UpdateVariableValue);
}
///
/// 更新变量数值
///
///
///
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 == CA_WATER_LEVEL)
{
string caLevelCurve = SC.GetStringValue($"Reservoir.{Module}.CALevelCurve");
ReservoirData.CaLevel = LevelCurveManager.Instance.CalculateLevelByWaterLevel(ReservoirData.CaWaterLevel, caLevelCurve);
}
if (variable == RETURN_VALVE_OPENING)
{
if (Convert.ToDouble(value) != 0)
{
ReservoirData.ReturnValveEnable = true;
}
else
{
ReservoirData.ReturnValveEnable = false;
}
}
}
if (_variableInitializeDic.ContainsKey(variable) && !_variableInitializeDic[variable])
{
_variableInitializeDic[variable] = true;
}
}
///
/// 写变量
///
///
///
///
protected bool WriteVariableValue(string variable, object value)
{
string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{variable}");
return IOModuleManager.Instance.WriteIoValue(ioName, value);
}
///
/// 定时器
///
///
protected virtual bool OnTimer()
{
CalculateCALevel();
AdjustRetrunFlowValve();
WaterLevelMonitor();
DireplenMonitor();
AutoOpenDegasValve();
HedMonitor();
AutoMonitor();
return true;
}
#region timer
///
/// 处于Auto时要监控的逻辑
///
protected virtual void AutoMonitor()
{
if (_persistentValue.OperatingMode == AUTO)
{
_caPumpSpeedHelper.Monitor(_resRecipe);
TemperatureCheck();
}
}
///
/// 监控TC
///
private void HedMonitor()
{
double _cellFlowStartLowlimit = SC.GetValue("PlatingCell.CellFlowStartLowLimit");
if (_reservoirData.CaFlow < _cellFlowStartLowlimit)
{
CAFlowLowOperation();
}
}
///
/// safety和ca flow满足条件,自动打开degas valve
///
public void AutoOpenDegasValve()
{
if(Recipe!= null && ReservoirData.CaFlow >= Recipe.CAFlowSetPoint) //缺了safety的条件,待补充
{
int degasValveOpenIdlePeriod = SC.GetValue($"Reservoir.DegasValveOpenIdlePeriod");
if (!_isFirstCaFlowOK)
{
_isFirstCaFlowOK = true;
_caFlowOKTime = DateTime.Now;
}
else
{
if(DateTime.Now.Subtract(_caFlowOKTime).TotalMinutes >= degasValveOpenIdlePeriod && !ReservoirData.DegasEnable)
{
DegasValveOn();
_caFlowOKTime = DateTime.Now;//开启后重置一下检测到ca flow ok的时间
}
}
}
else
{
_isFirstCaFlowOK = false;
}
}
///
/// 自动调节retrun valve 开闭
///
public void AdjustRetrunFlowValve()
{
ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module);
if (reservoirEntity != null)
{
//retrun valve打开
if (ReservoirData.ReturnValveEnable && _platingCellDevice!=null && (!reservoirEntity.IsInit && !reservoirEntity.IsError))
{
double overflow = _platingCellDevice.PlatingCellDeviceData.OverFlowLevel;
int _overflowLevelDelta = SC.GetValue($"Reservoir.{Module}.OverflowLevelDelta");
int _overflowLevelCheckTime = SC.GetValue($"Reservoir.{Module}.OverflowLevelCheckTime");
int _retrunOpenHoldStep = SC.GetValue($"Reservoir.{Module}.RetrunOpenHoldStep");
int _retrunOpenRampStep = SC.GetValue($"Reservoir.{Module}.RetrunOpenRampStep");
bool _isFull = "Full".Equals(_platingCellDevice.PlatingCellDeviceData.OverFlowStatus);
int adjustNumber = _isFull ? _retrunOpenHoldStep : _retrunOpenRampStep;
if (_isFull) //full的情况
{
if (overflow > _lastOverFlow)//液位升高的情况
{
if (overflow - _lastOverFlow > _overflowLevelDelta && DateTime.Now.Subtract(_adjustReturnvalveStartTime).TotalMilliseconds > _overflowLevelCheckTime)
{
double percent = ReservoirData.ReturnValveOpening - adjustNumber;
percent = percent >= 0 ? percent : 0;
ReturnValvePercent(percent);
_lastOverFlow = overflow;
_adjustReturnvalveStartTime = DateTime.Now;
}
}
else
{
if (_lastOverFlow - overflow > _overflowLevelDelta && DateTime.Now.Subtract(_adjustReturnvalveStartTime).TotalMilliseconds > _overflowLevelCheckTime)
{
double percent = ReservoirData.ReturnValveOpening + adjustNumber;
percent = percent <= 100 ? percent : 100;
ReturnValvePercent(percent);
_lastOverFlow = overflow;
_adjustReturnvalveStartTime = DateTime.Now;
}
}
}
else //empty或者high的情况
{
if ("High".Equals(_platingCellDevice.PlatingCellDeviceData.OverFlowStatus))
{
if (DateTime.Now.Subtract(_adjustReturnvalveStartTime).TotalMilliseconds > _overflowLevelCheckTime)
{
double percent = ReservoirData.ReturnValveOpening - adjustNumber;
percent = percent >= 0 ? percent : 0;
ReturnValvePercent(percent);
_lastOverFlow = overflow;
_adjustReturnvalveStartTime = DateTime.Now;
}
}
else
{
if (DateTime.Now.Subtract(_adjustReturnvalveStartTime).TotalMilliseconds > _overflowLevelCheckTime)
{
double percent = ReservoirData.ReturnValveOpening + adjustNumber;
percent = percent <= 100 ? percent : 100;
ReturnValvePercent(percent);
_lastOverFlow = overflow;
_adjustReturnvalveStartTime = DateTime.Now;
}
}
}
}
}
}
///
/// 计算CA
///
private void CalculateCALevel()
{
if (ReservoirData != null)
{
if (_CALevelSamples.Count >= _levelSampleCount)
{
_CALevelSamples.Dequeue();
_CALevelSamples.Enqueue(ReservoirData.CaLevel);
}
else
{
_CALevelSamples.Enqueue(ReservoirData.CaLevel);
}
_avgCALevel = _CALevelSamples.Count > 0 ? _CALevelSamples.Average() : 0;
}
}
///
/// WaterLevel监控
///
protected virtual void WaterLevelMonitor()
{
_caWaterLevelLowerTrigger.CLK = IsCALowLevel;
if (_caWaterLevelLowerTrigger.Q)
{
ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module);
string reason = $"Current CAWaterlevel:{ReservoirData.CaWaterLevel} is lower than CALowLevel Config:{SC.GetValue($"Reservoir.{Module}.CALowLevel")}";
LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, reason);
CALowLevelOperation();
if (reservoirEntity.IsAuto && !AlarmListManager.Instance.IsContainDataError(Module, "CAWaterLevel"))
{
AlarmListManager.Instance.AddDataError(Module,
$"CAWaterLevel", $"Current CAWaterlevel:{ReservoirData.CaWaterLevel} is lower than CALowLevel Config:{SC.GetValue($"Reservoir.{Module}.CALowLevel")}");
}
if (!reservoirEntity.IsError) reservoirEntity.PostMsg(ReservoirMsg.Error);
}
_caWaterLevelHighTrigger.CLK = IsCAHighLevel;
if (_caWaterLevelHighTrigger.Q)
{
HighLevelOperation();
}
}
///
/// CA Low Level触发对应操作
///
private void CAFlowLowOperation()
{
ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module);
//禁用TC
if (!string.IsNullOrEmpty(reservoirItem.TCID))
{
TemperatureController temperatureController = DEVICE.GetDevice(reservoirItem.TCID);
if (temperatureController != null && temperatureController.TemperatureData.ControlOperationModel == (int)TemperatureEnumData.ENABLE)
{
temperatureController.DisableOperation("", null);
LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "CA flow is lower than cellflowStartLowLimit,TC Disabled");
}
}
}
///
/// CA Low Level触发对应操作
///
private void CALowLevelOperation()
{
ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module);
if (_reservoirData.CaPumpEnable)
{
CAPumpOff("", null);
}
if (_reservoirData.CaIsolation)// 不确定是否是关闭cell flow
{
CAIsolationOff();
}
//禁用TC
if (!string.IsNullOrEmpty(reservoirItem.TCID))
{
TemperatureController temperatureController = DEVICE.GetDevice(reservoirItem.TCID);
if (temperatureController != null && temperatureController.TemperatureData.ControlOperationModel == (int)TemperatureEnumData.ENABLE)
{
temperatureController.DisableOperation("", null);
}
}
ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module);
if (!reservoirEntity.IsError) reservoirEntity.PostMsg(ReservoirMsg.Error);
}
///
/// High Level Common Operation
///
private void HighLevelOperation()
{
ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module);
SystemFacilities systemFacilities = DEVICE.GetDevice("System.Facilities");
if (systemFacilities != null)
{
if (systemFacilities.DIFillEnable) systemFacilities.DiFillDisableOperation("DIFillDisableOpeartion", null);
if (systemFacilities.DIReplenEnable) systemFacilities.DiReplenDisableOperation("DiReplenDisableOperation", null);
if (_reservoirData.CaDiReplen)
{
_currentDireplenOperation = DiReplenOperation.None;
CADiReplenOff("", null);
}
}
if (!reservoirEntity.IsError) reservoirEntity.PostMsg(ReservoirMsg.Error);
if (reservoirEntity.IsAuto && !AlarmListManager.Instance.IsContainDataError(Module, "CAWaterLevel"))
{
AlarmListManager.Instance.AddDataError(Module,
$"CAWaterLevel", $"Current CAWaterlevel:{ReservoirData.CaWaterLevel} is large than CAHighLevel Config:{SC.GetValue($"Reservoir.{Module}.CAHighLevel")}");
}
}
///
/// Direplen监控
///
private void DireplenMonitor()
{
var facilities = DEVICE.GetDevice("System.Facilities");
//补水监控
if (_direplenHelper != null)
{
_direplenHelper.MonitorPeriodTime(ref _isDIReplenMaxTimeOut);
if (!_isDIReplenMaxTimeOut && !_isDIReplenPerfillTimeOut && facilities.DIFillEnable)
{
AutoDireplenMonitor();
}
}
}
///
/// 自动补水
///
protected virtual void AutoDireplenMonitor()
{
if (_currentDireplenOperation == DiReplenOperation.ManualCADiReplen)
{
bool result = _direplenHelper.MonitorManualDiReplenComplete(_manualReplenSecond, CADiReplenOff, ref _isDIReplenMaxTimeOut);
if (result)
{
_currentDireplenOperation = DiReplenOperation.None;
}
}
if (_currentDireplenOperation == DiReplenOperation.AutoCADiReplen)
{
AutoDiReplenMonitor(CADiReplenOff, _reservoirData.CaLevel, _resRecipe.ReservoirCALevel, _resRecipe.DIReplenEnable,
_resRecipe.DIReplenTimeRate, _resRecipe.DIReplenCurrentRate);
}
}
///
/// 自动注水监控
///
///
///
///
private void AutoDiReplenMonitor(Func direplenOff, double level, double recipeLevel, bool replenEnable,
int direplenTimeRate, int direplenCurrentRate)
{
//判断是否注水超时(包括单次和累计)
bool result = _direplenHelper.AutoDiReplenMonitorTimeOut(direplenOff, ref _isDIReplenMaxTimeOut, ref _isDIReplenPerfillTimeOut);
if (result)
{
_currentDireplenOperation = DiReplenOperation.None;
}
else
{
//按液位补水
result = _direplenHelper.AutoDiReplenMonitorComplete(level, recipeLevel, replenEnable, direplenTimeRate, direplenCurrentRate, direplenOff);
if (result)
{
_currentDireplenOperation = DiReplenOperation.None;
}
}
}
#endregion
#region Mode switch
///
/// DisabledAction
///
///
///
///
private bool DisabledOperation(string cmd, object[] args)
{
string currentOperation = "Disabled";
string preOperation = _persistentValue.OperatingMode;
_persistentValue.OperatingMode = currentOperation;
LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"Operating mode is switched from {preOperation} to {currentOperation}");
ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
return true;
}
///
/// ManualAction
///
///
///
///
private bool ManualOperation(string cmd, object[] args)
{
string currentOperation = "Manual";
string preOperation = _persistentValue.OperatingMode;
_persistentValue.OperatingMode = currentOperation;
LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"Operating mode is switched from {preOperation} to {currentOperation}");
ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
return true;
}
///
/// AutoAction
///
///
///
///
private bool AutoOperation(string cmd, object[] args)
{
string currentOperation = "Auto";
string preOperation = _persistentValue.OperatingMode;
_persistentValue.OperatingMode = currentOperation;
LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"Operating mode is switched from {preOperation} to {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;
}
#endregion
///
/// 加载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;
}
///
/// 监控
///
public void Monitor()
{
}
#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 BeckhoffIOManager.Instance.WriteIoValue(ioName, caPumpSpeed);
}
///
/// 阴极Pump On
///
///
///
///
public 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 BeckhoffIOManager.Instance.WriteIoValue(enableIOName, true);
}
else
{
return false;
}
}
///
/// 阴极Pump Off
///
///
///
///
public bool CAPumpOff(string cmd, object[] args)
{
string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_PUMP_ENABLE}");
return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
}
#endregion
#region Return Valve
///
/// Return Valve
///
///
///
///
private bool ReturnValvePercentOperation(string cmd, object[] args)
{
if (double.TryParse(args[0].ToString(), out double percent))
{
_returnValvePercent = percent;
return ReturnValvePercent(_returnValvePercent);
}
else
{
LOG.WriteLog(eEvent.ERR_METAL, Module, $"{args[0]} is invalid percent");
return false;
}
}
///
/// 设置比例
///
///
///
public bool ReturnValvePercent(double percent)
{
string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{RETURN_VALVE_OPENING}");
return BeckhoffIOManager.Instance.WriteIoValue(ioName, percent);
}
///
/// Return Valve On
///
///
///
///
public bool ReturnValveOn(string cmd, object[] args)
{
double percent = SC.GetValue("Reservoir.ReturnOpenDefaultPercentage");
return ReturnValvePercent(percent);
}
///
/// Return Valve Off
///
///
///
///
public bool ReturnValveOff()
{
return ReturnValvePercent(0);
}
#endregion
///
/// CAIsolationOn
///
///
public bool CAIsolationOn()
{
return WriteVariableValue(CA_ISOLATION, true);
}
///
/// CAIsolationOff
///
///
public bool CAIsolationOff()
{
return WriteVariableValue(CA_ISOLATION, false);
}
///
/// DegasValveOn
///
///
public bool DegasValveOn()
{
return WriteVariableValue(DEGAS_ENABLE, true);
}
///
/// DegasValveOff
///
///
public bool DegasValveOff()
{
return WriteVariableValue(DEGAS_ENABLE, false);
}
///
/// HedValveOn
///
///
public bool HedValveOn()
{
return WriteVariableValue(HED_FLOW_ENABLE, true);
}
///
/// HedValveOff
///
///
public bool HedValveOff()
{
return WriteVariableValue(HED_FLOW_ENABLE, false);
}
///
/// PhValveOn
///
///
public bool PhValveOn()
{
return WriteVariableValue(PH_FLOW_VALVE, true);
}
///
/// PhValveOff
///
///
public bool PhValveOff()
{
return WriteVariableValue(PH_FLOW_VALVE, false);
}
///
/// SampleOutValveOn
///
///
public bool SampleOutValveOn()
{
return WriteVariableValue(SAMPLE_OUT, true);
}
///
/// SampleOutValveOff
///
///
public bool SampleOutValveOff()
{
return WriteVariableValue(SAMPLE_OUT, false);
}
#region CA DiReplen
///
/// 阴极DI Replen On
///
///
///
///
private bool CADiReplenOnOperation(string cmd, object[] args)
{
return CADiReplenOn();
}
///
/// 阴极DI Replen On
///
///
///
private bool CADiReplenOn()
{
bool preCondition = CheckPreDiReplenCondition();
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 BeckhoffIOManager.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 = BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
if (result)
{
_persistentValue.IsDiReplenOn = false;
if (_currentDireplenOperation == DiReplenOperation.ManualCADiReplen || _currentDireplenOperation == DiReplenOperation.AutoCADiReplen)
{
_currentDireplenOperation = DiReplenOperation.None;
_persistentValue.LastTotalReplen = _persistentValue.TotalReplen;
ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
}
}
return result;
}
///
/// 检验DiReplen前置条件
///
///
public bool CheckPreDiReplenCondition()
{
if (!CheckFacilitiesDiReplenStatus())
{
LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "Facilities DiReplen is Off, can't start auto diReplen");
return false;
}
SafetyDevice safetyDevice = DEVICE.GetDevice("Safety");
if (safetyDevice != null && safetyDevice.SafetyData.Reservoir1CALevelHigh)
{
LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Safety high is Activate, can't start auto diReplen");
return false;
}
if (CheckOtherReservoirDiReplenStatus())
{
LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"there is exist reservoir in diReplen, can't start auto diReplen");
return false;
}
return true;
}
///
/// 检验总Di有没有开
///
///
private bool CheckFacilitiesDiReplenStatus()
{
SystemFacilities systemFacilities = DEVICE.GetDevice("System.Facilities");
if (systemFacilities != null)
{
return systemFacilities.DIReplenEnable;
}
return false;
}
///
/// 检验是否其他Reservoir Direplen已经
///
///
protected bool CheckOtherReservoirDiReplenStatus()
{
List reservoirs = ReservoirItemManager.Instance.InstalledModules;
foreach (string item in reservoirs)
{
if (item != Module)
{
ReservoirDevice tmpDevice = DEVICE.GetDevice(item);
if (tmpDevice.ReservoirData.CaDiReplen)
{
return true;
}
ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(item);
if (reservoirItem.SubType == ReservoirType.DegasMembrance.ToString())
{
if (tmpDevice.ReservoirData.AnDiReplen)
{
return true;
}
}
}
}
return false;
}
#endregion
#region DiReplen Operation
///
/// 重置时长
///
///
///
///
private bool ResetTotalTime(string cmd, object[] objs)
{
_isDIReplenMaxTimeOut = false;
_isDIReplenPerfillTimeOut = false;
_persistentValue.TotalReplen = 0;
_persistentValue.LastTotalReplen = 0;
ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
return true;
}
///
/// 手动阴极注水
///
///
///
///
private bool ManualCADiReplen(string cmd, object[] args)
{
return ManualDiReplen(CADiReplenOnOperation, DiReplenOperation.ManualCADiReplen, args[0].ToString());
}
///
/// 手动注水
///
///
///
///
protected bool ManualDiReplen(Func direplenOn, DiReplenOperation direplenOperation, string timeLength)
{
if (_currentDireplenOperation != DiReplenOperation.None)
{
LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"current operation is {_currentDireplenOperation},cannot execute {direplenOperation}");
return false;
}
ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module);
if (!reservoirEntity.IsInitialized)
{
LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} is not initialized. Can't start DiReplen");
return false;
}
if (_isDIReplenMaxTimeOut)
{
double diValveMaxOnTime = SC.GetValue($"Reservoir.{Module}.DIValveMaxOnTime");
LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"Direplen time over conifg's DIValveMaxOnTime:{diValveMaxOnTime} min");
return false;
}
if (_isDIReplenPerfillTimeOut)
{
double diValveMaxOnTimePerFill = SC.GetValue($"Reservoir.{Module}.DIValveMaxOnTimePerFill");
LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"Direplen time over conifg's DIValveMaxOnTimePerFill:{diValveMaxOnTimePerFill} min");
return false;
}
bool result = direplenOn("", null);
if (result)
{
_currentDireplenOperation = direplenOperation;
_persistentValue.DiReplenTime = DateTime.Now;
ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
int.TryParse(timeLength, out _manualReplenSecond);
}
return result;
}
///
/// 阴极自动流水
///
///
public bool AutoCADiReplen()
{
if (IsCALowLevel)
{
LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"CALowLevel is activate,Can't AutoANDireplen");
return false;
}
return AutoDireplen(CADiReplenOn, DiReplenOperation.AutoCADiReplen);
}
///
/// 自动注水公共方法
///
///
protected bool AutoDireplen(Func direplenOn, DiReplenOperation reservoirOperation)
{
if (_currentDireplenOperation != DiReplenOperation.None)
{
LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"current operation is {_currentDireplenOperation},cannot execute {reservoirOperation}");
return false;
}
if (_resRecipe == null)
{
LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"recipe is null");
return false;
}
bool result = direplenOn();
if (result)
{
_currentDireplenOperation = reservoirOperation;
_persistentValue.DiReplenTime = DateTime.Now;
}
return result;
}
#endregion
///
/// 检验阴极是否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;
}
///
/// 检验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;
}
}
public void Reset()
{
}
public void Terminate()
{
}
///
/// 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 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 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 TemperatureWarningHigh parameter:{_resRecipe.TemperatureWarningHigh}");
_isTCControlWARN = true;
AlarmListManager.Instance.AddWarn(Module,
$"Temperature", $"{Module} temperature:{tempValue} is large than recipe temperatureWarningHigh{_resRecipe.TemperatureWarningHigh}");
}
}
else if (tempValue < _resRecipe.TemperatureWarningLow)
{
if (!_isTCControlWARN)
{
LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{temperatureController.Name} temperature;{tempValue} is less than recipe TemperatureWarningLow parameter:{_resRecipe.TemperatureWarningLow}");
_isTCControlWARN = true;
AlarmListManager.Instance.AddWarn(Module,
$"Temperature", $"{Module} temperature:{tempValue} is lower than recipe temperatureWarningLow{_resRecipe.TemperatureWarningLow}");
}
}
else
{
_isTCControlWARN = false;
}
}
}
}