using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.Routine; using Aitex.Core.UI.Control; using Aitex.Core.Util; using MECF.Framework.Common.Beckhoff.IOAxis; using MECF.Framework.Common.Beckhoff.ModuleIO; using MECF.Framework.Common.CommonData; using MECF.Framework.Common.CommonData.Metal; using MECF.Framework.Common.Persistent.Reservoirs; using MECF.Framework.Common.TwinCat; using CyberX8_Core; using CyberX8_RT.Devices.Prewet; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using MECF.Framework.Common.ToolLayout; using CyberX8_RT.Devices.Reservoir; using MECF.Framework.Common.Layout; using Aitex.Core.RT.SCCore; using System.Diagnostics; using MECF.Framework.Common.IOCore; namespace CyberX8_RT.Devices.Metal { public class CompactMembranMetalDevice : MetalCellDevice { private enum ANCellStatus { Unknow, Filling, Emptying, Full, Empty } private enum ANCellOperation { None, Fill, Drain } #region 常量 private const string SIDE_A = "SideA"; private const string SIDE_B = "SideB"; private const string AN_A_PINENABLE="ANAPinEnable"; private const string AN_B_PINENABLE = "ANBPinEnable"; private const string AN_A_POUTENABLE = "ANAPoutEnable"; private const string AN_B_POUTENABLE = "ANBPoutEnable"; private const string CELL_FLOW = "CellFlow"; private const string WH_CLAMP = "WHClamp"; private const string WH_UNCLAMP = "WHUnclamp"; private const string CELL_FLOW_VALVE = "CellFlowValve"; private const string COUNTER_VALUE = "CounterValue"; private const string COUNTER_START = "Start"; private const string COUNTER_STOP = "Stop"; private const string COUNTER_RESET = "Reset"; private const string AN_A_CELL_FLOW = "ANACellFlow"; private const string AN_B_CELL_FLOW = "ANBCellFlow"; #endregion #region 内部变量 /// /// 设备数据 /// private CompactMembranMetalDeviceData _metalDeviceData =new CompactMembranMetalDeviceData(); /// /// 变量是否初始化字典 /// private Dictionary _variableInitializeDic = new Dictionary(); /// /// 阳极A面cellFlow /// private CounterFlowData _anACellFlow = new CounterFlowData(); /// /// 阳极B面cellFlow /// private CounterFlowData _anBCellFlow = new CounterFlowData(); /// /// Counter字典 /// private Dictionary _nameCounterFlowData = new Dictionary(); /// /// 当前阳极A面操作 /// private ANCellOperation _currentANACellOperation; /// /// 当前阳机B面操作 /// private ANCellOperation _currentANBCellOperation; /// /// AN Fill Routine /// private CompactMembranFillRoutine _anANACellFillRoutine; /// /// 阳机B面Fill Routine /// private CompactMembranFillRoutine _anANBCellFillRoutine; /// /// 阳极A面流量总数值 /// private double _anATotalFillFlow = 0; /// /// 阳极B面流量总数值 /// private double _anBTotalFillFlow = 0; /// /// 阳极A面Drain时间 /// private DateTime _anADrainTime = DateTime.Now; /// /// 阳极B面Drain时间 /// private DateTime _anBDrainTime = DateTime.Now; /// /// Flow Valve计时 /// private Stopwatch _flowValveStopWatch = new Stopwatch(); #endregion #region 属性 /// /// 设备数据 /// public CompactMembranMetalDeviceData MetalDeviceData { get { return _metalDeviceData; } } /// /// 阳极A面CellFlow /// public CounterFlowData ANACellFlow { get { return _anACellFlow; } } /// /// 阳极B面CellFlow /// public CounterFlowData ANBCellFlow { get { return _anBCellFlow; } } /// /// Flow Valve稳定状态 /// public bool FlowValveStable { get { return _metalDeviceData.CellFlowValve && _flowValveStopWatch.ElapsedMilliseconds >= 3000; } } #endregion /// /// 构造函数 /// /// public CompactMembranMetalDevice(string moduleName) : base(moduleName) { } /// /// 初始化 /// /// public override bool Initialize() { base.Initialize(); InitializeRoutine(); SubscribeValueAction(); SubscribeData(); return true; } /// /// 初始化Routine /// private void InitializeRoutine() { _anANACellFillRoutine = new CompactMembranFillRoutine(Module,"A"); _anANBCellFillRoutine = new CompactMembranFillRoutine(Module,"B"); } /// /// 订阅数据 /// private void SubscribeData() { DATA.Subscribe($"{Module}.MetalData", () => _metalDeviceData, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.SideAFlow",()=>ANACellFlow.CounterValue, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.SideAFlowStatus", () => ANACellFlow.Status, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.SideBFlow", () => ANBCellFlow.CounterValue, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.SideBFlowStatus",()=>ANBCellFlow.Status, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.CellFlow",()=>MetalDeviceData.CellFlow, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ANBPinEnable",()=>_metalDeviceData.ANBPinEnable, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ANAPinEnable", () => _metalDeviceData.ANAPinEnable, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ANAPoutEnable", () => _metalDeviceData.ANAPoutEnable, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ANBPoutEnable", () => _metalDeviceData.ANBPoutEnable, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.CellFlowEnable", () => _metalDeviceData.CellFlowValve, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.WaferShuttleClamped", () => _metalDeviceData.WHClamp, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.WaferShuttleUnclamped", () => _metalDeviceData.WHUnclamp, SubscriptionAttribute.FLAG.IgnoreSaveDB); } /// /// 订阅变量数值发生变化 /// private void SubscribeValueAction() { BeckhoffIoSubscribeUpdateVariable(AN_A_PINENABLE); BeckhoffIoSubscribeUpdateVariable(AN_B_PINENABLE); BeckhoffIoSubscribeUpdateVariable(AN_A_POUTENABLE); BeckhoffIoSubscribeUpdateVariable(AN_B_POUTENABLE); BeckhoffIoSubscribeUpdateVariable(CELL_FLOW); BeckhoffIoSubscribeUpdateVariable(WH_CLAMP); BeckhoffIoSubscribeUpdateVariable(WH_UNCLAMP); BeckhoffIoSubscribeUpdateVariable(CELL_FLOW_VALVE); BeckhoffCounterSubscribeUpdateVariable(AN_A_CELL_FLOW,ANACellFlow); BeckhoffCounter anACellFlowCounter = BeckhoffCounterManager.Instance.GetBeckhoffCounter($"{Module}.{AN_A_CELL_FLOW}"); if(anACellFlowCounter!=null) { ANACellFlow.Period = anACellFlowCounter.Period; } BeckhoffCounterSubscribeUpdateVariable(AN_B_CELL_FLOW,ANBCellFlow); BeckhoffCounter anBCellFlowCounter = BeckhoffCounterManager.Instance.GetBeckhoffCounter($"{Module}.{AN_B_CELL_FLOW}"); if (anACellFlowCounter != null) { ANBCellFlow.Period = anBCellFlowCounter.Period; } } /// /// 订阅Operation /// protected override void InitializeOperation() { base.InitializeOperation(); OP.Subscribe($"{Module}.ANAFillOn",AnSideAFillOn); OP.Subscribe($"{Module}.ANAFillOff", AnSideAFillOff); OP.Subscribe($"{Module}.ANBFillOn", AnSideBFillOn); OP.Subscribe($"{Module}.ANBFillOff", AnSideBFillOff); OP.Subscribe($"{Module}.ANADrainOn", AnSideADrainOn); OP.Subscribe($"{Module}.ANADrainOff", AnSideADrainOff); OP.Subscribe($"{Module}.ANBDrainOn", AnSideBDrainOn); OP.Subscribe($"{Module}.ANBDrainOff", AnSideBDrainOff); OP.Subscribe($"{Module}.WHClampOn", WHClampOn); OP.Subscribe($"{Module}.WHClampOff", WHClampOff); OP.Subscribe($"{Module}.WHUnclampOn", WHUnClampOn); OP.Subscribe($"{Module}.WHUnclampOff", WHUnClampOff); OP.Subscribe($"{Module}.CellFlowValveOn", CellFlowValveOn); OP.Subscribe($"{Module}.CellFlowValveOff", CellFlowValveOff); OP.Subscribe($"{Module}.WaferHolderClampOn", WaferHolderClampOn); OP.Subscribe($"{Module}.WaferHolderUnclampOn", WaferHolderUnclampOn); OP.Subscribe($"{Module}.WaferHolderDisconnect", WaferHolderDisConnect); OP.Subscribe($"{Module}.A.Fill", ANSideAFillOperation); OP.Subscribe($"{Module}.B.Fill", ANSideBFillOperation); OP.Subscribe($"{Module}.A.Stop", ANSideAStopOperation); OP.Subscribe($"{Module}.B.Stop", ANSideBStopOperation); OP.Subscribe($"{Module}.A.Drain", ANSideADrainOperation); OP.Subscribe($"{Module}.B.Drain", ANSideBDrainOperation); } /// /// 订阅IO变量 /// /// private void BeckhoffIoSubscribeUpdateVariable(string variable) { _variableInitializeDic[variable] = false; IOModuleManager.Instance.SubscribeModuleVariable(Module, variable, UpdateVariableValue); } /// /// 更新变量数值 /// /// /// private void UpdateVariableValue(string variable, object value) { if (!_metalDeviceData.IsDataInitialized) { _metalDeviceData.IsDataInitialized = true; } PropertyInfo property = _metalDeviceData.GetType().GetProperty(variable); if (property != null) { property.SetValue(_metalDeviceData, value); } if (_variableInitializeDic.ContainsKey(variable) && !_variableInitializeDic[variable]) { _variableInitializeDic[variable] = true; } if (variable == CELL_FLOW_VALVE) { bool bValue = (bool)value; if (bValue) { _flowValveStopWatch.Restart(); } } } /// /// 订阅Counter变量 /// /// private void BeckhoffCounterSubscribeUpdateVariable(string variable,CounterFlowData counterFlowData) { _nameCounterFlowData[$"{Module}.{variable}"] = counterFlowData; BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_VALUE, UpdateCounterVariableValue); BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_START, UpdateCounterVariableValue); BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_STOP, UpdateCounterVariableValue); BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_RESET, UpdateCounterVariableValue); } /// /// 更新变量数值 /// /// /// private void UpdateCounterVariableValue(string variable, object value) { string[] strAry = variable.Split('.'); string lastVariable = strAry[strAry.Length - 1]; PropertyInfo property = null; string key = variable.Replace($".{lastVariable}", ""); if(_nameCounterFlowData.ContainsKey(key)) { CounterFlowData counterFlowData = _nameCounterFlowData[key]; if (counterFlowData != null) { property = counterFlowData.GetType().GetProperty(lastVariable); if (property != null) { property.SetValue(counterFlowData, value); } } } } #region Fill /// /// AN A面Fill On /// /// /// /// public bool AnSideAFillOn(string cmd, object[] param) { string ioName= BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_PINENABLE}"); string countName= BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_CELL_FLOW}"); bool result= BeckhoffCounterManager.Instance.StartCounter(countName); if (result) { return IOModuleManager.Instance.WriteIoValue(ioName, true); } else { return false; } } /// /// AN A面Fill Off /// /// /// /// public bool AnSideAFillOff(string cmd, object[] param) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_PINENABLE}"); string countName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_CELL_FLOW}"); bool result = BeckhoffCounterManager.Instance.StopCounter(countName); if(result) { result= BeckhoffCounterManager.Instance.ResetCounter(countName,0); if(result) { return IOModuleManager.Instance.WriteIoValue(ioName, false); } } return false; } /// /// AN B面Fill On /// /// /// /// public bool AnSideBFillOn(string cmd, object[] param) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_B_PINENABLE}"); string countName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_B_CELL_FLOW}"); bool result = BeckhoffCounterManager.Instance.StartCounter(countName); if (result) { return IOModuleManager.Instance.WriteIoValue(ioName, true); } else { return false; } } /// /// AN B面Fill Off /// /// /// /// public bool AnSideBFillOff(string cmd, object[] param) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_B_PINENABLE}"); string countName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_B_CELL_FLOW}"); bool result = BeckhoffCounterManager.Instance.StopCounter(countName); if (result) { result = BeckhoffCounterManager.Instance.ResetCounter(countName, 0); if (result) { return IOModuleManager.Instance.WriteIoValue(ioName, false); } } return false; } #endregion #region Drain /// /// AN A面Drain On /// /// /// /// private bool AnSideADrainOn(string cmd, object[] param) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_POUTENABLE}"); return IOModuleManager.Instance.WriteIoValue(ioName, true); } /// /// AN A面Drain Off /// /// /// /// public bool AnSideADrainOff(string cmd, object[] param) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_POUTENABLE}"); return IOModuleManager.Instance.WriteIoValue(ioName, false); } /// /// AN B面Drain On /// /// /// /// private bool AnSideBDrainOn(string cmd, object[] param) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_B_POUTENABLE}"); return IOModuleManager.Instance.WriteIoValue(ioName, true); } /// /// AN A面Drain Off /// /// /// /// public bool AnSideBDrainOff(string cmd, object[] param) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_B_POUTENABLE}"); return IOModuleManager.Instance.WriteIoValue(ioName, false); } #endregion #region WH Clamp /// /// WH Clamp On /// /// /// /// private bool WHClampOn(string cmd, object[] param) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}"); return IOModuleManager.Instance.WriteIoValue(ioName, true); } /// /// WH Clamp Off /// /// /// /// private bool WHClampOff(string cmd, object[] param) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}"); return IOModuleManager.Instance.WriteIoValue(ioName, false); } /// /// WH UnClamp On /// /// /// /// private bool WHUnClampOn(string cmd, object[] param) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_UNCLAMP}"); return IOModuleManager.Instance.WriteIoValue(ioName, true); } /// /// WH UnClamp Off /// /// /// /// private bool WHUnClampOff(string cmd, object[] param) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_UNCLAMP}"); return IOModuleManager.Instance.WriteIoValue(ioName, false); } /// /// Wafer Holder Clamp On /// /// /// /// public bool WaferHolderClampOn(string cmd, object[] param) { string unclampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_UNCLAMP}"); bool result = IOModuleManager.Instance.WriteIoValue(unclampIOName, false); if(result) { string clampIOName= BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}"); return IOModuleManager.Instance.WriteIoValue(clampIOName, true); } return false; } /// /// Wafer Holder Clamp On /// /// /// /// public bool WaferHolderUnclampOn(string cmd, object[] param) { string clampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}"); bool result = IOModuleManager.Instance.WriteIoValue(clampIOName, false); if (result) { string unclampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_UNCLAMP}"); return IOModuleManager.Instance.WriteIoValue(unclampIOName, true); } return false; } /// /// Wafer Holder Disconnect /// /// /// /// public bool WaferHolderDisConnect(string cmd, object[] param) { string clampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}"); bool result = IOModuleManager.Instance.WriteIoValue(clampIOName, false); if (result) { string unclampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_UNCLAMP}"); return IOModuleManager.Instance.WriteIoValue(unclampIOName, false); } return false; } #endregion #region Cell Flow Valve /// /// Cell Flow On /// /// /// /// public bool CellFlowValveOn(string cmd, object[] param) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CELL_FLOW_VALVE}"); return IOModuleManager.Instance.WriteIoValue(ioName, true); } /// /// Cell Flow Off /// /// /// /// public bool CellFlowValveOff(string cmd, object[] param) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CELL_FLOW_VALVE}"); return IOModuleManager.Instance.WriteIoValue(ioName, false); } #endregion #region AN Fill /// /// 阳极A面Fill /// /// /// /// private bool ANSideAFillOperation(string cmd, object[] objects) { if(_currentANACellOperation!=ANCellOperation.None) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} current is {_currentANACellOperation},cannot execute AN Side A Fill"); return false; } bool result = _anANACellFillRoutine.Start() == RState.Running; if (result) { _currentANACellOperation = ANCellOperation.Fill; } return result; } /// /// 阳极B面Fill /// /// /// /// private bool ANSideBFillOperation(string cmd, object[] objects) { if (_currentANBCellOperation != ANCellOperation.None) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} current is {_currentANBCellOperation},cannot execute AN Side B Fill"); return false; } bool result = _anANBCellFillRoutine.Start() == RState.Running; if (result) { _currentANBCellOperation = ANCellOperation.Fill; } return result; } #endregion #region AN Drain /// /// 阳极A面Drain /// /// /// /// private bool ANSideADrainOperation(string cmd, object[] objects) { if (_currentANACellOperation != ANCellOperation.None) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} current is {_currentANACellOperation},cannot execute AN Side A Drain"); return false; } bool result = true; CompactMembranReservoirDevice reservoirDevice = GetReservoirDevice(); if(CheckOtherMetalDeviceDrainStatus(reservoirDevice,"A")) { return false; } if (reservoirDevice != null && reservoirDevice.ReservoirData.ANADrainPump == 0) { result = reservoirDevice.AnADrainPumpOn("", null); } if (result) { result = AnSideADrainOn("", null); if (result) { ANACellFlow.Status = ANCellStatus.Emptying.ToString(); _anATotalFillFlow = 0; _anADrainTime=DateTime.Now; } else { reservoirDevice.AnADrainPump(0); } } return result; } /// /// 其他Metal Drain是否打开 /// /// /// /// private bool CheckOtherMetalDeviceDrainStatus(CompactMembranReservoirDevice reservoirDevice,string side) { if(reservoirDevice==null) { return false; } ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(reservoirDevice.Module); if(reservoirItem!=null) { foreach(var item in reservoirItem.MetalCells) { if(item.ModuleName!=Module) { CompactMembranMetalDevice metalDevice = DEVICE.GetDevice(item.ModuleName); if(metalDevice!=null) { if(side=="A"&&metalDevice.MetalDeviceData.ANAPoutEnable) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{item.ModuleName} A Drain is on"); return true; } if (side == "B" && metalDevice.MetalDeviceData.ANBPoutEnable) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{item.ModuleName} B Drain is on"); return true; } } } } } return false; } /// /// 阳极A面Drain /// /// /// /// private bool ANSideBDrainOperation(string cmd, object[] objects) { if (_currentANBCellOperation != ANCellOperation.None) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} current is {_currentANBCellOperation},cannot execute AN Side A Drain"); return false; } bool result = true; CompactMembranReservoirDevice reservoirDevice = GetReservoirDevice(); if (CheckOtherMetalDeviceDrainStatus(reservoirDevice, "B")) { return false; } if(reservoirDevice!=null&&reservoirDevice.ReservoirData.ANBDrainPump==0) { result= reservoirDevice.AnBDrainPumpOn("", null); } if (result) { result = AnSideBDrainOn("", null); if (result) { ANBCellFlow.Status = ANCellStatus.Emptying.ToString(); _anBTotalFillFlow = 0; _anBDrainTime=DateTime.Now; } else { reservoirDevice.AnBDrainPump(0); } } return result; } #endregion #region AN Stop /// /// 阳面A停止 /// /// /// /// private bool ANSideAStopOperation(string cmd, object[] objs) { CompactMembranReservoirDevice reservoirDevice = GetReservoirDevice(); if (reservoirDevice != null) { if (reservoirDevice.ReservoirData.ANPump != 0) { reservoirDevice.AnPump(0); } if (reservoirDevice.ReservoirData.ANADrainPump != 0) { reservoirDevice.AnADrainPump(0); } } if (MetalDeviceData.ANAPinEnable) { AnSideAFillOff("", null); } if (MetalDeviceData.ANAPoutEnable) { AnSideADrainOff("", null); } ANACellFlow.Status = ANCellStatus.Unknow.ToString(); _anATotalFillFlow = 0; return true; } /// /// 阳面A停止 /// /// /// /// private bool ANSideBStopOperation(string cmd, object[] objs) { CompactMembranReservoirDevice reservoirDevice = GetReservoirDevice(); if (reservoirDevice != null) { if (reservoirDevice.ReservoirData.ANPump != 0) { reservoirDevice.AnPump(0); } if(reservoirDevice.ReservoirData.ANBDrainPump!=0) { reservoirDevice.AnBDrainPump(0); } } if(MetalDeviceData.ANBPinEnable) { AnSideBFillOff("", null); } if(MetalDeviceData.ANBPoutEnable) { AnSideBDrainOff("", null); } ANBCellFlow.Status = ANCellStatus.Unknow.ToString(); _anBTotalFillFlow = 0; return true; } #endregion #region Timer定时器 /// /// 定时器 /// /// public override bool OnTimer(int interval) { if (_currentANACellOperation == ANCellOperation.Fill) { SideFillRoutineMonitor(_anANACellFillRoutine, "A", ANACellFlow, ref _currentANACellOperation); } if (_currentANBCellOperation == ANCellOperation.Fill) { SideFillRoutineMonitor(_anANBCellFillRoutine, "B", ANBCellFlow, ref _currentANBCellOperation); } //正在Filing if (ANACellFlow.Status == ANCellStatus.Filling.ToString()) { JudgeFillFull(ANACellFlow,interval,ref _anATotalFillFlow); } if (ANBCellFlow.Status == ANCellStatus.Filling.ToString()) { JudgeFillFull(ANBCellFlow,interval,ref _anBTotalFillFlow); } if (ANACellFlow.Status == ANCellStatus.Emptying.ToString()) { JudgeDrainEmpty("A"); } if (ANBCellFlow.Status == ANCellStatus.Emptying.ToString()) { JudgeDrainEmpty("B"); } return true; } /// /// 单面Fill Routine监控 /// /// /// /// private void SideFillRoutineMonitor(IRoutine routine, string side,CounterFlowData counterFlowData, ref ANCellOperation operation) { RState state = routine.Monitor(); if (state == RState.Failed || state == RState.Timeout) { CloseReservoirPumpAndMetalFill(side); operation = ANCellOperation.None; } else if (state == RState.End) { counterFlowData.Status = ANCellStatus.Filling.ToString(); operation = ANCellOperation.None; } } /// /// 判定是否fill Full /// private void JudgeFillFull(CounterFlowData counterFlowData,int interval,ref double totalFillFlow) { double anodeFillVolume = SC.GetValue($"Metal.AnodeFillVolume"); totalFillFlow += counterFlowData.CounterValue / 60 * ((double)interval / 1000); if (totalFillFlow >= anodeFillVolume) { counterFlowData.Status = "Full"; } } /// /// 判定是否Drain Empty /// /// private void JudgeDrainEmpty(string side) { if (side == "A") { JudgeSideADrain(ANACellFlow, _anADrainTime); if(ANACellFlow.Status==ANCellStatus.Empty.ToString()) { CompactMembranReservoirDevice reservoirDevice = GetReservoirDevice(); if (reservoirDevice != null) { reservoirDevice.AnADrainPump(0); } AnSideADrainOff("", null); } } else { JudgeSideADrain(ANBCellFlow, _anBDrainTime); if (ANBCellFlow.Status == ANCellStatus.Empty.ToString()) { CompactMembranReservoirDevice reservoirDevice = GetReservoirDevice(); if (reservoirDevice != null) { reservoirDevice.AnBDrainPump(0); } AnSideBDrainOff("", null); } } } /// /// 判定单面Drain的情况 /// /// /// private void JudgeSideADrain(CounterFlowData counterFlowData, DateTime drainDateTime) { double anodeDrainTime = SC.GetValue("Metal.AnodeDrainTime"); if (DateTime.Now.Subtract(drainDateTime).TotalMilliseconds >= anodeDrainTime * 1000) { counterFlowData.Status = ANCellStatus.Empty.ToString(); } } /// /// 关闭Reservoir Pump和Metal Fill /// private void CloseReservoirPumpAndMetalFill(string side) { CompactMembranReservoirDevice reservoirDevice = GetReservoirDevice(); if (reservoirDevice != null) { reservoirDevice.AnPump(0); if (side == "A") { AnSideAFillOff("", null); } else { AnSideBDrainOff("", null); } } } /// /// 获取Reservoir设备 /// /// private CompactMembranReservoirDevice GetReservoirDevice() { string reservoir = ReservoirItemManager.Instance.GetReservoirByMetal(Module); return DEVICE.GetDevice(reservoir); } #endregion /// /// Enter Disabled Operation /// /// public void EnterDisabledOperation() { ANSideAStopOperation("", null); ANSideBStopOperation("", null); if (_metalDeviceData.CellFlowValve) { CellFlowValveOff("", null); } } #region 设备接口 public override void Monitor() { } public override void Reset() { } public override void Terminate() { } #endregion } }