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.RecipeCenter; using MECF.Framework.Common.ToolLayout; using MECF.Framework.Common.TwinCat; using CyberX8_Core; using CyberX8_RT.Devices.Facilities; using CyberX8_RT.Devices.Metal; using CyberX8_RT.Modules.Reservoir; using System; using System.Collections.Generic; using System.Reflection; using CyberX8_RT.Modules; using System.Collections.ObjectModel; using CyberX8_RT.Devices.Dose; using CyberX8_RT.Modules.Metal; using CyberX8_RT.Devices.Temperature; using CyberX8_RT.Devices.PowerSupplier; using System.Linq; using CyberX8_RT.Devices.Safety; using MECF.Framework.Common.ProcessCell; using MECF.Framework.Common.Alarm; using MECF.Framework.Common.IOCore; using Aitex.Core.RT.Routine; namespace CyberX8_RT.Devices.Reservoir { public class StandardHotReservoirDevice : BaseDevice, IDevice { private enum ReservoirOperation { None, ManualDiReplen, AutoDiReplen } private enum DosingOperation { None, ManualDosing, AutoDosing, } #region 常量 private const string AUTO = "Auto"; private const string MANUAL = "Manual"; private const string DISABLE = "Disable"; private const string STRATUS = "Stratus"; private const string PERSISTENT_VALUE = "PersistentValue"; private const string FLOW = "Flow"; private const string HED_FLOW = "HedFlow"; private const string PH_FLOW_VALVE = "PHFlowValve"; private const string PH_VALUE = "PHValue"; private const string WATER_LEVEL = "WaterLevel"; private const string LOW_LEVEL = "LowLevel"; private const string HIGH_LEVEL = "HighLevel"; private const string SAFETY_HIGH_LEVEL = "SafetyHighLevel"; private const string DI_REPLEN = "DiReplen"; private const string RESERVOIRDEVICEDATA = "ReservoirDeviceData"; private const string REPLEN_LEVEL = "ReplenLevel"; private const string RESPOWERON = "ResPowerOn"; private const string HEDPOWERON = "HedPowerOn"; private const double PUMP_SPEED_CONVERT = 0.0672; private const int ENABLE = 5; #endregion #region 内部变量 /// /// Level取样平均值 /// private double _avgLevel; /// /// AN Level取样队列 /// private Queue _LevelSamples; /// /// Level计算平均值取样数 /// private int levelSampleCount; /// /// Prewet 持久性数值对象 /// private ReservoirsPersistentValue _persistentValue; /// /// 定时器Job /// PeriodicJob _periodicJob = null; /// /// 变量是否初始化字典 /// private Dictionary _variableInitializeDic = new Dictionary(); /// /// Reservoir数据 /// private StandardHotReservoirData _reservoirData = new StandardHotReservoirData(); /// /// 当前操作 /// private ReservoirOperation _currentOperation = ReservoirOperation.None; /// /// 手动注水时间(秒) /// private int _manualReplenSecond = 0; /// /// 注水是否出错 /// private bool _isDiReplenInFault = false; /// /// Recipe /// private ResRecipe _resRecipe; /// /// 平均PH值 /// private double _avaragePH; /// /// PH Routine /// private StandardHotPHRoutine _phRoutine; /// /// PH Routine状态 /// private RState _phState = RState.Init; /// /// PH结束时间 /// private DateTime _phRoutineEndTime = DateTime.Now; /// /// Direplen 逻辑对象 /// private ReservoirDiReplenHelper _direplenHelper; /// /// Replen数量 /// private int _replenNum = 0; /// /// Dose Replen数据 /// private ReplenData[] _replenDatas; /// /// ReplenType /// private string _replenType; /// /// Replen Recipe集合 /// private RdsRecipe[] _rdsRecipe; /// /// DosingSystemHelper对象列表 /// private List _dosingSystemHelperLst; /// /// ReplenLevel 列表 /// private List _replenLevelLst; /// /// 当前操作 /// private List _currentDosingOperation; /// /// 配置的metal device集合 /// private ObservableCollection _metalDevices = new ObservableCollection(); /// /// Replen Persistent Value /// private Dictionary _replenPersistentValue = new Dictionary(); /// /// DosingCommonHelper /// private DosingCommonHelper _dosingCommonHelper; /// /// WarningFlag /// private List _isCAFlowRateWARN; /// /// CMM Flow High Error /// private double _reservoirCMMFlowHighError; /// /// CMM Flow Low Error /// private double _reservoirCMMFlowLowError; /// /// ErrorMessage /// private bool _isTCControlWARN = false; private bool _isCMMPowerCurrentWARN = false; private bool _isCMMPowerFlowWARN = false; private bool _isExportCMMUsage = false; private bool _isAutoDIReplenError = false; private bool _isSafetyHigh = false; private bool _isSystemAutoMode = false; /// /// 用于控制打印错误log /// private HashSet errorLogSet = new HashSet(); #endregion #region 属性 /// /// 数据 /// public StandardHotReservoirData ReservoirData { get { return _reservoirData; } } /// /// Replen数据 /// public ReplenData[] ReplenDatas { get { return _replenDatas; } } /// /// DosingSystemHelper对象列表 /// public List DosingSystemHelpers { get { return _dosingSystemHelperLst; } } /// /// Replen数量 /// public int ReplenNum { get { return _replenNum; } } /// /// 操作模式 /// public string OperationMode { get { return _persistentValue.OperatingMode; } } /// /// 工程模式 /// public string EngineerMode { get { return _persistentValue.RecipeOperatingMode; } } /// /// 是否自动 /// public bool IsAuto { get { return _persistentValue.OperatingMode == AUTO; } } /// /// 是否需要补水 /// public bool NeedAutoDireplen { get { return GetNeedAutoDireplen(); } } /// /// 正在补水 /// public bool IsDireplenOn { get { return _reservoirData.DiReplen; } } /// /// 平均PH数值 /// public double AveragePH { get { return _avaragePH; } set { _avaragePH = value; } } /// /// 当前Recipe /// public ResRecipe Recipe { get { return _resRecipe; } } /// /// 当前Rds Recipe /// public RdsRecipe[] RdsRecipe { get { return _rdsRecipe; } } #endregion /// /// 初始化成功清除对应的错误log /// /// public void ClearErrorLogSet(string module) { // 使用构造函数复制 HashSet HashSet newHashSet = new HashSet(errorLogSet); foreach (var item in newHashSet) { if (item.Contains(module)) { errorLogSet.Remove(item); } } } /// /// 构造函数 /// /// /// public StandardHotReservoirDevice(string moduleName) : base(moduleName, moduleName, moduleName, moduleName) { levelSampleCount = SC.GetValue("Reservoir.LevelAvgSamples"); levelSampleCount = levelSampleCount == 0 ? 20 : levelSampleCount; _LevelSamples = new Queue(levelSampleCount); _periodicJob = new PeriodicJob(100, OnTimer, $"{Module}.OnTimer", true); ResPowerOn();//保持继电器常开 } /// /// 定时器 /// /// private bool OnTimer() { //计算AN/CA level的平均值 if (ReservoirData != null) { //AN if (_LevelSamples.Count >= levelSampleCount) { _LevelSamples.Dequeue(); _LevelSamples.Enqueue(ReservoirData.Level); } else { _LevelSamples.Enqueue(ReservoirData.Level); } _avgLevel = _LevelSamples.Count > 0 ? _LevelSamples.Average() : 0; } foreach (StandardHotMetalDevice device in _metalDevices) { device.OnTimer(_periodicJob.Interval); } ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); //报错停DosingSystem //if (_replenType != "" && _replenNum != 0 && reservoirEntity != null && reservoirEntity.IsError) //{ // for (int i = 0; i < _replenNum; i++) // { // string replenName = "Replen" + (i + 1).ToString(); // if (_replenPersistentValue[replenName].IsDosingRunning) // { // _dosingSystemHelperLst[i].StopDosing(); // _currentDosingOperation[i] = DosingOperation.None; // } // } //} /// /// WaterLevelMonitor /// WaterLevelMonitor(); //触发Safetyhigh将reservoir切成error SafetyDevice safetyDevice = DEVICE.GetDevice("Safety"); if (safetyDevice != null && safetyDevice.SafetyData.ReservoirHighLevel && !_isSafetyHigh) { _isSafetyHigh = true; LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Safety high is Activate"); reservoirEntity.PostMsg(ReservoirMsg.Error); } else { _isSafetyHigh = false; } //DIReplen if (_direplenHelper != null) { _direplenHelper.MonitorPeriodTime(); if (_currentOperation == ReservoirOperation.ManualDiReplen && _reservoirData.DiReplen) { bool result = _direplenHelper.MonitorManualDiReplenComplete(_manualReplenSecond, DIReplenOff); if (result) { _currentOperation = ReservoirOperation.None; } } else if (_currentOperation == ReservoirOperation.AutoDiReplen && _reservoirData.DiReplen) { bool result = _direplenHelper.AutoDiReplenMonitorTimeOut(DIReplenOff); if (result) { _currentOperation = ReservoirOperation.None; //触发注水异常信号 _isDiReplenInFault = true; } else { //按液位补水 result = _direplenHelper.AutoDiReplenMonitorComplete(_reservoirData.Level, _resRecipe.ReservoirCALevel, _resRecipe.DIReplenEnable, _resRecipe.DIReplenTimeRate, _resRecipe.DIReplenCurrentRate, DIReplenOff); if (result) { _currentOperation = ReservoirOperation.None; } } } } if (reservoirEntity == null || !reservoirEntity.IsInitialized) { return true; } if (_persistentValue.OperatingMode == AUTO) { CAFlowRateCheck(); TemperatureCheck(); CMMPowerCheck(); //CMM用电量记录 if (_isExportCMMUsage && _persistentValue.CMMStartTime != DateTime.MinValue) { ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module); if (!string.IsNullOrEmpty(reservoirItem.CMMSupplyID) && _resRecipe != null && _resRecipe.CMMEnable) { CellPowerSupplier powerSupplier = DEVICE.GetDevice(reservoirItem.CMMSupplyID); double cmmUsage = powerSupplier.PowerSupplierData.Current * DateTime.Now.Subtract(_persistentValue.CMMStartTime).TotalHours; ReservoirUsageManager.Instance.UpdateReservoirCMMUsage(Module, Math.Round(cmmUsage, 3)); _persistentValue.CMMStartTime = DateTime.Now; ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); _isExportCMMUsage = false; } } } if (_phState == RState.Running) { _phState = _phRoutine.Monitor(); if (_phState == RState.End) { _phRoutineEndTime = DateTime.Now; } } else if (_phState != RState.Init) { double phUpdatePeriod = SC.GetValue("Reservoir.PHUpdatePeriod"); if (DateTime.Now.Subtract(_phRoutineEndTime).TotalMilliseconds >= phUpdatePeriod * 1000) { StartDetectPHValve(); } } //if (_replenType != "" && _replenNum != 0) //{ // //DosingSystem 状态监控 // _dosingCommonHelper.DoseStatusMonitor(); // //Dosing监控 // if (_dosingCommonHelper.IsDosingSystemInitialized) // { // if (_replenPersistentValue["Replen1"].OperatingMode == "Manual") // { // //ManualDosing // _dosingCommonHelper.ManualDoseSystemMonitor(); // } // if (_replenPersistentValue["Replen1"].OperatingMode == "Auto") // { // //AutoDosing // _dosingCommonHelper.AutoDoseSystemMonitor(); // } // else // { // _dosingCommonHelper.CheckDoseOperation(); // } // } //} return true; } /// /// Low Level 触发操作 /// private void LowLevelOperation() { if (!_reservoirData.LowLevel) //true是正常的 { ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module); foreach (var metalDevice in _metalDevices) { if (metalDevice.MetalDeviceData.Circulation) { metalDevice.SwitchToBypass($"{metalDevice.Name}.SwitchToBypass", null); } if (metalDevice.MetalDeviceData.CellFlow > 0) { metalDevice.ClosePump("", null); } //水位过低时将起对应的metal也要切成error MetalEntity metalEntity = Singleton.Instance.GetModule(metalDevice.DeviceID); if (metalEntity != null && !metalEntity.IsError) { metalEntity.PostMsg(MetalMsg.Error); } } //禁用TC if (!String.IsNullOrEmpty(reservoirItem.TCID)) { TemperatureController temperatureController = DEVICE.GetDevice(reservoirItem.TCID); if (temperatureController != null && temperatureController.TemperatureData.ControlOperationModel == 5) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Lowlevel was activate"); temperatureController.DisableOperation("", null); } } } } /// /// High Level 触发操作 /// private void HighLevelOperation() { 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.DiReplen) { _currentOperation = ReservoirOperation.None; DIReplenOff("", null); } } } /// /// WaterLevelMonitor /// private void WaterLevelMonitor() { ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); _isSystemAutoMode = reservoirEntity.IsAuto; //触发水位过高或者过低将reservoir切成error if (!_reservoirData.LowLevel) { if (!errorLogSet.Contains($"{Module}.WaterLevel")) { errorLogSet.Add($"{Module}.WaterLevel"); LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"WaterLevel low is Activate"); } LowLevelOperation(); if (!reservoirEntity.IsError) { reservoirEntity.PostMsg(ReservoirMsg.Error); } if (_isSystemAutoMode && !AlarmListManager.Instance.IsContainDataError(Module, "WaterLevel")) { AlarmListManager.Instance.AddDataError(Module, $"WaterLevel", $"WaterLevel low is Activate"); } } else if (ReservoirData.WaterLevel > SC.GetValue($"Reservoir.{Module}.HighLevel")) { if (!errorLogSet.Contains($"{Module}.WaterLevel")) { errorLogSet.Add($"{Module}.WaterLevel"); LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"WaterLevel:{ReservoirData.WaterLevel} is larger than HighLevel Config:{SC.GetValue($"Reservoir.{Module}.HighLevel")}"); } HighLevelOperation(); if (!reservoirEntity.IsError) { reservoirEntity.PostMsg(ReservoirMsg.Error); } if (_isSystemAutoMode && !AlarmListManager.Instance.IsContainDataError(Module, "WaterLevel")) { AlarmListManager.Instance.AddDataError(Module, $"WaterLevel", $"WaterLevel:{ReservoirData.WaterLevel} is larger than HighLevel Config:{SC.GetValue($"Reservoir.{Module}.HighLevel")}"); } } //水位触发reservoir里面的high/low将对应的reservoir切成error if (_resRecipe == null) return; if (ReservoirData.Level < _resRecipe.CALevelErrorLow) { if (!errorLogSet.Contains($"{Module}.Level")) { errorLogSet.Add($"{Module}.Level"); LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current level:{ReservoirData.Level} is lower than recipe's CA Errorlow paramater:{_resRecipe.CALevelErrorLow}"); } if (!reservoirEntity.IsError) { reservoirEntity.PostMsg(ReservoirMsg.Error); } if (_isSystemAutoMode && !AlarmListManager.Instance.IsContainDataError(Module, "Level")) { AlarmListManager.Instance.AddDataError(Module, $"Level", $"Current level:{ReservoirData.Level} is lower than recipe's CA Errorlow paramater:{_resRecipe.CALevelErrorLow}"); } } else if (ReservoirData.Level > _resRecipe.CALevelErrorHigh) { if (!errorLogSet.Contains($"{Module}.Level")) { errorLogSet.Add($"{Module}.Level"); LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current level:{ReservoirData.Level} is larger than recipe's CA ErrorHigh paramater:{_resRecipe.CALevelErrorHigh}"); } if (!reservoirEntity.IsError) { reservoirEntity.PostMsg(ReservoirMsg.Error); } if (_isSystemAutoMode && !AlarmListManager.Instance.IsContainDataError(Module, "Level")) { AlarmListManager.Instance.AddDataError(Module, $"Level", $"Current level:{ReservoirData.Level} is larger than recipe CA ErrorHigh paramater:{_resRecipe.CALevelErrorHigh}"); } } } /// /// 获取是否需要补水 /// /// private bool GetNeedAutoDireplen() { if (IsAuto && _resRecipe != null) { if (_resRecipe.DIReplenEnable && _resRecipe.DIReplenCurrentRate == 0 && _resRecipe.DIReplenTimeRate == 0) { double levelHysteresis = SC.GetValue("Reservoir.LevelHysteresis"); return ReservoirData.Level < _resRecipe.ReservoirCALevel - levelHysteresis; } return false; } else { return false; } } /// /// 初始化 /// /// public bool Initialize() { InitializeRoutine(); InitializeParameter(); SubscribeData(); InitializeOperation(); SubscribeValueAction(); return true; } /// /// 初始化routine /// private void InitializeRoutine() { _phRoutine = new StandardHotPHRoutine(Module); } /// /// 初始化参数 /// 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"); } else { if (!string.IsNullOrEmpty(_persistentValue.Recipe)) { _resRecipe = RecipeFileManager.Instance.LoadGenericityRecipe(_persistentValue.Recipe); } _direplenHelper = new ReservoirDiReplenHelper(Module, _persistentValue); } ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module.ToString()); if (reservoirItem != null) { foreach (var item in reservoirItem.MetalCells) { if (item.ModuleName != Module) { StandardHotMetalDevice metalDevice = DEVICE.GetDevice(item.ModuleName); if (metalDevice != null) { _metalDevices.Add(metalDevice); } } } } _isCAFlowRateWARN = new List(new bool[_metalDevices.Count]); //DosingSystem数据初始化 _replenType = reservoirItem.ChemReplenType; _replenNum = reservoirItem.ChemReplenPumps; if (_replenType != "" && _replenNum != 0) { _replenDatas = new ReplenData[_replenNum]; _rdsRecipe = new RdsRecipe[_replenNum]; _replenLevelLst = new List(new bool[_replenNum]); _currentDosingOperation = new List(); for (int i = 0; i < _replenNum; i++) { string replenName = "Replen" + (i + 1).ToString(); _replenDatas[i] = new ReplenData(); _replenDatas[i].ReplenName = replenName; _replenDatas[i].RecipeName = ""; _replenDatas[i].BottleLevel = DosingSystemHelper.BottleLevelState.Empty.ToString(); _replenDatas[i].IsAutoDosingError = false; if (_dosingSystemHelperLst == null) _dosingSystemHelperLst = new List(); _dosingSystemHelperLst.Add(new DosingSystemHelper(Module, _replenDatas[i].ReplenName)); _currentDosingOperation.Add(DosingOperation.None); _replenPersistentValue[replenName] = ReplenPersistentManager.Instance.GetReplenPersistentValue(Module, replenName); } _dosingCommonHelper = new DosingCommonHelper(Module, _replenNum); } } /// /// 订阅数据 /// private void SubscribeData() { DATA.Subscribe($"{Module}.DIValveMaxOnTime", () => SC.GetValue($"Reservoir.{Module}.DIValveMaxOnTime") * 60, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsManualReplen", () => { return _currentOperation == ReservoirOperation.ManualDiReplen; }, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ReservoirData", () => _reservoirData, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ReservoirAverageLevel", () => _avgLevel, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.{PERSISTENT_VALUE}", () => _persistentValue, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ReplenPersistentValue", () => _replenPersistentValue, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PHValue", () => _avaragePH, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.CurrentRecipe", () => _resRecipe, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ReplenType", () => _replenType, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ReplenNum", () => _replenNum, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ReplenDatas", () => _replenDatas, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.DosingSystemState", () => _dosingCommonHelper != null ? _dosingCommonHelper.DosingSystemState : null, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.RecipeName", () => (_resRecipe != null ? _resRecipe.Ppid : ""), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.HedFlow", () => _reservoirData.HedFlow, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PHEnable", () => _reservoirData.PHFlowValve, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsDIReplenInFault", () => _isDiReplenInFault, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ReservoirPowerOn", () => _reservoirData.ResPowerOn, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.HedPowerOn", () => _reservoirData.HedPowerOn, 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}.DiReplenOn", DIReplenOnOperation); OP.Subscribe($"{Module}.DiReplenOff", DIReplenOff); OP.Subscribe($"{Module}.ManualDiReplen", ManualDiReplen); OP.Subscribe($"{Module}.ResetTotalTime", ResetTotalTime); OP.Subscribe($"{Module}.LoadRecipe", LoadRecipeOperation); OP.Subscribe($"{Module}.LoadDosingRecipe", LoadDosingRecipeOperation); OP.Subscribe($"{Module}.ReplenPumpOn", ReplenPumpOnOperation); OP.Subscribe($"{Module}.ReplenPumpOff", ReplenPumpOffOperation); OP.Subscribe($"{Module}.SetPumpFactor", SetPumpFactor); OP.Subscribe($"{Module}.ManualDosing", ManualDosing); OP.Subscribe($"{Module}.StopManualDosing", StopManualDosing); OP.Subscribe($"{Module}.ResetBottleVolume", ResetBottleVolume); OP.Subscribe($"{Module}.DosingInitialize", DosingInitialize); OP.Subscribe($"{Module}.HedPowerOn", HedPowerOnAction); OP.Subscribe($"{Module}.HedPowerOff", HedPowerOffAction); OP.Subscribe($"{Module}.ResPowerOn", ResPowerOnAction); OP.Subscribe($"{Module}.ResPowerOff", ResPowerOffAction); } private bool HedPowerOnAction(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{HEDPOWERON}"); if (!string.IsNullOrEmpty(ioName)) { bool result = IOModuleManager.Instance.WriteIoValue(ioName, true); if (!result) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Open HED Power Relay failed"); return false; } return true; } else { return true; } } private bool HedPowerOffAction(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{HEDPOWERON}"); if (!string.IsNullOrEmpty(ioName)) { bool result = IOModuleManager.Instance.WriteIoValue(ioName, false); if (!result) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Close HED Power Relay failed"); return false; } return true; } else { return true; } } private bool ResPowerOnAction(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{RESPOWERON}"); if (!string.IsNullOrEmpty(ioName)) { bool result = IOModuleManager.Instance.WriteIoValue(ioName, true); if (!result) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Open Res Power Relay failed"); return false; } return true; } else { return true; } } private bool ResPowerOffAction(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{RESPOWERON}"); if (!string.IsNullOrEmpty(ioName)) { bool result = IOModuleManager.Instance.WriteIoValue(ioName, false); if (!result) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Close Res Power Relay failed"); return false; } return true; } else { return true; } } #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 (args.Length >= 1 && (bool)args[0]) { foreach (var replenData in ReplenDatas) { if (_replenPersistentValue != null && _replenPersistentValue[replenData.ReplenName] != null) { _replenPersistentValue[replenData.ReplenName].OperatingMode = currentOperation; ReplenPersistentManager.Instance.UpdatePersistentValue(Module, replenData.ReplenName); } } for (int i = 0; i < _replenNum; i++) { string replenName = "Replen" + (i + 1).ToString(); if (_replenPersistentValue[replenName].IsDosingRunning) { _dosingSystemHelperLst[i].StopDosing(); _currentDosingOperation[i] = DosingOperation.None; } } DosingEnterInit(); } else { ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); if (_persistentValue != null && reservoirEntity != null && _persistentValue.OperatingMode != currentOperation) { string preOperation = _persistentValue.OperatingMode; if (reservoirEntity.IsBusy) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} is Busy, can't switch to Disabled mode"); return false; } if (_persistentValue.OperatingMode == "Auto" && 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 switch to Disabled mode"); return false; } foreach (var metalDevice in _metalDevices) { metalDevice.DisabledOperation("", null); MetalEntity metalEntity = Singleton.Instance.GetModule(metalDevice.Module); metalEntity.AbortRecipe(null); metalDevice.EnterDisabledOperation(); } EnterDisabledOperation(); reservoirEntity.EnterInit(); _persistentValue.OperatingMode = currentOperation; LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"Operating mode is switched from {preOperation} to {currentOperation}"); } ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); _currentOperation = ReservoirOperation.None; } return true; } /// /// ManualAction /// /// /// /// private bool ManualOperation(string cmd, object[] args) { string currentOperation = "Manual"; if (args.Length >= 1 && (bool)args[0]) { foreach (var replenData in ReplenDatas) { if (_replenPersistentValue != null && _replenPersistentValue[replenData.ReplenName] != null) { _replenPersistentValue[replenData.ReplenName].OperatingMode = currentOperation; ReplenPersistentManager.Instance.UpdatePersistentValue(Module, replenData.ReplenName); } } DosingEnterInit(); } else { ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); if (_persistentValue != null && reservoirEntity != null && _persistentValue.OperatingMode != currentOperation) { string preOperation = _persistentValue.OperatingMode; if (reservoirEntity.IsBusy) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} is Busy, can't switch to Manual mode"); return false; } if (_persistentValue.OperatingMode == "Auto" && 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 switch to Manual mode"); return false; } foreach (var metalDevice in _metalDevices) { metalDevice.ManualOperation("", null); } reservoirEntity.EnterInit(); if (_reservoirData.DiReplen) DIReplenOff("", null); _persistentValue.OperatingMode = currentOperation; LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"Operating mode is switched from {preOperation} to {currentOperation}"); } ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); _currentOperation = ReservoirOperation.None; } return true; } /// /// AutoAction /// /// /// /// private bool AutoOperation(string cmd, object[] args) { if (!_reservoirData.LowLevel) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Lowlevel was activated, can't switch to Auto mode"); return false; } string currentOperation = "Auto"; if (args.Length >= 1 && (bool)args[0]) { foreach (var replenData in ReplenDatas) { if (_replenPersistentValue != null && _replenPersistentValue[replenData.ReplenName] != null) { _replenPersistentValue[replenData.ReplenName].OperatingMode = currentOperation; ReplenPersistentManager.Instance.UpdatePersistentValue(Module, replenData.ReplenName); } } DosingEnterInit(); } else { ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); if (_persistentValue != null && reservoirEntity != null && _persistentValue.OperatingMode != currentOperation) { string preOperation = _persistentValue.OperatingMode; if (reservoirEntity.IsBusy) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} is Busy, can't switch to Auto mode"); return false; } reservoirEntity.EnterInit(); _persistentValue.OperatingMode = currentOperation; if (_reservoirData.DiReplen) DIReplenOff("", null); _isDiReplenInFault = false; 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; } /// /// 加载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]; } try { _resRecipe = RecipeFileManager.Instance.LoadGenericityRecipe(_persistentValue.Recipe); ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module.ToString()); LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"Load {recipeRoute} Recipe {_resRecipe.Ppid} Success"); } catch { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Load {recipeRoute} Recipe {_persistentValue.Recipe} failed"); } return true; } /// /// DiReplen On /// /// /// /// public bool DIReplenOnOperation(string cmd, object[] args) { return DIReplenOn(true); } /// /// 自动注水 /// /// public bool DIReplenOn(bool showError) { if (ReservoirData.WaterLevel > SC.GetValue($"Reservoir.{Module}.HighLevel")) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "Highlevel is activate"); return false; } if (!_reservoirData.LowLevel) //信号是相反的 { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"WaterLevel low is Activate"); return false; } bool preCondition = CheckPreDiReplenCondition(showError); if (!preCondition) { return false; } string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{DI_REPLEN}"); bool result = IOModuleManager.Instance.WriteIoValue(ioName, true); if (result) { _persistentValue.IsDiReplenOn = true; } return result; } /// /// 打开继电器 /// /// public void ResPowerOn() { bool result = false; string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{RESPOWERON}"); if (!string.IsNullOrEmpty(ioName)) { result = IOModuleManager.Instance.WriteIoValue(ioName, true); if (!result) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Open {Module} Power Relay failed"); } } ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{HEDPOWERON}"); if (!string.IsNullOrEmpty(ioName)) { result = IOModuleManager.Instance.WriteIoValue(ioName, true); if (!result) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Open {Module} Hed Power Relay failed"); } } } /// /// 检验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; } /// /// DiReplen Off /// /// /// /// private bool DIReplenOff(string cmd, object[] args) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{DI_REPLEN}"); bool result = IOModuleManager.Instance.WriteIoValue(ioName, false); if (result) { _persistentValue.IsDiReplenOn = false; if (_currentOperation == ReservoirOperation.ManualDiReplen || _currentOperation == ReservoirOperation.AutoDiReplen) { _currentOperation = ReservoirOperation.None; _persistentValue.LastTotalReplen = _persistentValue.TotalReplen; ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); } } return result; } /// /// 手动注水 /// /// /// /// private bool ManualDiReplen(string cmd, object[] args) { if (_currentOperation != ReservoirOperation.None) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"current operation is {_currentOperation},cannot execute ManualDireplen operation"); return false; } bool result = DIReplenOnOperation("", null); if (result) { _currentOperation = ReservoirOperation.ManualDiReplen; _persistentValue.DiReplenTime = DateTime.Now; ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); int.TryParse(args[0].ToString(), out _manualReplenSecond); } return result; } /// /// 自动注水 /// /// public bool AutoDireplen() { if (!_reservoirData.LowLevel && !_isAutoDIReplenError) { _isAutoDIReplenError = true; LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"LowLevel is activate,Can't AutoDireplen"); return false; } else { _isAutoDIReplenError = false; } if (_currentOperation != ReservoirOperation.None) { return false; } if (_resRecipe == null) { return false; } bool result = DIReplenOn(false); if (result) { _currentOperation = ReservoirOperation.AutoDiReplen; _persistentValue.DiReplenTime = DateTime.Now; } return result; } /// /// 启动PH检测 /// public bool StartDetectPHValve() { if (_persistentValue.OperatingMode == MANUAL) { return false; } _phState = _phRoutine.Start(); LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, "Start Detect PH"); return true; } /// /// 打开PH Valve /// /// public bool PHValveOn() { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{PH_FLOW_VALVE}"); return IOModuleManager.Instance.WriteIoValue(ioName, true); } /// /// 关闭PH Valve /// /// public bool PHValveOff() { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{PH_FLOW_VALVE}"); return IOModuleManager.Instance.WriteIoValue(ioName, false); } /// /// CAFlowRateCheck /// private void CAFlowRateCheck() { if (_resRecipe == null) return; for (int i = 0; i < _metalDevices.Count; i++) { StandardHotMetalDevice hotMetalDevice = _metalDevices[i]; if (hotMetalDevice != null && !hotMetalDevice.IsDisable && hotMetalDevice.IsAuto) { if (hotMetalDevice.MetalDeviceData == null || !hotMetalDevice.MetalDeviceData.Circulation) continue; if (!hotMetalDevice.FlowValveStable) continue; MetalEntity metalEntity = Singleton.Instance.GetModule(hotMetalDevice.Name); double cellFlow = hotMetalDevice.MetalDeviceData.CellFlow; if (cellFlow < _resRecipe.CAFlowRateErrorLow) { if (!metalEntity.IsError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"cell {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, $"cell {hotMetalDevice.Name} cellflow:{cellFlow} is less than recipe's CAFlowRateWarningLow parameter:{_resRecipe.CAFlowRateWarningLow}"); _isCAFlowRateWARN[i] = true; } } else { _isCAFlowRateWARN[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; } } /// /// CMMPowerCheck /// private void CMMPowerCheck() { ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); ReservoirItem _reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module.ToString()); if (!string.IsNullOrEmpty(_reservoirItem.CMMSupplyID)) { CellPowerSupplier _powerSupplier = DEVICE.GetDevice(_reservoirItem.CMMSupplyID); if (_powerSupplier == null || _powerSupplier.PowerSupplierData == null || _resRecipe == null || !_resRecipe.CMMEnable || !_powerSupplier.PowerSupplierData.Enabled || _powerSupplier.PowerSupplierData.Current == 0) return; //CMM Current Check double current = _powerSupplier.PowerSupplierData.Current; if (current > _resRecipe.CMMCurrentSetPoint * (1 + (double)_resRecipe.CMMCurrentFaultPercent / 100)) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{_powerSupplier.Name} current:{current} is over error upper limit:{_resRecipe.CMMCurrentSetPoint * (1 + (double)_resRecipe.CMMCurrentFaultPercent / 100)} based on recipe's CMMCurrentFaultPercent parameter:{_resRecipe.CMMCurrentFaultPercent} %"); reservoirEntity.PostMsg(ReservoirMsg.Error); if (_powerSupplier.PowerSupplierData.Enabled) { _powerSupplier.DisableOperation("", null); _persistentValue.CMMStartTime = DateTime.MinValue; ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); } } else if (current < _resRecipe.CMMCurrentSetPoint * (1 - (double)_resRecipe.CMMCurrentFaultPercent / 100)) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{_powerSupplier.Name} current:{current} is less than error lower limit:{_resRecipe.CMMCurrentSetPoint * (1 - (double)_resRecipe.CMMCurrentFaultPercent / 100)} based on recipe's CMMCurrentFaultPercent parameter:{_resRecipe.CMMCurrentFaultPercent}%"); reservoirEntity.PostMsg(ReservoirMsg.Error); if (_powerSupplier.PowerSupplierData.Enabled) { _powerSupplier.DisableOperation("", null); _persistentValue.CMMStartTime = DateTime.MinValue; ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module); } } else if (current > _resRecipe.CMMCurrentSetPoint * (1 + (double)_resRecipe.CMMCurrentWarningPercent / 100)) { if (!_isCMMPowerCurrentWARN) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{_powerSupplier.Name} current:{current} is over warning upper limit:{_resRecipe.CMMCurrentSetPoint * (1 + (double)_resRecipe.CMMCurrentWarningPercent / 100)} based on recipe's CMMCurrentWarningPercent parameter:{_resRecipe.CMMCurrentWarningPercent}%"); _isCMMPowerCurrentWARN = true; } } else if (current < _resRecipe.CMMCurrentSetPoint * (1 - (double)_resRecipe.CMMCurrentWarningPercent / 100)) { if (!_isCMMPowerCurrentWARN) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{_powerSupplier.Name} current:{current} is less than warning lower limit{_resRecipe.CMMCurrentSetPoint * (1 - (double)_resRecipe.CMMCurrentWarningPercent / 100)} based on recipe's CMMCurrentWarningPercent parameter:{_resRecipe.CMMCurrentWarningPercent}%"); _isCMMPowerCurrentWARN = true; } } else { _isCMMPowerCurrentWARN = false; } //CMM Voltage Check double voltage = _powerSupplier.PowerSupplierData.Voltage; if (voltage < _resRecipe.CMMMinVoltage) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{_powerSupplier.Name} voltage:{voltage} is less than recipe's CMMMinVoltage parameter:{_resRecipe.CMMMinVoltage}"); reservoirEntity.PostMsg(ReservoirMsg.Error); if (_powerSupplier.PowerSupplierData.Enabled) _powerSupplier.DisableOperation("", null); } //CMM Flow Check double flow = ReservoirData.Flow; double cmmFlowHighFault = SC.GetValue($"Reservoir.{Module}.CMMFlowHighFault"); double cmmFlowHighWarning = SC.GetValue($"Reservoir.{Module}.CMMFlowHighWarning"); double cmmFlowLowFault = SC.GetValue($"Reservoir.{Module}.CMMFlowLowFault"); double cmmFlowLowWarning = SC.GetValue($"Reservoir.{Module}.CMMFlowLowWarning"); if (flow < cmmFlowLowFault) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} CMM flow:{flow} is less than config item CMMFlowLowFault:{cmmFlowLowFault}"); if (_powerSupplier.PowerSupplierData.Enabled) _powerSupplier.DisableOperation("", null); reservoirEntity.PostMsg(ReservoirMsg.Error); } else if (flow < cmmFlowLowWarning) { if (!_isCMMPowerFlowWARN) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} CMM flow:{flow} is less than config item CMMFlowLowWarning:{cmmFlowLowWarning}"); _isCMMPowerFlowWARN = true; } } else if (flow > cmmFlowHighFault) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} CMM flow:{flow} is over config item CMMFlowHighFault:{cmmFlowLowFault}"); if (_powerSupplier.PowerSupplierData.Enabled) _powerSupplier.DisableOperation("", null); reservoirEntity.PostMsg(ReservoirMsg.Error); } else if (flow > cmmFlowHighWarning) { if (!_isCMMPowerFlowWARN) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} CMM flow:{flow} is over config item CMMFlowHighWarning:{cmmFlowLowWarning}"); _isCMMPowerFlowWARN = true; } } else { _isCMMPowerFlowWARN = false; } } } #region DosingSystem /// /// 加载Replen Recipe /// /// /// /// private bool LoadDosingRecipeOperation(string cmd, object[] args) { string replenName = args[1].ToString(); int replenID = int.Parse(args[1].ToString().Substring(6, 1)); string replenRecipe = args[0].ToString(); _rdsRecipe[replenID - 1] = RecipeFileManager.Instance.LoadGenericityRecipe(replenRecipe); _replenDatas[replenID - 1].RecipeName = args[2].ToString(); LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"Load Replen Recipe {_rdsRecipe[replenID - 1].Ppid} Success"); return true; } #region Replen Pump /// /// Replen Pump On 操作(根据PumpFactor和InitialDosingSpeed调速) /// /// /// /// public bool ReplenPumpOnOperation(string cmd, object[] args) { string replenName = args[0].ToString(); int replenID = int.Parse(args[0].ToString().Substring(6, 1)); //加载InitialDosingSpeed double InitialDosingSpeed = 0; if (SC.ContainsItem($"Reservoir.{Module}.InitialDosingSpeed")) { InitialDosingSpeed = SC.GetValue($"Reservoir.{Module}.InitialDosingSpeed"); if (InitialDosingSpeed == 0) { _replenDatas[replenID - 1].ReplenPumpEnable = false; LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "InitialDosingSpeed is zero. Can't open replen pump"); return false; } } else { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "Configuration item of InitialDosingSpeed doesn't exist!"); return false; } //加载ReplenPumpFactor double PumpFactor = 0; PumpFactor = _replenPersistentValue[replenName].ReplenPumpFactor; if (PumpFactor == 0) { _replenDatas[replenID - 1].ReplenPumpEnable = false; LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "PumpFactor is zero. Can't open replen pump"); return false; } //计算PumpSpeed(mL/min) double replenPumpSpeed = InitialDosingSpeed * PumpFactor; SCConfigItem item = SC.GetConfigItem($"Reservoir.{Module}.InitialDosingSpeed"); double speedMax = double.Parse(item.Max); if (replenPumpSpeed > speedMax) replenPumpSpeed = speedMax; bool result = ReplenPump(replenPumpSpeed / PUMP_SPEED_CONVERT, replenID); if (!result) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Opening replen{replenID} pump is failed"); _replenDatas[replenID - 1].ReplenPumpSpeed = 0; _replenDatas[replenID - 1].ReplenPumpEnable = false; return false; } _replenDatas[replenID - 1].ReplenPumpSpeed = replenPumpSpeed; _replenDatas[replenID - 1].ReplenPumpEnable = true; LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"Replen{replenID} pump is opened"); return true; } /// /// Replen Pump Off操作 /// /// /// /// public bool ReplenPumpOffOperation(string cmd, object[] args) { string replenName = args[0].ToString(); int replenID = int.Parse(args[0].ToString().Substring(6, 1)); bool result = ReplenPump(0, replenID); if (!result) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Closing replen{replenID} pump is failed"); return false; } _replenDatas[replenID - 1].ReplenPumpSpeed = 0; _replenDatas[replenID - 1].ReplenPumpEnable = false; LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"Replen{replenID} pump is closed"); return true; } /// /// Replen Pump WriteIOValue /// /// /// private bool ReplenPump(double speed, int replenNum) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.Replen{replenNum}PumpSpeed"); return IOModuleManager.Instance.WriteIoValue(ioName, speed); } #endregion /// /// 设置PumpFactor /// /// /// /// public bool SetPumpFactor(string cmd, object[] args) { int replenID = int.Parse(args[0].ToString().Substring(6, 1)); double targetPumpFactor = (double)args[1]; _dosingSystemHelperLst[replenID - 1].SetPumpfactor(targetPumpFactor); return true; } /// /// 手动Dosing /// /// /// /// private bool ManualDosing(string cmd, object[] args) { ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); if (reservoirEntity == null || !_dosingCommonHelper.IsDosingSystemInitialized) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "Dosing System is not initialized!"); return true; } string replenName = args[0].ToString(); int replenID = int.Parse(args[0].ToString().Substring(6, 1)); double manualDosingVolume = (double)args[1]; if (manualDosingVolume == 0) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "Dosing Volume is zero, can't do manual dosing"); return false; } if (!CheckandUpdateBottleLevel(replenName, manualDosingVolume)) { return false; } if (_replenPersistentValue[replenName].IsDosingRunning) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "Dosing is runnning, can't do manual dosing"); return false; } LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, "ManualDosing starts now"); _currentDosingOperation[replenID - 1] = DosingOperation.ManualDosing; bool result = _dosingSystemHelperLst[replenID - 1].StartDosing(manualDosingVolume, false); return result; } /// /// 停止手动Dosing /// /// /// /// private bool StopManualDosing(string cmd, object[] args) { string replenName = args[0].ToString(); int replenID = int.Parse(args[0].ToString().Substring(6, 1)); if (!_replenPersistentValue[replenName].IsDosingRunning) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "ManualDosing is not running. Can't stop!"); } _currentDosingOperation[replenID - 1] = DosingOperation.None; bool result = _dosingSystemHelperLst[replenID - 1].StopDosing(); if (result) { LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, "ManualDosing has stopped now"); } return result; } /// /// 检查并更新BottleLevel状态 /// /// /// public bool CheckandUpdateBottleLevel(string replenName, double targetVolume = -1, bool isError = true) { int replenId = int.Parse(replenName.Substring(6, 1)); double remainVolume = _replenPersistentValue[replenName].RemainDosingVolume; bool result = true; if (ReservoirData.ReplenLevel[replenId - 1]) { ReplenDatas[replenId - 1].BottleLevel = DosingSystemHelper.BottleLevelState.Full.ToString(); if (targetVolume > remainVolume) { ReplenDatas[replenId - 1].BottleLevel = DosingSystemHelper.BottleLevelState.Warning.ToString(); if (isError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current Bottle is in Warning Level!"); } result = false; } } else { ReplenDatas[replenId - 1].BottleLevel = DosingSystemHelper.BottleLevelState.Empty.ToString(); if (isError) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current Bottle is in Empty Level!"); } result = false; } return result; } /// /// Reset BottleVolume /// /// /// /// private bool ResetBottleVolume(string cmd, object[] args) { string replenName = args[0].ToString(); int replenID = int.Parse(args[0].ToString().Substring(6, 1)); if (SC.ContainsItem($"Reservoir.{Module}.BottleReserveVolume{replenID}")) { _replenPersistentValue[replenName].RemainDosingVolume = SC.GetValue($"Reservoir.{Module}.BottleReserveVolume{replenID}"); } ReplenPersistentManager.Instance.UpdatePersistentValue(Module, replenName); LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"Bottle Reserve Volume of Replen{replenID} has been reset now"); return true; } /// /// DosingSystem初始化 /// /// /// /// private bool DosingInitialize(string cmd, object[] args) { ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); if (reservoirEntity == null || !reservoirEntity.IsInitialized) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} is not initialized"); return false; } return _dosingCommonHelper.DosingInitialize(); ; } /// /// Enetr Init State /// /// /// /// private bool DosingEnterInit() { return _dosingCommonHelper.DosingEnterInit(); } #endregion /// /// Enter Disabled Operation /// private void EnterDisabledOperation() { ReservoirItem _reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module.ToString()); //关CMMPower if (!string.IsNullOrEmpty(_reservoirItem.CMMSupplyID)) { CellPowerSupplier powerSupplier = DEVICE.GetDevice(_reservoirItem.CMMSupplyID); if (powerSupplier != null && powerSupplier.PowerSupplierData.Enabled) powerSupplier.DisableOperation("", null); } //关TC if (!string.IsNullOrEmpty(_reservoirItem.TCID)) { TemperatureController temperatureController = DEVICE.GetDevice(_reservoirItem.TCID); if (temperatureController != null) temperatureController.DisableOperation("", null); } _phRoutine.Abort(); if (_reservoirData.PHFlowValve) { PHValveOff(); } if (_reservoirData.DiReplen) { DIReplenOff("", null); } } /// /// Set Export CMMUsage /// public void SetExportCMMUsage() { _isExportCMMUsage = true; } /// /// ReservoirUsage监控 /// public void ReservoirUsageMonitor() { ReservoirUsage reservoirUsage = ReservoirUsageManager.Instance.GetReservoirUsage(Module); ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(Module); if (reservoirUsage == null || reservoirEntity == null) return; //reservoirTotalAmpHours Check double reservoirTotalAmpHoursWarningLimit = 0; if (SC.ContainsItem($"Reservoir.{Module}.ReservoirTotalAmpHoursWarningLimit")) { reservoirTotalAmpHoursWarningLimit = (double)SC.GetValue($"Reservoir.{Module}.ReservoirTotalAmpHoursWarningLimit"); } double reservoirTotalAmpHoursFaultLimit = 0; if (SC.ContainsItem($"Reservoir.{Module}.ReservoirTotalAmpHoursFaultLimit")) { reservoirTotalAmpHoursFaultLimit = (double)SC.GetValue($"Reservoir.{Module}.ReservoirTotalAmpHoursFaultLimit"); } if (reservoirUsage.TotalUsage > reservoirTotalAmpHoursFaultLimit && reservoirTotalAmpHoursFaultLimit != 0) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Total Usage(AHr):{reservoirUsage.TotalUsage} is over config item ReservoirTotalAmpHoursFaultLimit:{reservoirTotalAmpHoursFaultLimit}"); reservoirEntity.PostMsg(ReservoirMsg.Error); AlarmListManager.Instance.AddDataError(Module, $"TotalUsage", $"{Module} usage:{reservoirUsage.TotalUsage} is over ReservoirTotalAmpHoursFaultLimit:{reservoirTotalAmpHoursFaultLimit}"); } else if (reservoirUsage.TotalUsage > reservoirTotalAmpHoursWarningLimit && reservoirTotalAmpHoursWarningLimit != 0) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Total Usage(AHr):{reservoirUsage.TotalUsage} is over config item ReservoirTotalAmpHoursWarningLimit:{reservoirTotalAmpHoursWarningLimit}"); AlarmListManager.Instance.AddWarn(Module, $"TotalUsage", $"{Module} usage:{reservoirUsage.TotalUsage} is over ReservoirTotalAmpHoursWarningLimit:{reservoirTotalAmpHoursWarningLimit}"); } //MembraneTotalAmpHoursCheck double membraneTotalAmpHoursWarningLimit = 0; if (SC.ContainsItem($"Reservoir.{Module}.MembraneTotalAmpHoursWarningLimit")) { membraneTotalAmpHoursWarningLimit = (double)SC.GetValue($"Reservoir.{Module}.MembraneTotalAmpHoursWarningLimit"); } double membraneTotalAmpHoursFaultLimit = 0; if (SC.ContainsItem($"Reservoir.{Module}.MembraneTotalAmpHoursFaultLimit")) { membraneTotalAmpHoursFaultLimit = (double)SC.GetValue($"Reservoir.{Module}.MembraneTotalAmpHoursFaultLimit"); } if (reservoirUsage.MembranceUsage > membraneTotalAmpHoursFaultLimit && membraneTotalAmpHoursFaultLimit != 0) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Membrane Usage(AHr):{reservoirUsage.MembranceUsage} is over config item MembraneTotalAmpHoursFaultLimit:{membraneTotalAmpHoursFaultLimit}"); reservoirEntity.PostMsg(ReservoirMsg.Error); AlarmListManager.Instance.AddDataError(Module, $"MembraneUsage", $"{Module} usage:{reservoirUsage.MembranceUsage} is over MembraneTotalAmpHoursFaultLimit:{membraneTotalAmpHoursFaultLimit}"); } else if (reservoirUsage.MembranceUsage > membraneTotalAmpHoursWarningLimit && membraneTotalAmpHoursWarningLimit != 0) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Membrane Usage(AHr):{reservoirUsage.MembranceUsage} is over config item MembraneTotalAmpHoursWarningLimit:{membraneTotalAmpHoursWarningLimit}"); AlarmListManager.Instance.AddWarn(Module, $"MembraneUsage", $"{Module} usage:{reservoirUsage.MembranceUsage} is over MembraneTotalAmpHoursWarningLimit:{membraneTotalAmpHoursWarningLimit}"); } //ANBathTotalAmpHoursCheck //double anBathTotalAmpHoursWarningLimit = 0; //if (SC.ContainsItem($"Reservoir.{Module}.ANBathTotalAmpHoursWarningLimit")) //{ // anBathTotalAmpHoursWarningLimit = (double)SC.GetValue($"Reservoir.{Module}.ANBathTotalAmpHoursWarningLimit"); //} //double anBathTotalAmpHoursFaultLimit = 0; //if (SC.ContainsItem($"Reservoir.{Module}.ANBathTotalAmpHoursFaultLimit")) //{ // anBathTotalAmpHoursFaultLimit = (double)SC.GetValue($"Reservoir.{Module}.ANBathTotalAmpHoursFaultLimit"); //} //if (reservoirUsage.AnodeUsage > anBathTotalAmpHoursFaultLimit && anBathTotalAmpHoursFaultLimit != 0) //{ // LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Anolyte Bath Usage(AHr):{reservoirUsage.AnodeUsage} is over config item ANBathTotalAmpHoursFaultLimit:{anBathTotalAmpHoursFaultLimit}"); // reservoirEntity.PostMsg(ReservoirMsg.Error); // AlarmListManager.Instance.AddDataError(Module, // $"AnodeUsage", $"{Module} usage:{reservoirUsage.AnodeUsage} is over ANBathTotalAmpHoursFaultLimit:{anBathTotalAmpHoursFaultLimit}"); //} //else if (reservoirUsage.AnodeUsage > anBathTotalAmpHoursWarningLimit && anBathTotalAmpHoursWarningLimit != 0) //{ // LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Anolyte Bath Usage(AHr):{reservoirUsage.AnodeUsage} is over config item ANBathTotalAmpHoursWarningLimit:{anBathTotalAmpHoursWarningLimit}"); // AlarmListManager.Instance.AddWarn(Module, // $"AnodeUsage", $"{Module} usage:{reservoirUsage.AnodeUsage} is over ANBathTotalAmpHoursWarningLimit:{anBathTotalAmpHoursWarningLimit}"); //} //BathTotalAmpHoursCheck double bathTotalAmpHoursWarningLimit = 0; if (SC.ContainsItem($"Reservoir.{Module}.BathTotalAmpHoursWarningLimit")) { bathTotalAmpHoursWarningLimit = (double)SC.GetValue($"Reservoir.{Module}.BathTotalAmpHoursWarningLimit"); } double bathTotalAmpHoursFaultLimit = 0; if (SC.ContainsItem($"Reservoir.{Module}.BathTotalAmpHoursFaultLimit")) { bathTotalAmpHoursFaultLimit = (double)SC.GetValue($"Reservoir.{Module}.BathTotalAmpHoursFaultLimit"); } if (reservoirUsage.BathUsage > bathTotalAmpHoursFaultLimit && bathTotalAmpHoursFaultLimit != 0) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Bath Usage(AHr):{reservoirUsage.BathUsage} is over config item BathTotalAmpHoursFaultLimit:{bathTotalAmpHoursFaultLimit}"); reservoirEntity.PostMsg(ReservoirMsg.Error); AlarmListManager.Instance.AddDataError(Module, $"BathUsage", $"{Module} usage:{reservoirUsage.BathUsage} is over BathTotalAmpHoursFaultLimit:{bathTotalAmpHoursFaultLimit}"); } else if (reservoirUsage.BathUsage > bathTotalAmpHoursWarningLimit && bathTotalAmpHoursWarningLimit != 0) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Bath Usage(AHr):{reservoirUsage.BathUsage} is over config item BathTotalAmpHoursWarningLimit:{bathTotalAmpHoursWarningLimit}"); AlarmListManager.Instance.AddWarn(Module, $"BathUsage", $"{Module} usage:{reservoirUsage.BathUsage} is over BathTotalAmpHoursWarningLimit:{bathTotalAmpHoursWarningLimit}"); } //BathTotalDaysCheck int bathTotalDaysWarningLimit = 0; if (SC.ContainsItem($"Reservoir.{Module}.BathTotalDaysWarningLimit")) { bathTotalDaysWarningLimit = SC.GetValue($"Reservoir.{Module}.BathTotalDaysWarningLimit"); } int bathTotalDaysFaultLimit = 0; if (SC.ContainsItem($"Reservoir.{Module}.BathTotalDaysFaultLimit")) { bathTotalDaysFaultLimit = SC.GetValue($"Reservoir.{Module}.BathTotalDaysFaultLimit"); } if (reservoirUsage.BathUsageDays > bathTotalDaysFaultLimit && bathTotalDaysFaultLimit != 0) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Bath Usage(Days):{reservoirUsage.BathUsageDays} is over config item BathTotalDaysFaultLimit:{bathTotalDaysFaultLimit}"); reservoirEntity.PostMsg(ReservoirMsg.Error); AlarmListManager.Instance.AddDataError(Module, $"BathUsageDays", $"{Module} usage:{reservoirUsage.BathUsageDays} is over BathTotalDaysFaultLimit:{bathTotalDaysFaultLimit}"); } else if (reservoirUsage.BathUsageDays > bathTotalDaysWarningLimit && bathTotalDaysWarningLimit != 0) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Bath Usage(Days):{reservoirUsage.BathUsage} is over config item BathTotalDaysWarningLimit:{bathTotalDaysWarningLimit}"); AlarmListManager.Instance.AddWarn(Module, $"BathUsageDays", $"{Module} usage:{reservoirUsage.BathUsageDays} is over BathTotalDaysWarningLimit:{bathTotalDaysWarningLimit}"); } //ReservoirTotalWafersCheck int reservoirTotalWafersWarningLimit = 0; if (SC.ContainsItem($"Reservoir.{Module}.ReservoirTotalWafersWarningLimit")) { reservoirTotalWafersWarningLimit = SC.GetValue($"Reservoir.{Module}.ReservoirTotalWafersWarningLimit"); } int reservoirTotalWafersFaultLimit = 0; if (SC.ContainsItem($"Reservoir.{Module}.ReservoirTotalWafersFaultLimit")) { reservoirTotalWafersFaultLimit = SC.GetValue($"Reservoir.{Module}.ReservoirTotalWafersFaultLimit"); } if (reservoirUsage.TotalWafers > reservoirTotalWafersFaultLimit && reservoirTotalWafersFaultLimit != 0) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Total Wafers:{reservoirUsage.TotalWafers} is over config item ReservoirTotalWafersFaultLimit:{reservoirTotalWafersFaultLimit}"); reservoirEntity.PostMsg(ReservoirMsg.Error); AlarmListManager.Instance.AddDataError(Module, $"TotalWafers", $"{Module} usage:{reservoirUsage.TotalWafers} is over ReservoirTotalWafersFaultLimit:{reservoirTotalWafersFaultLimit}"); } else if (reservoirUsage.TotalWafers > reservoirTotalWafersWarningLimit && reservoirTotalWafersWarningLimit != 0) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Total Wafers:{reservoirUsage.TotalWafers} is over config item ReservoirTotalWafersWarningLimit:{reservoirTotalWafersWarningLimit}"); AlarmListManager.Instance.AddWarn(Module, $"TotalWafers", $"{Module} usage:{reservoirUsage.TotalWafers} is over ReservoirTotalWafersWarningLimit:{reservoirTotalWafersWarningLimit}"); } //CMMAnodeTotalAmpHoursCheck double cmmAnodeTotalAmpHoursWarningLimit = 0; if (SC.ContainsItem($"Reservoir.{Module}.CMMAnodeTotalAmpHoursWarningLimit")) { cmmAnodeTotalAmpHoursWarningLimit = (double)SC.GetValue($"Reservoir.{Module}.CMMAnodeTotalAmpHoursWarningLimit"); } double cmmAnodeTotalAmpHoursFaultLimit = 0; if (SC.ContainsItem($"Reservoir.{Module}.CMMAnodeTotalAmpHoursFaultLimit")) { cmmAnodeTotalAmpHoursFaultLimit = (double)SC.GetValue($"Reservoir.{Module}.CMMAnodeTotalAmpHoursFaultLimit"); } if (reservoirUsage.CMMAnodeUsage > cmmAnodeTotalAmpHoursFaultLimit && cmmAnodeTotalAmpHoursFaultLimit != 0) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} CMM Anode Usage(AHr):{reservoirUsage.CMMAnodeUsage} is over config item CMMAnodeTotalAmpHoursFaultLimit:{cmmAnodeTotalAmpHoursFaultLimit}"); reservoirEntity.PostMsg(ReservoirMsg.Error); AlarmListManager.Instance.AddDataError(Module, $"CMMAnodeUsage", $"{Module} CMM Anode Usage(AHr):{reservoirUsage.CMMAnodeUsage} is over CMMAnodeTotalAmpHoursFaultLimit:{cmmAnodeTotalAmpHoursFaultLimit}"); } else if (reservoirUsage.CMMAnodeUsage > cmmAnodeTotalAmpHoursWarningLimit && cmmAnodeTotalAmpHoursWarningLimit != 0) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} CMM Anode Usage(AHr):{reservoirUsage.CMMAnodeUsage} is over config item CMMAnodeTotalAmpHoursWarningLimit:{cmmAnodeTotalAmpHoursWarningLimit}"); AlarmListManager.Instance.AddWarn(Module, $"CMMAnodeUsage", $"{Module} CMM Anode Usage(AHr):{reservoirUsage.CMMAnodeUsage} is over CMMAnodeTotalAmpHoursWarningLimit:{cmmAnodeTotalAmpHoursWarningLimit}"); } //CMMCathodeTotalAmpHoursCheck double cmmCathodeTotalAmpHoursWarningLimit = 0; if (SC.ContainsItem($"Reservoir.{Module}.CMMCathodeTotalAmpHoursWarningLimit")) { cmmCathodeTotalAmpHoursWarningLimit = (double)SC.GetValue($"Reservoir.{Module}.CMMCathodeTotalAmpHoursWarningLimit"); } double cmmCathodeTotalAmpHoursFaultLimit = 0; if (SC.ContainsItem($"Reservoir.{Module}.CMMCathodeTotalAmpHoursFaultLimit")) { cmmCathodeTotalAmpHoursFaultLimit = (double)SC.GetValue($"Reservoir.{Module}.CMMCathodeTotalAmpHoursFaultLimit"); } if (reservoirUsage.CMMMembranceUsage > cmmCathodeTotalAmpHoursFaultLimit && cmmCathodeTotalAmpHoursFaultLimit != 0) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} CMM Cathode Usage(AHr):{reservoirUsage.CMMMembranceUsage} is over config item CMMCathodeTotalAmpHoursFaultLimit:{cmmCathodeTotalAmpHoursFaultLimit}"); reservoirEntity.PostMsg(ReservoirMsg.Error); AlarmListManager.Instance.AddDataError(Module, $"CMMCathodeUsage", $"{Module} CMM Cathode Usage(AHr):{reservoirUsage.CMMMembranceUsage} is over CMMCathodeTotalAmpHoursFaultLimit:{cmmCathodeTotalAmpHoursFaultLimit}"); } else if (reservoirUsage.CMMMembranceUsage > cmmCathodeTotalAmpHoursWarningLimit && cmmCathodeTotalAmpHoursWarningLimit != 0) { LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} CMM Cathode Usage(AHr):{reservoirUsage.CMMMembranceUsage} is over config item CMMCathodeTotalAmpHoursWarningLimit:{cmmCathodeTotalAmpHoursWarningLimit}"); AlarmListManager.Instance.AddWarn(Module, $"CMMCathodeUsage", $"{Module} CMM Cathode Usage(AHr):{reservoirUsage.CMMMembranceUsage} is over CMMCathodeTotalAmpHoursWarningLimit:{cmmCathodeTotalAmpHoursWarningLimit}"); } } #endregion /// /// 订阅变量数值发生变化 /// private void SubscribeValueAction() { BeckhoffIoSubscribeUpdateVariable(FLOW); BeckhoffIoSubscribeUpdateVariable(HED_FLOW); BeckhoffIoSubscribeUpdateVariable(DI_REPLEN); BeckhoffIoSubscribeUpdateVariable(PH_FLOW_VALVE); BeckhoffIoSubscribeUpdateVariable(PH_VALUE); BeckhoffIoSubscribeUpdateVariable(WATER_LEVEL); BeckhoffIoSubscribeUpdateVariable(LOW_LEVEL); BeckhoffIoSubscribeUpdateVariable(HIGH_LEVEL); BeckhoffIoSubscribeUpdateVariable(SAFETY_HIGH_LEVEL); BeckhoffIoSubscribeUpdateVariable(RESPOWERON); BeckhoffIoSubscribeUpdateVariable(HEDPOWERON); for (int i = 0; i < _replenNum; i++) { BeckhoffIoSubscribeUpdateVariable($"Replen{i + 1}Level"); } } /// /// 订阅IO变量 /// /// private void BeckhoffIoSubscribeUpdateVariable(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 == WATER_LEVEL) { string levelCurve = SC.GetStringValue($"Reservoir.{Module}.LevelCurve"); ReservoirData.Level = LevelCurveManager.Instance.CalculateLevelByWaterLevel(ReservoirData.WaterLevel, levelCurve); } } if (variable.Contains("Replen") && variable.Substring(0, 6) == "Replen") { property = ReservoirData.GetType().GetProperty(REPLEN_LEVEL); _replenLevelLst[int.Parse(variable.Substring(6, 1)) - 1] = (bool)value; property.SetValue(_reservoirData, _replenLevelLst); } 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_RESERVOIR, Module, $"{item} is not initialized"); return false; } } return true; } public void Monitor() { } public void Reset() { } public void Terminate() { } } }