290 lines
8.8 KiB
C#
290 lines
8.8 KiB
C#
using System;
|
||
using System.Diagnostics;
|
||
using System.Xml;
|
||
using Aitex.Core.Common.DeviceData;
|
||
using Aitex.Core.RT.DataCenter;
|
||
using Aitex.Core.RT.Device;
|
||
using Aitex.Core.RT.Event;
|
||
using Aitex.Core.RT.IOCore;
|
||
using Aitex.Core.RT.Log;
|
||
using Aitex.Core.RT.OperationCenter;
|
||
using Aitex.Core.RT.SCCore;
|
||
using Aitex.Core.Util;
|
||
using MECF.Framework.Common.Event;
|
||
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Pumps;
|
||
|
||
namespace Aitex.Core.RT.Device.Unit
|
||
{
|
||
/// <summary>
|
||
/// 泵2对应的IO要求:
|
||
/// diRunning 【如果未定义,默认泵为常开】
|
||
/// diOverloadAlarm【可以不定义】
|
||
///
|
||
/// doResetError【可以不定义】
|
||
/// doStartStop【可以不定义】
|
||
/// doPowerOn【可以不定义,默认主电源常供】
|
||
/// </summary>
|
||
public class IoPump2 : BaseDevice, IDevice, IPump
|
||
{
|
||
public bool IsRunning
|
||
{
|
||
get
|
||
{
|
||
if (_diRunning != null)
|
||
return _diRunning.Value;
|
||
return true;
|
||
}
|
||
}
|
||
|
||
public bool IsPumpOverloadAlarm
|
||
{
|
||
get
|
||
{
|
||
return _diOverloadAlarm != null && _diOverloadAlarm.Value;
|
||
}
|
||
}
|
||
|
||
public bool ResetErrorSetPoint
|
||
{
|
||
get
|
||
{
|
||
return _doResetError != null && _doResetError.Value;
|
||
}
|
||
set
|
||
{
|
||
if (_doResetError!=null)
|
||
_doResetError.Value = value;
|
||
}
|
||
}
|
||
|
||
public bool StartSetPoint
|
||
{
|
||
get
|
||
{
|
||
return _doStart != null && _doStart.Value;
|
||
}
|
||
set
|
||
{
|
||
if (_doStart != null)
|
||
_doStart.Value = value;
|
||
}
|
||
}
|
||
|
||
public bool MainPowerOnSetPoint
|
||
{
|
||
get
|
||
{
|
||
return _doPowerOn != null && _doPowerOn.Value;
|
||
}
|
||
set
|
||
{
|
||
if (_doPowerOn != null)
|
||
_doPowerOn.Value = value;
|
||
}
|
||
}
|
||
|
||
private AITPumpData DeviceData
|
||
{
|
||
get
|
||
{
|
||
AITPumpData data = new AITPumpData()
|
||
{
|
||
DeviceName = Name,
|
||
DeviceSchematicId = DeviceID,
|
||
DisplayName = Display,
|
||
DeviceModule = Module,
|
||
Module = Module,
|
||
|
||
IsOn = IsRunning,
|
||
IsError = HasAlarm,
|
||
IsOverLoad = IsPumpOverloadAlarm,
|
||
};
|
||
|
||
return data;
|
||
}
|
||
}
|
||
|
||
|
||
private DIAccessor _diRunning = null;
|
||
private DIAccessor _diOverloadAlarm;
|
||
|
||
private DOAccessor _doStart;
|
||
private DOAccessor _doPowerOn;
|
||
private DOAccessor _doResetError;
|
||
|
||
private R_TRIG _trigOverload = new R_TRIG();
|
||
|
||
public AlarmEventItem AlarmOverload { get; set; }
|
||
public AlarmEventItem AlarmFailedStartStop { get; set; }
|
||
|
||
private Stopwatch _timerResetError = new Stopwatch();
|
||
private Stopwatch _timerStartStop = new Stopwatch();
|
||
|
||
private SCConfigItem _scStartTimeout;
|
||
private SCConfigItem _scResetErrorTimeout;
|
||
|
||
public IoPump2(string module, XmlElement node, string ioModule = "")
|
||
{
|
||
var attrModule = node.GetAttribute("module");
|
||
base.Module = string.IsNullOrEmpty(attrModule) ? module : attrModule;
|
||
|
||
base.Name = node.GetAttribute("id");
|
||
base.Display = node.GetAttribute("display");
|
||
base.DeviceID = node.GetAttribute("schematicId");
|
||
|
||
_diRunning = ParseDiNode("diRunning", node, ioModule);
|
||
_diOverloadAlarm = ParseDiNode("diOverloadAlarm", node, ioModule);
|
||
|
||
_doStart = ParseDoNode("doStartStop", node, ioModule);
|
||
_doPowerOn = ParseDoNode("doPowerOn", node, ioModule);
|
||
_doResetError = ParseDoNode("doReset", node, ioModule);
|
||
|
||
string scBasePath = node.GetAttribute("scBasePath");
|
||
if (string.IsNullOrEmpty(scBasePath))
|
||
scBasePath = $"{Module}.{Name}";
|
||
else
|
||
{
|
||
scBasePath = scBasePath.Replace("{module}", Module);
|
||
}
|
||
|
||
_scStartTimeout = ParseScNode("", node, ioModule, $"{scBasePath}.{Name}.StartTimeout");
|
||
_scResetErrorTimeout = ParseScNode("", node, ioModule, $"{scBasePath}.{Name}.ResetErrorTimeout");
|
||
|
||
System.Diagnostics.Debug.Assert(_scResetErrorTimeout != null, "SC not defined");
|
||
System.Diagnostics.Debug.Assert(_scStartTimeout != null, "SC not defined");
|
||
}
|
||
|
||
|
||
public bool Initialize()
|
||
{
|
||
DATA.Subscribe($"{Module}.{Name}.DeviceData", () => DeviceData);
|
||
|
||
DATA.Subscribe($"{Module}.{Name}.IsOverload", () => IsPumpOverloadAlarm);
|
||
DATA.Subscribe($"{Module}.{Name}.IsRunning", () => IsRunning);
|
||
DATA.Subscribe($"{Module}.{Name}.StartSetPoint", () => StartSetPoint);
|
||
|
||
OP.Subscribe($"{Module}.{Name}.{AITPumpOperation.SetOnOff}" , SetPumpOnOff);
|
||
OP.Subscribe($"{Module}.{Name}.{AITPumpOperation.PumpOn}", SetPumpOn);
|
||
OP.Subscribe($"{Module}.{Name}.{AITPumpOperation.PumpOff}", SetPumpOff);
|
||
|
||
AlarmOverload = SubscribeAlarm($"{Module}.{Name}.OverloadAlarm", "", ResetOverload);
|
||
AlarmFailedStartStop = SubscribeAlarm($"{Module}.{Name}.FailedStartStopAlarm", "", null);
|
||
|
||
return true;
|
||
}
|
||
|
||
private bool SetPumpOn(out string reason, int time, object[] param)
|
||
{
|
||
return SetPump(out reason, time, true);
|
||
}
|
||
|
||
private bool SetPumpOff(out string reason, int time, object[] param)
|
||
{
|
||
return SetPump(out reason, time, false);
|
||
}
|
||
|
||
private bool SetPumpOnOff(out string reason, int time, object[] param)
|
||
{
|
||
return SetPump(out reason, time, Convert.ToBoolean((string)param[0]));
|
||
}
|
||
|
||
public bool SetMainPowerOnOff(bool isOn, out string reason)
|
||
{
|
||
MainPowerOnSetPoint = isOn;
|
||
reason = string.Empty;
|
||
return true;
|
||
}
|
||
|
||
public bool ResetOverload()
|
||
{
|
||
if (IsPumpOverloadAlarm)
|
||
{
|
||
if (!ResetErrorSetPoint)
|
||
{
|
||
_timerResetError.Restart();
|
||
ResetErrorSetPoint = true;
|
||
}
|
||
}
|
||
|
||
return !IsPumpOverloadAlarm;
|
||
}
|
||
|
||
public bool SetPump(out string reason, int time, bool isOn)
|
||
{
|
||
if (HasAlarm)
|
||
{
|
||
reason = $"{Display} Has active alarm, reset error first.";
|
||
return false;
|
||
}
|
||
|
||
reason = string.Empty;
|
||
|
||
_timerStartStop.Restart();
|
||
StartSetPoint = isOn;
|
||
|
||
return true;
|
||
}
|
||
|
||
public void Terminate()
|
||
{
|
||
}
|
||
|
||
public void Monitor()
|
||
{
|
||
try
|
||
{
|
||
if (StartSetPoint != IsRunning)
|
||
{
|
||
if (_timerStartStop.IsRunning &&
|
||
_timerStartStop.ElapsedMilliseconds > _scStartTimeout.IntValue * 1000)
|
||
{
|
||
var onoff = StartSetPoint ? "start up" : "shut down";
|
||
_timerStartStop.Stop();
|
||
AlarmFailedStartStop.Description =
|
||
$"{Display} can not {onoff} in {_scStartTimeout.IntValue} seconds";
|
||
AlarmFailedStartStop.Set();
|
||
StartSetPoint = IsRunning;
|
||
}
|
||
}
|
||
|
||
_trigOverload.CLK = IsPumpOverloadAlarm;
|
||
if (_trigOverload.Q)
|
||
{
|
||
AlarmOverload.Set("Pump Overload or Error");
|
||
StartSetPoint = false;
|
||
}
|
||
|
||
if (ResetErrorSetPoint)
|
||
{
|
||
if (!IsPumpOverloadAlarm)
|
||
{
|
||
AlarmOverload.Reset();
|
||
ResetErrorSetPoint = false;
|
||
_timerResetError.Stop();
|
||
}
|
||
|
||
if (IsPumpOverloadAlarm && _timerResetError.IsRunning &&
|
||
_timerResetError.ElapsedMilliseconds > _scResetErrorTimeout.IntValue * 1000)
|
||
{
|
||
_timerResetError.Stop();
|
||
EV.PostWarningLog(Module, $"Can not reset {Display} error in {_scResetErrorTimeout.IntValue} seconds");
|
||
ResetErrorSetPoint = false;
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
}
|
||
}
|
||
|
||
public void Reset()
|
||
{
|
||
AlarmFailedStartStop.Reset();
|
||
AlarmOverload.Reset();
|
||
|
||
|
||
}
|
||
}
|
||
}
|