Refactorization : BenchControl -> Rig

This commit is contained in:
Milan Hanajik
2021-03-05 16:12:24 +01:00
parent 84c8ec26b6
commit 6cf3bd6160
1461 changed files with 6330 additions and 6330 deletions
+279
View File
@@ -0,0 +1,279 @@
///
/// Copyright (c) 2013-2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.IO.Ports;
using log4net;
using Common;
using Config;
using Config.Entities;
using SchematicDrawing;
using TBF.Rig.Generic;
using TBF.Boxes;
namespace TBF.Rig.Ambient.Comet
{
/// <summary>
/// Ambient temperature / humidity / pressure meter 'Greco' connected via serial interface (RS232)
/// Connection settings: 9600 Bd 8-bits No-parity 2-stop-bits Flow control: none.
/// </summary>
public class Ambient : ComponentBase, IDevice, IOperation, GenericDevices.IAmbient, IDrawingItCmpntWithMeasuredVal
{
private static readonly ILog log = LogManager.GetLogger(typeof(Ambient));
public override string ToString() { return string.Format("Ambient({0})", Cfg.ToString(1)); }
///
/// Configuration and wrappers
///
private readonly AmbientCfg ambientCfg;
///
Unit TempUnit { get { return ambientCfg.TempUnit; } }
double TempLimLo { get { return Units.ConvertFrom(TempUnit, ambientCfg.TempLimLo); } }
double TempLimHi { get { return Units.ConvertFrom(TempUnit, ambientCfg.TempLimHi); } }
double DefaultTemperature { get { return Units.ConvertFrom(TempUnit, ambientCfg.DefaultTemp); } }
///
Unit PressureUnit { get { return ambientCfg.PressureUnit; } }
double PressureLimLo { get { return Units.ConvertFrom(PressureUnit, ambientCfg.PressureLimLo); } }
double PressureLimHi { get { return Units.ConvertFrom(PressureUnit, ambientCfg.PressureLimHi); } }
double DefaultPressure { get { return Units.ConvertFrom(PressureUnit, ambientCfg.DefaultPressure); } }
///
Unit HumiUnit { get { return ambientCfg.HumiUnit; } }
double HumiLimLo { get { return Units.ConvertFrom(HumiUnit, ambientCfg.HumiLimLo); } }
double HumiLimHi { get { return Units.ConvertFrom(HumiUnit, ambientCfg.HumiLimHi); } }
double DefaultHumidity { get { return Units.ConvertFrom(HumiUnit, ambientCfg.DefaultHumi); } }
///
/// IDrawingItCmpntWithMeasuredVal interface
///
public IDrawingItem DrawingItem { get { return ambientCfg as IDrawingItem; } }
public bool MsrmntAvailable { get { return true; } }
public double MeasuredVal { get { return temperature; } }
public string AltString
{
get {
return string.Format(ambientCfg.Format, Units.ConvertTo(TempUnit, temperature),
Units.ConvertTo(PressureUnit, pressure),
Units.ConvertTo(HumiUnit, humidity));
}
}
/// Private fields
SerialPort serialPort;
/// <summary>The state of the measurement</summary>
MsrmntState msrmntState;
int msrmntTimeStamp;
/// Measured values when MsrmntState == MsrmntState.Valid
double temperature; /// [°C]
double pressure; /// [bar]
double humidity; /// [R%]
public Ambient()
{
}
/// <summary>
/// Ambient temperature / humidity / pressure meter 'Greco' connected via serial interface (RS232)
/// </summary>
public Ambient(AmbientCfg cfg, IList<Generic.IComponent> components)
: this(cfg)
{
}
public Ambient(Generic.IComponentCfg cfg)
: base(cfg)
{
ambientCfg = cfg as AmbientCfg;
temperature = DefaultTemperature;
pressure = DefaultPressure;
humidity = DefaultHumidity;
log.Warn(this.ToString());
}
public void Initialize()
{
if (ambientCfg.DebugLevel == DebugMode.Simulate)
{
msrmntTimeStamp = StateMachine.Time;
msrmntState = MsrmntState.Valid;
return;
}
string comPortName = "COM" + ambientCfg.ComPortNr.ToString();
serialPort = new SerialPort(comPortName, ambientCfg.BaudRate, ambientCfg.Parity, ambientCfg.DataBits, ambientCfg.StopBits);
serialPort.Handshake = ambientCfg.Handshake;
serialPort.Open();
if (ambientCfg.SetDtrToOne)
{
serialPort.DtrEnable = true;
}
msrmntTimeStamp = 0;
msrmntState = MsrmntState.Busy;
log.FatalFormat("Successfully initialized device {0}", ToString());
}
/// <summary>Run this device</summary>
public void RunDeviceBefore()
{
if ((ambientCfg.DebugLevel == DebugMode.Normal) && (serialPort != null))
{
///
/// Read response
///
try
{
int receivedBytes = serialPort.BytesToRead;
if (receivedBytes >= 13)
{
byte[] byteArr = new byte[receivedBytes];
for (int i = 0; i < receivedBytes; i++) byteArr[i] = (byte)serialPort.ReadByte();
log.Debug(Telegram.LogTelegram("Received ", byteArr));
if ((receivedBytes == 13) && (byteArr[0] == 1) && (byteArr[1] == 3) && (byteArr[2] == 8) && Telegram.VerifyTelegramCRC(byteArr))
{
int value = (int)byteArr[3] * 256 + (int)byteArr[4];
temperature = value / 10.0;
value = (int)byteArr[5] * 256 + (int)byteArr[6];
humidity = value / 10.0;
value = (int)byteArr[9] * 256 + (int)byteArr[10];
pressure = value / 10000.0;
msrmntTimeStamp = StateMachine.Time;
msrmntState = MsrmntState.Valid;
UpdateProcessData(temperature, pressure, humidity);
log.InfoFormat("Ambient: temperature = {0:F1} C, humidity = {1:F1} %, pressure = {2:F0} mbar", temperature, humidity, 1000 * pressure);
}
}
}
catch (Exception e)
{
DebugLevel = DebugMode.FailureDuringOperation;
//serialPort.Close(); /// ?
serialPort = null;
log.FatalFormat("Ambient: Serial port read failure : {0}", e.Message);
if (e.InnerException != null)
{
log.FatalFormat("InnerMessage : {0}", e.InnerException.Message);
}
}
}
}
/// <summary>Run this device</summary>
public void RunDeviceAfter()
{
if ((ambientCfg.DebugLevel == DebugMode.Normal) && (serialPort != null))
{
if ((StateMachine.Time % 10) == 0)
{
///
/// Send request once per 10 seconds
///
try
{
/// Read four registers: 0x31, 0x32, 0x33, 0x34
UInt16 regAddr = 0x0030; /// register addr. = 0x31 (Modbus!)
UInt16 count = 4;
/// Prepare data to be sent
byte[] msg = new byte[8];
msg[0] = 1; /// (byte)ambientCfg.BusAddress;
msg[1] = 3; /// CMD = Read registers
msg[2] = (byte)(regAddr >> 8); /// Control Word Hi
msg[3] = (byte)(regAddr & 0xFF); /// Control Word Lo
msg[4] = (byte)(count >> 8); /// Serial Com Reference Hi
msg[5] = (byte)(count & 0xFF); /// Serial Com Reference Lo
Telegram.UpdateTelegramCRC(msg);
log.Debug(Telegram.LogTelegram("Sending ", msg));
serialPort.Write(msg, 0, msg.Length);
}
catch (Exception e)
{
DebugLevel = DebugMode.FailureDuringOperation;
//serialPort.Close(); /// ?
serialPort = null;
log.FatalFormat("Ambient: Serail port read failure : {0}", e.Message);
if (e.InnerException != null)
{
log.FatalFormat("InnerMessage : {0}", e.InnerException.Message);
}
}
}
}
}
/// <summary>Stop this device</summary>
public void StopDevice()
{
if ((ambientCfg.DebugLevel == DebugMode.Normal) && (serialPort != null))
{
serialPort.Close();
serialPort = null;
}
}
public void StopDevice2() { }
void UpdateProcessData(double temperature, double pressure, double humidity)
{
TBF.Rig.Sequences.ProcessData.AmbTemp.Val = temperature;
TBF.Rig.Sequences.ProcessData.AmbPress.Val = pressure;
TBF.Rig.Sequences.ProcessData.AmbHumi.Val = humidity;
}
///
/// Boxes for the operation result
///
DoubleBox tempBox;
DoubleBox pressureBox;
DoubleBox humiBox;
public IOperation ReadAmbientOp(DoubleBox temperature, DoubleBox pressure, DoubleBox humidity)
{
this.tempBox = temperature;
this.pressureBox = pressure;
this.humiBox = humidity;
return this;
}
/// <summary>Start this operation</summary>
public void Start()
{
if (tempBox != null) tempBox.Val = temperature;
if (pressureBox != null) pressureBox.Val = pressure;
if (humiBox != null) humiBox.Val = humidity;
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.FlowInDone or Event.FlowOutDone
/// </returns>
public Event Run()
{
if (tempBox != null) tempBox.Val = temperature;
if (pressureBox != null) pressureBox.Val = pressure;
if (humiBox != null) humiBox.Val = humidity;
return Event.AmbientDone;
}
/// <summary>Stop this operation</summary>
public void Stop() { }
}
}
+350
View File
@@ -0,0 +1,350 @@
///
/// Copyright (c) 2013-2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Xml.Serialization;
using Config;
using Config.Entities;
using SchematicDrawing;
using TBF.Rig.Generic;
using TBF.Resources;
namespace TBF.Rig.Ambient.Comet
{
public class AmbientCfg : ComponentCfgBase, Generic.IComponentCfg, IParamsProvider, IDrawingItemWithMeasuredVal
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(AmbientCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Component> cmpntEntities)
{
return new Configs.ParamsProvider.ComponentCfgCtrl(this, null);
}
///
/// Serialized parameters
///
public int ComPortNr; /// 0
public int BaudRate; /// 1
public Parity Parity; /// 2
public int DataBits; /// 3
public StopBits StopBits; /// 4
public Handshake Handshake; /// 5
public bool SetDtrToOne; /// 6
public Unit TempUnit; /// 7
public double TempLimLo; /// 8
public double TempLimHi; /// 9
public double DefaultTemp; /// 10
public Unit PressureUnit; /// 11
public double PressureLimLo; /// 12
public double PressureLimHi; /// 13
public double DefaultPressure; /// 14
public Unit HumiUnit; /// 15
public double HumiLimLo; /// 16
public double HumiLimHi; /// 17
public double DefaultHumi; /// 18
public string Format; /// 19
/// Schematic drawing info
public Shape Shape { get; set; }
public int X { get; set; }
public int Y { get; set; }
public Sz Sz { get; set; }
public Orient Orient { get; set; }
public bool Flip { get; set; }
public int LblX { get; set; }
public int LblY { get; set; }
public Orient LblOrient { get; set; }
public int MsrdX { get; set; }
public int MsrdY { get; set; }
public Orient MsrdOrient { get; set; }
[XmlIgnore]
public string MsrdFormat { get { return string.Empty; } }
[XmlIgnore]
public Config.Unit MsrdUnit { get { return TempUnit; } }
[XmlIgnore]
public double MsrdValLimLo { get { return TempLimLo; } }
[XmlIgnore]
public double MsrdValLimHi { get { return TempLimHi; } }
[XmlIgnore]
public IList<GNode> GNodes { get; set; }
/// Private parameterless constructor invoked by all other (public) constructors
AmbientCfg()
{
GNodes = new List<GNode>();
Format = string.Empty;
}
public AmbientCfg(string name, IComponentFactory factory)
: this()
{
Shape = Shape.Ambient;
Sz = Sz.M;
Factory = factory;
Name = name;
ParentName = string.Empty;
InitializeAll();
}
public string ComponentName { get { return Name; } }
public void InitializeAll()
{
ComPortNr = 6;
BaudRate = 9600;
Parity = System.IO.Ports.Parity.None;
DataBits = 8;
StopBits = System.IO.Ports.StopBits.Two;
Handshake = System.IO.Ports.Handshake.None;
SetDtrToOne = false;
TempUnit = Unit.C;
TempLimLo = 15;
TempLimHi = 30;
DefaultTemp = 25;
PressureUnit = Unit.hPa;
PressureLimLo = 960;
PressureLimHi = 1060;
DefaultPressure = 1013;
HumiUnit = Unit.RPct;
HumiLimLo = 20;
HumiLimHi = 80;
DefaultHumi = 50;
Format = "{0:F1} °C\n{1:F0} hPa\n{2:F0} R%";
MsrdY = 22;
}
string[] paramNames = new string[]
{
"Serial port number", /// 0
"Baud rate", /// 1
"Parity", /// 2
"Data bits", /// 3
"Stop bits", /// 4
"Handshake", /// 5
"Set DTR to one", /// 6
"Unit of temperature", /// 7
"Temperature limit Lo", /// 8
"Temperature limit Hi", /// 9
"Default temperature", /// 10
"Unit of pressure", /// 11
"Pressure limit Lo", /// 12
"Pressure limit Hi", /// 13
"Default pressure", /// 14
"Unit of rel. humidity", /// 15
"Rel. humidity limit Lo", /// 16
"Rel. humidity limit Hi", /// 17
"Default retl. humidity", /// 18
"Display format", /// 19
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
public ICollection<string> ParamValues(int i)
{
switch (i)
{
case 1:
return new string[] { "150", "300", "600", "1200", "2400", "4800", "9600",
"19200", "38400", "57600", "76800", "115200"};
case 2:
return new string[] { Parity.None.ToString(), Parity.Odd.ToString(), Parity.Even.ToString() };
case 3:
return new string[] { "7", "8" };
case 4:
return new string[] { StopBits.None.ToString(),
StopBits.One.ToString(),
StopBits.OnePointFive.ToString(),
StopBits.Two.ToString() };
case 5:
return new string[] { Handshake.None.ToString(),
Handshake.XOnXOff.ToString(),
Handshake.RequestToSend.ToString(),
Handshake.RequestToSendXOnXOff.ToString() };
case 6:
return new string[] { Strings.yes, Strings.no };
case 7:
return new string[] { "°C", "°F", "K" };
case 11:
return new string[] { "Pa", "hPa", "mbar", "kPa", "inHg", "psi", "bar", "MPa" };
case 15:
return new string[] { "R%" };
default:
return null;
}
}
public string ToString(int i)
{
switch (i)
{
case 0: return ComPortNr.ToString();
case 1: return BaudRate.ToString();
case 2: return Parity.ToString();
case 3: return DataBits.ToString();
case 4: return StopBits.ToString();
case 5: return Handshake.ToString();
case 6: return SetDtrToOne ? Strings.yes : Strings.no;
case 7: return TempUnit.ToDescription();
case 8: return TempLimLo.ToString();
case 9: return TempLimHi.ToString();
case 10: return DefaultTemp.ToString();
case 11: return PressureUnit.ToDescription();
case 12: return PressureLimLo.ToString();
case 13: return PressureLimHi.ToString();
case 14: return DefaultPressure.ToString();
case 15: return HumiUnit.ToDescription();
case 16: return HumiLimLo.ToString();
case 17: return HumiLimHi.ToString();
case 18: return DefaultHumi.ToString();
case 19: return Format.Replace("\n", "<LF>");
default:
return string.Format("{0} {1}[{2},{3}] Com{4}, {5}Bd, {6}-bits, parity={7}, stopBits={8}, {9}",
Name, Shape, X, Y, ComPortNr, BaudRate, DataBits, Parity, StopBits, Handshake);
}
}
public CfgUpdateFlags UpdateParam(int i, string str)
{
switch (i)
{
case 0: ComPortNr = int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 1: BaudRate = int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 2: Parity = TBF.Utils.GetParity(str); return CfgUpdateFlags.RestartRqrd;
case 3: DataBits = int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 4: StopBits = TBF.Utils.GetStopBits(str); return CfgUpdateFlags.RestartRqrd;
case 5: Handshake = TBF.Utils.GetHandshake(str); return CfgUpdateFlags.RestartRqrd;
case 6: SetDtrToOne = (str == Strings.yes); return CfgUpdateFlags.RestartRqrd;
case 7:
foreach (var u in new Unit[] { Unit.C, Unit.F, Unit.K })
{
if (str == u.ToDescription()) { TempUnit = u; return CfgUpdateFlags.RestartRqrd; }
}
return CfgUpdateFlags.None;
case 8: TempLimLo = Utils.ParseSDouble(str); return CfgUpdateFlags.RestartRqrd;
case 9: TempLimHi = Utils.ParseSDouble(str); return CfgUpdateFlags.RestartRqrd;
case 10: DefaultTemp = Utils.ParseSDouble(str); return CfgUpdateFlags.RestartRqrd;
case 11:
foreach (var u in new Unit[] { Unit.Pa, Unit.hPa, Unit.mbar, Unit.kPa, Unit.inHg, Unit.psi, Unit.bar, Unit.MPa })
{
if (str == u.ToDescription()) { PressureUnit = u; return CfgUpdateFlags.RestartRqrd; }
}
return CfgUpdateFlags.None;
case 12: PressureLimLo = Utils.ParseUDouble(str); return CfgUpdateFlags.RestartRqrd;
case 13: PressureLimHi = Utils.ParseUDouble(str); return CfgUpdateFlags.RestartRqrd;
case 14: DefaultPressure = Utils.ParseUDouble(str); return CfgUpdateFlags.RestartRqrd;
case 15:
foreach (var u in new Unit[] { Unit.RPct })
{
if (str == u.ToDescription()) { HumiUnit = u; return CfgUpdateFlags.RestartRqrd; }
}
return CfgUpdateFlags.None;
case 16: HumiLimLo = Utils.ParseUDouble(str); return CfgUpdateFlags.RestartRqrd;
case 17: HumiLimHi = Utils.ParseUDouble(str); return CfgUpdateFlags.RestartRqrd;
case 18: DefaultHumi = Utils.ParseUDouble(str); return CfgUpdateFlags.RestartRqrd;
case 19: Format = str.Replace("<LF>", "\n"); return CfgUpdateFlags.RestartRqrd;
default: return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string str, out string message)
{
message = string.Empty;
int idummy;
double dummy;
switch (i)
{
case 0:
if (int.TryParse(str, out idummy) && idummy > 0) return true;
break;
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 11:
case 15:
if (ParamValues(i).Contains(str)) return true;
break;
case 8:
case 9:
case 10:
if (TBF.Utils.TryParseSDouble(str, out dummy)) return true;
break;
case 12:
case 13:
case 14:
case 16:
case 17:
case 18:
if (TBF.Utils.TryParseUDouble(str, out dummy)) return true;
break;
case 19:
return true;
default:
message = "Invalid index";
return false;
}
message = ParamName(i) + " is invalid";
return false;
}
void CopyContentTo(AmbientCfg prms)
{
prms.ParentName = this.ParentName;
prms.Shape = this.Shape;
prms.Sz = this.Sz;
prms.Orient = this.Orient;
prms.Flip = this.Flip;
prms.LblX = this.LblX;
prms.LblY = this.LblY;
prms.LblOrient = this.LblOrient;
prms.MsrdX = this.MsrdX;
prms.MsrdY = this.MsrdY;
prms.MsrdOrient = this.MsrdOrient;
prms.ComPortNr = this.ComPortNr;
prms.BaudRate = this.BaudRate;
prms.Parity = this.Parity;
prms.DataBits = this.DataBits;
prms.StopBits = this.StopBits;
prms.Handshake = this.Handshake;
prms.SetDtrToOne = this.SetDtrToOne;
prms.TempUnit = this.TempUnit;
prms.TempLimLo = this.TempLimLo;
prms.TempLimHi = this.TempLimHi;
prms.DefaultTemp = this.DefaultTemp;
prms.PressureUnit = this.PressureUnit;
prms.PressureLimLo = this.PressureLimLo;
prms.PressureLimHi = this.PressureLimHi;
prms.DefaultPressure = this.DefaultPressure;
prms.HumiUnit = this.HumiUnit;
prms.HumiLimLo = this.HumiLimLo;
prms.HumiLimHi = this.HumiLimHi;
prms.DefaultHumi = this.DefaultHumi;
prms.Format = this.Format;
}
public Config.Entities.IParamsProvider Clone()
{
AmbientCfg pars = new AmbientCfg();
CopyContentTo(pars);
return pars;
}
public bool UpdateEmbeddedDbEntity()
{
return true; /// =OK, do nothing
}
}
}
+27
View File
@@ -0,0 +1,27 @@
///
/// Copyright (c) 2013-2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.Ambient.Comet
{
public class Factory : IComponentFactory
{
public string ClassName { get { return GetType().Namespace.Substring(8); } }
public override string ToString() { return ClassName; }
public void ResetStaticProperties() { Ambient.ResetStaticProperties(); }
public IComponent DummyComponent() { return new Ambient(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Ambient(cfg); }
public IComponentCfg DefaultConfig() { return new AmbientCfg("Ambient", this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(AmbientCfg.Serializer, component, this);
}
}
}
+253
View File
@@ -0,0 +1,253 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO.Ports;
using System.Text;
using log4net;
using Config;
using Config.Entities;
using SchematicDrawing;
using TBF.Rig.Generic;
using TBF.Boxes;
namespace TBF.Rig.Ambient.Greco
{
/// <summary>
/// Ambient temperature / humidity / pressure meter 'Greco' connected via serial interface (RS232)
/// Connection settings: 19200 Bd 8-bits No-parity 1-stop-bit Flow control: none or hardware.
/// </summary>
public class Ambient : ComponentBase, IDevice, IOperation, GenericDevices.IAmbient, IDrawingItCmpntWithMeasuredVal
{
private static readonly ILog log = LogManager.GetLogger(typeof(Ambient));
public override string ToString() { return string.Format("Ambient({0})", Cfg.ToString(1)); }
private readonly AmbientCfg ambientCfg;
///
Unit TempUnit { get { return ambientCfg.TempUnit; } }
double TempLimLo { get { return Units.ConvertFrom(TempUnit, ambientCfg.TempLimLo); } }
double TempLimHi { get { return Units.ConvertFrom(TempUnit, ambientCfg.TempLimHi); } }
double DefaultTemperature { get { return Units.ConvertFrom(TempUnit, ambientCfg.DefaultTemp); } }
///
Unit PressureUnit { get { return ambientCfg.PressureUnit; } }
double PressureLimLo { get { return Units.ConvertFrom(PressureUnit, ambientCfg.PressureLimLo); } }
double PressureLimHi { get { return Units.ConvertFrom(PressureUnit, ambientCfg.PressureLimHi); } }
double DefaultPressure { get { return Units.ConvertFrom(PressureUnit, ambientCfg.DefaultPressure); } }
///
Unit HumiUnit { get { return ambientCfg.HumiUnit; } }
double HumiLimLo { get { return Units.ConvertFrom(HumiUnit, ambientCfg.HumiLimLo); } }
double HumiLimHi { get { return Units.ConvertFrom(HumiUnit, ambientCfg.HumiLimHi); } }
double DefaultHumidity { get { return Units.ConvertFrom(HumiUnit, ambientCfg.DefaultHumi); } }
///
/// IDrawingItCmpntWithMeasuredVal interface
///
public IDrawingItem DrawingItem { get { return ambientCfg as IDrawingItem; } }
public bool MsrmntAvailable { get { return true; } }
public double MeasuredVal { get { return temperature; } }
public string AltString
{
get {
return string.Format(ambientCfg.Format, Units.ConvertTo(TempUnit, temperature),
Units.ConvertTo(PressureUnit, pressure),
Units.ConvertTo(HumiUnit, humidity));
}
}
/// Private fields
SerialPort serialPort;
StringBuilder measurementBuilder;
/// <summary>The state of the measurement</summary>
MsrmntState msrmntState;
///
/// Measured values when MsrmntState == MsrmntState.Valid
///
double temperature; /// [°C]
double pressure; /// [bar]
double humidity; /// [R%]
/// <summary>Measurement time stamp when MsrmntState == MsrmntState.Valid</summary>
int msrmntTimeStamp;
public Ambient()
{
}
/// <summary>
/// Ambient temperature / humidity / pressure meter 'Greco' connected via serial interface (RS232)
/// Connection settings: 19200 Bd 8-bits No-parity 1-stop-bit Flow control: none or hardware.
/// </summary>
public Ambient(AmbientCfg cfg, IList<Generic.IComponent> components)
: this(cfg)
{
}
public Ambient(Generic.IComponentCfg cfg)
: base(cfg)
{
ambientCfg = cfg as AmbientCfg;
temperature = DefaultTemperature;
pressure = DefaultPressure;
humidity = DefaultHumidity;
log.Warn(this.ToString());
}
public void Initialize()
{
if (ambientCfg.DebugLevel == DebugMode.Simulate)
{
msrmntTimeStamp = StateMachine.Time;
msrmntState = MsrmntState.Valid;
return;
}
string comPortName = "COM" + ambientCfg.ComPortNr.ToString();
serialPort = new SerialPort(comPortName, ambientCfg.BaudRate, ambientCfg.Parity, ambientCfg.DataBits, ambientCfg.StopBits);
serialPort.Handshake = ambientCfg.Handshake;
serialPort.Open();
measurementBuilder = new StringBuilder(40);
msrmntState = MsrmntState.Busy;
log.FatalFormat("Successfully initialized device {0}", ToString());
}
/// <summary>Run this device</summary>
public void RunDeviceBefore()
{
if (ambientCfg.DebugLevel == DebugMode.Simulate ||
ambientCfg.DebugLevel == DebugMode.FailureDuringOperation)
{
msrmntTimeStamp = StateMachine.Time;
return;
}
try
{
measurementBuilder.Append(serialPort.ReadExisting());
int len = measurementBuilder.Length;
///
/// Device sends each 20 sec one line of ASCII text with data in the following format:
/// (temp) 6 characters, two decimal digits, with leading spaces
/// TAB 1 character
/// (humi) 6 characters, two decimal digits, with leading spaces
/// TAB 1 character
/// (pressure) 6 characters, one decimal digits, with leading spaces is LT 1000
/// CR + LF 2 characters
/// Example:
/// 23.42 38.08 1061.1
/// 23.39 38.04 1060.8
/// 23.39 38.08 1061.4
///
if (len >= 22)
{
string measurement = measurementBuilder.ToString();
measurementBuilder.Clear();
double t = 0;
double h = 0;
double p = 0;
if (double.TryParse(measurement.Substring(len - 22, 6), NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingWhite,
CultureInfo.InvariantCulture, out t) &&
measurement[len - 16] == '\t' &&
double.TryParse(measurement.Substring(len - 15, 6), NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingWhite,
CultureInfo.InvariantCulture, out h) &&
measurement[len - 9] == '\t' &&
double.TryParse(measurement.Substring(len - 8, 6), NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingWhite,
CultureInfo.InvariantCulture, out p) &&
measurement[len - 2] == '\r' &&
measurement[len - 1] == '\n')
{
temperature = t;
humidity = h;
pressure = p / 1000.0;
UpdateProcessData(temperature, pressure, humidity);
msrmntTimeStamp = StateMachine.Time;
msrmntState = MsrmntState.Valid;
log.InfoFormat("Ambient: temperature = {0:F1} C, humidity = {1:F1} %, pressure = {2:F0} mbar", temperature, humidity, 1000 * pressure);
}
else
{
log.Warn("Invalid string received: " + measurement);
}
}
}
catch (Exception e)
{
DebugLevel = DebugMode.FailureDuringOperation;
serialPort = null;
log.FatalFormat("Ambient: Serail port read failure : {0}", e.Message);
if (e.InnerException != null)
{
log.FatalFormat("InnerMessage : {0}", e.InnerException.Message);
}
}
}
/// <summary>Run this device</summary>
public void RunDeviceAfter()
{
}
/// <summary>Stop this device</summary>
public void StopDevice()
{
if (serialPort != null) serialPort.Close();
}
public void StopDevice2() { }
void UpdateProcessData(double temperature, double pressure, double humidity)
{
TBF.Rig.Sequences.ProcessData.AmbTemp.Val = temperature;
TBF.Rig.Sequences.ProcessData.AmbPress.Val = pressure;
TBF.Rig.Sequences.ProcessData.AmbHumi.Val = humidity;
}
///
/// Boxes for the operation result
///
DoubleBox tempBox;
DoubleBox pressureBox;
DoubleBox humiBox;
public IOperation ReadAmbientOp(DoubleBox temperature, DoubleBox pressure, DoubleBox humidity)
{
this.tempBox = temperature;
this.pressureBox = pressure;
this.humiBox = humidity;
return this;
}
/// <summary>Start this operation</summary>
public void Start()
{
if (tempBox != null) tempBox.Val = temperature;
if (pressureBox != null) pressureBox.Val = pressure;
if (humiBox != null) humiBox.Val = humidity;
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.FlowInDone or Event.FlowOutDone
/// </returns>
public Event Run()
{
if (tempBox != null) tempBox.Val = temperature;
if (pressureBox != null) pressureBox.Val = pressure;
if (humiBox != null) humiBox.Val = humidity;
return Event.AmbientDone;
}
/// <summary>Stop this operation</summary>
public void Stop() { }
}
}
+341
View File
@@ -0,0 +1,341 @@
///
/// Copyright (c) 2013-2021 Sensus Slovensko a.s.
///
using System;
using System.IO;
using System.Collections.Generic;
using System.IO.Ports;
using System.Xml.Serialization;
using Config;
using Config.Entities;
using SchematicDrawing;
using TBF.Rig.Generic;
namespace TBF.Rig.Ambient.Greco
{
public class AmbientCfg : ComponentCfgBase, Generic.IComponentCfg, IParamsProvider, IDrawingItemWithMeasuredVal
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(AmbientCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Component> cmpntEntities)
{
return new Configs.ParamsProvider.ComponentCfgCtrl(this, null);
}
///
/// Serialized parameters
///
public int ComPortNr; /// 0
public int BaudRate; /// 1
public Parity Parity; /// 2
public int DataBits; /// 3
public StopBits StopBits; /// 4
public Handshake Handshake; /// 5
public Unit TempUnit; /// 6
public double TempLimLo; /// 7
public double TempLimHi; /// 8
public double DefaultTemp; /// 9
public Unit PressureUnit; /// 10
public double PressureLimLo; /// 11
public double PressureLimHi; /// 12
public double DefaultPressure; /// 13
public Unit HumiUnit; /// 14
public double HumiLimLo; /// 15
public double HumiLimHi; /// 16
public double DefaultHumi; /// 17
public string Format; /// 18
/// Schematic drawing info
public Shape Shape { get; set; }
public int X { get; set; }
public int Y { get; set; }
public Sz Sz { get; set; }
public Orient Orient { get; set; }
public bool Flip { get; set; }
public int LblX { get; set; }
public int LblY { get; set; }
public Orient LblOrient { get; set; }
public int MsrdX { get; set; }
public int MsrdY { get; set; }
public Orient MsrdOrient { get; set; }
[XmlIgnore]
public string MsrdFormat { get { return string.Empty; } }
[XmlIgnore]
public Config.Unit MsrdUnit { get { return TempUnit; } }
[XmlIgnore]
public double MsrdValLimLo { get { return TempLimLo; } }
[XmlIgnore]
public double MsrdValLimHi { get { return TempLimHi; } }
[XmlIgnore]
public IList<GNode> GNodes { get; set; }
/// Private parameterless constructor invoked by all other (public) constructors
AmbientCfg()
{
GNodes = new List<GNode>();
Format = string.Empty;
}
public AmbientCfg(string name, IComponentFactory factory)
: this()
{
Shape = Shape.Ambient;
Sz = Sz.M;
Factory = factory;
Name = name;
ParentName = string.Empty;
InitializeAll();
}
public string ComponentName { get { return Name; } }
public void InitializeAll()
{
ComPortNr = 6;
BaudRate = 19200;
Parity = System.IO.Ports.Parity.None;
DataBits = 8;
StopBits = System.IO.Ports.StopBits.One;
Handshake = System.IO.Ports.Handshake.None;
TempUnit = Unit.C;
TempLimLo = 15;
TempLimHi = 30;
DefaultTemp = 25;
PressureUnit = Unit.hPa;
PressureLimLo = 960;
PressureLimHi = 1060;
DefaultPressure = 1013;
HumiUnit = Unit.RPct;
HumiLimLo = 20;
HumiLimHi = 80;
DefaultHumi = 50;
Format = "{0:F1} °C\n{1:F0} hPa\n{2:F0} R%";
MsrdY = 22;
}
string[] paramNames = new string[]
{
"Serial port number", /// 0
"Baud rate", /// 1
"Parity", /// 2
"Data bits", /// 3
"Stop bits", /// 4
"Handshake", /// 5
"Unit of temperature", /// 6
"Temperature limit Lo", /// 7
"Temperature limit Hi", /// 8
"Default temperature", /// 9
"Unit of pressure", /// 10
"Pressure limit Lo", /// 11
"Pressure limit Hi", /// 12
"Default pressure", /// 13
"Unit of rel. humidity", /// 14
"Rel. humidity limit Lo", /// 15
"Rel. humidity limit Hi", /// 16
"Default retl. humidity", /// 17
"Display format", /// 18
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
public ICollection<string> ParamValues(int i)
{
switch (i)
{
case 1:
return new string[] { "150", "300", "600", "1200", "2400", "4800", "9600",
"19200", "38400", "57600", "76800", "115200"};
case 2:
return new string[] { Parity.None.ToString(), Parity.Odd.ToString(), Parity.Even.ToString() };
case 3:
return new string[] { "7", "8" };
case 4:
return new string[] { StopBits.None.ToString(),
StopBits.One.ToString(),
StopBits.OnePointFive.ToString(),
StopBits.Two.ToString() };
case 5:
return new string[] { Handshake.None.ToString(),
Handshake.XOnXOff.ToString(),
Handshake.RequestToSend.ToString(),
Handshake.RequestToSendXOnXOff.ToString() };
case 6:
return new string[] { "°C", "°F", "K" };
case 10:
return new string[] { "Pa", "hPa", "mbar", "kPa", "inHg", "psi", "bar", "MPa" };
case 14:
return new string[] { "R%" };
default:
return null;
}
}
public string ToString(int i)
{
switch (i)
{
case 0: return ComPortNr.ToString();
case 1: return BaudRate.ToString();
case 2: return Parity.ToString();
case 3: return DataBits.ToString();
case 4: return StopBits.ToString();
case 5: return Handshake.ToString();
case 6: return TempUnit.ToDescription();
case 7: return TempLimLo.ToString();
case 8: return TempLimHi.ToString();
case 9: return DefaultTemp.ToString();
case 10: return PressureUnit.ToDescription();
case 11: return PressureLimLo.ToString();
case 12: return PressureLimHi.ToString();
case 13: return DefaultPressure.ToString();
case 14: return HumiUnit.ToDescription();
case 15: return HumiLimLo.ToString();
case 16: return HumiLimHi.ToString();
case 17: return DefaultHumi.ToString();
case 18: return Format.Replace("\n", "<LF>");
default:
return string.Format("{0} {1}[{2},{3}] Com{4}, {5}Bd, {6}-bits, parity={7}, stopBits={8}, {9}",
Name, Shape, X, Y, ComPortNr, BaudRate, DataBits, Parity, StopBits, Handshake);
}
}
public CfgUpdateFlags UpdateParam(int i, string str)
{
switch (i)
{
case 0: ComPortNr = int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 1: BaudRate = int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 2: Parity = TBF.Utils.GetParity(str); return CfgUpdateFlags.RestartRqrd;
case 3: DataBits = int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 4: StopBits = TBF.Utils.GetStopBits(str); return CfgUpdateFlags.RestartRqrd;
case 5: Handshake = TBF.Utils.GetHandshake(str); return CfgUpdateFlags.RestartRqrd;
case 6:
foreach (var u in new Unit[] { Unit.C, Unit.F, Unit.K })
{
if (str == u.ToDescription()) { TempUnit = u; return CfgUpdateFlags.RestartRqrd; }
}
return CfgUpdateFlags.None;
case 7: TempLimLo = Utils.ParseSDouble(str); return CfgUpdateFlags.RestartRqrd;
case 8: TempLimHi = Utils.ParseSDouble(str); return CfgUpdateFlags.RestartRqrd;
case 9: DefaultTemp = Utils.ParseSDouble(str); return CfgUpdateFlags.RestartRqrd;
case 10:
foreach (var u in new Unit[] { Unit.Pa, Unit.hPa, Unit.mbar, Unit.kPa, Unit.inHg, Unit.psi, Unit.bar, Unit.MPa })
{
if (str == u.ToDescription()) { PressureUnit = u; return CfgUpdateFlags.RestartRqrd; }
}
return CfgUpdateFlags.None;
case 11: PressureLimLo = Utils.ParseUDouble(str); return CfgUpdateFlags.RestartRqrd;
case 12: PressureLimHi = Utils.ParseUDouble(str); return CfgUpdateFlags.RestartRqrd;
case 13: DefaultPressure = Utils.ParseUDouble(str); return CfgUpdateFlags.RestartRqrd;
case 14:
foreach (var u in new Unit[] { Unit.RPct })
{
if (str == u.ToDescription()) { HumiUnit = u; return CfgUpdateFlags.RestartRqrd; }
}
return CfgUpdateFlags.None;
case 15: HumiLimLo = Utils.ParseUDouble(str); return CfgUpdateFlags.RestartRqrd;
case 16: HumiLimHi = Utils.ParseUDouble(str); return CfgUpdateFlags.RestartRqrd;
case 17: DefaultHumi = Utils.ParseUDouble(str); return CfgUpdateFlags.RestartRqrd;
case 18: Format = str.Replace("<LF>", "\n"); return CfgUpdateFlags.RestartRqrd;
default: return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string str, out string message)
{
message = string.Empty;
int idummy;
double dummy;
switch (i)
{
case 0:
if (int.TryParse(str, out idummy) && idummy > 0) return true;
break;
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 10:
case 14:
if (ParamValues(i).Contains(str)) return true;
break;
case 7:
case 8:
case 9:
if (TBF.Utils.TryParseSDouble(str, out dummy)) return true;
break;
case 11:
case 12:
case 13:
case 15:
case 16:
case 17:
if (TBF.Utils.TryParseUDouble(str, out dummy)) return true;
break;
case 18:
return true;
default:
message = "Invalid index";
return false;
}
message = ParamName(i) + " is invalid";
return false;
}
void CopyContentTo(AmbientCfg prms)
{
prms.ParentName = this.ParentName;
prms.Shape = this.Shape;
prms.Sz = this.Sz;
prms.Orient = this.Orient;
prms.Flip = this.Flip;
prms.LblX = this.LblX;
prms.LblY = this.LblY;
prms.LblOrient = this.LblOrient;
prms.MsrdX = this.MsrdX;
prms.MsrdY = this.MsrdY;
prms.MsrdOrient = this.MsrdOrient;
prms.ComPortNr = this.ComPortNr;
prms.BaudRate = this.BaudRate;
prms.Parity = this.Parity;
prms.DataBits = this.DataBits;
prms.StopBits = this.StopBits;
prms.Handshake = this.Handshake;
prms.TempUnit = this.TempUnit;
prms.TempLimLo = this.TempLimLo;
prms.TempLimHi = this.TempLimHi;
prms.DefaultTemp = this.DefaultTemp;
prms.PressureUnit = this.PressureUnit;
prms.PressureLimLo = this.PressureLimLo;
prms.PressureLimHi = this.PressureLimHi;
prms.DefaultPressure = this.DefaultPressure;
prms.HumiUnit = this.HumiUnit;
prms.HumiLimLo = this.HumiLimLo;
prms.HumiLimHi = this.HumiLimHi;
prms.DefaultHumi = this.DefaultHumi;
prms.Format = this.Format;
}
public Config.Entities.IParamsProvider Clone()
{
AmbientCfg pars = new AmbientCfg();
CopyContentTo(pars);
return pars;
}
public bool UpdateEmbeddedDbEntity()
{
return true; /// =OK, do nothing
}
}
}
+27
View File
@@ -0,0 +1,27 @@
///
/// Copyright (c) 2013-2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.Ambient.Greco
{
public class Factory : IComponentFactory
{
public string ClassName { get { return GetType().Namespace.Substring(8); } }
public override string ToString() { return ClassName; }
public void ResetStaticProperties() { Ambient.ResetStaticProperties(); }
public IComponent DummyComponent() { return new Ambient(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Ambient(cfg); }
public IComponentCfg DefaultConfig() { return new AmbientCfg("Ambient", this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(AmbientCfg.Serializer, component, this);
}
}
}
+62
View File
@@ -0,0 +1,62 @@
///
/// Copyright (c) 2013-2015 Sensus Metering Systems
///
using System.Collections.Generic;
using TBF.Rig.GenericDevices;
namespace TBF.Rig
{
public class BenchPath
{
public int ItemNr;
public string Name;
public float Qfrom;
public float Qto;
public ITempMeter TempMtrUp;
public ITempMeter TempMtrDown;
public IPressureMeter PressMtrUp;
public IPressureMeter PressMtrDown;
public IPressureMeter PressMtrDelta;
public IValve StopBFValve;
public IList<IValve> ValvesOpen;
public IList<IValve> ValvesClose;
/// Constructor from name, the rest is empty
public BenchPath(string name, int itemNr)
{
ItemNr = itemNr;
Name = name;
ValvesOpen = new List<IValve>();
ValvesClose = new List<IValve>();
}
/// Constructor from data entity
public BenchPath(Config.Entities.BenchPath entity, IList<Rig.Generic.IComponent> components)
: this(entity.Name, entity.ItemNr)
{
Qfrom = entity.Qfrom;
Qto = entity.Qto;
TempMtrUp = TbfComponents.FindComponent(entity.TempMtrUp, components) as ITempMeter;
TempMtrDown = TbfComponents.FindComponent(entity.TempMtrDown, components) as ITempMeter;
PressMtrUp = TbfComponents.FindComponent(entity.PressMtrUp, components) as IPressureMeter;
PressMtrDown = TbfComponents.FindComponent(entity.PressMtrDown, components) as IPressureMeter;
PressMtrDelta = TbfComponents.FindComponent(entity.PressMtrDelta, components) as IPressureMeter;
StopBFValve = TbfComponents.FindComponent(entity.StopBFValve, components) as IValve;
string[] vOpen = entity.ValvesOpen.Split(new char[] { ';' });
ValvesOpen = new List<IValve>();
foreach (var vName in vOpen) ValvesOpen.Add((IValve)TbfComponents.FindComponent(vName, components));
string[] vClose = entity.ValvesClose.Split(new char[] { ';' });
ValvesClose = new List<IValve>();
foreach (var vName in vClose) ValvesClose.Add((IValve)TbfComponents.FindComponent(vName, components));
}
public override string ToString()
{
return string.Format("{0} StopBF={1}",
Name,
(StopBFValve != null) ? StopBFValve.Name : "---");
}
}
}
+61
View File
@@ -0,0 +1,61 @@
///
/// Copyright (c) 2013-2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using Dirichlet.Numerics;
using log4net;
using TBF.Rig.ControlBoard;
namespace TBF.Rig.BuiltIn.Pump
{
public class Pump : ComponentBase, GenericDevices.IPump, GenericDevices.IValve, SchematicDrawing.IDrawingItCmpnt
{
private static readonly ILog log = LogManager.GetLogger(typeof(Pump));
public override string ToString() { return string.Format("Pump({0})", Cfg.ToString(1)); }
readonly PumpCfg pumpCfg;
public SchematicDrawing.IDrawingItem DrawingItem { get { return pumpCfg as SchematicDrawing.IDrawingItem; } }
public int Delay { get { return pumpCfg.Delay; } }
public ValveCategory Category { get { return ValveCategory.Feeding; } } /// Pump category is Feeding
public GenericDevices.IValve CoupledTo { get { return null; } }
public bool InvertCouple { get { return false; } }
public int LagOpening { get { return 0; } }
public int LagClosing { get { return 0; } }
public double Power { get { return State ? 100.0 : 0; } }
readonly IControlBoard controlBoard;
readonly int bitPosition; /// 0 .. 127
public readonly UInt128 Mask; /// derived from bitPosition in the constructor
public Pump()
{
}
public Pump(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
: base(cfg)
{
pumpCfg = cfg as PumpCfg;
controlBoard = TbfComponents.FindComponent(cfg.ParentName, components) as IControlBoard;
if (controlBoard == null) throw new Exception("Cannot find " + Name + " parent");
bitPosition = pumpCfg.BitNr;
Mask = (((UInt128)1) << pumpCfg.BitNr);
log.Warn(this.ToString());
}
public bool State
{
get { return (controlBoard.Route & Mask) != 0; }
}
}
}
+72
View File
@@ -0,0 +1,72 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
using System.Collections.Generic;
using System.Xml.Serialization;
using SchematicDrawing;
using TBF.Rig.Generic;
namespace TBF.Rig.BuiltIn.Pump
{
public class PumpCfg : ComponentCfgBase, IChildComponentCfg, IRouteBasedDrawingItem
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(PumpCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new PumpCfgCtrl(); }
///
/// Serialized parameters
///
public int BitNr { get; set; }
public bool Inverted { get; set; } /// When true the pump function is inverted: 0 = on, 1 = off
public int Delay;
public Shape Shape { get; set; }
public int X { get; set; }
public int Y { get; set; }
public Sz Sz { get; set; }
public Orient Orient { get; set; }
public bool Flip { get; set; }
public int LblX { get; set; }
public int LblY { get; set; }
public Orient LblOrient { get; set; }
[XmlIgnore]
public IList<GNode> GNodes { get; set; }
[XmlIgnore]
public IList<GEdge> EdgesToSet { get; set; }
/// Private parameterless constructor invoked by all other (public) constructors
PumpCfg()
{
GNodes = new List<GNode>();
EdgesToSet = new List<GEdge>();
}
public PumpCfg(IComponentFactory factory)
: this()
{
Shape = Shape.Pump;
Sz = Sz.M;
Factory = factory;
Name = "P";
ParentName = "CB";
BitNr = 0;
Delay = 1;
}
public string ToString(int i)
{
return string.Format("Name={0}, Parent={1}, Bit={2}, Delay={3}",
Name,
(string.IsNullOrEmpty(ParentName) ? "-" : ParentName),
BitNr,
Delay);
}
}
}
+156
View File
@@ -0,0 +1,156 @@
///
/// Copyright (c) 2013-2015 Sensus Metering Systems
///
namespace TBF.Rig.BuiltIn.Pump
{
partial class PumpCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.bitPositionTextBox = new System.Windows.Forms.TextBox();
this.bitPositionLabel = new System.Windows.Forms.Label();
this.parentNameLabel = new System.Windows.Forms.Label();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
this.classNameLabel = new System.Windows.Forms.Label();
this.parentNameComboBox = new System.Windows.Forms.ComboBox();
this.delayTextBox = new System.Windows.Forms.TextBox();
this.delayLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// bitPositionTextBox
//
this.bitPositionTextBox.Enabled = false;
this.bitPositionTextBox.Location = new System.Drawing.Point(122, 99);
this.bitPositionTextBox.Name = "bitPositionTextBox";
this.bitPositionTextBox.Size = new System.Drawing.Size(46, 20);
this.bitPositionTextBox.TabIndex = 6;
//
// bitPositionLabel
//
this.bitPositionLabel.AutoSize = true;
this.bitPositionLabel.Location = new System.Drawing.Point(36, 102);
this.bitPositionLabel.Name = "bitPositionLabel";
this.bitPositionLabel.Size = new System.Drawing.Size(59, 13);
this.bitPositionLabel.TabIndex = 5;
this.bitPositionLabel.Text = "Bit Position";
//
// parentNameLabel
//
this.parentNameLabel.AutoSize = true;
this.parentNameLabel.Location = new System.Drawing.Point(36, 76);
this.parentNameLabel.Name = "parentNameLabel";
this.parentNameLabel.Size = new System.Drawing.Size(69, 13);
this.parentNameLabel.TabIndex = 3;
this.parentNameLabel.Text = "Parent Name";
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(122, 47);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(130, 20);
this.nameTextBox.TabIndex = 2;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(36, 50);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 1;
this.nameLabel.Text = "Name";
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(119, 21);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
this.classNameLabel.TabIndex = 0;
this.classNameLabel.Text = "ComonentName";
//
// parentNameComboBox
//
this.parentNameComboBox.Enabled = false;
this.parentNameComboBox.FormattingEnabled = true;
this.parentNameComboBox.Location = new System.Drawing.Point(122, 73);
this.parentNameComboBox.Name = "parentNameComboBox";
this.parentNameComboBox.Size = new System.Drawing.Size(130, 21);
this.parentNameComboBox.TabIndex = 4;
//
// delayTextBox
//
this.delayTextBox.Enabled = false;
this.delayTextBox.Location = new System.Drawing.Point(122, 124);
this.delayTextBox.Name = "delayTextBox";
this.delayTextBox.Size = new System.Drawing.Size(46, 20);
this.delayTextBox.TabIndex = 8;
//
// delayLabel
//
this.delayLabel.AutoSize = true;
this.delayLabel.Location = new System.Drawing.Point(36, 127);
this.delayLabel.Name = "delayLabel";
this.delayLabel.Size = new System.Drawing.Size(48, 13);
this.delayLabel.TabIndex = 7;
this.delayLabel.Text = "Delay [s]";
//
// PumpCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.delayTextBox);
this.Controls.Add(this.delayLabel);
this.Controls.Add(this.parentNameComboBox);
this.Controls.Add(this.bitPositionTextBox);
this.Controls.Add(this.bitPositionLabel);
this.Controls.Add(this.parentNameLabel);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "PumpCfgCtrl";
this.Size = new System.Drawing.Size(300, 200);
this.Load += new System.EventHandler(this.PumpCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox bitPositionTextBox;
private System.Windows.Forms.Label bitPositionLabel;
private System.Windows.Forms.Label parentNameLabel;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label classNameLabel;
private System.Windows.Forms.ComboBox parentNameComboBox;
private System.Windows.Forms.TextBox delayTextBox;
private System.Windows.Forms.Label delayLabel;
}
}
+113
View File
@@ -0,0 +1,113 @@
///
/// Copyright (c) 2013-2015 Sensus Metering Systems
///
using System;
using System.Windows.Forms;
using Config.Entities;
using TBF.Rig.Generic;
using TBF.UI.Bench.Components;
namespace TBF.Rig.BuiltIn.Pump
{
public partial class PumpCfgCtrl : UserControl, IComponentCfgCtrl
{
ComponentParametersDlg parent;
public bool ShowMore { get { return false; } }
PumpCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as PumpCfg;
Redraw();
}
}
public PumpCfgCtrl()
{
InitializeComponent();
}
private void PumpCfgCtrl_Load(object sender, EventArgs e)
{
parent = ParentForm as ComponentParametersDlg;
if (parent == null) return;
if (parent.CmpntEntities != null)
{
foreach (var cmpnt in parent.CmpntEntities)
{
if (cmpnt.ClassName.Contains("ControlBoard"))
{
parentNameComboBox.Items.Add(cmpnt.Name);
}
}
}
Redraw();
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
parentNameComboBox.Text = string.IsNullOrEmpty(config.ParentName) ? "---" : config.ParentName;
bitPositionTextBox.Text = config.BitNr.ToString();
delayTextBox.Text = config.Delay.ToString();
}
public void Unlock()
{
nameTextBox.Enabled = true;
parentNameComboBox.Enabled = true;
bitPositionTextBox.Enabled = true;
delayTextBox.Enabled = true;
}
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
config.Name = nameTextBox.Text;
config.ParentName = parentNameComboBox.Text.Equals("---") ? string.Empty : parentNameComboBox.Text;
config.BitNr = int.Parse(bitPositionTextBox.Text);
config.Delay = int.Parse(delayTextBox.Text);
return flags;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
int dummy;
if (!parentNameComboBox.Items.Contains(parentNameComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Parent Name'";
}
if (!int.TryParse(bitPositionTextBox.Text, out dummy) || dummy < 0 || dummy >= 128)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Bit Position' should be between 0 and 127";
}
if (!int.TryParse(delayTextBox.Text, out dummy) || dummy < 0 || dummy >= 300 || (dummy % StateMachine.Period) != 0)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Delay' should be between 0 and 300s (5min)";
}
return flags;
}
}
}
+120
View File
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+27
View File
@@ -0,0 +1,27 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.BuiltIn.Pump
{
public class PumpFactory : IComponentFactory
{
public string ClassName { get { return "Pump"; } }
public override string ToString() { return ClassName; }
public void ResetStaticProperties() { Pump.ResetStaticProperties(); }
public IComponent DummyComponent() { return new Pump(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Pump(cfg, components); }
public IComponentCfg DefaultConfig() { return new PumpCfg(this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(PumpCfg.Serializer, component, this);
}
}
}
+179
View File
@@ -0,0 +1,179 @@
///
/// Copyright (c) 2013-2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using Dirichlet.Numerics;
using log4net;
using TBF.Rig.ControlBoard.Legacy;
namespace TBF.Rig.BuiltIn.PumpTandem
{
public class Pump : ComponentBase, GenericDevices.IPumpFM, GenericDevices.IValve, IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(Pump));
public override string ToString() { return string.Format("PumpTandem({0})", Cfg.ToString(1)); }
readonly PumpCfg pumpCfg;
readonly GenericDevices.IPump pump1;
readonly GenericDevices.IPump pump2;
readonly GenericDevices.IPumpFM pumpFm1;
readonly GenericDevices.IPumpFM pumpFm2;
public bool State { get { return pump1.State || pump2.State; } }
public int Delay { get { return Math.Max(pump1.Delay, pump2.Delay); } }
public ValveCategory Category { get { return ValveCategory.Feeding; } } /// Pump category is Feeding
public GenericDevices.IValve CoupledTo { get { return null; } }
public bool InvertCouple { get { return false; } }
public int LagOpening { get { return 0; } }
public int LagClosing { get { return 0; } }
/// <summary>
/// Pump power in [%] in range 0 .. 100.0
/// </summary>
public double Power
{
get { return (pump1.Power + pump2.Power) / 2; }
}
readonly UInt128 mask1;
readonly UInt128 mask2;
public UInt128 Mask { get { return mask1 | mask2; } } /// derived from masks of two pumps
public Pump()
{
}
public Pump(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
: base(cfg)
{
pumpCfg = cfg as PumpCfg;
pump1 = (GenericDevices.IPump)TbfComponents.FindComponent(pumpCfg.Pump1, components);
if (pump1 == null) throw new Exception("Cannot find component Pump 1");
pump2 = (GenericDevices.IPump)TbfComponents.FindComponent(pumpCfg.Pump2, components);
if (pump2 == null) throw new Exception("Cannot find component Pump 2");
pumpFm1 = pump1 as GenericDevices.IPumpFM;
pumpFm2 = pump2 as GenericDevices.IPumpFM;
if (pump1 is BuiltIn.Pump.Pump) { mask1 = (pump1 as BuiltIn.Pump.Pump).Mask; }
else if (pump1 is Elde.PumpWithFM.Pump) { mask1 = (pump1 as Elde.PumpWithFM.Pump).Mask; }
else if (pump1 is Danfoss.VLT2800.Pump) { mask1 = (pump1 as Danfoss.VLT2800.Pump).Mask; }
else { mask1 = 0; }
if (pump2 is BuiltIn.Pump.Pump) { mask2 = (pump2 as BuiltIn.Pump.Pump).Mask; }
else if (pump2 is Elde.PumpWithFM.Pump) { mask2 = (pump2 as Elde.PumpWithFM.Pump).Mask; }
else if (pump2 is Danfoss.VLT2800.Pump) { mask2 = (pump2 as Danfoss.VLT2800.Pump).Mask; }
else { mask2 = 0; }
log.Warn(this.ToString());
}
public void TurnOn(double powerArg)
{
if ((pumpFm1 != null) && (pumpFm2 != null))
{
pumpFm1.TurnOn(powerArg);
pumpFm2.TurnOn(powerArg);
}
else if ((pumpFm1 != null) && (pumpFm2 == null))
{
// TODO
if (powerArg >= 50)
{
pumpFm1.TurnOn(2 * (powerArg - 50.0));
//pump2.
}
else
{
pumpFm1.TurnOn(2 * powerArg);
//pump2.
}
// TODO
}
}
public void TurnOff()
{
if ((pumpFm1 != null) && (pumpFm2 != null))
{
pumpFm1.TurnOff();
pumpFm2.TurnOff();
}
else
{
// TODO
}
}
/// <summary>
/// The currently running operation.
/// </summary>
public enum CurrentOp
{
None,
TurnOn,
TurnOff,
}
///
CurrentOp currentOp;
double powerForOp;
/// <summary>
/// Turn the pump frequency inverter on.
/// </summary>
public IOperation TurnOnOp(double powerArg)
{
if (currentOp != CurrentOp.None) throw new Exception("Sequence error");
currentOp = CurrentOp.TurnOn;
powerForOp = powerArg;
return this;
}
/// <summary>
/// Turn the pump frequency inverter on.
/// </summary>
public IOperation TurnOffOp()
{
if (currentOp != CurrentOp.None) throw new Exception("Sequence error");
currentOp = CurrentOp.TurnOff;
return this;
}
/// <summary>Start the operation</summary>
public void Start()
{
switch (currentOp)
{
case CurrentOp.TurnOn:
TurnOn(powerForOp);
return;
case CurrentOp.TurnOff:
default:
TurnOff();
return;
}
}
/// <summary>Run the operation</summary>
public Event Run()
{
return Event.TurnPumpOnOffDone;
}
/// <summary>Stop the operation</summary>
public void Stop()
{
currentOp = CurrentOp.None;
}
}
}
+46
View File
@@ -0,0 +1,46 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
using System.Collections.Generic;
using System.Xml.Serialization;
using TBF.Rig.Generic;
namespace TBF.Rig.BuiltIn.PumpTandem
{
public class PumpCfg : ComponentCfgBase, IChildComponentCfg
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(PumpCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new PumpCfgCtrl(); }
///
/// Serialized parameters
///
public string Pump1; /// Name of the pump 1 component
public string Pump2; /// Name of the pump 2 component
/// Private parameterless constructor invoked by all other (public) constructors
PumpCfg()
{
Name = "PumpTandem";
ParentName = string.Empty;
Pump1 = string.Empty;
Pump2 = string.Empty;
}
public PumpCfg(IComponentFactory factory)
: this()
{
this.Factory = factory;
}
public string ToString(int i)
{
return string.Format("Name={0}, Pump1={1}, Pump2={2}",
Name,
string.IsNullOrEmpty(Pump1) ? "-" : Pump1,
string.IsNullOrEmpty(Pump2) ? "-" : Pump2);
}
}
}
+134
View File
@@ -0,0 +1,134 @@
///
/// Copyright (c) 2013-2015 Sensus Metering Systems
///
namespace TBF.Rig.BuiltIn.PumpTandem
{
partial class PumpCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
this.classNameLabel = new System.Windows.Forms.Label();
this.pump2ComboBox = new System.Windows.Forms.ComboBox();
this.pump2Label = new System.Windows.Forms.Label();
this.pump1ComboBox = new System.Windows.Forms.ComboBox();
this.pump1Label = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(140, 47);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(130, 20);
this.nameTextBox.TabIndex = 2;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(30, 50);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 1;
this.nameLabel.Text = "Name";
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(119, 21);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
this.classNameLabel.TabIndex = 0;
this.classNameLabel.Text = "ComonentName";
//
// pump2ComboBox
//
this.pump2ComboBox.Enabled = false;
this.pump2ComboBox.FormattingEnabled = true;
this.pump2ComboBox.Location = new System.Drawing.Point(140, 96);
this.pump2ComboBox.Name = "pump2ComboBox";
this.pump2ComboBox.Size = new System.Drawing.Size(130, 21);
this.pump2ComboBox.TabIndex = 12;
//
// pump2Label
//
this.pump2Label.AutoSize = true;
this.pump2Label.Location = new System.Drawing.Point(30, 99);
this.pump2Label.Name = "pump2Label";
this.pump2Label.Size = new System.Drawing.Size(43, 13);
this.pump2Label.TabIndex = 11;
this.pump2Label.Text = "Pump 2";
//
// pump1ComboBox
//
this.pump1ComboBox.Enabled = false;
this.pump1ComboBox.FormattingEnabled = true;
this.pump1ComboBox.Location = new System.Drawing.Point(140, 71);
this.pump1ComboBox.Name = "pump1ComboBox";
this.pump1ComboBox.Size = new System.Drawing.Size(130, 21);
this.pump1ComboBox.TabIndex = 10;
//
// pump1Label
//
this.pump1Label.AutoSize = true;
this.pump1Label.Location = new System.Drawing.Point(30, 74);
this.pump1Label.Name = "pump1Label";
this.pump1Label.Size = new System.Drawing.Size(43, 13);
this.pump1Label.TabIndex = 9;
this.pump1Label.Text = "Pump 1";
//
// PumpCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.pump2ComboBox);
this.Controls.Add(this.pump2Label);
this.Controls.Add(this.pump1ComboBox);
this.Controls.Add(this.pump1Label);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "PumpCfgCtrl";
this.Size = new System.Drawing.Size(300, 200);
this.Load += new System.EventHandler(this.PumpCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label classNameLabel;
private System.Windows.Forms.ComboBox pump2ComboBox;
private System.Windows.Forms.Label pump2Label;
private System.Windows.Forms.ComboBox pump1ComboBox;
private System.Windows.Forms.Label pump1Label;
}
}
+108
View File
@@ -0,0 +1,108 @@
///
/// Copyright (c) 2013-2015 Sensus Metering Systems
///
using System;
using System.Windows.Forms;
using Config.Entities;
using TBF.Rig.Generic;
using TBF.UI.Bench.Components;
namespace TBF.Rig.BuiltIn.PumpTandem
{
public partial class PumpCfgCtrl : UserControl, IComponentCfgCtrl
{
ComponentParametersDlg parentDlg;
public bool ShowMore { get { return false; } }
PumpCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as PumpCfg;
Redraw();
}
}
public PumpCfgCtrl()
{
InitializeComponent();
}
private void PumpCfgCtrl_Load(object sender, EventArgs e)
{
parentDlg = ParentForm as ComponentParametersDlg;
if (parentDlg == null) return;
if (parentDlg.CmpntEntities != null)
{
foreach (var cmpnt in parentDlg.CmpntEntities)
{
if (TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is BuiltIn.Pump.PumpFactory ||
TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is Elde.PumpWithFM.PumpFactory ||
TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is Danfoss.VLT2800.PumpFactory ||
TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is BuiltIn.PumpTandem.PumpFactory)
{
pump1ComboBox.Items.Add(cmpnt.Name);
pump2ComboBox.Items.Add(cmpnt.Name);
}
}
}
Redraw();
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
pump1ComboBox.Text = string.IsNullOrEmpty(config.Pump1) ? "---" : config.Pump1;
pump2ComboBox.Text = string.IsNullOrEmpty(config.Pump2) ? "---" : config.Pump2;
}
public void Unlock()
{
nameTextBox.Enabled = true;
pump1ComboBox.Enabled = true;
pump2ComboBox.Enabled = true;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
if (!pump1ComboBox.Items.Contains(pump1ComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Pump 1'";
}
if (!pump2ComboBox.Items.Contains(pump2ComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Pump 2'";
}
return flags;
}
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
config.Name = nameTextBox.Text;
config.Pump1 = pump1ComboBox.Text.Equals("---") ? string.Empty : pump1ComboBox.Text;
config.Pump2 = pump2ComboBox.Text.Equals("---") ? string.Empty : pump2ComboBox.Text;
return flags;
}
}
}
+120
View File
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+27
View File
@@ -0,0 +1,27 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.BuiltIn.PumpTandem
{
public class PumpFactory : IComponentFactory
{
public string ClassName { get { return "PumpTandem"; } }
public override string ToString() { return ClassName; }
public void ResetStaticProperties() { Pump.ResetStaticProperties(); }
public IComponent DummyComponent() { return new Pump(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Pump(cfg, components); }
public IComponentCfg DefaultConfig() { return new PumpCfg(this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(PumpCfg.Serializer, component, this);
}
}
}
+325
View File
@@ -0,0 +1,325 @@
///
/// Copyright (c) 2013-2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using Dirichlet.Numerics;
using TBF.Rig.ControlBoard;
using TBF.Rig.GenericDevices;
namespace TBF.Rig.BuiltIn
{
public class SetValvesOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(SetValvesOp));
/// Set by the constructor
IControlBoard controlBoard;
class SwitchPoint
{
public int TimeSec; /// Relative time in [s] from the start of the operation
public IList<IValve> VOpen; /// List of valves to open in this point of time
public IList<IValve> VClose; /// List of valves to close in this point of time
public UInt128 MasksOpen; /// OR-ed bitmasks of valves to open in this point of time
public UInt128 MasksClose; /// OR-ed bitmasks of valves to close in this point of time
public SwitchPoint(int time, IList<IValve> vOpen, IList<IValve> vClose)
{
this.TimeSec = time;
this.VOpen = (vOpen == null) ? new List<IValve>() : vOpen;
this.VClose = (vClose == null) ? new List<IValve>() : vClose;
}
/// <summary>
/// Max. delay of all valves that were opened or closed
/// </summary>
/// <param name="changed">'ulong' with bits of valves that were actually changed set ot '1'</param>
/// <returns>Delay in [s]</returns>
public int MaxDelay(UInt128 changed)
{
int max = 0;
foreach (var vlv in VOpen)
{
/// Skip the delay evaluation and update in case the valve/pump have not changed
if (vlv is Valve.Valve && ((vlv as Valve.Valve).Mask & changed) == 0) continue;
if (vlv is Pump.Pump && ((vlv as Pump.Pump).Mask & changed) == 0) continue;
if (vlv is Elde.PumpWithFM.Pump && ((vlv as Elde.PumpWithFM.Pump).Mask & changed) == 0) continue;
if (vlv is Danfoss.VLT2800.Pump && ((vlv as Danfoss.VLT2800.Pump).Mask & changed) == 0) continue;
if (vlv is Modbus.PumpFM.DanfossVLT.Pump && ((vlv as Modbus.PumpFM.DanfossVLT.Pump).Mask & changed) == 0) continue;
if ((vlv != null) && (vlv.Delay > max)) max = vlv.Delay;
}
foreach (var vlv in VClose)
{
/// Skip the delay evaluation and update in case the valve/pump have not changed
if (vlv is Valve.Valve && ((vlv as Valve.Valve).Mask & changed) == 0) continue;
if (vlv is Pump.Pump && ((vlv as Pump.Pump).Mask & changed) == 0) continue;
if (vlv is Elde.PumpWithFM.Pump && ((vlv as Elde.PumpWithFM.Pump).Mask & changed) == 0) continue;
if (vlv is Danfoss.VLT2800.Pump && ((vlv as Danfoss.VLT2800.Pump).Mask & changed) == 0) continue;
if (vlv is Modbus.PumpFM.DanfossVLT.Pump && ((vlv as Modbus.PumpFM.DanfossVLT.Pump).Mask & changed) == 0) continue;
if ((vlv != null) && (vlv.Delay > max)) max = vlv.Delay;
}
return max;
}
}
IList<SwitchPoint> switchPointsRaw;
IList<SwitchPoint> switchPoints;
int nextIx;
int swStartTime;
int maxDelayTime; /// Max. delay from all valve/pump switches.
/// Relative time in [s] from the start of the operation
/// <summary>
/// Processes coupled valves and creates switch points.
/// </summary>
/// <param name="valvesOpen">A list of opening master valves</param>
/// <param name="valvesClose">A list of closing master valves</param>
/// <returns></returns>
IList<SwitchPoint> AddSwitchPoints(IList<SwitchPoint> swPoints, IList<IValve> valvesOpen, IList<IValve> valvesClose, int time)
{
int ix0 = swPoints.Count;
swPoints.Add(new SwitchPoint(time, valvesOpen, valvesClose));
foreach (var valve in StateMachine.CoupledValves)
{
if ((!valve.InvertCouple && valvesOpen.Contains(valve.CoupledTo)) ||
(valve.InvertCouple && valvesClose.Contains(valve.CoupledTo)))
{
/// The coupled valve 'valve' is opening
int lag = time + valve.LagOpening;
if (lag == time)
{
swPoints[ix0].VOpen.Add(valve);
}
else
{
swPoints.Add(new SwitchPoint(lag, ValveBase.MakeList(valve), null));
}
}
else if ((!valve.InvertCouple && valvesClose.Contains(valve.CoupledTo)) ||
(valve.InvertCouple && valvesOpen.Contains(valve.CoupledTo)))
{
/// The coupled valve 'valve' is closing
int lag = time + valve.LagClosing;
if (lag == time)
{
swPoints[ix0].VClose.Add(valve);
}
else
{
swPoints.Add(new SwitchPoint(lag, null, ValveBase.MakeList(valve)));
}
}
}
return swPoints;
}
IList<SwitchPoint> SortAndMergeSwitchPoints(IList<SwitchPoint> unsorted)
{
IList<SwitchPoint> result = new List<SwitchPoint>();
SwitchPoint lastAdded = null;
while (unsorted.Count > 0)
{
SwitchPoint first = null;
foreach (var point in unsorted)
{
if (first == null || first.TimeSec > point.TimeSec) first = point;
}
if (lastAdded == null || lastAdded.TimeSec != first.TimeSec)
{
result.Add(first);
lastAdded = first;
}
else
{
lastAdded.VOpen = ValveBase.Merge(lastAdded.VOpen, first.VOpen);
lastAdded.VClose = ValveBase.Merge(lastAdded.VClose, first.VClose);
}
unsorted.Remove(first);
}
return result;
}
void MakeMasks(IList<SwitchPoint> switchPoints, int timeShift)
{
foreach (var point in switchPoints)
{
/// Only Elde.Valve valves are used, other valves are ignored
point.MasksOpen = 0;
foreach (var valve in point.VOpen)
{
if (valve is Valve.Valve) point.MasksOpen |= (valve as Valve.Valve).Mask;
if (valve is Pump.Pump) point.MasksOpen |= (valve as Pump.Pump).Mask;
if (valve is Elde.PumpWithFM.Pump) point.MasksOpen |= (valve as Elde.PumpWithFM.Pump).Mask;
if (valve is Danfoss.VLT2800.Pump) point.MasksOpen |= (valve as Danfoss.VLT2800.Pump).Mask;
if (valve is Modbus.PumpFM.DanfossVLT.Pump) point.MasksOpen |= (valve as Modbus.PumpFM.DanfossVLT.Pump).Mask;
if (valve is PumpTandem.Pump) point.MasksOpen |= (valve as PumpTandem.Pump).Mask;
}
point.MasksClose = 0;
foreach (var valve in point.VClose)
{
if (valve is Valve.Valve) point.MasksClose |= (valve as Valve.Valve).Mask;
if (valve is Pump.Pump) point.MasksClose |= (valve as Pump.Pump).Mask;
if (valve is Elde.PumpWithFM.Pump) point.MasksClose |= (valve as Elde.PumpWithFM.Pump).Mask;
if (valve is Danfoss.VLT2800.Pump) point.MasksClose |= (valve as Danfoss.VLT2800.Pump).Mask;
if (valve is Modbus.PumpFM.DanfossVLT.Pump) point.MasksClose |= (valve as Modbus.PumpFM.DanfossVLT.Pump).Mask;
if (valve is PumpTandem.Pump) point.MasksClose |= (valve as PumpTandem.Pump).Mask;
}
point.TimeSec += timeShift;
}
}
/// <summary>
/// Open and/or close multiple valves.
/// Events: ValvesSet
/// </summary>
/// <param name="cb">Control board device</param>
/// <param name="valvesOpen">A list of opening master valves</param>
/// <param name="valvesClose">A list of closing master valves</param>
/// <remarks>Only Elde.Valve valves are used, other valves on the lists are ignored</remarks>
public SetValvesOp(IControlBoard cb, IList<IValve> valvesOpen, IList<IValve> valvesClose)
{
controlBoard = cb;
if (controlBoard == null) throw new ArgumentNullException("ctrlBoard");
if (valvesOpen == null) valvesOpen = new List<IValve>();
if (valvesClose == null) valvesClose = new List<IValve>();
switchPointsRaw = new List<SwitchPoint>();
AddSwitchPoints(switchPointsRaw, valvesOpen, valvesClose, 0);
switchPoints = SortAndMergeSwitchPoints(switchPointsRaw);
int timeShift = -switchPoints[0].TimeSec;
MakeMasks(switchPoints, timeShift);
}
/// <summary>
/// Open one valve and/or close one valve.
/// Events: ValvesSet
/// </summary>
/// <param name="cb">Control board device</param>
/// <param name="valveOpen">Valve to be opened</param>
/// <param name="valveClose">Valve to be closed</param>
/// <remarks>Only Elde.Valve valves are used, other valves on the lists are ignored</remarks>
public SetValvesOp(IControlBoard cb, IValve valveOpen, IValve valveClose)
: this(cb, ValveBase.MakeList(valveOpen), ValveBase.MakeList(valveClose))
{
}
/// <summary>
/// OPEN or CLOSE start/stop valve and associated valves and/or pumps.
/// Events: ValvesSet
/// </summary>
/// <param name="controlBoard">Control board device</param>
/// <param name="open">true: open start valve, false: close start valve</param>
/// <param name="outPath">OutputPath specifying the start valve and associated valves/pumps</param>
/// <remarks>Only Elde.Valve valves are used, other valves on the lists are ignored</remarks>
public SetValvesOp(IControlBoard cb, bool open, OutputPath outPath)
{
controlBoard = cb;
if (controlBoard == null) throw new ArgumentNullException("ctrlBoard");
IList<IValve> none = new List<IValve>(); /// An empty list of valves
switchPointsRaw = new List<SwitchPoint>();
if (open)
{
if (outPath.InvertSV1)
AddSwitchPoints(switchPointsRaw, none, ValveBase.MakeList(outPath.StartValve1), 0); /// close SV1
else
AddSwitchPoints(switchPointsRaw, ValveBase.MakeList(outPath.StartValve1), none, 0); /// open SV1
if (outPath.StartValve2 != null)
{
if (outPath.InvertSV2)
AddSwitchPoints(switchPointsRaw, none, ValveBase.MakeList(outPath.StartValve2), -outPath.LagSV2); /// close SV2 after lag
else
AddSwitchPoints(switchPointsRaw, ValveBase.MakeList(outPath.StartValve2), none, -outPath.LagSV2); /// open SV2 after lag
}
if (outPath.StartValve3 != null)
{
if (outPath.InvertSV3)
AddSwitchPoints(switchPointsRaw, none, ValveBase.MakeList(outPath.StartValve3), -outPath.LagSV3); /// close SV3 after lag
else
AddSwitchPoints(switchPointsRaw, ValveBase.MakeList(outPath.StartValve3), none, -outPath.LagSV3); /// open SV3 after lag
}
}
else
{
if (outPath.InvertSV1)
AddSwitchPoints(switchPointsRaw, ValveBase.MakeList(outPath.StartValve1), none, 0); /// open SV1
else
AddSwitchPoints(switchPointsRaw, none, ValveBase.MakeList(outPath.StartValve1), 0); /// close SV1
if (outPath.StartValve2 != null)
{
if (outPath.InvertSV2)
AddSwitchPoints(switchPointsRaw, ValveBase.MakeList(outPath.StartValve2), none, outPath.LagSV2); /// open SV2 after lag
else
AddSwitchPoints(switchPointsRaw, none, ValveBase.MakeList(outPath.StartValve2), outPath.LagSV2); /// close SV2 after lag
}
if (outPath.StartValve3 != null)
{
if (outPath.InvertSV3)
AddSwitchPoints(switchPointsRaw, ValveBase.MakeList(outPath.StartValve3), none, outPath.LagSV3); /// open SV3 after lag
else
AddSwitchPoints(switchPointsRaw, none, ValveBase.MakeList(outPath.StartValve3), outPath.LagSV3); /// close SV3 after lag
}
}
switchPoints = SortAndMergeSwitchPoints(switchPointsRaw);
int timeShift = -switchPoints[0].TimeSec;
MakeMasks(switchPoints, timeShift);
}
/// <summary>Start this operation</summary>
public void Start()
{
UInt128 changed = controlBoard.SetValves(switchPoints[0].MasksOpen, switchPoints[0].MasksClose, StateMachine.ExtendedValves);
swStartTime = StateMachine.Time;
maxDelayTime = switchPoints[0].MaxDelay(changed);
nextIx = 1;
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.SetValvesDone
/// </returns>
public Event Run()
{
if (nextIx >= switchPoints.Count)
{
return (StateMachine.Time >= swStartTime + maxDelayTime) ? Event.ValvesSet : Event.ValvesBusy;
}
if (StateMachine.Time >= swStartTime + switchPoints[nextIx].TimeSec)
{
UInt128 changed = controlBoard.SetValves(switchPoints[nextIx].MasksOpen, switchPoints[nextIx].MasksClose, StateMachine.ExtendedValves);
int nextDelay = switchPoints[nextIx].MaxDelay(changed);
if (switchPoints[nextIx].TimeSec + nextDelay > maxDelayTime)
{
maxDelayTime = switchPoints[nextIx].TimeSec + nextDelay;
}
nextIx++;
}
return Event.ValvesBusy;
}
/// <summary>Start this operation</summary>
public void Stop()
{
}
}
}
+103
View File
@@ -0,0 +1,103 @@
///
/// Copyright (c) 2013-2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using Dirichlet.Numerics;
using log4net;
using TBF.Rig.GenericDevices;
namespace TBF.Rig.BuiltIn.Valve
{
/// <summary>
/// Plain valve, open/close state is controlled by 1 bit from the route
/// </summary>
public class Valve : ValveBase, IValve, SchematicDrawing.IDrawingItCmpnt
{
private static readonly ILog log = LogManager.GetLogger(typeof(Valve));
public override string ToString() { return string.Format("Valve({0})", Cfg.ToString(1)); }
readonly ValveCfg valveCfg;
public SchematicDrawing.IDrawingItem DrawingItem { get { return valveCfg as SchematicDrawing.IDrawingItem; } }
readonly TBF.Rig.ControlBoard.IControlBoard controlBoard;
public ValveCategory Category { get { return valveCfg.Category; } }
public int Delay { get { return valveCfg.OpenCloseTime; } }
public bool Inverted { get { return valveCfg.Inverted; } }
public IValve CoupledTo { get { return coupledTo; } }
readonly IValve coupledTo;
public bool InvertCouple { get { return valveCfg.InvertCouple; } }
public int LagOpening { get { return valveCfg.LagOpening; } }
public int LagClosing { get { return valveCfg.LagClosing; } }
public readonly UInt128 Mask; /// derived from bitPosition in the constructor
public int BitPosition { get { return valveCfg.BitNr; } }
public Valve()
{
}
public Valve(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
: base(cfg)
{
valveCfg = cfg as ValveCfg;
controlBoard = TbfComponents.FindComponent(cfg.ParentName, components) as TBF.Rig.ControlBoard.IControlBoard;
if (controlBoard == null) throw new Exception("Cannot find " + Name + " parent");
if (valveCfg.BitNr < 0 || valveCfg.BitNr >= 128)
{
throw new ArgumentOutOfRangeException("position");
}
this.Mask = (((UInt128)1) << valveCfg.BitNr);
if (valveCfg.CoupledToName != null)
{
coupledTo = (IValve)TbfComponents.FindComponent(valveCfg.CoupledToName, components);
}
log.Warn(this.ToString());
}
public bool State
{
get { return (controlBoard.Route & Mask) != 0; }
}
#region Configuration Change Handling
public static void OnCfgChange(object sender, CfgChangeArgs args)
{
if (CfgChangeHandler == null) return;
try { CfgChangeHandler(sender, args); }
catch (Exception e) { log.Error("CfgChangeHandler(...) failed", e); }
}
public static event EventHandler<CfgChangeArgs> CfgChangeHandler;
public override void StartChangeHandler()
{
CfgChangeHandler += delegate(object sender, CfgChangeArgs args)
{
ValveCfg tmpcfg = args.Cfg as ValveCfg;
if (tmpcfg != null && tmpcfg.Name.Equals(Name))
{
if (args.Command == CfgChangeCmd.CfgChange)
{
valveCfg.OpenCloseTime = tmpcfg.OpenCloseTime;
valveCfg.LagOpening = tmpcfg.LagOpening;
valveCfg.LagClosing = tmpcfg.LagClosing;
}
}
};
}
#endregion Configuration Change Handling
}
}
+94
View File
@@ -0,0 +1,94 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
using System.Collections.Generic;
using System.Xml.Serialization;
using SchematicDrawing;
using TBF.Rig.Generic;
namespace TBF.Rig.BuiltIn.Valve
{
public class ValveCfg : ComponentCfgBase, IChildComponentCfg, IRouteBasedDrawingItem
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(ValveCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new ValveCfgCtrl(); }
///
/// Serialized parameters
///
public int BitNr { get; set; } /// Bit-position
public bool Inverted { get; set; } /// When true the valve function is inverted: 0 = open, 1 = closed
public ValveCategory Category; /// None, Feeding, Bench or Output
public int OpenCloseTime; /// Delay for SetValvesOp operations
///
public string CoupledToName; /// Name of the coupled valve or null
public bool InvertCouple; /// The coupled valve has inverted position
public int LagOpening; /// Delay (referred to the master valve) when opening this valve in [s]
public int LagClosing; /// Delay (referred to the master valve) when closing this valve in [s]
/// Negative values of delays mean an earlier function of the coupled valve.
/// Schematic drawing info
public Shape Shape { get; set; }
public int X { get; set; }
public int Y { get; set; }
public Sz Sz { get; set; }
public Orient Orient { get; set; }
public bool Flip { get; set; }
public int LblX { get; set; }
public int LblY { get; set; }
public Orient LblOrient { get; set; }
[XmlIgnore]
public IList<GNode> GNodes { get; set; }
[XmlIgnore]
public IList<GEdge> EdgesToSet { get; set; }
/// Private parameterless constructor invoked by all other (public) constructors
ValveCfg()
{
GNodes = new List<GNode>();
EdgesToSet = new List<GEdge>();
}
public ValveCfg(IComponentFactory factory)
: this()
{
Shape = Shape.Valve;
Sz = Sz.M;
Factory = factory;
Name = "V";
ParentName = "UniCB";
BitNr = 0;
Category = ValveCategory.None;
OpenCloseTime = 1;
Inverted = false;
CoupledToName = string.Empty;
InvertCouple = false;
LagOpening = 0;
LagClosing = 0;
}
public string ToString(int i)
{
return string.Format("{0}({1}) {2}[{3},{4}] bit={5} inv={6} delay={7}s cat={8} coupled to={9} inv.couple={10} lagO={11}s lagC={12}s",
Name,
string.IsNullOrEmpty(ParentName) ? "-" : ParentName,
Shape,
X,
Y,
BitNr,
Inverted ? "yes" : "no",
OpenCloseTime,
Category,
string.IsNullOrEmpty(CoupledToName) ? "-" : CoupledToName,
InvertCouple ? "yes" : "no",
LagOpening,
LagClosing);
}
}
}
+293
View File
@@ -0,0 +1,293 @@
///
/// Copyright (c) 2013-2015 Sensus Metering Systems
///
namespace TBF.Rig.BuiltIn.Valve
{
partial class ValveCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.bitPositionTextBox = new System.Windows.Forms.TextBox();
this.bitPositionLabel = new System.Windows.Forms.Label();
this.parentNameLabel = new System.Windows.Forms.Label();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
this.classNameLabel = new System.Windows.Forms.Label();
this.coupledToLabel = new System.Windows.Forms.Label();
this.invertCoupleCheckBox = new System.Windows.Forms.CheckBox();
this.parentNameComboBox = new System.Windows.Forms.ComboBox();
this.lagOpeningLabel = new System.Windows.Forms.Label();
this.lagClosingLabel = new System.Windows.Forms.Label();
this.lagOpeningTextBox = new System.Windows.Forms.TextBox();
this.lagClosingTextBox = new System.Windows.Forms.TextBox();
this.coupledToComboBox = new System.Windows.Forms.ComboBox();
this.categoryLabel = new System.Windows.Forms.Label();
this.categoryComboBox = new System.Windows.Forms.ComboBox();
this.openCloseTimeTextBox = new System.Windows.Forms.TextBox();
this.openCloseTimeLabel = new System.Windows.Forms.Label();
this.invertedCheckBox = new System.Windows.Forms.CheckBox();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// bitPositionTextBox
//
this.bitPositionTextBox.Enabled = false;
this.bitPositionTextBox.Location = new System.Drawing.Point(158, 99);
this.bitPositionTextBox.Name = "bitPositionTextBox";
this.bitPositionTextBox.Size = new System.Drawing.Size(81, 20);
this.bitPositionTextBox.TabIndex = 8;
//
// bitPositionLabel
//
this.bitPositionLabel.AutoSize = true;
this.bitPositionLabel.Location = new System.Drawing.Point(42, 102);
this.bitPositionLabel.Name = "bitPositionLabel";
this.bitPositionLabel.Size = new System.Drawing.Size(58, 13);
this.bitPositionLabel.TabIndex = 7;
this.bitPositionLabel.Text = "Bit position";
//
// parentNameLabel
//
this.parentNameLabel.AutoSize = true;
this.parentNameLabel.Location = new System.Drawing.Point(42, 54);
this.parentNameLabel.Name = "parentNameLabel";
this.parentNameLabel.Size = new System.Drawing.Size(67, 13);
this.parentNameLabel.TabIndex = 3;
this.parentNameLabel.Text = "Parent name";
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(158, 28);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(132, 20);
this.nameTextBox.TabIndex = 2;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(42, 31);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 1;
this.nameLabel.Text = "Name";
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(156, 8);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
this.classNameLabel.TabIndex = 0;
this.classNameLabel.Text = "ComonentName";
//
// coupledToLabel
//
this.coupledToLabel.AutoSize = true;
this.coupledToLabel.Location = new System.Drawing.Point(42, 125);
this.coupledToLabel.Name = "coupledToLabel";
this.coupledToLabel.Size = new System.Drawing.Size(52, 13);
this.coupledToLabel.TabIndex = 10;
this.coupledToLabel.Text = "Copled to";
//
// invertCoupleCheckBox
//
this.invertCoupleCheckBox.AutoSize = true;
this.invertCoupleCheckBox.Enabled = false;
this.invertCoupleCheckBox.Location = new System.Drawing.Point(248, 124);
this.invertCoupleCheckBox.Name = "invertCoupleCheckBox";
this.invertCoupleCheckBox.Size = new System.Drawing.Size(53, 17);
this.invertCoupleCheckBox.TabIndex = 12;
this.invertCoupleCheckBox.Text = "Invert";
this.invertCoupleCheckBox.UseVisualStyleBackColor = true;
//
// parentNameComboBox
//
this.parentNameComboBox.Enabled = false;
this.parentNameComboBox.FormattingEnabled = true;
this.parentNameComboBox.Location = new System.Drawing.Point(158, 51);
this.parentNameComboBox.Name = "parentNameComboBox";
this.parentNameComboBox.Size = new System.Drawing.Size(132, 21);
this.parentNameComboBox.TabIndex = 4;
//
// lagOpeningLabel
//
this.lagOpeningLabel.AutoSize = true;
this.lagOpeningLabel.Location = new System.Drawing.Point(16, 47);
this.lagOpeningLabel.Name = "lagOpeningLabel";
this.lagOpeningLabel.Size = new System.Drawing.Size(162, 13);
this.lagOpeningLabel.TabIndex = 15;
this.lagOpeningLabel.Text = "Lag when opening coupled v. [s]";
//
// lagClosingLabel
//
this.lagClosingLabel.AutoSize = true;
this.lagClosingLabel.Location = new System.Drawing.Point(16, 70);
this.lagClosingLabel.Name = "lagClosingLabel";
this.lagClosingLabel.Size = new System.Drawing.Size(157, 13);
this.lagClosingLabel.TabIndex = 17;
this.lagClosingLabel.Text = "Lag when closing coupled v. [s]";
//
// lagOpeningTextBox
//
this.lagOpeningTextBox.Enabled = false;
this.lagOpeningTextBox.Location = new System.Drawing.Point(184, 44);
this.lagOpeningTextBox.Name = "lagOpeningTextBox";
this.lagOpeningTextBox.Size = new System.Drawing.Size(81, 20);
this.lagOpeningTextBox.TabIndex = 16;
//
// lagClosingTextBox
//
this.lagClosingTextBox.Enabled = false;
this.lagClosingTextBox.Location = new System.Drawing.Point(184, 67);
this.lagClosingTextBox.Name = "lagClosingTextBox";
this.lagClosingTextBox.Size = new System.Drawing.Size(81, 20);
this.lagClosingTextBox.TabIndex = 18;
//
// coupledToComboBox
//
this.coupledToComboBox.Enabled = false;
this.coupledToComboBox.FormattingEnabled = true;
this.coupledToComboBox.Location = new System.Drawing.Point(158, 122);
this.coupledToComboBox.Name = "coupledToComboBox";
this.coupledToComboBox.Size = new System.Drawing.Size(81, 21);
this.coupledToComboBox.TabIndex = 11;
//
// categoryLabel
//
this.categoryLabel.AutoSize = true;
this.categoryLabel.Location = new System.Drawing.Point(42, 78);
this.categoryLabel.Name = "categoryLabel";
this.categoryLabel.Size = new System.Drawing.Size(49, 13);
this.categoryLabel.TabIndex = 5;
this.categoryLabel.Text = "Category";
//
// categoryComboBox
//
this.categoryComboBox.Enabled = false;
this.categoryComboBox.FormattingEnabled = true;
this.categoryComboBox.Location = new System.Drawing.Point(158, 75);
this.categoryComboBox.Name = "categoryComboBox";
this.categoryComboBox.Size = new System.Drawing.Size(132, 21);
this.categoryComboBox.TabIndex = 6;
//
// openCloseTimeTextBox
//
this.openCloseTimeTextBox.Enabled = false;
this.openCloseTimeTextBox.Location = new System.Drawing.Point(184, 21);
this.openCloseTimeTextBox.Name = "openCloseTimeTextBox";
this.openCloseTimeTextBox.Size = new System.Drawing.Size(81, 20);
this.openCloseTimeTextBox.TabIndex = 14;
//
// openCloseTimeLabel
//
this.openCloseTimeLabel.AutoSize = true;
this.openCloseTimeLabel.Location = new System.Drawing.Point(16, 24);
this.openCloseTimeLabel.Name = "openCloseTimeLabel";
this.openCloseTimeLabel.Size = new System.Drawing.Size(99, 13);
this.openCloseTimeLabel.TabIndex = 13;
this.openCloseTimeLabel.Text = "Open/close time [s]";
//
// invertedCheckBox
//
this.invertedCheckBox.AutoSize = true;
this.invertedCheckBox.Enabled = false;
this.invertedCheckBox.Location = new System.Drawing.Point(248, 101);
this.invertedCheckBox.Name = "invertedCheckBox";
this.invertedCheckBox.Size = new System.Drawing.Size(65, 17);
this.invertedCheckBox.TabIndex = 9;
this.invertedCheckBox.Text = "Inverted";
this.invertedCheckBox.UseVisualStyleBackColor = true;
//
// groupBox1
//
this.groupBox1.Controls.Add(this.openCloseTimeLabel);
this.groupBox1.Controls.Add(this.lagOpeningLabel);
this.groupBox1.Controls.Add(this.openCloseTimeTextBox);
this.groupBox1.Controls.Add(this.lagClosingLabel);
this.groupBox1.Controls.Add(this.lagOpeningTextBox);
this.groupBox1.Controls.Add(this.lagClosingTextBox);
this.groupBox1.Location = new System.Drawing.Point(25, 161);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(301, 97);
this.groupBox1.TabIndex = 19;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Parameters applied immediately (no restart required)";
//
// ValveCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.invertedCheckBox);
this.Controls.Add(this.categoryComboBox);
this.Controls.Add(this.categoryLabel);
this.Controls.Add(this.coupledToComboBox);
this.Controls.Add(this.parentNameComboBox);
this.Controls.Add(this.invertCoupleCheckBox);
this.Controls.Add(this.coupledToLabel);
this.Controls.Add(this.bitPositionTextBox);
this.Controls.Add(this.bitPositionLabel);
this.Controls.Add(this.parentNameLabel);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "ValveCfgCtrl";
this.Size = new System.Drawing.Size(388, 291);
this.Load += new System.EventHandler(this.ValveCfgCtrl_Load);
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox bitPositionTextBox;
private System.Windows.Forms.Label bitPositionLabel;
private System.Windows.Forms.Label parentNameLabel;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label classNameLabel;
private System.Windows.Forms.Label coupledToLabel;
private System.Windows.Forms.CheckBox invertCoupleCheckBox;
private System.Windows.Forms.ComboBox parentNameComboBox;
private System.Windows.Forms.Label lagOpeningLabel;
private System.Windows.Forms.Label lagClosingLabel;
private System.Windows.Forms.TextBox lagOpeningTextBox;
private System.Windows.Forms.TextBox lagClosingTextBox;
private System.Windows.Forms.ComboBox coupledToComboBox;
private System.Windows.Forms.Label categoryLabel;
private System.Windows.Forms.ComboBox categoryComboBox;
private System.Windows.Forms.TextBox openCloseTimeTextBox;
private System.Windows.Forms.Label openCloseTimeLabel;
private System.Windows.Forms.CheckBox invertedCheckBox;
private System.Windows.Forms.GroupBox groupBox1;
}
}
+203
View File
@@ -0,0 +1,203 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
using System;
using System.Windows.Forms;
using Config.Entities;
using TBF.Rig.Generic;
using TBF.UI.Bench.Components;
using TBF.UI.Bench.Components;
namespace TBF.Rig.BuiltIn.Valve
{
public partial class ValveCfgCtrl : UserControl, IComponentCfgCtrl
{
ComponentParametersDlg parent;
public bool ShowMore { get { return false; } }
ValveCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as ValveCfg;
Redraw();
}
}
public ValveCfgCtrl()
{
InitializeComponent();
}
private void ValveCfgCtrl_Load(object sender, EventArgs e)
{
parent = ParentForm as ComponentParametersDlg;
if (parent == null) return;
categoryComboBox.Items.Add(ValveCategory.Feeding.ToString());
categoryComboBox.Items.Add(ValveCategory.Bench.ToString());
categoryComboBox.Items.Add(ValveCategory.Output.ToString());
categoryComboBox.Items.Add(ValveCategory.None.ToString());
if (parent.CmpntEntities != null)
{
parentNameComboBox.Items.Add("---");
coupledToComboBox.Items.Add("---");
foreach (var cmpnt in parent.CmpntEntities)
{
if (cmpnt.ClassName.Contains("ControlBoard"))
{
parentNameComboBox.Items.Add(cmpnt.Name);
}
if (TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is BuiltIn.Valve.ValveFactory)
{
coupledToComboBox.Items.Add(cmpnt.Name);
}
}
}
Redraw();
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
parentNameComboBox.Text = string.IsNullOrEmpty(config.ParentName) ? "---" : config.ParentName;
bitPositionTextBox.Text = config.BitNr.ToString();
invertedCheckBox.Checked = config.Inverted;
openCloseTimeTextBox.Text = config.OpenCloseTime.ToString();
categoryComboBox.Text = config.Category.ToString();
coupledToComboBox.Text = string.IsNullOrEmpty(config.CoupledToName) ? "---" : config.CoupledToName;
invertCoupleCheckBox.Checked = config.InvertCouple;
lagOpeningTextBox.Text = config.LagOpening.ToString();
lagClosingTextBox.Text = config.LagClosing.ToString();
}
public void Unlock()
{
nameTextBox.Enabled = true;
parentNameComboBox.Enabled = true;
bitPositionTextBox.Enabled = true;
invertedCheckBox.Enabled = true;
openCloseTimeTextBox.Enabled = true;
categoryComboBox.Enabled = true;
coupledToComboBox.Enabled = true;
invertCoupleCheckBox.Enabled = true;
lagOpeningTextBox.Enabled = true;
lagClosingTextBox.Enabled = true;
}
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
string newParentName = parentNameComboBox.Text.Equals("---") ? string.Empty : parentNameComboBox.Text;
int newBitPosition = int.Parse(bitPositionTextBox.Text);
string newCoupledToName = coupledToComboBox.Text.Equals("---") ? string.Empty : coupledToComboBox.Text;
int newLagOpening = int.Parse(lagOpeningTextBox.Text);
int newLagClosing = int.Parse(lagClosingTextBox.Text);
int newOpenCloseTime = int.Parse(openCloseTimeTextBox.Text);
ValveCategory newCategory;
if (categoryComboBox.Text.Equals(ValveCategory.Feeding.ToString())) newCategory = ValveCategory.Feeding;
else if (categoryComboBox.Text.Equals(ValveCategory.Bench.ToString())) newCategory = ValveCategory.Bench;
else if (categoryComboBox.Text.Equals(ValveCategory.Output.ToString())) newCategory = ValveCategory.Output;
else newCategory = ValveCategory.None;
if (config.Name != nameTextBox.Text ||
config.ParentName != newParentName ||
config.BitNr != newBitPosition ||
config.Category != newCategory ||
config.Inverted != invertedCheckBox.Checked ||
config.CoupledToName != newCoupledToName ||
config.InvertCouple != invertCoupleCheckBox.Checked)
{
config.Name = nameTextBox.Text;
config.ParentName = newParentName;
config.BitNr = newBitPosition;
config.Category = newCategory;
config.Inverted = invertedCheckBox.Checked;
config.CoupledToName = newCoupledToName;
config.InvertCouple = invertCoupleCheckBox.Checked;
flags |= (CfgUpdateFlags.RestartRqrd | CfgUpdateFlags.AnyChange);
}
if (config.OpenCloseTime != newOpenCloseTime ||
config.LagOpening != newLagOpening ||
config.LagClosing != newLagClosing)
{
config.OpenCloseTime = newOpenCloseTime;
config.LagOpening = newLagOpening;
config.LagClosing = newLagClosing;
flags |= (CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
}
if ((flags & CfgUpdateFlags.InvokeCfgChange) != 0)
{
Valve.OnCfgChange(this, new CfgChangeArgs(CfgChangeCmd.CfgChange, config));
}
return flags;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
int dummy;
if (!parentNameComboBox.Items.Contains(parentNameComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Parent Name'";
}
if (!categoryComboBox.Items.Contains(categoryComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Category'";
}
if (!coupledToComboBox.Items.Contains(coupledToComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Coupled To'";
}
if (!int.TryParse(bitPositionTextBox.Text, out dummy) || dummy < 0 || dummy >= 128)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Bit Position' should be between 0 and 127";
}
if (!int.TryParse(openCloseTimeTextBox.Text, out dummy) || dummy < 0 || dummy > 300 || (dummy % StateMachine.Period) != 0)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Open/close time' should be between 0 and 300 s";
if (dummy % StateMachine.Period != 0)
message += Environment.NewLine + string.Format("and a multiple of {0}", StateMachine.Period);
}
if (!int.TryParse(lagOpeningTextBox.Text, out dummy) || (dummy % StateMachine.Period) != 0)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + string.Format("'Delay when opening' error should be a multiple of {0}", StateMachine.Period);
}
if (!int.TryParse(lagClosingTextBox.Text, out dummy) || (dummy % StateMachine.Period) != 0)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + string.Format("'Delay when closing' error should be a multiple of {0}", StateMachine.Period);
}
return flags;
}
}
}
+120
View File
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+27
View File
@@ -0,0 +1,27 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.BuiltIn.Valve
{
public class ValveFactory : IComponentFactory
{
public string ClassName { get { return "Valve"; } }
public override string ToString() { return ClassName; }
public void ResetStaticProperties() { Valve.ResetStaticProperties(); }
public IComponent DummyComponent() { return new Valve(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Valve(cfg, components); }
public IComponentCfg DefaultConfig() { return new ValveCfg(this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(ValveCfg.Serializer, component, this);
}
}
}
+103
View File
@@ -0,0 +1,103 @@
///
/// Copyright (c) 2013-2015 Sensus Metering Systems
///
using System;
using System.Collections.Generic;
using TBF.Rig.GenericDevices;
namespace TBF.Rig.BuiltIn
{
public class ValveBase : ComponentBase
{
public ValveBase()
{
}
/// <summary>
/// Invokes ComponentBase constructor
/// </summary>
public ValveBase(Generic.IComponentCfg cfg) : base(cfg)
{
}
/// <summary>
/// Process the list of components and return all valves (masters and coupled)
/// </summary>
public static IList<IValve> AllValves(IList<Generic.IComponent> cmpnts)
{
IList<IValve> result = new List<IValve>();
foreach (var cmpnt in cmpnts) if (cmpnt is IValve) result.Add(cmpnt as IValve);
return result;
}
/// <summary>
/// Process the list of components and return masters valves
/// </summary>
public static IList<IValve> GetMasterValves(IList<Generic.IComponent> cmpnts)
{
IList<IValve> result = new List<IValve>();
foreach (var cmpnt in cmpnts)
{
IValve valve = cmpnt as IValve;
if (valve != null && valve.CoupledTo == null) result.Add(valve);
}
return result;
}
/// <summary>
/// Process the list of components and return coupled valves
/// </summary>
public static IList<IValve> CoupledValves(IList<Generic.IComponent> cmpnts)
{
IList<IValve> result = new List<IValve>();
foreach (var cmpnt in cmpnts)
{
IValve valve = cmpnt as IValve;
if (valve != null && valve.CoupledTo != null) result.Add(valve);
}
return result;
}
/// <summary>
/// Process the list of components and return extended valves
/// </summary>
public static IList<BuiltIn.ValveEx.Valve> ExtendedValves(IList<Generic.IComponent> cmpnts)
{
IList<BuiltIn.ValveEx.Valve> result = new List<BuiltIn.ValveEx.Valve>();
foreach (var cmpnt in cmpnts)
{
if (cmpnt is BuiltIn.ValveEx.Valve) result.Add(cmpnt as BuiltIn.ValveEx.Valve);
}
return result;
}
/// <summary>
/// Create a list with one valved passed as an argument to this function
/// </summary>
/// <param name="valve">Valve</param>
/// <returns>List with one valve</returns>
public static IList<IValve> MakeList(IValve valve)
{
IList<IValve> result = new List<IValve>();
if (valve != null) result.Add(valve);
return result;
}
public static IList<IValve> Merge(IList<IValve> valves1, IList<IValve> valves2)
{
IList<IValve> result = new List<IValve>();
if (valves1 != null) foreach (var valve in valves1) result.Add(valve);
if (valves2 != null) foreach (var valve in valves2) result.Add(valve);
return result;
}
public static IList<IValve> Merge(IList<IValve> valves1, IList<IValve> valves2, IList<IValve> valves3)
{
IList<IValve> result = new List<IValve>();
if (valves1 != null) foreach (var valve in valves1) result.Add(valve);
if (valves2 != null) foreach (var valve in valves2) result.Add(valve);
if (valves3 != null) foreach (var valve in valves3) result.Add(valve);
return result;
}
}
}
+93
View File
@@ -0,0 +1,93 @@
///
/// Copyright (c) 2015-2016 Sensus Metering Systems
///
using System;
using System.Collections.Generic;
using log4net;
using TBF.Rig.GenericDevices;
using Dirichlet.Numerics;
namespace TBF.Rig.BuiltIn.ValveEx
{
public class Valve : ComponentBase, Generic.IComponent
{
private static readonly ILog log = LogManager.GetLogger(typeof(Valve));
public override string ToString() { return string.Format("ValveEx({0})", Cfg.ToString(1)); }
readonly ValveCfg valveCfg;
public readonly UInt128 Mask; /// derived from bitPosition in the constructor
///
public readonly IValve[] InputValves;
public Valve()
{
}
public Valve(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
: base(cfg)
{
valveCfg = cfg as ValveCfg;
//controlBoard = (ControlBoardDev)TbfComponents.FindComponent(cfg.ParentName, components);
//if (controlBoard == null) throw new Exception("Cannot find " + Name + " parent");
if (valveCfg.BitPosition < 0 || valveCfg.BitPosition >= 128)
{
throw new ArgumentOutOfRangeException("position");
}
this.Mask = (((UInt128)1) << valveCfg.BitPosition);
InputValves = new IValve[valveCfg.InputValvesCount];
InputValves[0] = TbfComponents.FindComponent(valveCfg.Input1, components) as IValve;
InputValves[1] = TbfComponents.FindComponent(valveCfg.Input2, components) as IValve;
if (InputValves.Length > 2)
{
InputValves[2] = TbfComponents.FindComponent(valveCfg.Input3, components) as IValve;
}
if (InputValves.Length > 3)
{
InputValves[3] = TbfComponents.FindComponent(valveCfg.Input4, components) as IValve;
}
if (InputValves.Length > 4)
{
InputValves[4] = TbfComponents.FindComponent(valveCfg.Input5, components) as IValve;
}
log.Warn(this.ToString());
}
public void UpdateRoute(ref UInt128 route)
{
bool output;
if (valveCfg.LogicalOp == ValveExOperation.And)
{
output = true;
foreach (var valve in InputValves)
{
if (valve != null) output = output && valve.State;
}
}
else if (valveCfg.LogicalOp == ValveExOperation.Or)
{
output = false;
foreach (var valve in InputValves)
{
if (valve != null) output = output || valve.State;
}
}
else
return;
if (output != valveCfg.InvertOutput)
{
route = route | Mask; /// Set the output bit to true
}
else
{
route = route & (~Mask); /// Reset the output bit to false
}
}
}
}
+68
View File
@@ -0,0 +1,68 @@
///
/// Copyright (c) 2015-2016 Sensus Metering Systems
///
using System.Collections.Generic;
using System.Xml.Serialization;
using TBF.Rig.Generic;
namespace TBF.Rig.BuiltIn.ValveEx
{
public class ValveCfg : ComponentCfgBase, IComponentCfg
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(ValveCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new ValveCfgCtrl(); }
///
/// Serialized parameters
///
public int BitPosition; /// Bit-position
///
public ValveExOperation LogicalOp; /// Logical operation between input valves
public bool InvertOutput; /// Invert the output of logical operation
public int InputValvesCount;
public string Input1; /// Input valve 1
public string Input2; /// Input valve 2
public string Input3; /// Input valve 3
public string Input4; /// Input valve 4
public string Input5; /// Input valve 5
/// Private parameterless constructor invoked by all other (public) constructors
ValveCfg()
{
Name = "VEx";
ParentName = string.Empty;
BitPosition = 0;
LogicalOp = ValveExOperation.And;
InvertOutput = false;
InputValvesCount = 2;
Input1 = string.Empty;
Input2 = string.Empty;
Input3 = string.Empty;
Input4 = string.Empty;
Input5 = string.Empty;
}
public ValveCfg(IComponentFactory factory)
: this()
{
this.Factory = factory;
}
public string ToString(int i)
{
return string.Format("Name={0}, Bit={1}, LogOp.={2}, Inv.Output={3}, #inputs={4}, I1={5}, I2={6}, I3={7}, I4={8}s, I5={9}",
Name,
BitPosition,
(LogicalOp == ValveExOperation.And) ? "AND" : "OR",
InvertOutput ? "yes" : "no",
InputValvesCount,
Input1,
Input2,
Input3,
Input4,
Input5);
}
}
}
+291
View File
@@ -0,0 +1,291 @@
///
/// Copyright (c) 2015 Sensus Metering Systems
///
namespace TBF.Rig.BuiltIn.ValveEx
{
partial class ValveCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.bitPositionTextBox = new System.Windows.Forms.TextBox();
this.bitPositionLabel = new System.Windows.Forms.Label();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
this.classNameLabel = new System.Windows.Forms.Label();
this.inputsCountLabel = new System.Windows.Forms.Label();
this.inputsCountTextBox = new System.Windows.Forms.TextBox();
this.logicalOpLabel = new System.Windows.Forms.Label();
this.logicalOpComboBox = new System.Windows.Forms.ComboBox();
this.invertedOutpCheckBox = new System.Windows.Forms.CheckBox();
this.input1ComboBox = new System.Windows.Forms.ComboBox();
this.input1Label = new System.Windows.Forms.Label();
this.input2ComboBox = new System.Windows.Forms.ComboBox();
this.input2Label = new System.Windows.Forms.Label();
this.input3ComboBox = new System.Windows.Forms.ComboBox();
this.input3Label = new System.Windows.Forms.Label();
this.input4ComboBox = new System.Windows.Forms.ComboBox();
this.input4Label = new System.Windows.Forms.Label();
this.input5ComboBox = new System.Windows.Forms.ComboBox();
this.input5Label = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// bitPositionTextBox
//
this.bitPositionTextBox.Enabled = false;
this.bitPositionTextBox.Location = new System.Drawing.Point(117, 58);
this.bitPositionTextBox.Name = "bitPositionTextBox";
this.bitPositionTextBox.Size = new System.Drawing.Size(66, 20);
this.bitPositionTextBox.TabIndex = 4;
//
// bitPositionLabel
//
this.bitPositionLabel.AutoSize = true;
this.bitPositionLabel.Location = new System.Drawing.Point(17, 61);
this.bitPositionLabel.Name = "bitPositionLabel";
this.bitPositionLabel.Size = new System.Drawing.Size(58, 13);
this.bitPositionLabel.TabIndex = 3;
this.bitPositionLabel.Text = "Bit position";
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(117, 35);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(130, 20);
this.nameTextBox.TabIndex = 2;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(17, 38);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 1;
this.nameLabel.Text = "Name";
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(115, 15);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
this.classNameLabel.TabIndex = 0;
this.classNameLabel.Text = "ComonentName";
//
// inputsCountLabel
//
this.inputsCountLabel.AutoSize = true;
this.inputsCountLabel.Location = new System.Drawing.Point(17, 108);
this.inputsCountLabel.Name = "inputsCountLabel";
this.inputsCountLabel.Size = new System.Drawing.Size(66, 13);
this.inputsCountLabel.TabIndex = 8;
this.inputsCountLabel.Text = "Inputs count";
//
// inputsCountTextBox
//
this.inputsCountTextBox.Enabled = false;
this.inputsCountTextBox.Location = new System.Drawing.Point(117, 105);
this.inputsCountTextBox.Name = "inputsCountTextBox";
this.inputsCountTextBox.Size = new System.Drawing.Size(66, 20);
this.inputsCountTextBox.TabIndex = 9;
this.inputsCountTextBox.TextChanged += new System.EventHandler(this.inputsCountTextBox_TextChanged);
//
// logicalOpLabel
//
this.logicalOpLabel.AutoSize = true;
this.logicalOpLabel.Location = new System.Drawing.Point(17, 84);
this.logicalOpLabel.Name = "logicalOpLabel";
this.logicalOpLabel.Size = new System.Drawing.Size(88, 13);
this.logicalOpLabel.TabIndex = 6;
this.logicalOpLabel.Text = "Logical operation";
//
// logicalOpComboBox
//
this.logicalOpComboBox.Enabled = false;
this.logicalOpComboBox.FormattingEnabled = true;
this.logicalOpComboBox.Location = new System.Drawing.Point(117, 81);
this.logicalOpComboBox.Name = "logicalOpComboBox";
this.logicalOpComboBox.Size = new System.Drawing.Size(66, 21);
this.logicalOpComboBox.TabIndex = 7;
//
// invertedOutpCheckBox
//
this.invertedOutpCheckBox.AutoSize = true;
this.invertedOutpCheckBox.Enabled = false;
this.invertedOutpCheckBox.Location = new System.Drawing.Point(196, 61);
this.invertedOutpCheckBox.Name = "invertedOutpCheckBox";
this.invertedOutpCheckBox.Size = new System.Drawing.Size(98, 17);
this.invertedOutpCheckBox.TabIndex = 5;
this.invertedOutpCheckBox.Text = "Inverted output";
this.invertedOutpCheckBox.UseVisualStyleBackColor = true;
//
// input1ComboBox
//
this.input1ComboBox.Enabled = false;
this.input1ComboBox.FormattingEnabled = true;
this.input1ComboBox.Location = new System.Drawing.Point(117, 127);
this.input1ComboBox.Name = "input1ComboBox";
this.input1ComboBox.Size = new System.Drawing.Size(130, 21);
this.input1ComboBox.TabIndex = 11;
//
// input1Label
//
this.input1Label.AutoSize = true;
this.input1Label.Location = new System.Drawing.Point(18, 130);
this.input1Label.Name = "input1Label";
this.input1Label.Size = new System.Drawing.Size(40, 13);
this.input1Label.TabIndex = 10;
this.input1Label.Text = "Input 1";
//
// input2ComboBox
//
this.input2ComboBox.Enabled = false;
this.input2ComboBox.FormattingEnabled = true;
this.input2ComboBox.Location = new System.Drawing.Point(117, 150);
this.input2ComboBox.Name = "input2ComboBox";
this.input2ComboBox.Size = new System.Drawing.Size(130, 21);
this.input2ComboBox.TabIndex = 13;
//
// input2Label
//
this.input2Label.AutoSize = true;
this.input2Label.Location = new System.Drawing.Point(17, 153);
this.input2Label.Name = "input2Label";
this.input2Label.Size = new System.Drawing.Size(40, 13);
this.input2Label.TabIndex = 12;
this.input2Label.Text = "Input 2";
//
// input3ComboBox
//
this.input3ComboBox.Enabled = false;
this.input3ComboBox.FormattingEnabled = true;
this.input3ComboBox.Location = new System.Drawing.Point(117, 173);
this.input3ComboBox.Name = "input3ComboBox";
this.input3ComboBox.Size = new System.Drawing.Size(130, 21);
this.input3ComboBox.TabIndex = 15;
//
// input3Label
//
this.input3Label.AutoSize = true;
this.input3Label.Location = new System.Drawing.Point(18, 176);
this.input3Label.Name = "input3Label";
this.input3Label.Size = new System.Drawing.Size(40, 13);
this.input3Label.TabIndex = 14;
this.input3Label.Text = "Input 3";
//
// input4ComboBox
//
this.input4ComboBox.Enabled = false;
this.input4ComboBox.FormattingEnabled = true;
this.input4ComboBox.Location = new System.Drawing.Point(117, 196);
this.input4ComboBox.Name = "input4ComboBox";
this.input4ComboBox.Size = new System.Drawing.Size(130, 21);
this.input4ComboBox.TabIndex = 17;
//
// input4Label
//
this.input4Label.AutoSize = true;
this.input4Label.Location = new System.Drawing.Point(18, 199);
this.input4Label.Name = "input4Label";
this.input4Label.Size = new System.Drawing.Size(40, 13);
this.input4Label.TabIndex = 16;
this.input4Label.Text = "Input 4";
//
// input5ComboBox
//
this.input5ComboBox.Enabled = false;
this.input5ComboBox.FormattingEnabled = true;
this.input5ComboBox.Location = new System.Drawing.Point(117, 219);
this.input5ComboBox.Name = "input5ComboBox";
this.input5ComboBox.Size = new System.Drawing.Size(130, 21);
this.input5ComboBox.TabIndex = 19;
//
// input5Label
//
this.input5Label.AutoSize = true;
this.input5Label.Location = new System.Drawing.Point(18, 222);
this.input5Label.Name = "input5Label";
this.input5Label.Size = new System.Drawing.Size(40, 13);
this.input5Label.TabIndex = 18;
this.input5Label.Text = "Input 5";
//
// ValveCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.input5ComboBox);
this.Controls.Add(this.input5Label);
this.Controls.Add(this.input4ComboBox);
this.Controls.Add(this.input4Label);
this.Controls.Add(this.input3ComboBox);
this.Controls.Add(this.input3Label);
this.Controls.Add(this.input2ComboBox);
this.Controls.Add(this.input2Label);
this.Controls.Add(this.input1ComboBox);
this.Controls.Add(this.input1Label);
this.Controls.Add(this.invertedOutpCheckBox);
this.Controls.Add(this.logicalOpComboBox);
this.Controls.Add(this.logicalOpLabel);
this.Controls.Add(this.inputsCountTextBox);
this.Controls.Add(this.inputsCountLabel);
this.Controls.Add(this.bitPositionTextBox);
this.Controls.Add(this.bitPositionLabel);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "ValveCfgCtrl";
this.Size = new System.Drawing.Size(300, 250);
this.Load += new System.EventHandler(this.ValveCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox bitPositionTextBox;
private System.Windows.Forms.Label bitPositionLabel;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label classNameLabel;
private System.Windows.Forms.Label inputsCountLabel;
private System.Windows.Forms.TextBox inputsCountTextBox;
private System.Windows.Forms.Label logicalOpLabel;
private System.Windows.Forms.ComboBox logicalOpComboBox;
private System.Windows.Forms.CheckBox invertedOutpCheckBox;
private System.Windows.Forms.ComboBox input1ComboBox;
private System.Windows.Forms.Label input1Label;
private System.Windows.Forms.ComboBox input2ComboBox;
private System.Windows.Forms.Label input2Label;
private System.Windows.Forms.ComboBox input3ComboBox;
private System.Windows.Forms.Label input3Label;
private System.Windows.Forms.ComboBox input4ComboBox;
private System.Windows.Forms.Label input4Label;
private System.Windows.Forms.ComboBox input5ComboBox;
private System.Windows.Forms.Label input5Label;
}
}
+185
View File
@@ -0,0 +1,185 @@
///
/// Copyright (c) 2015 Sensus Metering Systems
///
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Config.Entities;
using TBF.Rig.Generic;
using TBF.UI.Bench.Components;
namespace TBF.Rig.BuiltIn.ValveEx
{
public partial class ValveCfgCtrl : UserControl, IComponentCfgCtrl
{
ComponentParametersDlg parent;
public bool ShowMore { get { return false; } }
ValveCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as ValveCfg;
Redraw();
}
}
public ValveCfgCtrl()
{
InitializeComponent();
}
private void ValveCfgCtrl_Load(object sender, EventArgs e)
{
parent = ParentForm as ComponentParametersDlg;
if (parent == null) return;
logicalOpComboBox.Items.Add("AND");
logicalOpComboBox.Items.Add("OR");
if (parent.CmpntEntities != null)
{
AddValvePumpItemsToCombo(input1ComboBox, parent.CmpntEntities);
AddValvePumpItemsToCombo(input2ComboBox, parent.CmpntEntities);
AddValvePumpItemsToCombo(input3ComboBox, parent.CmpntEntities);
AddValvePumpItemsToCombo(input4ComboBox, parent.CmpntEntities);
AddValvePumpItemsToCombo(input5ComboBox, parent.CmpntEntities);
}
Redraw();
}
void AddValvePumpItemsToCombo(ComboBox combo, IList<Config.Entities.Component> components)
{
foreach (var cmpntEntity in components)
{
IComponent comp = TbfComponents.CmpntFactoryFromClassName(cmpntEntity.ClassName).DummyComponent();
if (comp is GenericDevices.IValve )
{
combo.Items.Add(cmpntEntity.Name);
}
}
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
bitPositionTextBox.Text = config.BitPosition.ToString();
invertedOutpCheckBox.Checked = config.InvertOutput;
logicalOpComboBox.Text = (config.LogicalOp == ValveExOperation.And) ? "AND" : ((config.LogicalOp == ValveExOperation.Or) ? "OR" : "---");
inputsCountTextBox.Text = config.InputValvesCount.ToString();
input1ComboBox.Text = config.Input1;
input2ComboBox.Text = config.Input2;
input3ComboBox.Text = config.Input3;
input4ComboBox.Text = config.Input4;
input5ComboBox.Text = config.Input5;
}
public void Unlock()
{
nameTextBox.Enabled = true;
bitPositionTextBox.Enabled = true;
invertedOutpCheckBox.Enabled = true;
logicalOpComboBox.Enabled = true;
inputsCountTextBox.Enabled = true;
input1ComboBox.Enabled = true;
input2ComboBox.Enabled = true;
input3ComboBox.Enabled = true;
input4ComboBox.Enabled = true;
input5ComboBox.Enabled = true;
}
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
config.Name = nameTextBox.Text;
config.BitPosition = int.Parse(bitPositionTextBox.Text);
config.InvertOutput = invertedOutpCheckBox.Checked;
config.LogicalOp = (logicalOpComboBox.Text == "AND") ? ValveExOperation.And : ValveExOperation.Or;
config.InputValvesCount = int.Parse(inputsCountTextBox.Text);
config.Input1 = input1ComboBox.Text.Equals("---") ? string.Empty : input1ComboBox.Text;
config.Input2 = input2ComboBox.Text.Equals("---") ? string.Empty : input2ComboBox.Text;
if (config.InputValvesCount >= 3) config.Input3 = input3ComboBox.Text.Equals("---") ? string.Empty : input3ComboBox.Text;
if (config.InputValvesCount >= 4) config.Input4 = input4ComboBox.Text.Equals("---") ? string.Empty : input4ComboBox.Text;
if (config.InputValvesCount >= 5) config.Input5 = input5ComboBox.Text.Equals("---") ? string.Empty : input5ComboBox.Text;
return flags;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
int dummy;
if (!int.TryParse(bitPositionTextBox.Text, out dummy) || dummy < 0 || dummy >= 128)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Bit Position' should be between 0 and 127";
}
if (!logicalOpComboBox.Items.Contains(logicalOpComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Category'";
}
int nrInputs;
if (!int.TryParse(inputsCountTextBox.Text, out nrInputs) || nrInputs < 2 || nrInputs > 5)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Inputs count' out of range (2..5)";
}
if (!input1ComboBox.Items.Contains(input1ComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Input 1'";
}
if (!input2ComboBox.Items.Contains(input2ComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Input 2'";
}
if (nrInputs >= 3 && !input3ComboBox.Items.Contains(input3ComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Input 3'";
}
if (nrInputs >= 4 && !input4ComboBox.Items.Contains(input4ComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Input 4'";
}
if (nrInputs >= 5 && !input5ComboBox.Items.Contains(input5ComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Input 5'";
}
return flags;
}
private void inputsCountTextBox_TextChanged(object sender, EventArgs e)
{
int count;
if (int.TryParse(inputsCountTextBox.Text, out count) && count >= 2 || count <= 5)
{
input3Label.Visible = (count >= 3);
input4Label.Visible = (count >= 4);
input5Label.Visible = (count >= 5);
input3ComboBox.Visible = (count >= 3);
input4ComboBox.Visible = (count >= 4);
input5ComboBox.Visible = (count >= 5);
}
}
}
}
+120
View File
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+27
View File
@@ -0,0 +1,27 @@
///
/// Copyright (c) 2015-2016 Sensus Metering Systems
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.BuiltIn.ValveEx
{
public class ValveFactory : IComponentFactory
{
public string ClassName { get { return "ValveEx"; } }
public override string ToString() { return ClassName; }
public void ResetStaticProperties() { Valve.ResetStaticProperties(); }
public IComponent DummyComponent() { return new Valve(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Valve(cfg, components); }
public IComponentCfg DefaultConfig() { return new ValveCfg(this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(ValveCfg.Serializer, component, this);
}
}
}
+19
View File
@@ -0,0 +1,19 @@
///
/// Copyright (c) 2013-2015 Sensus Metering Systems
///
using System;
namespace TBF.Rig
{
public class CfgChangeArgs : EventArgs
{
public CfgChangeCmd Command;
public Generic.IComponentCfg Cfg;
public CfgChangeArgs(CfgChangeCmd command, Generic.IComponentCfg cfg)
{
Command = command;
Cfg = cfg;
}
}
}
+21
View File
@@ -0,0 +1,21 @@
///
/// Copyright (c) 2021 Sensus Metering Systems
///
using System;
namespace TBF.Rig
{
public class CmdResponseArgs : EventArgs
{
public CfgChangeCmd Command;
public int Id; /// Either Idx1(RV) or BitPosition (Div) to identify the component
public Int16 Response;
public CmdResponseArgs(CfgChangeCmd command, int id, Int16 response)
{
Command = command;
Id = id;
Response = response;
}
}
}
+61
View File
@@ -0,0 +1,61 @@
///
/// Copyright (c) 2013-2019 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using Config.Entities;
using TBF.Rig.Generic;
namespace TBF.Rig
{
public class ComponentBase : IComponent
{
readonly Generic.IComponentCfg cfg;
public Generic.IComponentCfg Cfg { get { return cfg; } }
public string Name { get { return cfg.Name; } }
public string ClassName { get { return cfg.Factory.ClassName; } }
public string ParentName { get { return cfg.ParentName; } }
public Generic.IComponentFactory Factory { get { return cfg.Factory; } }
public int ItemNr { get { return cfg.ItemNr; } }
public DebugMode DebugLevel { get { return cfg.DebugLevel; } set { cfg.DebugLevel = value; } }
public LogLevel LogLevel { get { return cfg.LogLevel; } }
public IList<MeasurementCorrection> Corrections
{
get { return cfg.Corrections; }
set { cfg.Corrections = value; }
}
public IList<Uncertainty> Uncertainties
{
get { return cfg.Uncertainties; }
set { cfg.Uncertainties = value; }
}
/// Constructor, components created in this way is used by
/// IComponentFactory.DummyComponent() function. Such dummy component should be used
/// only for runtime class type identification (e.g. object is iValve)
public ComponentBase()
{
cfg = null;
}
/// Constructor with configuration as an argument
public ComponentBase(IComponentCfg cfg)
{
if (cfg == null) throw new ArgumentNullException("cfg");
this.cfg = cfg;
}
/// <summary> Empty implementation, might be overriden in derived classes </summary>
public static void ResetStaticProperties() { }
/// <summary> Empty implementation, might be overriden in derived classes </summary>
public virtual void StartChangeHandler() { }
/// <summary> Empty implementation, might be overriden in derived classes </summary>
public virtual void StopChangeHandler() { }
}
}
+285
View File
@@ -0,0 +1,285 @@
///
/// Copyright (c) 2013-2019 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using Config.Entities;
using TBF.Rig.Generic;
namespace TBF.Rig
{
public class ComponentCfgBase
{
[XmlIgnore]
public string Name
{
get { return name; }
set { name = value; }
}
string name;
[XmlIgnore]
public Generic.IComponentFactory Factory
{
get { return factory; }
set { factory = value; }
}
Generic.IComponentFactory factory;
[XmlIgnore]
public string ClassName
{
get { return Factory.ToString(); }
}
[XmlIgnore]
public string ParentName
{
get { return parentName; }
set { parentName = value; }
}
string parentName;
[XmlIgnore]
public int ItemNr
{
get { return itemNr; }
set { itemNr = value; }
}
int itemNr;
[XmlIgnore]
public DebugMode DebugLevel
{
get { return debugLevel; }
set { debugLevel = value; }
}
DebugMode debugLevel;
[XmlIgnore]
public LogLevel LogLevel
{
get { return logLevel; }
set { logLevel = value; }
}
LogLevel logLevel;
[XmlIgnore]
public IList<MeasurementCorrection> Corrections
{
get { return corrections; }
set { corrections = value; }
}
IList<MeasurementCorrection> corrections;
[XmlIgnore]
public IList<Uncertainty> Uncertainties
{
get { return uncertainties; }
set { uncertainties = value; }
}
IList<Uncertainty> uncertainties;
protected ComponentCfgBase()
{
itemNr = 0;
debugLevel = DebugMode.Normal;
logLevel = LogLevel.Off;
}
protected ComponentCfgBase(Generic.IComponentFactory factory)
: this()
{
this.factory = factory;
}
protected ComponentCfgBase(Generic.IComponentFactory factory, string name)
: this(factory)
{
this.name = name;
}
protected ComponentCfgBase(Generic.IComponentFactory factory, string name, string parentName)
: this(factory, name)
{
this.parentName = parentName;
}
public virtual XmlSerializer GetSerializer() { return new XmlSerializer(GetType()); }
public Component CreateDbEntity()
{
using (var writer = new StringWriter())
{
GetSerializer().Serialize(writer, this);
return Component.CreateFromCfg(Name, factory.ClassName, ParentName, ItemNr, DebugLevel, LogLevel, writer.ToString());
}
}
public static IComponentCfg CreateFromDbEntity(XmlSerializer s, Component cmpntEntity, IComponentFactory factory)
{
using (var reader = new StringReader(cmpntEntity.Parameters))
{
IComponentCfg config = s.Deserialize(reader) as IComponentCfg;
if (config != null)
{
config.Name = cmpntEntity.Name;
config.ParentName = cmpntEntity.Parent;
config.ItemNr = cmpntEntity.ItemNr;
config.DebugLevel = cmpntEntity.DebugMode;
config.LogLevel = cmpntEntity.LogLevel;
config.Corrections = cmpntEntity.Corrections;
config.Uncertainties = cmpntEntity.Uncertainties;
config.Factory = factory;
}
return config;
}
}
public void LoadTestParamsFromDB(Test test)
{
ITestParams tstPrms = (GetRuntimeTestParamsProvider() as ITestParams);
if (tstPrms != null)
{
tstPrms.FromDbEntity(Name, test);
}
}
public void LoadProcedureParamsFromDB(Procedure procedure)
{
IProcedureParams procPrms = (GetRuntimeProcParamsProvider() as IProcedureParams);
if (procPrms != null)
{
procPrms.FromDbEntity(Name, procedure);
}
}
/// <summary>
/// If there are any procedure parameters, this function should be overriden
/// by one returning a reference to a newly created object
/// implementing IParamsProvider and IProcedureParams.
///
/// This default implementation returns null = no procedure parameters.
/// </summary>
/// <returns>Procedure parameters provider for this component or null</returns>
public virtual IParamsProvider CreateProcParamsProvider()
{
return null;
}
/// <summary>
/// If there are any procedure parameters, this function should be overriden
/// by one returning a reference to an object
/// implementing IParamsProvider and IProcedureParams used in runtime.
///
/// This default implementation returns null = no procedure parameters.
/// </summary>
/// <returns>Procedure parameters provider for this component or null</returns>
public virtual IParamsProvider GetRuntimeProcParamsProvider()
{
return null;
}
public virtual IParamsProvider GetUIProcParamsProvider(Procedure procedure)
{
if (GetRuntimeProcParamsProvider() == null)
{
/// Component has no test parametes
return null;
}
ComponentProcedure procParamsEntity = procedure.GetProcedureParamsEntity(Name);
if (procParamsEntity != null)
{
if (procParamsEntity.GetParamsProvider() != null)
{
/// Parameters provider for this entity already fetched - return it
return procParamsEntity.GetParamsProvider();
}
else
{
/// Parameters provider for this entity will be created and updated from the entity later on
IParamsProvider paramsProvider = CreateProcParamsProvider();
(paramsProvider as IProcedureParams).UpdateFromDbEntity(procParamsEntity);
procParamsEntity.SetParamsProvider(paramsProvider);
return paramsProvider;
}
}
else
{
IParamsProvider paramsProvider = CreateProcParamsProvider();
(paramsProvider as IProcedureParams).FromDbEntity(Name, procedure);
return paramsProvider;
}
}
/// <summary>
/// If there are any procedure parameters, this function should be overriden
/// by one returning a reference to a newly created object
/// implementing IParamsProvider and ITestParams.
///
/// This default implementation returns null = no test parameters.
/// </summary>
/// <returns>Procedure parameters provider for this component or null</returns>
public virtual IParamsProvider CreateTestParamsProvider()
{
return null;
}
/// <summary>
/// If there are any test parameters, this function should be overriden
/// by one returning a reference to an object
/// implementing IParamsProvider and ITestParams used in runtime.
///
/// This default implementation returns null = no test parameters.
/// </summary>
/// <returns>Test parameters provider for this component or null</returns>
public virtual IParamsProvider GetRuntimeTestParamsProvider()
{
return null;
}
public virtual IParamsProvider GetUITestParamsProvider(Test test)
{
if (GetRuntimeTestParamsProvider() == null)
{
/// Component has no test parametes
return null;
}
ComponentTest testParamsEntity = test.GetTestParamsEntity(Name);
if (testParamsEntity != null)
{
if (testParamsEntity.GetParamsProvider() != null)
{
/// Parameters provider for this entity already fetched - return it
return testParamsEntity.GetParamsProvider();
}
else
{
/// Parameters provider for this entity will be created and updated from the entity later on
IParamsProvider paramsProvider = CreateTestParamsProvider();
(paramsProvider as ITestParams).UpdateFromDbEntity(testParamsEntity);
testParamsEntity.SetParamsProvider(paramsProvider);
return paramsProvider;
}
}
else
{
IParamsProvider paramsProvider = CreateTestParamsProvider();
(paramsProvider as ITestParams).FromDbEntity(Name, test);
return paramsProvider;
}
}
}
}
+126
View File
@@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Config.Entities;
using TBF.Rig;
namespace TBF.Rig.Configs
{
public class ConfigCtrlUtils : UserControl
{
protected PageOrientation GetOrientation(string str)
{
if (str.Equals(PageOrientation.Landscape.ToString())) return PageOrientation.Landscape;
if (str.Equals(PageOrientation.Portrait.ToString())) return PageOrientation.Portrait;
return (PageOrientation)(-1);
}
/// <summary>
/// Updates destination variable when its value differes from the source value.
/// Returns appropriate flags
/// </summary>
/// <param name="cfgVar">Reference to destination variable</param>
/// <param name="intVal">Source value</param>
/// <param name="flagsWhenUpdated">Flags returned when an update occurs</param>
/// <returns>Flags or 0</returns>
protected CfgUpdateFlags UpdateDifferent(ref int cfgVar, int intVal, CfgUpdateFlags flagsWhenUpdated)
{
if (cfgVar != intVal) { cfgVar = intVal; return flagsWhenUpdated; } else return 0;
}
/// <summary>
/// Updates destination variable when its value differes from the source value.
/// Returns appropriate flags
/// </summary>
/// <param name="cfgVar">Reference to destination variable</param>
/// <param name="toBeParsedString">Source integer value is obtained by parsing this string</param>
/// <param name="flagsWhenUpdated">Flags returned when an update occurs</param>
/// <returns>Flags or 0</returns>
protected CfgUpdateFlags UpdateDifferent(ref int cfgVar, string toBeParsedString, CfgUpdateFlags flagsWhenUpdated)
{
int itmp = int.Parse(toBeParsedString);
if (cfgVar != itmp) { cfgVar = itmp; return flagsWhenUpdated; } else return 0;
}
/// <summary>
/// Updates destination variable when its value differes from the source value.
/// Returns appropriate flags
/// </summary>
/// <param name="cfgVar">Reference to destination variable</param>
/// <param name="toBeParsedString">Source integer value is obtained by parsing this string</param>
/// <param name="flagsWhenUpdated">Flags returned when an update occurs</param>
/// <returns>Flags or 0</returns>
protected CfgUpdateFlags UpdateDifferent(ref float cfgVar, string toBeParsedString, CfgUpdateFlags flagsWhenUpdated)
{
float ftmp = Utils.ParseSFloat(toBeParsedString);
if (cfgVar != ftmp) { cfgVar = ftmp; return flagsWhenUpdated; } else return 0;
}
/// <summary>
/// Updates destination variable when its value differes from the source value.
/// Returns appropriate flags
/// </summary>
/// <param name="cfgVar">Reference to destination variable</param>
/// <param name="toBeParsedString">Source integer value is obtained by parsing this string</param>
/// <param name="flagsWhenUpdated">Flags returned when an update occurs</param>
/// <returns>Flags or 0</returns>
protected CfgUpdateFlags UpdateDifferent(ref double cfgVar, string toBeParsedString, CfgUpdateFlags flagsWhenUpdated)
{
double dtmp = Utils.ParseSDouble(toBeParsedString);
if (cfgVar != dtmp) { cfgVar = dtmp; return flagsWhenUpdated; } else return 0;
}
/// <summary>
/// Updates destination variable when its value differes from the source value.
/// Returns appropriate flags
/// </summary>
/// <param name="cfgVar">Reference to destination variable</param>
/// <param name="boolVal">Source value</param>
/// <param name="flagsWhenUpdated">Flags returned when an update occurs</param>
/// <returns>Flags or 0</returns>
protected CfgUpdateFlags UpdateDifferent(ref bool cfgVar, bool boolVal, CfgUpdateFlags flagsWhenUpdated)
{
if (cfgVar != boolVal) { cfgVar = boolVal; return flagsWhenUpdated; } else return 0;
}
/// <summary>
/// Updates destination variable when its value differes from the source value.
/// Returns appropriate flags
/// </summary>
/// <param name="cfgVar">Reference to destination variable</param>
/// <param name="stringVal">Source value</param>
/// <param name="flagsWhenUpdated">Flags returned when an update occurs</param>
/// <returns>Flags or 0</returns>
protected CfgUpdateFlags UpdateDifferent(ref string cfgVar, string stringVal, CfgUpdateFlags flagsWhenUpdated)
{
if (cfgVar != stringVal) { cfgVar = stringVal; return flagsWhenUpdated; } else return 0;
}
/// <summary>
/// Updates destination variable when its value differes from the source value.
/// Returns appropriate flags
/// </summary>
/// <param name="cfgVar">Reference to destination array</param>
/// <param name="stringArrVal">Source array of strings</param>
/// <param name="flagsWhenUpdated">Flags returned when an update occurs</param>
/// <returns>Flags or 0</returns>
protected CfgUpdateFlags UpdateDifferent(ref string[] cfgVar, string[] stringArrVal, CfgUpdateFlags flagsWhenUpdated)
{
if (cfgVar == null && stringArrVal == null)
{
return 0;
}
else if (cfgVar == null || stringArrVal == null || !cfgVar.SequenceEqual<string>(stringArrVal))
{
cfgVar = stringArrVal;
return flagsWhenUpdated;
}
else
{
return 0;
}
}
}
}
+33
View File
@@ -0,0 +1,33 @@
///
/// Copyright (c) 2016 Sensus Metering Systems
///
using System.Collections.Generic;
using System.Xml.Serialization;
using TBF.Rig.Generic;
namespace TBF.Rig.Configs.NameOnly
{
public class TestMethodCfg : ComponentCfgBase, Generic.IComponentCfg
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(TestMethodCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new TestMethodCfgCtrl(); }
/// Private parameterless constructor invoked by all other (public) constructors
TestMethodCfg() { }
public TestMethodCfg(string name, IComponentFactory factory)
: this()
{
Name = name;
Factory = factory;
ParentName = string.Empty;
}
public string ToString(int i)
{
return string.Format("Name={0}", Name);
}
}
}
@@ -0,0 +1,69 @@
///
/// Copyright (c) 2016 Sensus Metering Systems
///
using System;
using System.Windows.Forms;
using Config.Entities;
using TBF.Rig.Generic;
namespace TBF.Rig.Configs.NameOnly
{
public partial class TestMethodCfgCtrl : UserControl, IComponentCfgCtrl
{
public bool ShowMore { get { return false; } }
TestMethodCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as TestMethodCfg;
Redraw();
}
}
public TestMethodCfgCtrl()
{
InitializeComponent();
}
private void EntryFormCfgCtrl_Load(object sender, EventArgs e)
{
Redraw();
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
}
public void Unlock()
{
nameTextBox.Enabled = true;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
return flags;
}
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
config.Name = nameTextBox.Text;
return flags;
}
}
}
+86
View File
@@ -0,0 +1,86 @@
///
/// Copyright (c) 2016 Sensus Metering Systems
///
namespace TBF.Rig.Configs.NameOnly
{
partial class TestMethodCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
this.classNameLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(137, 57);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(130, 20);
this.nameTextBox.TabIndex = 5;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(27, 60);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 4;
this.nameLabel.Text = "Name";
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(134, 33);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
this.classNameLabel.TabIndex = 3;
this.classNameLabel.Text = "ComonentName";
//
// BasicPrinterCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "BasicPrinterCfgCtrl";
this.Size = new System.Drawing.Size(300, 200);
this.Load += new System.EventHandler(this.EntryFormCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label classNameLabel;
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -0,0 +1,192 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using log4net;
using Config.Entities;
using TBF.Rig.Generic;
using TBF.Resources;
namespace TBF.Rig.Configs.ParamsProvider
{
public partial class ComponentCfgCtrl : UserControl, IComponentCfgCtrl
{
static readonly ILog log = LogManager.GetLogger(typeof(ComponentCfgCtrl));
public bool ShowMore { get { return false; } }
IParamsProvider paramsProvider;
///
public IComponentCfg Config
{
get
{
return paramsProvider as IComponentCfg;
}
set
{
paramsProvider = value as IParamsProvider;
Redraw();
}
}
Control[] editors;
CfgUpdateFlags flags;
public ComponentCfgCtrl()
{
InitializeComponent();
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="paramsProvider">Parameters provider implementing IComponentCfg and IParamsProvider</param>
/// <param name="parents">A list of parents or null, null hides parentComboBox</param>
public ComponentCfgCtrl(IParamsProvider paramsProvider, IEnumerable<Component> parents)
: this()
{
this.paramsProvider = paramsProvider;
if (parents == null)
{
parentLabel.Visible = false;
parentComboBox.Visible = false;
}
else
{
foreach (var p in parents) parentComboBox.Items.Add(p.Name);
}
editors = new Control[paramsProvider.ParamsCount()];
for (int i = 0; i < paramsProvider.ParamsCount(); i++)
{
ICollection<string> values = paramsProvider.ParamValues(i);
if (values == null)
{
editors[i] = new TextBox();
}
else
{
ComboBox cb = new ComboBox();
foreach (var v in values) cb.Items.Add(v);
editors[i] = cb;
}
editors[i].Visible = false;
this.Controls.Add(editors[i]);
}
flags = CfgUpdateFlags.None;
paramsListViewEx.SubItemClicked += new Results.Forms.SubItemEventHandler(paramsListViewEx_SubItemClicked);
paramsListViewEx.SubItemEndEditing += new Results.Forms.SubItemEndEditingEventHandler(paramsListViewEx_SubItemEndEditing);
}
void Localize()
{
componentClassLabel.Text = Strings.Component_class;
nameLabel.Text = Strings.Name;
parentLabel.Text = Strings.Parent_name;
}
private void EntryFormCfgCtrl_Load(object sender, EventArgs e)
{
Localize();
paramsListViewEx.Columns.Add(Strings.Parameter, 210);
paramsListViewEx.Columns.Add(Strings.Value, 210);
Redraw();
}
public void Closing()
{
/// Close CmdResponse handlers here
}
void Redraw()
{
if (paramsProvider == null) return; /// Control was not loaded, settings were not changed
componentClassTextBox.Text = Config.Factory.ClassName;
nameTextBox.Text = Config.Name;
if (parentComboBox.Visible) parentComboBox.Text = Config.ParentName;
paramsListViewEx.Items.Clear();
for (int i = 0; i < paramsProvider.ParamsCount(); i++)
{
ListViewItem lvi = new ListViewItem(paramsProvider.ParamName(i));
lvi.SubItems.Add(paramsProvider.ToString(i));
lvi.Tag = i;
paramsListViewEx.Items.Add(lvi);
}
}
public void Unlock()
{
nameTextBox.Enabled = true;
parentComboBox.Enabled = true; /// It still may be invisible
paramsListViewEx.Enabled = true;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
/// Verify the parent (if parent combo box is visible)
if (!parentComboBox.Visible || parentComboBox.Items.Contains(parentComboBox.Text))
{
return CfgUpdateFlags.None;
}
message += Environment.NewLine + string.Format(Strings.Invalid_0, parentLabel.Text);
return CfgUpdateFlags.Error;
}
public CfgUpdateFlags UpdateCfg()
{
if (paramsProvider == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
CfgUpdateFlags f = this.flags;
if (Config.Name != nameTextBox.Text)
{
Config.Name = nameTextBox.Text;
f |= CfgUpdateFlags.RestartRqrd;
}
if (parentComboBox.Visible && Config.ParentName != parentComboBox.Text)
{
Config.ParentName = parentComboBox.Text;
f |= CfgUpdateFlags.RestartRqrd;
}
return f;
}
private void paramsListViewEx_SubItemClicked(object sender, Results.Forms.SubItemEventArgs e)
{
if (e.SubItem != 1) return;
int itemNr = (int)e.Item.Tag;
paramsListViewEx.StartEditing(editors[itemNr], e.Item, e.SubItem);
}
private void paramsListViewEx_SubItemEndEditing(object sender, Results.Forms.SubItemEndEditingEventArgs e)
{
if (e.SubItem != 1) return;
int itemNr = (int)e.Item.Tag;
string message;
if (paramsProvider.ValidateParam(itemNr, e.DisplayText, out message))
{
flags |= paramsProvider.UpdateParam(itemNr, e.DisplayText);
}
else
{
MessageBox.Show(message);
e.DisplayText = e.Item.SubItems[e.SubItem].Text;
e.Cancel = true;
}
}
}
}
@@ -0,0 +1,171 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
namespace TBF.Rig.Configs.ParamsProvider
{
partial class ComponentCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
this.parentComboBox = new System.Windows.Forms.ComboBox();
this.parentLabel = new System.Windows.Forms.Label();
this.componentClassLabel = new System.Windows.Forms.Label();
this.componentClassTextBox = new System.Windows.Forms.TextBox();
this.paramsListViewEx = new Results.Forms.ListViewEx();
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
this.splitContainer1.Panel1.SuspendLayout();
this.splitContainer1.Panel2.SuspendLayout();
this.splitContainer1.SuspendLayout();
this.SuspendLayout();
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(161, 30);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(262, 20);
this.nameTextBox.TabIndex = 5;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(6, 33);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 4;
this.nameLabel.Text = "Name";
//
// splitContainer1
//
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
this.splitContainer1.IsSplitterFixed = true;
this.splitContainer1.Location = new System.Drawing.Point(0, 0);
this.splitContainer1.Name = "splitContainer1";
this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal;
//
// splitContainer1.Panel1
//
this.splitContainer1.Panel1.Controls.Add(this.parentComboBox);
this.splitContainer1.Panel1.Controls.Add(this.parentLabel);
this.splitContainer1.Panel1.Controls.Add(this.componentClassLabel);
this.splitContainer1.Panel1.Controls.Add(this.componentClassTextBox);
this.splitContainer1.Panel1.Controls.Add(this.nameLabel);
this.splitContainer1.Panel1.Controls.Add(this.nameTextBox);
//
// splitContainer1.Panel2
//
this.splitContainer1.Panel2.Controls.Add(this.paramsListViewEx);
this.splitContainer1.Size = new System.Drawing.Size(444, 353);
this.splitContainer1.SplitterDistance = 80;
this.splitContainer1.TabIndex = 6;
//
// parentComboBox
//
this.parentComboBox.Enabled = false;
this.parentComboBox.FormattingEnabled = true;
this.parentComboBox.Location = new System.Drawing.Point(161, 52);
this.parentComboBox.Name = "parentComboBox";
this.parentComboBox.Size = new System.Drawing.Size(262, 21);
this.parentComboBox.TabIndex = 9;
//
// parentLabel
//
this.parentLabel.AutoSize = true;
this.parentLabel.Location = new System.Drawing.Point(6, 55);
this.parentLabel.Name = "parentLabel";
this.parentLabel.Size = new System.Drawing.Size(38, 13);
this.parentLabel.TabIndex = 8;
this.parentLabel.Text = "Parent";
//
// componentClassLabel
//
this.componentClassLabel.AutoSize = true;
this.componentClassLabel.Location = new System.Drawing.Point(6, 11);
this.componentClassLabel.Name = "componentClassLabel";
this.componentClassLabel.Size = new System.Drawing.Size(89, 13);
this.componentClassLabel.TabIndex = 7;
this.componentClassLabel.Text = "Component Class";
//
// componentClassTextBox
//
this.componentClassTextBox.Enabled = false;
this.componentClassTextBox.Location = new System.Drawing.Point(161, 8);
this.componentClassTextBox.Name = "componentClassTextBox";
this.componentClassTextBox.Size = new System.Drawing.Size(262, 20);
this.componentClassTextBox.TabIndex = 6;
//
// paramsListViewEx
//
this.paramsListViewEx.AllowColumnReorder = true;
this.paramsListViewEx.Dock = System.Windows.Forms.DockStyle.Fill;
this.paramsListViewEx.DoubleClickActivation = false;
this.paramsListViewEx.Enabled = false;
this.paramsListViewEx.FullRowSelect = true;
this.paramsListViewEx.GridLines = true;
this.paramsListViewEx.LabelWrap = false;
this.paramsListViewEx.Location = new System.Drawing.Point(0, 0);
this.paramsListViewEx.Name = "paramsListViewEx";
this.paramsListViewEx.Size = new System.Drawing.Size(444, 269);
this.paramsListViewEx.TabIndex = 0;
this.paramsListViewEx.UseCompatibleStateImageBehavior = false;
this.paramsListViewEx.View = System.Windows.Forms.View.Details;
this.paramsListViewEx.SubItemClicked += new Results.Forms.SubItemEventHandler(this.paramsListViewEx_SubItemClicked);
this.paramsListViewEx.SubItemEndEditing += new Results.Forms.SubItemEndEditingEventHandler(this.paramsListViewEx_SubItemEndEditing);
//
// ComponentCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.splitContainer1);
this.Name = "ComponentCfgCtrl";
this.Size = new System.Drawing.Size(444, 353);
this.Load += new System.EventHandler(this.EntryFormCfgCtrl_Load);
this.splitContainer1.Panel1.ResumeLayout(false);
this.splitContainer1.Panel1.PerformLayout();
this.splitContainer1.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
this.splitContainer1.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.SplitContainer splitContainer1;
private System.Windows.Forms.ComboBox parentComboBox;
private System.Windows.Forms.Label parentLabel;
private System.Windows.Forms.Label componentClassLabel;
private System.Windows.Forms.TextBox componentClassTextBox;
private Results.Forms.ListViewEx paramsListViewEx;
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+14
View File
@@ -0,0 +1,14 @@
///
/// Copyright (c) 2013-2017 Sensus Metering Systems
///
namespace TBF.Rig
{
public static class Constants
{
/// <summary>
/// A fraction of the tank volume that is considered to be safe.
/// When the estimated test end tank volume exceeds this fraction, tank emptying is forced.
/// </summary>
public const float TankFullFactor = 0.95f;
}
}
+82
View File
@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using Config.Entities;
using Dirichlet.Numerics;
using TBF.Rig.Generic;
using TBF.Rig.GenericDevices;
namespace TBF.Rig.ControlBoard
{
public interface IControlBoard : IDevice, IValveControl
{
void SpecifyInvertedValves(UInt128 valvesToInvert);
/// <summary>
/// Called on beginning of a test
/// </summary>
void ClearProcessValues();
///
/// Values valid always
///
UInt128 Route { get; } /// State of valves
UInt64 DigitalInputs { get; } /// Inputs
///
/// Values valid during a test
///
double RefFrequency { get; }
double RefFlow { get; }
///
/// Last test results
///
double TestTime { get; }
int RefPulses { get; }
double TestTimeWM(int wmNr1);
int RefPulsesWM(int wmNr1);
int PulsesWM(int wmNr1);
float ValveOpenCloseTime { get; } /// Start valve open or close time in sec
/// <summary>
/// Select devices used for control and measurement
/// </summary>
/// <param name="outPath"></param>
OutputPath Devices { set; get; }
/// <summary>
/// Returns operation which sets the flow. Events:
/// </summary>
/// <param name="flowLimLo">Lower flow limit</param>
/// <param name="flowLimHi">Upper flow limit</param>
/// <param name="measuredFlow">Reference to calss keeping current flow value</param>
/// <param name="timeout">Timeout in seconds</param>
/// <returns>Operation</returns>
IOperation SetFlowOp(double flowLimLo, double flowLimHi, TBF.Boxes.DoubleBox measuredFlow, int timeout);
IOperation StopFlowRegulationOp();
/// <summary>
/// Start a test, Events: MeasurementStarted
/// </summary>
/// <param name="iParam">Int32 parameter 1</param>
/// <param name="dParam1">Double parameter 1 (alternative lower flow limit)</param>
/// <param name="dParam2">Double parameter 2 (alternative upper flow limit)</param>
/// <returns>Operation</returns>
IOperation StartTestOp(Test test, int iParam = 0, double dParam1 = 0, double dParam2 = 0);
IOperation ReadDiverterTransitionOp(bool isStart, Sequences.Statistics plotter, int batchNr, string testName, int repetition);
/// <summary>
/// Returns operation with events: Event.MeasurementCompleted or Event.None
/// </summary>
/// <returns>Operation</returns>
IOperation QueryMeasurementEndOp();
IOperation StopPreviousOp();
}
}
+113
View File
@@ -0,0 +1,113 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
using System;
namespace TBF.Rig.ControlBoard.Legacy
{
public enum Command
{
None = 0, /// Do nothing, just transfer data (route, etc.)
Start = 1, /// Start the measurement
Stop = 2, /// Stop the measurement
ReadDivTransition = 4,
ReadExtremasOfPulses = 6,
ReadShapesOfPulses = 7,
ResetShapesOfPulses = 8,
EnduranceCycleParamsUpload = 11,
EnduranceCycleStart = 12,
EnduranceCycleStop = 13,
}
#if FUZHOU_300 || IZRAEL_200 || TORINO_50 || BADGER_MALA_TRAT || BADGER_STREDNA_TRAT || TURA_IPERL || TURA_IPERL_NEW || TURA_SPECIAL || BADGER_VELKA_TRAT || PUCHONG_200 || SLM_50 || GENESIS || MALTA_WSD25 || SLM_END || WARSAW_END || BERLIN || GELSENWASSER || SLM_150 || PETERSBURG_50 || PETERSBURG_200 || DEWA_300 || ROMA_200 || KEMPNO_50 || BAHRAIN_50 || RUM_MOB || KRAKOW_50 || JUZNA_AFRIKA_50 || IZRAEL_25 || ZAMBIA || ZODINO || FEWA_50 || FILIPINY_50 || SENTEC || FUZHOU_100 || CEVAK_200 || IZRAEL_50 || ALZIR_25
public enum StatusP : ulong
{
RefFlowMeterMask = 0x7, /// bits 0,1,2
TestCompleted = 0x10, /// bit 4
TestInProgress = 0x20, /// bit 5
//DiverterError = 0x20,
MsrmntWithDivrtr = 0x80, /// bit 7
RefPulsesMsrmnt = 0x100, /// bit 8
SynchroMethod = 0x800, /// bit 11
WaterMeterCalib = 0x1000, /// bit 12
EmgcyStopActive = 0x2000, /// bit 13
MsrmntGateActive = 0x4000, /// bit 14
TimeMeasurement = 0x8000, /// bit 15
FrequencyMeasured = 0x80000, /// bit 19
CoaxRegValveBusy = 0x200000, /// bit 21
ADCError = 0x80000000, /// bit 31
TimeoutOccured = 0x100000000, /// bit 32
MeretAddresses = 0x200000000, /// bit 33
SampleBuferFull = 0x400000000, /// bit 34
ErrorTempMeter = 0x10000000000, /// bit 40
ErrorPressMeter1 = 0x1000000000000, /// bit 48
ErrorPressMeter2 = 0x2000000000000, /// bit 49
ErrorPressMeter3 = 0x4000000000000, /// bit 50
ErrorPressMeter4 = 0x8000000000000, /// bit 51
EndurCycleRunning = 0x200000000000000, /// bit 57
}
#else // DN100 || MUNICH || FUZHOU_150 || TORUN_50 || CEVAK_40 || MURES_40 || FUZHOU_50
public enum StatusP : ulong
{
RefFlowMeterMask = 0x7,
TestInProgress = 0x8,
TestCompleted = 0x10,
DiverterError = 0x20,
MsrmntWithDivrtr = 0x80,
RefPulsesMsrmnt = 0x100,
SynchroMethod = 0x800,
WaterMeterCalib = 0x1000,
EmgcyStopActive = 0x2000,
MsrmntGateActive = 0x4000,
TimeMeasurement = 0x8000,
FrequencyMeasured = 0x80000,
CoaxRegValveBusy = 0x200000, /// bit 21
ADCError = 0x80000000,
TimeoutOccured = 0x100000000,
MeretAddresses = 0x200000000,
SampleBuferFull = 0x400000000,
ErrorTempMeter = 0x10000000000,
ErrorPressMeter1 = 0x1000000000000,
ErrorPressMeter2 = 0x2000000000000,
ErrorPressMeter3 = 0x4000000000000,
ErrorPressMeter4 = 0x8000000000000,
EndurCycleRunning = 0x200000000000000, /// bit 57
}
#endif
public enum StopDevs
{
None = 0,
Reference = 0x01, /// bit 0
Diverter = 0x02, /// bit 1
GatePulse = 0x08, /// bit 3
TimeMeasurement = 0x10, /// bit 4
BypassDevCoupled2Div = 0x20, /// bit 5
RegValveRegulation = 0x80, /// bit 7
All = 0xFF,
}
public enum TestMethods
{
Diverter = 0x01, /// bit 0: 1=Mass method (diverters are used), 0=Volume method
FixedStart = 0x02, /// bit 1: 1=fixed start method, 0=flying start method
Synchro = 0x04, /// bit 2: 1=Synchro method, 0=Pulse counting
MassAndContinue = 0x10, /// bit 4: 1=Method with mass measurement followed by a volume method
}
public enum RegulValveMode : byte
{
None = 0,
PulseWidth = 1, /// Pulse width 0.05 .. 2 sec.
TargetPosition = 2, /// Low and high position (=DAC value) limits (0..100%) are specified
TargetFrequency = 3, /// Low and high frequency limits (0..2000Hz,0..2200Hz) are specified
Stop = 4, /// Stop regulation
}
public enum RegulValveState
{
Idle = 0,
PwOrFreqRegul = 2,
DacValueRegul = 3,
}
}
@@ -0,0 +1,45 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
using System.Collections.Generic;
using System.Xml.Serialization;
using TBF.Rig.Generic;
namespace TBF.Rig.ControlBoard.Legacy
{
public class ControlBoardCfg : ComponentCfgBase, IComponentCfg
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(ControlBoardCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new ControlBoardCfgCtrl(); }
///
/// Serialized parameters
///
public int ComPortNr;
public int VirtualValvesRangeLo;
public int VirtualValvesRangeHi;
/// Private parameterless constructor invoked by all other (public) constructors
ControlBoardCfg()
{
Name = "CB";
ParentName = string.Empty;
ComPortNr = 1;
VirtualValvesRangeLo = 50;
VirtualValvesRangeHi = 59;
}
public ControlBoardCfg(IComponentFactory factory)
: this()
{
this.Factory = factory;
}
public string ToString(int i)
{
return string.Format("Name={0}, Com{1}, VVRangeLo={2}, VVRangeHi={3}", Name, ComPortNr, VirtualValvesRangeLo, VirtualValvesRangeHi);
}
}
}
@@ -0,0 +1,155 @@
///
/// Copyright (c) 2013-2015 Sensus Metering Systems
///
namespace TBF.Rig.ControlBoard.Legacy
{
partial class ControlBoardCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.comPortNrLabel = new System.Windows.Forms.Label();
this.comPortNrTextBox = new System.Windows.Forms.TextBox();
this.classNameLabel = new System.Windows.Forms.Label();
this.nameLabel = new System.Windows.Forms.Label();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.vValveRangeLoTextBox = new System.Windows.Forms.TextBox();
this.vValveRangeLoLabel = new System.Windows.Forms.Label();
this.vValveRangeHiTextBox = new System.Windows.Forms.TextBox();
this.vValveRangeHiLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// comPortNrLabel
//
this.comPortNrLabel.AutoSize = true;
this.comPortNrLabel.Location = new System.Drawing.Point(42, 85);
this.comPortNrLabel.Name = "comPortNrLabel";
this.comPortNrLabel.Size = new System.Drawing.Size(95, 13);
this.comPortNrLabel.TabIndex = 0;
this.comPortNrLabel.Text = "Serial port number:";
//
// comPortNrTextBox
//
this.comPortNrTextBox.Enabled = false;
this.comPortNrTextBox.Location = new System.Drawing.Point(166, 82);
this.comPortNrTextBox.Name = "comPortNrTextBox";
this.comPortNrTextBox.Size = new System.Drawing.Size(80, 20);
this.comPortNrTextBox.TabIndex = 1;
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(163, 26);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
this.classNameLabel.TabIndex = 2;
this.classNameLabel.Text = "ComonentName";
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(42, 60);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 3;
this.nameLabel.Text = "Name";
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(166, 57);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(80, 20);
this.nameTextBox.TabIndex = 4;
//
// vValveRangeLoTextBox
//
this.vValveRangeLoTextBox.Enabled = false;
this.vValveRangeLoTextBox.Location = new System.Drawing.Point(166, 107);
this.vValveRangeLoTextBox.Name = "vValveRangeLoTextBox";
this.vValveRangeLoTextBox.Size = new System.Drawing.Size(80, 20);
this.vValveRangeLoTextBox.TabIndex = 6;
//
// vValveRangeLoLabel
//
this.vValveRangeLoLabel.AutoSize = true;
this.vValveRangeLoLabel.Location = new System.Drawing.Point(42, 110);
this.vValveRangeLoLabel.Name = "vValveRangeLoLabel";
this.vValveRangeLoLabel.Size = new System.Drawing.Size(118, 13);
this.vValveRangeLoLabel.TabIndex = 5;
this.vValveRangeLoLabel.Text = "Virtual valves range Lo:";
//
// vValveRangeHiTextBox
//
this.vValveRangeHiTextBox.Enabled = false;
this.vValveRangeHiTextBox.Location = new System.Drawing.Point(166, 132);
this.vValveRangeHiTextBox.Name = "vValveRangeHiTextBox";
this.vValveRangeHiTextBox.Size = new System.Drawing.Size(80, 20);
this.vValveRangeHiTextBox.TabIndex = 8;
//
// vValveRangeHiLabel
//
this.vValveRangeHiLabel.AutoSize = true;
this.vValveRangeHiLabel.Location = new System.Drawing.Point(42, 135);
this.vValveRangeHiLabel.Name = "vValveRangeHiLabel";
this.vValveRangeHiLabel.Size = new System.Drawing.Size(116, 13);
this.vValveRangeHiLabel.TabIndex = 7;
this.vValveRangeHiLabel.Text = "Virtual valves range Hi:";
//
// ControlBoardCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.vValveRangeHiTextBox);
this.Controls.Add(this.vValveRangeHiLabel);
this.Controls.Add(this.vValveRangeLoTextBox);
this.Controls.Add(this.vValveRangeLoLabel);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Controls.Add(this.comPortNrTextBox);
this.Controls.Add(this.comPortNrLabel);
this.Name = "ControlBoardCfgCtrl";
this.Size = new System.Drawing.Size(300, 200);
this.Load += new System.EventHandler(this.ControlBoardCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label comPortNrLabel;
private System.Windows.Forms.TextBox comPortNrTextBox;
private System.Windows.Forms.Label classNameLabel;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.TextBox vValveRangeLoTextBox;
private System.Windows.Forms.Label vValveRangeLoLabel;
private System.Windows.Forms.TextBox vValveRangeHiTextBox;
private System.Windows.Forms.Label vValveRangeHiLabel;
}
}
@@ -0,0 +1,105 @@
///
/// Copyright (c) 2013-2015 Sensus Slovensko a.s.
///
using System;
using System.Windows.Forms;
using Config.Entities;
using TBF.Rig.Generic;
namespace TBF.Rig.ControlBoard.Legacy
{
public partial class ControlBoardCfgCtrl : UserControl, IComponentCfgCtrl
{
public bool ShowMore { get { return false; } }
ControlBoardCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as ControlBoardCfg;
Redraw();
}
}
public ControlBoardCfgCtrl()
{
InitializeComponent();
}
private void ControlBoardCfgCtrl_Load(object sender, EventArgs e)
{
Redraw();
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
comPortNrTextBox.Text = config.ComPortNr.ToString();
vValveRangeLoTextBox.Text = config.VirtualValvesRangeLo.ToString();
vValveRangeHiTextBox.Text = config.VirtualValvesRangeHi.ToString();
}
public void Unlock()
{
nameTextBox.Enabled = true;
comPortNrTextBox.Enabled = true;
vValveRangeLoTextBox.Enabled = true;
vValveRangeHiTextBox.Enabled = true;
}
/// <summary>
/// Verify current user controls for validity.
/// Called when user wants to close/save the configuration.
/// </summary>
/// <returns>See VerifyFlags</returns>
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
int dummy;
if (!int.TryParse(comPortNrTextBox.Text, out dummy) || dummy <= 0 || dummy > 999)
{
message += "Control board serial port number is invalid";
flags |= CfgUpdateFlags.Error;
}
if (!int.TryParse(vValveRangeLoTextBox.Text, out dummy) || dummy < 0 || dummy > 63)
{
message += "Virtual valves range Lo is invalid";
flags |= CfgUpdateFlags.Error;
}
if (!int.TryParse(vValveRangeHiTextBox.Text, out dummy) || dummy < 0 || dummy > 63)
{
message += "Virtual valves range Hi is invalid";
flags |= CfgUpdateFlags.Error;
}
return flags;
}
/// <summary>
/// Save settings to the configuration class.
/// </summary>
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
this.Name = nameTextBox.Text;
this.config.ComPortNr = int.Parse(comPortNrTextBox.Text);
this.config.VirtualValvesRangeLo = int.Parse(vValveRangeLoTextBox.Text);
this.config.VirtualValvesRangeHi = int.Parse(vValveRangeHiTextBox.Text);
return flags;
}
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -0,0 +1,864 @@
///
/// Copyright (c) 2013-2020 Sensus Slovensko a.s.
///
using System;
using System.Text;
using System.IO.Ports;
using System.Collections.Generic;
using log4net;
using Config.Entities;
using Dirichlet.Numerics;
using TBF.Rig.Generic;
using TBF.Rig.GenericDevices;
namespace TBF.Rig.ControlBoard.Legacy
{
public class CBoard : ComponentBase, IControlBoard
{
private static readonly ILog log = LogManager.GetLogger(typeof(CBoard));
public override string ToString() { return string.Format("ControlBoard({0})", Cfg.ToString(1)); }
const int FiltersCount = 8;
readonly ControlBoardCfg controlBoardCfg;
///
/// Reference to the control board component
///
IControlCom controlCom;
/// <summary>
/// Emergency stop signal state updated by RunDevice().
/// 'modelessDlg' is notified about the changes and uses this information to change its visibility.
/// </summary>
//UiBridge.EmergencyStopEventArgs.State emergencyStopState;
///
/// Public read only wrappers for Elde software component fields
///
/// rvNr1 = 1 .. nrRegulValves (one based)
/// wmNr0 = 0 .. nrWaterMeters-1 (zero based)
/// tmpNr0 = 0 .. nrTempMeters-1 (zero based)
/// prsNr0 = 0 .. nrPressureMeters-1 (zero based)
///
public StatusP StatusP { get { return controlCom.StatusP; } }
public int EtPulsesK { get { return controlCom.EtPulsesK; } }
public int EtPulses2 { get { return controlCom.EtPulses2; } } /// DEWA_300: pulses from I12
public int EtPulses3 { get { return controlCom.EtPulses3; } } /// DEWA_300: pulses from I13
public int WMeterReference(int wmNr0) { return controlCom.WMeterReference(wmNr0); }
public uint RegulValveDAC(int rvNr0) { return controlCom.RegulValveDAC(rvNr0); }
public float Pressure(int prsNr0) { return controlCom.Pressure(prsNr0); }
public float Temperature(int tmpNr0) { return controlCom.Temperature(tmpNr0); }
public RegulValveState RegulValveState(int rvNr1) { return (RegulValveState)controlCom.RegulValveState(rvNr1); }
public UInt128 RRoute { get { return controlCom.RRoute; } }
public uint DivTime(int id) { return controlCom.DivTime(id); }
public uint FmState { get { return controlCom.FmState; } }
public uint BeginState(int wmNr0) { return controlCom.BeginState(wmNr0); }
public double RefFrequency { get { return controlCom.ReferenceFreq; } } /// In [Hz] 0..2500, nom.=2000
public double ReferenceFreqs(int i) { return controlCom.ReferenceFreqs(i); }
public double RefFlow { get { return controlCom.ReferenceFlow; } }
public float RValvePosition(int rvNr1) { return controlCom.RValvePosition(rvNr1); }
public float DivSamples(int time, int divIx0) { return controlCom.DivSamples(time, divIx0); } /// Time unit is 2 ms
public int ScopeSamples(int i, int j, int k) { return controlCom.ScopeSamples(i, j, k); }
public ulong DigitalInputs { get { return controlCom.DigitalInputs; } }
public float AnalogInput(int adcNr0) { return controlCom.AnalogInput(adcNr0); }
public uint AnalogInputRaw(int adcNr0, int bank) { return controlCom.AnalogInputRaw(adcNr0, bank); } /// adcNr0: 0=RV1, 1=RV2,... bank: 0=RV, 1=Temp
public float ReferenceVolume { get { return controlCom.TotalRefVolume; } }
public float VyslExt(int wmNr0, int what) { return controlCom.VyslExt(wmNr0, what); }
public uint[] CyclePar { get { return controlCom.CyclePar; } set { controlCom.CyclePar = value; } }
public uint[] WMeterCont { get { return controlCom.WMeterCont; } }
public bool ManualUIAllowed { get { return controlCom.ManualUIAllowed; } set { controlCom.ManualUIAllowed = value; } }
public float ValveOpenCloseTime { get { return controlCom.ValveOpenCloseTime; } }
/// <summary> Extracted from the StatusP in RunDeviceBefore </summary>
public bool EmergencyStop { get { return emergencyStop; } }
bool emergencyStop;
bool previousEmergencyStop;
///
/// IControlBoard interface
///
public int RefPulses { get { return controlCom.EtPulses(0); } }
public double TestTime { get { return (double)controlCom.TTime; } }
public int RefPulsesWM(int wmNr1) { return (wmNr1 > 0 && wmNr1 <= Config.Data.WMsCount) ? controlCom.EtPulses(wmNr1) : 0; }
public int PulsesWM(int wmNr1) { return (wmNr1 > 0 && wmNr1 <= Config.Data.WMsCount) ? unwrappedWMPulses[wmNr1] : 0; }
public double TestTimeWM(int wmNr1) { return (wmNr1 > 0 && wmNr1 <= Config.Data.WMsCount) ? (double)controlCom.ImpulseTime(wmNr1) : 0; }
public void DiverterToTank(int flowMtrNr)
{
cbCommandQueue.Enqueue(new SendCommandArgs(Command.Start, flowMtrNr, int.MaxValue, int.MaxValue, TestMethods.Diverter | TestMethods.Synchro, StopDevs.None));
}
///
public void DiverterToSink(int flowMtrNr)
{
cbCommandQueue.Enqueue(new SendCommandArgs(Command.Stop, 0, 0, 0, TestMethods.Diverter,
StopDevs.Diverter | StopDevs.GatePulse | StopDevs.Reference | StopDevs.RegValveRegulation));
}
///
public void ReadDiverterTransition(int flowMtrNr)
{
cbCommandQueue.Enqueue(new SendCommandArgs(Command.ReadDivTransition, flowMtrNr, 0, 0, TestMethods.Diverter, 0));
}
///
/// Initialization data updated by constructors of children components
/// and sent to 'controlCom2panel' by SendCalibData() method.
///
#if DEWA_300 || ROMA_200
public float[,] TempCalibData = new float[16, 5];
#else
public float[,] TempCalibData = new float[8, 5];
#endif
public uint[] DiverterEdge; /// Created and initialized in this.Initialize()
public byte MeretProtocol = 0;
// Array length is the reference flowmeters count plus one
#if DN100 || FUZHOU_150 || FUZHOU_300 || IZRAEL_200 || SENTEC || CEVAK_200
public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}};
public byte[] MeretRS485Address = new byte[4];
public float[] EtCalib = new float[6] { 1, 1, 1, 1, 1, 1 };
#elif PUCHONG_200 || GENESIS || BERLIN || GELSENWASSER || PETERSBURG_200 || RUM_MOB || SLM_150
public uint[,] RegValveCalib = new uint[16, 2] { {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500},
{100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500} };
public byte[] MeretRS485Address = new byte[4];
public float[] EtCalib = new float[7] { 1, 1, 1, 1, 1, 1, 1 };
#elif DEWA_300
public uint[,] RegValveCalib = new uint[16, 2] { {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500},
{100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500} };
public byte[] MeretRS485Address = new byte[4];
public float[] EtCalib = new float[8] { 1, 1, 1, 1, 1, 1, 1, 1 };
#elif ROMA_200
public uint[,] RegValveCalib = new uint[16, 2] { {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500},
{100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500} };
public byte[] MeretRS485Address = new byte[5];
public float[] EtCalib = new float[8] { 1, 1, 1, 1, 1, 1, 1, 1 };
#elif MUNICH || TORINO_50 || BADGER_MALA_TRAT || BADGER_STREDNA_TRAT || TORUN_50 || CEVAK_40 || TURA_IPERL || TURA_IPERL_NEW || TURA_SPECIAL || MURES_40 || FUZHOU_50 || SLM_50 || PETERSBURG_50 || KEMPNO_50 || BAHRAIN_50 || KRAKOW_50 || JUZNA_AFRIKA_50 || IZRAEL_25 || ZAMBIA || ZODINO || FEWA_50 || FILIPINY_50 || FUZHOU_100 || ALZIR_25
public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}};
#if IZRAEL_50
public byte[] MeretRS485Address = new byte[6];
#else
public byte[] MeretRS485Address = new byte[4];
#endif
public float[] EtCalib = new float[5] { 1, 1, 1, 1, 1 };
#elif IZRAEL_50 || SLM_END
public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}};
public byte[] MeretRS485Address = new byte[7]; /// Modbus addresses of Pr1, Pr2, Pr3, Pr4, Pr5, Pr6, T9 (Izrael) or Pr1, Pr2, Pr3, Pr4, T9, T10 (SLM END)
public float[] EtCalib = new float[5] { 1, 1, 1, 1, 1 };
#elif WARSAW_END
public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}};
public byte[] MeretRS485Address = new byte[4];
public float[] EtCalib = new float[5] { 1, 1, 1, 1, 1 };
#elif MALTA_WSD25
public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}};
public byte[] MeretRS485Address = new byte[12];
public float[] EtCalib = new float[9] { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
#elif BADGER_VELKA_TRAT
public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}};
public byte[] MeretRS485Address = new byte[4];
public float[] EtCalib = new float[8] { 1, 1, 1, 1, 1, 1, 1, 1 };
#else
/// New benches => no initialization buffers at all
public uint[,] RegValveCalib = new uint[0,0];
public byte[] MeretRS485Address = new byte[0];
public float[] EtCalib = new float[0];
#endif
public uint[] BalanceRange = new uint[2];
Queue<SendCommandArgs> cbCommandQueue;
/// <summary>
/// Route: 128-bit word representing the current state of all valves and pumps
/// </summary>
public UInt128 Route { get { return benchModelRoute; } }
UInt128 benchModelRoute;
UInt128 valvesToInvert; /// Route = valesToInvert ^ RequiredRouteWithoutInvertedVlaves
readonly UInt128 routeMask; /// This mask masks out virtual valves, routeMask is set in the constructor
public OutputPath Devices
{
set { devices = value; }
get { return devices; }
}
OutputPath devices;
int[] filters;
float[] FMFreq;
int regConst;
int shortImp;
private int[] unwrappedWMPulses; /// Initialized to zeros
///
private void UnwrapPulses()
{
for (int i = 1; i <= Config.Data.WMsCount; i++)
{
UInt16 lowerWord = controlCom.WMeterPulses(i);
int uncorrected = (int)(((uint)unwrappedWMPulses[i] & 0xFFFF0000) | lowerWord);
if (Math.Abs(uncorrected - unwrappedWMPulses[i]) <= Int16.MaxValue)
{
unwrappedWMPulses[i] = uncorrected;
}
else if (Math.Abs(uncorrected + 65536 - unwrappedWMPulses[i]) <= Int16.MaxValue)
{
unwrappedWMPulses[i] = uncorrected + 65536;
}
else if (Math.Abs(uncorrected - 65536 - unwrappedWMPulses[i]) <= Int16.MaxValue)
{
unwrappedWMPulses[i] = uncorrected - 65536;
}
}
}
///
public void ClearProcessValues()
{
for (int i = 1; i <= Config.Data.WMsCount; i++)
{
unwrappedWMPulses[i] = 0;
}
UnwrapPulses();
}
/// <summary>
/// Set values to be applied during a test
/// </summary>
/// <param name="filters">Filters for meter pulses</param>
/// <param name="pid">PID coefficient for flow control</param>
/// <param name="shortPulses">Short pulses mode (0 = off)</param>
public void SetFiltersPidShortPulses(int[] filters, float pid, int shortPulses)
{
this.filters = filters;
this.regConst = (int)pid;
this.shortImp = shortPulses;
}
/// <summary>
/// Sets the power of the selected pump
/// </summary>
/// <param name="index">Pump index 0 .. 5, invalid pump index sets all pumps to 0%</param>
/// <param name="power">Power (0.0f .. 100.0f)</param>
public void SetFMFreq(int index, double power)
{
bool pumpPowerChanged = false;
#if DN100 || MUNICH || FUZHOU_150
if ((FMFreq == null) || (FMFreq.Length != 2))
{
FMFreq = new float[2];
pumpPowerChanged = true; /// Forces sending a command using Command.None
}
#elif SLM_END || WARSAW_END
if ((FMFreq == null) || (FMFreq.Length != 4))
{
FMFreq = new float[4];
pumpPowerChanged = true; /// Forces sending a command using Command.None
}
#else /// all newer benches
if ((FMFreq == null) || (FMFreq.Length != 6))
{
FMFreq = new float[6];
pumpPowerChanged = true; /// Forces sending a command using Command.None
}
#endif
if (index >= 0 && index < FMFreq.Length)
{
if (FMFreq[index] != power)
{
FMFreq[index] = (float)power;
pumpPowerChanged = true; /// Forces sending a command using Command.None
string s = string.Format("FMFreq=[{0}{1}{2}{3}{4}{5}]", FMFreq[0].ToString(),
(FMFreq.Length > 1) ? ("," + FMFreq[1].ToString()) : "",
(FMFreq.Length > 2) ? ("," + FMFreq[2].ToString()) : "",
(FMFreq.Length > 3) ? ("," + FMFreq[3].ToString()) : "",
(FMFreq.Length > 4) ? ("," + FMFreq[4].ToString()) : "",
(FMFreq.Length > 5) ? ("," + FMFreq[5].ToString()) : "");
log.Warn(s);
}
}
else
{
log.ErrorFormat("Wrong FM pump: index = {0}, power = {1}", index, power);
}
}
public void UpdateWeights()
{
/// Mettler-Toledo scales
for (int i = 0; i < MettlerToledo.Standard.BalanceDev.BalancesCount; i++)
{
controlCom.SetWeight(i, MettlerToledo.Standard.BalanceDev.Masses[i]);
}
/// Mettler-Toledo-multi scales (Badger Brno, ...)
for (int i = 0; i < MettlerToledo.Multi.BalanceDev.BalancesCount; i++)
{
controlCom.SetWeight(i, MettlerToledo.Multi.BalanceDev.Masses[i]);
}
/// Tanks (CEVAK, ...)
int firstTankIx = Math.Max(MettlerToledo.Standard.BalanceDev.BalancesCount, MettlerToledo.Multi.BalanceDev.BalancesCount);
for (int i = 0; i < Various.TankWithLevelMsrmnt.Tank.TanksCount; i++)
{
controlCom.SetWeight(firstTankIx + i, Various.TankWithLevelMsrmnt.Tank.Tanks[i].Volume);
}
}
/// <summary>
/// Display value in ELDE component, update UI
/// </summary>
/// <param name="sParam">String parameter</param>
/// <param name="iParam">Integer parameter</param>
/// <param name="value">Value to be displayed</param>
public void UpdateUI(string sParam, int iParam, double value)
{
if (sParam == "ReservoirTemp")
{
controlCom.SetReservoirTemp(iParam, (float)value);
return;
}
}
public CBoard()
{
}
/// <summary>
/// Constructor
/// </summary>
public CBoard(Generic.IComponentCfg cfg)
: base(cfg)
{
controlBoardCfg = cfg as ControlBoardCfg;
/// Buffers used in UnwrapPulses() and PulsesWM(wmNr1)
unwrappedWMPulses = new int[Config.Data.WMsCount + 1];
cbCommandQueue = new Queue<SendCommandArgs>();
lastSentFilters = new uint[FiltersCount];
#if DN100 || MUNICH || FUZHOU_150
FMFreq = new float[2] { 0, 0 }; /// Nr. of pumps: Fuzhou150=2, Fuzhou300=6, newer=6
#elif SLM_END || WARSAW_END
FMFreq = new float[4] { 0, 0, 0, 0 };
#else /// all newer benches
FMFreq = new float[6] { 0, 0, 0, 0, 0, 0 };
#endif
emergencyStop = false;
previousEmergencyStop = false;
routeMask = 0;
for (int i = 0; i < 128; i++)
{
if (i < controlBoardCfg.VirtualValvesRangeLo || i > controlBoardCfg.VirtualValvesRangeHi)
{
routeMask = routeMask | ((UInt128)1 << i);
}
}
log.Debug(this.ToString());
}
/// <summary>
/// Specific pre-initialization for control board only
/// </summary>
/// <param name="eldeComponent"></param>
public void SpecifyInvertedValves(UInt128 valvesToInvert)
{
this.valvesToInvert = valvesToInvert;
this.benchModelRoute = valvesToInvert;
if (controlBoardCfg.DebugLevel == DebugMode.Simulate)
{
controlCom = new ControlComSim();
}
else
{
// controlCom = new ControlComWrap(eldeComponent);
/// Default number of scales (and BalanceRange length) is 2.
/// If there are more scales, BalanceRange length is larger.
// int scalesCnt = Math.Max(2, tankCapacities.Length);
// BalanceRange = new uint[scalesCnt];
// for (int i = 0; i < scalesCnt; i++)
// {
// BalanceRange[i] = (uint)((i < tankCapacities.Length) ? tankCapacities[i] : 0);
// }
}
}
/// <summary>Initialize this device</summary>
public void Initialize()
{
int divertersCount = Rig.Elde.Diverter.Diverter.DivertersCount;
DiverterEdge = new uint[divertersCount];
for (int i = 0; i < divertersCount; i++)
{
DiverterEdge[i] = (uint)Rig.Elde.Diverter.Diverter.Diverters[i].ThresholdGate;
controlCom.SetDivLimit(i, (uint)Rig.Elde.Diverter.Diverter.Diverters[i].ThresholdLo,
(uint)Rig.Elde.Diverter.Diverter.Diverters[i].ThresholdHi);
}
controlCom.SendCalibData(RegValveCalib,
MeretRS485Address,
controlBoardCfg.ComPortNr,
TempCalibData,
EtCalib,
DiverterEdge,
BalanceRange,
MeretProtocol);
log.FatalFormat("Successfully initialized device {0}", ToString());
}
/// <summary>
/// Run this device
/// </summary>
public void RunDeviceBefore()
{
if (DebugLevel == DebugMode.Simulate) return;
controlCom.RunDeviceBefore();
UnwrapPulses();
}
///
/// Used in RunDeviceAfter() when sending commands
///
UInt128 lastSentRoute;
uint[] lastSentFilters;
float[] lastSentFMFreq;
int lastsentRegConst;
int lastSentShortImp;
/// <summary>
/// Run this device
/// </summary>
public void RunDeviceAfter()
{
if (DebugLevel == DebugMode.Simulate) return;
previousEmergencyStop = emergencyStop;
emergencyStop = (controlCom.StatusP & StatusP.EmgcyStopActive) != 0;
///
if (emergencyStop)
{
/// Modify the queue in case of an emergency stop
cbCommandQueue.Clear();
cbCommandQueue.Enqueue(new SendCommandArgs(Command.Stop, 0, 0, 0, 0, StopDevs.All));
}
///
if (emergencyStop && !previousEmergencyStop)
{
/// Stop the cycle - Press 'STOP' button in the BenchControlPanel
TBF.UiBridge.Bridge.Ui2Bench(TBF.UiBridge.UI2BenchCmd.Stop);
Program.MainWnd.Invoke(new ShowEmergencyStopFormDlgt(ShowEmergencyStopForm));
}
else if (!emergencyStop && previousEmergencyStop)
{
UiBridge.Bridge.OnEmergencyStopChanged(this, UiBridge.EmergencyStopEventArgs.State.CloseForm);
}
UpdateWeights();
/// Prepare uintFilters array and evaluate changes
uint[] uintFilters = new uint[FiltersCount];
uintFilters[0] = (filters != null && filters.Length > 0) ? (uint)filters[0] : 0;
bool filtersAreDifferent = (uintFilters[0] != lastSentFilters[0]);
for (int i = 1; i < FiltersCount; i++)
{
uintFilters[i] = (filters != null && filters.Length > i) ? (uint)filters[i] : uintFilters[i - 1];
filtersAreDifferent |= (uintFilters[i] != lastSentFilters[i]);
}
/// Evaluate FMFreq changes
bool fmFreqsAreDifferent = false;
if ((FMFreq == null) || (lastSentFMFreq == null) || (FMFreq.Length != lastSentFMFreq.Length))
{
fmFreqsAreDifferent = true;
}
else
{
for (int i = 0; i < FMFreq.Length; i++)
{
if (FMFreq[i] != lastSentFMFreq[i])
{
fmFreqsAreDifferent = true;
break;
}
}
}
if (cbCommandQueue.Count > 0)
{
///
/// There is a command in the queue
///
controlCom.SendCommand(cbCommandQueue.Dequeue(), (benchModelRoute & routeMask), uintFilters, FMFreq, regConst, shortImp);
lastSentRoute = (benchModelRoute & routeMask);
lastsentRegConst = regConst;
lastSentShortImp = shortImp;
/// Deep copy of arrays lastSentFilters and lastSentFMFreq
if ((lastSentFilters == null) || (lastSentFilters.Length != uintFilters.Length)) lastSentFilters = new uint[(uintFilters == null) ? 0 : uintFilters.Length];
for (int i = 0; i < lastSentFilters.Length; i++) lastSentFilters[i] = uintFilters[i];
if ((lastSentFMFreq == null) || (lastSentFMFreq.Length != FMFreq.Length)) lastSentFMFreq = new float[(FMFreq == null) ? 0 : FMFreq.Length];
for (int i = 0; i < lastSentFMFreq.Length; i++) lastSentFMFreq[i] = FMFreq[i];
}
else if (((benchModelRoute & routeMask) != lastSentRoute) ||
filtersAreDifferent ||
fmFreqsAreDifferent ||
(lastsentRegConst != regConst) ||
(lastSentShortImp != shortImp))
{
///
/// Command queue is mepty, but 'route', pump frequency, PID coef., filters or shortImp have changed
///
controlCom.SendCommand(new SendCommandArgs(Command.None, 0, 0, 0, 0, 0), (benchModelRoute & routeMask), uintFilters, FMFreq, regConst, shortImp);
lastSentRoute = (benchModelRoute & routeMask);
lastsentRegConst = regConst;
lastSentShortImp = shortImp;
/// Deep copy of arrays lastSentFilters and lastSentFMFreq
if ((lastSentFilters == null) || (lastSentFilters.Length != uintFilters.Length)) lastSentFilters = new uint[(uintFilters == null) ? 0 : uintFilters.Length];
for (int i = 0; i < lastSentFilters.Length; i++) lastSentFilters[i] = uintFilters[i];
if ((lastSentFMFreq == null) || (lastSentFMFreq.Length != FMFreq.Length)) lastSentFMFreq = new float[(FMFreq == null) ? 0 : FMFreq.Length];
for (int i = 0; i < lastSentFMFreq.Length; i++) lastSentFMFreq[i] = FMFreq[i];
}
controlCom.RunDeviceAfter();
}
/// <summary>Stop this device</summary>
public void StopDevice() { }
public void StopDevice2() { }
delegate void ShowEmergencyStopFormDlgt();
///
void ShowEmergencyStopForm()
{
(new TBF.UI.Shared.EmergencyStopForm()).Show();
}
/// <summary>
/// Sends a command to the control board.
/// </summary>
/// <param name="cmd">See ControlBoard.Command enum</param>
/// <param name="refFlowmtrNr">Number of the etalon/reference (1..5)</param>
/// <param name="route">State of valves, 128-bit word</param>
/// <param name="totalRefPulses">kolko impulzov ma trvat skuska</param>
/// <param name="testMethods">See ControlBoard.TestMethods enum</param>
/// <param name="filterConstant">0 = No filtering (0..255)</param>
/// <param name="regConst">Coefficient used to control reg. valves (1..100)</param>
/// <param name="shortImp">0 = default value, 1 = spec. processing of very short pulses</param>
/// <param name="stopDevs">What to stop</param>
public void SendCommand(Command cmd, int refFlowmtrNr, int totalRefPulses, int massRefPulses,
TestMethods testMethods, StopDevs stopDevs)
{
cbCommandQueue.Enqueue(new SendCommandArgs(cmd, refFlowmtrNr, totalRefPulses, massRefPulses, testMethods, stopDevs));
}
/// <summary>
/// Set valves to new positions.
/// </summary>
/// <param name="valvesToOpen">'ulong' with bits of valves to open set to '1'</param>
/// <param name="valvesToClose">'ulong' with bits of valves to close set to '1'</param>
/// <returns>'ulong' with bits of valves that have changed set to '1'</returns>
public UInt128 SetValves(UInt128 valvesToOpen, UInt128 valvesToClose, IList<TBF.Rig.BuiltIn.ValveEx.Valve> extendedValves)
{
UInt128 oldRoute = benchModelRoute;
benchModelRoute = (((benchModelRoute ^ valvesToInvert) | valvesToOpen) & (~valvesToClose)) ^ valvesToInvert;
foreach (var extV in extendedValves) extV.UpdateRoute(ref benchModelRoute);
log.DebugFormat("SetValves(x,x), new route = {0}", Utils.RouteToStr(benchModelRoute));
return oldRoute ^ benchModelRoute;
}
/// <summary>
/// Set Route to value returned by RRoute. Take virtual valves into account.
/// </summary>
/// <returns>'ulong' with bits of valves that have changed set to '1'</returns>
public UInt128 SyncRoute()
{
UInt128 oldRoute = benchModelRoute;
benchModelRoute = (RRoute & routeMask) | (benchModelRoute & (~routeMask));
log.DebugFormat("SyncRoute(), new route = {0}", Utils.RouteToStr(benchModelRoute));
return oldRoute ^ benchModelRoute;
}
/// <summary>
/// Regulation valves control.
/// </summary>
/// <param name="valveNo">Regulation valve nr. (1..5)</param>
/// <param name="valveMode">Valve regulation mode, see the enum</param>
/// <param name="valveValue">Target position or target frequency or pulse duration</param>
/// <param name="stableTime">Stabilization time when setting the flow: 0=200ms, step 50ms, max. 1.5 sec.</param>
public void ValveMove(int valveNo, RegulValveMode valveMode, double[] valveValue, int stableTime)
{
controlCom.ValveMove(valveNo, valveMode, valveValue, stableTime);
}
/// <summary>
/// Open one valve and/or close one valve.
/// Events: ValvesSet
/// </summary>
/// <param name="valveOpen">Valve to be opened</param>
/// <param name="valveClose">Valve to be closed</param>
/// <returns>Created operation</returns>
public IOperation SetValvesOp(IValve valveOpen, IValve valveClose)
{
return new BuiltIn.SetValvesOp(this, valveOpen, valveClose);
}
/// <summary>
/// Open and/or close multiple valves.
/// Events: ValvesSet
/// </summary>
/// <param name="valvesOpen">A list of valves to be opened</param>
/// <param name="valvesClose">A list of valves to be closed</param>
/// <returns>Created operation</returns>
public IOperation SetValvesOp(IList<IValve> valvesOpen, IList<IValve> valvesClose)
{
return new BuiltIn.SetValvesOp(this, valvesOpen, valvesClose);
}
/// <summary>
/// Open start/stop valve.
/// Events: ValvesSet, ValvesBusy, Error
/// </summary>
/// <returns>Created operation</returns>
public IOperation OpenStartValveOp()
{
return new BuiltIn.SetValvesOp(this, true, devices);
}
/// <summary>
/// Close start/stop valve.
/// Events: ValvesSet, ValvesBusy, Error
/// </summary>
/// <returns>Created operation</returns>
public IOperation CloseStartValveOp()
{
return new BuiltIn.SetValvesOp(this, false, devices);
}
public IOperation SetFlowOp(double reqrdFlowLo, double reqrdFlowHi, TBF.Boxes.DoubleBox measuredFlow, int timeout)
{
if (Devices.RegValve == null || Devices.FlowMeter == null) return null;
return Devices.RegValve.SetFlowOp(Devices.FlowMeter, reqrdFlowLo, reqrdFlowHi, measuredFlow, timeout);
}
/// <summary>
/// Start a test, Events: MeasurementStarted
/// </summary>
/// <param name="iParam">Int32 parameter 1</param>
/// <param name="dParam1">Double parameter 1 (alternative lower flow limit)</param>
/// <param name="dParam2">Double parameter 2 (alternative upper flow limit)</param>
/// <returns>Operation</returns>
public IOperation StartTestOp(Test test, int iParam = 0, double dParam1 = 0, double dParam2 = 0)
{
if (controlBoardCfg.DebugLevel == DebugMode.Simulate)
{
return new Operations.ReturnGivenEventOp(Event.MeasurementStarted);
}
/// Get total number of pulses
int totalPulses = Convert.ToInt32(Math.Round(test.Volume / devices.FlowMeter.LtrPerPulse));
/// Get method class string
string methodClass;
if (!StateMachine.TestMethod2Class.TryGetValue(test.Name, out methodClass)) return null;
if (methodClass.Contains("TestMethods.Adjustment."))
{
return new StartMeasurementOp(this, devices, TestMethods.Synchro, test.Qfrom, test.Qto, totalPulses);
}
if (methodClass.Contains("TestMethods.CombinedWithDetection."))
{
return new StartMeasurementOp(this, devices, (TestMethods.Diverter | TestMethods.Synchro), dParam1, dParam2, totalPulses);
}
if (methodClass == "TestMethods.DiverterTest")
{
if (iParam == 0) return null;
return new StartMeasurementOp(this, devices, (TestMethods.Diverter | TestMethods.Synchro), test.Qfrom, test.Qto, totalPulses / iParam);
}
if (methodClass == "TestMethods.Dummy")
{
}
if (methodClass == "TestMethods.Endurance")
{
return new StartMeasurementOp(this, devices, TestMethods.Synchro, test.Qfrom, test.Qto, totalPulses);
}
if (methodClass.Contains("TestMethods.FixedStart."))
{
return new StartMeasurementOp(this, devices, TestMethods.Synchro, test.Qfrom, test.Qto, 2 * totalPulses, 10);
}
if (methodClass.Contains("TestMethods.FixedStartAdvanced."))
{
return new StartMeasurementOp(this, devices, TestMethods.Synchro, test.Qfrom, test.Qto, 2 * totalPulses, 10);
}
if (methodClass.Contains("TestMethods.FixedStartDefferedEval."))
{
return new StartMeasurementOp(this, devices, TestMethods.Synchro, test.Qfrom, test.Qto, 2 * totalPulses, 10);
}
if (methodClass.Contains("TestMethods.FixedStartMassCollDeferredEval."))
{
return new StartMeasurementOp(this, devices, (TestMethods.Diverter | TestMethods.Synchro), test.Qfrom, test.Qto, 2 * totalPulses, 10);
}
if (methodClass.Contains("TestMethods.FixedStartMassCollection."))
{
return new StartMeasurementOp(this, devices, (TestMethods.Diverter | TestMethods.FixedStart), test.Qfrom, test.Qto, 2 * totalPulses, 10);
}
if (methodClass.Contains("TestMethods.FixedStartTankCollection."))
{
return new StartMeasurementOp(this, devices, (TestMethods.Diverter | TestMethods.Synchro), test.Qfrom, test.Qto, (totalPulses * 5 / 4), 10);
}
if (methodClass.Contains("TestMethods.FlyingStart."))
{
return new StartMeasurementOp(this, devices, TestMethods.Synchro, test.Qfrom, test.Qto, totalPulses);
}
if (methodClass.Contains("TestMethods.FlyingStartFirstRepetWithMassColl."))
{
TestMethods tm = (iParam == 1) ? (TestMethods.Diverter | TestMethods.Synchro) : TestMethods.Synchro;
return new StartMeasurementOp(this, devices, tm, test.Qfrom, test.Qto, totalPulses);
}
if (methodClass.Contains("TestMethods.FlyingStartMassCollComparative."))
{
return new StartMeasurementOp(this, devices, (TestMethods.Diverter | TestMethods.Synchro), test.Qfrom, test.Qto, totalPulses);
}
if (methodClass.Contains("TestMethods.FlyingStartMassCollection."))
{
return new StartMeasurementOp(this, devices, (TestMethods.Diverter | TestMethods.Synchro), test.Qfrom, test.Qto, totalPulses);
}
if (methodClass.Contains("TestMethods.FlyingStartMassCollProlonged."))
{
if (iParam == 0) return null;
return new StartMeasurementOp(this, devices, (TestMethods.Diverter | TestMethods.Synchro), test.Qfrom, test.Qto, totalPulses, iParam);
}
if (methodClass.Contains("TestMethods.FlyingStartTankCollection."))
{
return new StartMeasurementOp(this, devices, (TestMethods.Diverter | TestMethods.Synchro), test.Qfrom, test.Qto, totalPulses);
}
if (methodClass == "TestMethods.PulsesTest")
{
return new StartMeasurementOp(this, devices, TestMethods.Synchro, test.Qfrom, test.Qto, totalPulses);
}
if (methodClass == "TestMethods.PulsesTestManual")
{
return new StartMeasurementOp(this, devices, TestMethods.Synchro, test.Qfrom, test.Qto, totalPulses);
}
return null;
}
/// <summary>
/// Starts the measurement.
/// Events: MeasurementStarted
/// </summary>
/// <param name="flowMeter">Flow meter</param>
/// <param name="readers">An array of register readers</param>
/// <param name="refPulses">Number of reference pulses to complete the test</param>
/// <returns>Created operation</returns>
public IOperation StartProlongedMeasurementOp(OutputPath outputPath,
double requiredFlowLo, double requiredFlowHi,
int totalRefPulses, int massRefPulses, int delayBeforeFlowRegulation = 0)
{
if (controlBoardCfg.DebugLevel == DebugMode.Simulate)
{
return new Operations.ReturnGivenEventOp(Event.MeasurementStarted);
}
else
{
return new StartMeasurementOp(this, outputPath, TestMethods.Diverter | TestMethods.Synchro | TestMethods.MassAndContinue,
requiredFlowLo, requiredFlowHi, totalRefPulses, massRefPulses, delayBeforeFlowRegulation);
}
}
/// <summary>
/// Read diverter samples from the control board and calculated the transition time.
/// Events: Event.None
/// </summary>
/// <param name="div">Diverter</param>
/// <param name="runsCountWhenSendingCmd">State machine ticks from test start/end when diverter read command is issued (obsolete)</param>
/// <param name="runsCountWhenReadingDiv">State machine ticks from test start/end when diverter samples are read</param>
/// <param name="transitionTimeSec">FloatBox for the resulting transition time in s</param>
/// <param name="plotter">Statistics for plotting diverter transitions</param>
/// <param name="batchNr">Batch number</param>
/// <param name="testName">Test name (without repetitions)</param>
/// <param name="repetition">Repetition number</param>
/// <returns>Created operation</returns>
public IOperation ReadDiverterTransitionOp(bool isStart, Sequences.Statistics plotter, int batchNr, string testName, int repetition)
{
if (controlBoardCfg.DebugLevel == DebugMode.Simulate) return new Operations.ReturnGivenEventOp(Event.None);
return new ReadDiverterTransitionOp(this, devices.Diverter, 1, 3, isStart, plotter, batchNr, testName, repetition);
}
/// <summary>
/// Queries th econtrol board whether the measurement was completed.
/// Events: MeasurementCompleted or None
/// </summary>
/// <returns>Created operation</returns>
public IOperation QueryMeasurementEndOp()
{
return new QueryMeasurementEndOp(this);
}
/// <summary>
/// Stop controls board flow regulation operation
/// Events: FlowRegulationStopped
/// </summary>
/// <returns>Created operation</returns>
public IOperation StopFlowRegulationOp()
{
return new StopFlowRegulationOp(this);
}
/// <summary>
/// Stop the previous control board operation (diverter, gate, etc.)
/// Events: PreviousStopped
/// </summary>
/// <returns>Created operation</returns>
public IOperation StopPreviousOp()
{
return new StopPreviousOp(this);
}
/// <summary>
/// Sends commands to the control board.
/// Events: Event.None, Event.CommandCompleted
/// </summary>
/// <param name="commandOnStartOp">Command sent to CB when this operation starts</param>
/// <param name="commandOnStopOp">Command sent to CB when this operation stops</param>
/// <param name="testMethod">Test method parameter</param>
/// <returns>Created operation</returns>
public IOperation ExecuteCommandOp(Command commandOnStartOp, Command commandOnStopOp, TestMethods testMethod)
{
return new ExecuteCommandOp(this, commandOnStartOp, commandOnStopOp, testMethod);
}
}
}
@@ -0,0 +1,389 @@
///
/// Copyright (c) 2013-2019 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Text;
using Dirichlet.Numerics;
using log4net;
namespace TBF.Rig.ControlBoard.Legacy
{
public class ControlComSim : IControlCom
{
private static readonly ILog log = LogManager.GetLogger(typeof(ControlComSim));
public override string ToString() { return string.Format("ControlComSim"); }
StatusP statusP;
public StatusP StatusP { get { return statusP; } }
double referenceFreq = 650.0;
public double ReferenceFreq { get { return referenceFreq; } }
public double ReferenceFreqs(int i) { return 0; }
int[] etPulses = new int[Config.Data.WMsCount + 1];
public int EtPulses(int wmNr1)
{
return etPulses[wmNr1];
}
public int EtPulsesK { get { return 1; } }
public int EtPulses2 { get { return 0; } }
public int EtPulses3 { get { return 0; } }
double[] errFactor = new double[Config.Data.WMsCount + 1]; /// Internal
double[] wMeterPulsesF = new double[Config.Data.WMsCount + 1]; /// Internal
UInt16[] wMeterPulses = new UInt16[Config.Data.WMsCount + 1]; /// Rounded from wMeterPulsesF
public UInt16 WMeterPulses(int wmNr1)
{
return wMeterPulses[wmNr1];
}
int[] wMeterReference = new int[Config.Data.WMsCount + 1];
public int WMeterReference(int wmNr1)
{
return wMeterReference[wmNr1];
}
public uint RegulValveDAC(int rvNr0) { return 0; }
public float Pressure(int prsNr0) { return 0; }
public float Temperature(int tmpNr0) { return (float)(20 + tmpNr0); }
public RegulValveState RegulValveState(int rvNr1) { return 0; }
public UInt128 RRoute { get { return simRoute; } }
public uint DivTime(int id) { return 0; }
public void SetDivLimit(int divNo, uint limLoPct, uint limHiPct) { }
float tTime = 1;
public float TTime { get { return tTime; } }
public float ImpulseTime(int wmNr1) { return tTime; }
public uint FmState { get { return 0; } }
public uint BeginState(int wmNr0) { return 0; }
double referenceFlow;
public double ReferenceFlow { get { return referenceFlow; } }
public float RValvePosition(int rvNr1) { return 0; }
public float DivSamples(int ms, int divIx0) { return 0; }
public int ScopeSamples(int i, int j, int k) { return 0; }
public ulong DigitalInputs { get { return 0; } }
public float AnalogInput(int adcNr0) { return 0; }
public uint AnalogInputRaw(int adcNr0, int bank) { return 0; } /// bank0=RV, bank1=Temp
public float TotalRefVolume { get { return 0; } }
public float VyslExt(int wmNr0, int what) { return 0; }
public void SetWeight(int pos, double mass) { return; } /// not available in sim. mode
public uint[] CyclePar { get { return cyclePar; } set { cyclePar = value; } } /// dummy
public uint[] WMeterCont { get { return wMeterCont; } } /// dummy
public float ValveOpenCloseTime { get { return 0.001f; } }
///
public bool ManualUIAllowed
{
get { return manualUIAllowed; }
set { manualUIAllowed = value; }
}
bool manualUIAllowed = true;
public void SetReservoirTemp(int nr, float temp) { }
///
/// Private initialization data updated by contructors of children components
/// and sent to 'controlCom2panel' by SendCalibData() method.
///
uint[,] regValveCalib;
byte[] meretRS485Address;
float[,] tempCalibData;
float[] etCalib;
uint[] diverterEdge;
uint[] balanceRange;
byte meretProtocol;
uint[] cyclePar;
uint[] wMeterCont;
///
/// Private values set by SendCommand()
///
Command cmd;
int refFlowmtrNr;
UInt128 simRoute;
int totalRefPulses;
int massRefPulses;
TestMethods testMethods;
uint[] filterConstants;
float[] FMFreq;
int regConst;
int shortImp;
StopDevs stopDevs;
///
/// Private values set by ValveMove()
///
int regulValveNo;
RegulValveMode regulValveMode;
double[] regulValveValue;
Random rand;
/// <summary>
/// Constructor
/// </summary>
public ControlComSim()
{
rand = new Random();
cyclePar = new uint[163];
wMeterCont = new uint[3] { 1, 2, 3 };
}
/// <summary>
/// Sends calibration and configuration data to the control board.
/// </summary>
/// <param name="rvCalib">Regulating valves calib.coefs, ix1 = valve nr. (1..5), ix2 = coef.nr. (0..1), values typ. c0 = 0, c1 = 0.2</param>
/// <param name="meretA">Meret address, index = 0..1, value typ. 99 and 100</param>
/// <param name="usedCom">COM port number of the control board (typ. 1)</param>
/// <param name="tempCalib">Temp.calc.coefs, ix1 = temp.sens.nr. (0..7 ???), ix2 = coef.nr</param>
/// <param name="etCalib">Etalon nominal values</param>
/// <param name="divEdge">Percentages for switching of diverters, ix = diverter nr.(0,1), typ.value 50 (%)</param>
public void SendCalibData(uint[,] rvCalib, byte[] meretA, int usedCom, float[,] tempCalib, float[] etCalib, uint[] divEdge, uint[] balanceRange, byte meretProtocol)
{
log.Info("SendCalibData(...)");
this.regValveCalib = rvCalib;
this.meretRS485Address = meretA;
this.tempCalibData = tempCalib;
this.etCalib = etCalib;
this.diverterEdge = divEdge;
this.balanceRange = balanceRange;
this.meretProtocol = meretProtocol;
}
/// <summary>
/// Sends a command to the control board.
/// </summary>
/// <param name="cmd">See ControlBoard.Command enum</param>
/// <param name="refFlowmtrNr">Number of the etalon/reference (1..5)</param>
/// <param name="route">State of valves, 128-bit word</param>
/// <param name="refPulses">kolko impulzov ma trvat skuska</param>
/// <param name="testMethods">See ControlBoard.TestMethods enum</param>
/// <param name="filterConstant">0 = No filtering (0..255)</param>
/// <param name="fmFreq">Freq.inverter control (not applicable in DT100, Munich)</param>
/// <param name="regConst">Coefficient used to control reg. valves (1..100)</param>
/// <param name="shortImp">0 = default value, 1 = spec. processing of very short pulses</param>
/// <param name="stopDevs">What to stop</param>
public void SendCommand(SendCommandArgs sendCommandArgs, UInt128 route, uint[] filterConstants, float[] fmFreq, int regConst, int shortImp)
{
log.InfoFormat("SendCommand(Cmd={0},Ref#={1},Route={2} {3} {4} {5},TotalPls={6},MassPls={7},TstM={8},filt={9},FM=[{10}{11}{12}{13}{14}{15}],Reg={16},ShrtImp={17},Stop={18})",
sendCommandArgs.Cmd, sendCommandArgs.RefFlowmtrNr, /// 0, 1
((route >> 48) & 0xFFFF).ToString("X4"), /// 2
((route >> 32) & 0xFFFF).ToString("X4"), /// 3
((route >> 16) & 0xFFFF).ToString("X4"), /// 4
(route & 0xFFFF).ToString("X4"), /// 5
totalRefPulses, massRefPulses, testMethods, filterConstants, /// 6, 7, 8, 9
fmFreq[0].ToString(), /// 10
(fmFreq.Length > 1) ? ("," + fmFreq[1].ToString()) : "", /// 11
(fmFreq.Length > 2) ? ("," + fmFreq[2].ToString()) : "", /// 12
(fmFreq.Length > 3) ? ("," + fmFreq[3].ToString()) : "", /// 13
(fmFreq.Length > 4) ? ("," + fmFreq[4].ToString()) : "", /// 14
(fmFreq.Length > 5) ? ("," + fmFreq[5].ToString()) : "", /// 15
regConst, shortImp, stopDevs); /// 16, 17, 18
///
/// Simulation
///
Command lastCmd = this.cmd;
this.cmd = sendCommandArgs.Cmd;
this.refFlowmtrNr = sendCommandArgs.RefFlowmtrNr;
#if FUZHOU_300
///
/// The following code deals with the situation that all FM controlled pums share bit #39.
/// In settings the bits of pumps should be sent as follows: P1=50, P2=51, P3=52, P4=53, P5=54 and P7=55
/// (in FUZHOU_300 the FM pump bit should be set set to value FMIndex+50).
///
bool bit39 = (route & 0x00FC000000000000) != 0; /// true if any of bits 50 through 55 is set
route = route & 0xFF03FFFFFFFFFFFF;
if (bit39) route = route | 0x0000008000000000;
log.DebugFormat("SendCommand route = {0}", Utils.RouteToStr(route));
#endif
TestBenchSim.SimRoute = this.simRoute = route;
this.totalRefPulses = sendCommandArgs.TotalRefPulses;
this.massRefPulses = sendCommandArgs.MassRefPulses;
this.testMethods = sendCommandArgs.TestMethods;
this.stopDevs = sendCommandArgs.StopDevs;
this.filterConstants = filterConstants;
this.FMFreq = fmFreq;
this.regConst = regConst;
this.shortImp = shortImp;
#pragma warning disable
statusP = (StatusP)(((ulong)statusP & (ulong)0xFFFFFFFFFFFFFFF8L) | (ulong)refFlowmtrNr);
#pragma warning restore
if (cmd == Command.Start && lastCmd != Command.Start )
{
statusP |= StatusP.TestInProgress;
///
/// Clear all counters
///
if (etPulses != null) { for (int i = 0; i < etPulses.Length; i++) etPulses[i] = 0; }
if (wMeterPulses != null) { for (int i = 0; i < wMeterPulses.Length; i++) wMeterPulses[i] = 0; }
if (wMeterPulsesF != null) { for (int i = 0; i < wMeterPulsesF.Length; i++) wMeterPulsesF[i] = 0; }
if (wMeterReference != null) { for (int i = 0; i < wMeterReference.Length; i++) wMeterReference[i] = 0; }
if (errFactor != null)
{
for (int i = 0; i < errFactor.Length; i++) errFactor[i] = ((float)rand.Next(100) + 950.0f) / 1000.0f;
}
tTime = 0;
}
else if (cmd == Command.Stop)
{
statusP = 0;
//statusP &= ~StatusP.Running;
}
}
/// <summary>
/// Control of regulating valves.
/// </summary>
/// <param name="regulValveNo">Regulating valve nr. (1..5)</param>
/// <param name="regulValveMode">???</param>
/// <param name="regulValveValue">???</param>
/// <param name="stableTime">Stabilization time when setting the flow: 0=200ms, step 50ms, max. 1.5 sec.</param>
public void ValveMove(int regulValveNo, RegulValveMode regulValveMode, double[] regulValveValue, int stableTime)
{
log.InfoFormat("ValveMove({0}, {1}, [{2},{3}], {4})", regulValveNo, regulValveMode, regulValveValue[0], regulValveValue[1], stableTime);
this.regulValveNo = regulValveNo;
this.regulValveMode = regulValveMode;
this.regulValveValue = regulValveValue;
}
public void RunDeviceBefore()
{
log.DebugFormat("RunDeviceBefore() ... regV#={0}, flowM#{1}, statusP={2}", regulValveNo, refFlowmtrNr, statusP.ToString("X"));
TestBenchSim.RunDevice(regulValveNo, refFlowmtrNr, statusP);
log.DebugFormat("refFreq={0}", referenceFreq);
tTime += 1.0f;
float Qnom = (regulValveNo > 0) ? etCalib[regulValveNo] : 0;
switch (cmd)
{
case Command.None:
break;
case Command.Start:
if ((testMethods & TestMethods.Diverter) == TestMethods.Diverter)
{
TestBenchSim.SetSimDiverter(true);
}
break;
case Command.Stop:
if ((testMethods & TestMethods.Diverter) == TestMethods.Diverter)
{
TestBenchSim.SetSimDiverter(false);
}
break;
}
switch (regulValveMode)
{
case RegulValveMode.TargetFrequency:
double targetFlow = ((regulValveValue[0] + regulValveValue[1]) / 2.0) * (Qnom / 2000.0);
TestBenchSim.UpdateSimFlow(targetFlow);
//if (referenceFreq < valveValue[0]) referenceFreq += ((float)rand.Next(20) + 10.0f) / 2.0f;
//else if (referenceFreq > valveValue[1]) referenceFreq -= ((float)rand.Next(20) + 10.0f) / 2.0f;
//else referenceFreq += ((float)rand.Next(10) - 5.0f) / 2.0f;
referenceFreq = TestBenchSim.GetSimFlow() * 2000.0 / Qnom;
if (referenceFreq < 0) referenceFreq = 0;
if (referenceFreq > 2500) referenceFreq = 2500;
break;
default:
break;
}
referenceFlow = referenceFreq / 2000.0;
bool stopTest = false;
if (cmd == Command.Start)
{
double pwFactor = 1.0;
/// Increment reference flow meters
for (int i = 0; i <= Config.Data.WMsCount; i++)
{
etPulses[i] += (int)referenceFreq;
if (etPulses[i] > totalRefPulses)
{
pwFactor = 1.0 - (etPulses[i] - totalRefPulses) / referenceFreq;
etPulses[i] = totalRefPulses;
stopTest = true;
}
}
/// Increment water meters
double flowLtrPerSec = TestBenchSim.GetSimFlow() / 1800.0;
for (int i = 1; i <= Config.Data.WMsCount; i++)
{
float wmPulsesPerLiter = 0;
if ((Rig.Sequences.ProcessData.RegisterReaders[i - 1] != null) &&
(Rig.Sequences.ProcessData.BatchRslts.Batch.WaterMeters.Count >= i) &&
(Rig.Sequences.ProcessData.BatchRslts.Batch.WaterMeters[i - 1] != null))
{
wmPulsesPerLiter = (float)Rig.Sequences.ProcessData.RegisterReaders[i-1].PulsesPerLtr;
}
wMeterPulsesF[i] += errFactor[i] * pwFactor * ((float)rand.Next(100) + 450.0f) * wmPulsesPerLiter * flowLtrPerSec;
wMeterPulses[i] = (UInt16)wMeterPulsesF[i];
}
if (etPulses[0] > totalRefPulses)
{
statusP |= StatusP.TestCompleted;
statusP &= ~StatusP.TestInProgress;
}
}
if (stopTest)
{
TestBenchSim.SetSimDiverter(false);
statusP = (statusP | StatusP.TestCompleted);
statusP = (statusP & ~StatusP.TestInProgress);
}
}
StatusP lastStatusP;
UInt128 lastRoute;
public void RunDeviceAfter()
{
StatusP bufferedStatusP = StatusP;
if (lastStatusP != bufferedStatusP)
{
string statusPStr = ((ulong)bufferedStatusP).ToString("x16");
log.InfoFormat("RunDeviceAfter() StatusP = {0}", statusPStr);
Program.MainWnd.UpdateStatusP(statusPStr);
lastStatusP = bufferedStatusP;
}
UInt128 bufferedRoute = simRoute;
if (lastRoute != bufferedRoute)
{
string routeStr = bufferedRoute.ToString("x16");
log.InfoFormat("RunDeviceAfter() Route = {0}", routeStr);
Program.MainWnd.UpdateRoute(routeStr);
lastRoute = bufferedRoute;
}
}
}
}
@@ -0,0 +1,106 @@
///
/// Copyright (c) 2016 Sensus Metering Systems
///
using System;
using log4net;
namespace TBF.Rig.ControlBoard.Legacy
{
public class ExecuteCommandOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(ExecuteCommandOp));
public override string ToString() { return string.Format("ExecuteCommandOp( command={0}, testMethod={1} )", commandOnStartOp, testMethod); }
/// Set by the constructor
readonly CBoard controlBoard;
readonly Command commandOnStartOp;
readonly Command commandOnStopOp;
readonly TestMethods testMethod;
bool started = false;
///
/// Internal states of this operation
///
enum OpState
{
StartingCommand,
CommandStarted,
OpCompleted,
}
OpState opState;
/// <summary>
/// Starts the measurement.
/// Events: MeasurementStarted
/// </summary>
/// <param name="controlBoard">Control board component reference</param>
/// <param name="outputPath">Specifies used components</param>
/// <param name="testMethod">Test method</param>
/// <param name="refPulses">Test duration in number of reference flowmeter pulses</param>
/// <param name="filterConstant">Specifies filter for watermeter pulses</param>
public ExecuteCommandOp(CBoard controlBoard, Command commandOnStartOp, Command commandOnStopOp, TestMethods testMethod)
{
if (controlBoard == null) throw new ArgumentNullException("controlBoardDev");
this.controlBoard = controlBoard;
this.commandOnStartOp = commandOnStartOp;
this.commandOnStopOp = commandOnStopOp;
this.testMethod = testMethod;
log.Debug(this.ToString());
}
/// <summary>Start this operation</summary>
public void Start()
{
controlBoard.SyncRoute();
controlBoard.SendCommand(commandOnStartOp, 0, 0, 0, testMethod, StopDevs.None);
opState = OpState.StartingCommand;
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.FlowInDone or Event.FlowOutDone
/// </returns>
public Event Run()
{
if (opState == OpState.StartingCommand)
{
StatusP statusP = controlBoard.StatusP;
log.DebugFormat("statusP = {0} {1} {2} {3}",
(((ulong)statusP >> 48) & 0xFFFF).ToString("X4"),
(((ulong)statusP >> 32) & 0xFFFF).ToString("X4"),
(((ulong)statusP >> 16) & 0xFFFF).ToString("X4"),
((ulong)statusP & 0xFFFF).ToString("X4"));
log.Info("Run() - StartingCommand");
opState = OpState.CommandStarted;
return Event.None;
}
else if (opState == OpState.CommandStarted)
{
log.InfoFormat("Run() - CommandStarted");
opState = OpState.OpCompleted;
return Event.None;
}
else if (opState == OpState.OpCompleted)
{
return Event.CommandCompleted;
}
return Event.None;
}
/// <summary>Stop this operation</summary>
public void Stop()
{
if (commandOnStopOp != Command.None)
{
controlBoard.SyncRoute();
controlBoard.SendCommand(commandOnStopOp, 0, 0, 0, testMethod, StopDevs.None);
}
}
}
}
+37
View File
@@ -0,0 +1,37 @@
///
/// Copyright (c) 2013-2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.ControlBoard.Legacy
{
public class Factory : IComponentFactory
{
public string ClassName { get { return GetType().Namespace.Substring(8); } }
public override string ToString() { return ClassName; }
/// <summary>Max. number of components of this class in the system</summary>
public int MaxCount { get { return 1; } }
public IComponent DummyComponent() { return new CBoard(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new CBoard(cfg); }
public IComponentCfg DefaultConfig() { return new ControlBoardCfg(this); }
public IComponentCfgCtrl CreateCfgCtrl() { return new ControlBoardCfgCtrl(); }
public IComponent ComponentFromCmpntCfg(IComponentCfg config, IList<Generic.IComponent> components)
{
return new CBoard((ControlBoardCfg)config);
}
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(ControlBoardCfg.Serializer, component, this);
}
public void ResetStaticProperties() { CBoard.ResetStaticProperties(); }
}
}
@@ -0,0 +1,84 @@
///
/// Copyright (c) 2013-2019 Sensus Slovensko a.s.
///
using System;
using Dirichlet.Numerics;
namespace TBF.Rig.ControlBoard.Legacy
{
interface IControlCom
{
StatusP StatusP { get; }
int EtPulses(int wmNr1);
int EtPulsesK { get; }
int EtPulses2 { get; }
int EtPulses3 { get; }
UInt16 WMeterPulses(int wmNr1);
int WMeterReference(int wmNr0);
uint RegulValveDAC(int rvNr0);
float Pressure(int prsNr0);
float Temperature(int tmpNr0);
RegulValveState RegulValveState(int rvNr1);
UInt128 RRoute { get; }
uint DivTime(int id); /// 50% id=0, 10% id=1, 90% id=2
float TTime { get; }
float ImpulseTime(int WMNr1);
uint FmState { get; }
uint BeginState(int wmNr0);
double ReferenceFreq { get; }
double ReferenceFreqs(int i); /// Frequences for doble/tripple flowmeter
double ReferenceFlow { get; }
float RValvePosition(int rvNr1);
float DivSamples(int time, int divIx0); /// time unit is 2 ms
int ScopeSamples(int i, int j, int k);
ulong DigitalInputs { get; }
float AnalogInput(int adcNr0);
uint AnalogInputRaw(int adcNr0, int bank);
float TotalRefVolume { get; }
float VyslExt(int wmNr0, int what);
void SetWeight(int pos, double mass);
uint[] CyclePar { get; set; }
uint[] WMeterCont { get; }
bool ManualUIAllowed { get; set; }
float ValveOpenCloseTime { get; }
void SetDivLimit(int divNr, uint limLoPct, uint limHiPct);
void SetReservoirTemp(int nr, float temp);
/// <summary>
/// Sends calibration and configuration data to the control board.
/// </summary>
/// <param name="rvCalib">Regulating valves calib.coefs, ix1 = valve nr. (1..5), ix2 = coef.nr. (0..1), values typ. c0 = 0, c1 = 0.2</param>
/// <param name="meretA">Meret address, index = 0..1, value typ. 99 and 100</param>
/// <param name="usedCom">COM port number of the control board (typ. 1)</param>
/// <param name="tempCalib">Temp.calc.coefs, ix1 = temp.sens.nr. (0..7 ???), ix2 = coef.nr</param>
/// <param name="etCalib">Etalon nominal values</param>
/// <param name="divEdge">Percentages for switching of diverters, ix = diverter nr.(0,1), typ.value 50 (%)</param>
/// <param name="balanceRange">TODO</param>
/// <param name="meretProtocol">TODO</param>
void SendCalibData(uint[,] rvCalib, byte[] meretA, int usedCom, float[,] tempCalib, float[] etCalib, uint[] divEdge, uint[] balanceRange, byte meretProtocol);
/// <summary>
/// Updates a command that is regularly sent to the control board by SendCommand.
/// </summary>
/// <param name="sendCommandArgs">Arguments, see SendCommandArgs class</param>
/// <param name="route">State of valves, 128-bit word</param>
/// <param name="filterConstants">Array with length=8 of filter costants (0..255, 0 = no filtering)</param>
/// <param name="fmFreq">Freq.inverter control (not applicable in DT100, Munich)</param>
/// <param name="regConst">PID coefficient for flow control</param>
/// <param name="shortImp">0 = default value, 1 = spec. processing of very short pulses</param>
void SendCommand(SendCommandArgs sendCommandArgs, UInt128 route, uint[] filterConstants, float[] fmFreq, int regConst, int shortImp);
/// <summary>
/// Control of regulating valves.
/// </summary>
/// <param name="valveNo">Regulating valve nr. (1..5)</param>
/// <param name="valveMode">???</param>
/// <param name="valveValue">???</param>
/// <param name="stableTime">Stabilization time when setting the flow: 0=200ms, step 50ms, max. 1.5 sec.</param>
void ValveMove(int valveNo, RegulValveMode valveMode, double[] valveValue, int stableTime);
void RunDeviceBefore();
void RunDeviceAfter();
}
}
@@ -0,0 +1,59 @@
///
/// Copyright (c) 2013-2020 Sensus Slovensko a.s.
///
using System;
using log4net;
namespace TBF.Rig.ControlBoard.Legacy
{
public class QueryMeasurementEndOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(QueryMeasurementEndOp));
public override string ToString() { return string.Format("QueryMeasurementEndOp()"); }
/// Set by the constructor
readonly CBoard controlBoard;
bool done;
/// <summary>
/// Events: MeasurementCompleted
/// </summary>
/// <param name="eventDone">Event to be returned by Run() when completed OK</param>
public QueryMeasurementEndOp(CBoard controlBoardDev)
{
if (controlBoardDev == null) throw new ArgumentNullException("controlBoardDev");
this.controlBoard = controlBoardDev;
done = false;
log.Debug(this.ToString());
}
/// <summary> Start this operation </summary>
public void Start()
{
done = false;
}
/// <summary> Run this operation </summary>
/// <returns>
/// Event.FlowInDone or Event.FlowOutDone
/// </returns>
public Event Run()
{
if (done) return Event.MeasurementCompleted;
if (0 != (controlBoard.StatusP & StatusP.TestCompleted))
{
done = true;
return Event.MeasurementCompleted;
}
return Event.None;
}
/// <summary> Stop this operation </summary>
public void Stop()
{
}
}
}
@@ -0,0 +1,203 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System;
using log4net;
using TBF.Boxes;
namespace TBF.Rig.ControlBoard.Legacy
{
public class ReadDiverterTransitionOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(ReadDiverterTransitionOp));
public override string ToString()
{
return string.Format("ReadDiverterTransitionOp(.,{0},{1},{2},...)", div.Name, runsCountWhenSendingCmd, runsCountWhenReadingDiv);
}
const int SamplesCount = 240; /// Should be less then or equal to 256
float[] samples;
/// Set by the constructor
readonly CBoard controlBoard;
readonly GenericDevices.IDiverter div;
readonly bool toTank;
readonly int runsCountWhenSendingCmd;
readonly int runsCountWhenReadingDiv;
readonly Sequences.Statistics plotter;
readonly int batchNr;
readonly string testName;
readonly int repetition;
int counter;
bool cmdSent = false;
bool divRead = false;
/// <summary>
/// Starts the measurement.
/// Events: MeasurementStarted
/// </summary>
/// <param name="controlBoard">Control board component reference</param>
/// <param name="outputPath">Specifies used components</param>
/// <param name="method">Test method</param>
/// <param name="refPulses">Test duration in number of reference flowmeter pulses</param>
/// <param name="filterConstant">Specifies filter for watermeter pulses</param>
public ReadDiverterTransitionOp(CBoard controlBoard, GenericDevices.IDiverter div, int runsCountWhenSendingCmd, int runsCountWhenReadingDiv, bool toTank,
Sequences.Statistics plotter, int batchNr, string testName, int repetition)
{
if (controlBoard == null) throw new ArgumentNullException("controlBoardDev");
if (div == null) throw new ArgumentNullException("div");
if (runsCountWhenSendingCmd < 0) throw new ArgumentNullException("runsCountWhenSendingCmd");
if (runsCountWhenReadingDiv <= runsCountWhenSendingCmd) throw new ArgumentNullException("runsCountWhenReadingDiv");
this.controlBoard = controlBoard;
this.div = div;
this.runsCountWhenSendingCmd = runsCountWhenSendingCmd;
this.runsCountWhenReadingDiv = runsCountWhenReadingDiv;
this.toTank = toTank;
this.plotter = plotter;
this.batchNr = batchNr;
this.testName = testName;
this.repetition = repetition;
samples = new float[SamplesCount];
log.Debug(this.ToString());
}
/// <summary>Start this operation</summary>
public void Start()
{
counter = 0;
if (runsCountWhenSendingCmd == 0 && div.DiverterNr > 0)
{
SendCommand();
log.DebugFormat("Start() ... Sending a command to read diverter {0}", div.Name);
}
if (plotter != null)
{
plotter.Start(batchNr, testName, repetition);
log.DebugFormat("Start() ... plotter.Start({0}, {1}, {2})", batchNr, testName, repetition);
}
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.FlowInDone or Event.FlowOutDone
/// </returns>
public Event Run()
{
counter++;
if (counter == runsCountWhenSendingCmd && div.DiverterNr > 0)
{
SendCommand();
log.DebugFormat("Run() ... Sending a command to read diverter {0}", div.Name);
}
else if (counter == runsCountWhenReadingDiv && div.DiverterNr > 0)
{
if (plotter == null)
{
ReadDiverterTransitionTimes();
log.DebugFormat("Run() ... Reading diverter {0} transition times: {1}s", div.Name, (toTank ? div.SwitchTimeStart : div.SwitchTimeEnd).Val);
}
else
{
log.DebugFormat("Run() ... Reading diverter {0} samples", div.Name);
for (int i = 0; i < SamplesCount; i++)
{
float oneSample = controlBoard.DivSamples(i, div.DiverterNr - 1);
samples[i] = oneSample;
plotter.Update(oneSample);
}
plotter.Stop();
log.DebugFormat("Run() ... Calculating diverter {0} transition times: {1}s", div.Name, (toTank ? div.SwitchTimeStart : div.SwitchTimeEnd).Val);
CalculateDiverterTransitionTimes();
}
}
return Event.None;
}
/// <summary>Stop this operation</summary>
public void Stop()
{
log.DebugFormat("Stop()");
}
void SendCommand()
{
controlBoard.SyncRoute();
controlBoard.SendCommand(Command.ReadDivTransition, 0, 0, 0, 0, StopDevs.None);
cmdSent = true;
}
/// <summary>
/// Diverter transition time is read from the control board
/// </summary>
/// <returns>true (always)</returns>
bool ReadDiverterTransitionTimes()
{
(toTank ? div.SwitchTimeStart : div.SwitchTimeEnd).Val = (float)controlBoard.DivTime(2) - (float)controlBoard.DivTime(1);
return true;
}
/// <summary>
/// Diverter transition time is calculated from ADC samples and threshold levels
/// </summary>
/// <returns>true when transition time calculated OK</returns>
bool CalculateDiverterTransitionTimes()
{
bool startedRising = false;
bool startedFalling = false;
bool stopped = false;
int transitionStartIdx = 0;
int transitionEndIdx = 0;
float level = samples[0];
for (int i = 1; i < SamplesCount; i++)
{
if (!startedRising && !startedFalling)
{
if (level <= div.ThresholdLo && samples[i] > div.ThresholdLo)
{
transitionStartIdx = i;
startedRising = true;
}
else if (level >= div.ThresholdHi && samples[i] < div.ThresholdHi)
{
transitionStartIdx = i;
startedFalling = true;
}
}
else if (startedRising && !stopped && level < div.ThresholdHi && samples[i] >= div.ThresholdHi)
{
transitionEndIdx = i;
stopped = true;
break;
}
else if (startedFalling && !stopped && level > div.ThresholdLo && samples[i] <= div.ThresholdLo)
{
transitionEndIdx = i;
stopped = true;
break;
}
}
if ((startedRising || startedFalling) && stopped)
{
(toTank ? div.SwitchTimeStart : div.SwitchTimeEnd).Val = 0.002f * (float)(transitionEndIdx - transitionStartIdx); /// 2 ms per sample
return true;
}
else
{
return false;
}
}
}
}
+70
View File
@@ -0,0 +1,70 @@
///
/// Copyright (c) 2017 Sensus Slovensko a.s.
///
using System;
using log4net;
using TBF.Boxes;
namespace TBF.Rig.ControlBoard.Legacy
{
public class ReadFlowOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(ReadFlowOp));
public override string ToString() { return string.Format("ReadFlowOp({0},.,.,{1})", flowMeter.Idx1, eventDone); }
/// Set by the constructor
readonly GenericDevices.IFlowMeter flowMeter;
readonly CBoard controlBoard;
readonly DoubleBox flowBox;
readonly Event eventDone;
/// <summary>
/// Events: FlowInDone, FlowOutDone or Error
/// </summary>
/// <param name="flowMeter">Flow meter reference</param>
/// <param name="flowBox">Reference to the measured flow variable, value is in bar</param>
/// <param name="eventDone">Event to be returned by Run() when completed OK</param>
public ReadFlowOp(GenericDevices.IFlowMeter flowMeter, CBoard controlBoard, ref DoubleBox flowBox, Event eventDone)
{
if (flowMeter == null || controlBoard == null) throw new ArgumentNullException();
this.flowMeter = flowMeter;
this.controlBoard = controlBoard;
this.eventDone = eventDone;
this.flowBox = flowBox;
log.Debug(this.ToString());
}
public ReadFlowOp(GenericDevices.IFlowMeter flowMeter, CBoard controlBoard, ref DoubleBox flowBox)
: this(flowMeter, controlBoard, ref flowBox, Event.FlowMeasurementDone)
{
}
/// <summary>Start this operation</summary>
public void Start()
{
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.FlowInDone or Event.FlowOutDone
/// </returns>
public Event Run()
{
if ((int)(controlBoard.StatusP & StatusP.RefFlowMeterMask) == flowMeter.Idx1)
{
flowBox.Val = flowMeter.ReadFlow();
return eventDone;
}
else
{
return Event.Error;
}
}
/// <summary>Stop this operation</summary>
public void Stop()
{
}
}
}
@@ -0,0 +1,33 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
///
using System;
using Dirichlet.Numerics;
namespace TBF.Rig.ControlBoard.Legacy
{
public class SendCommandArgs
{
public Command Cmd;
public int RefFlowmtrNr;
public int TotalRefPulses;
public int MassRefPulses;
public TestMethods TestMethods;
public StopDevs StopDevs;
public SendCommandArgs()
{
}
public SendCommandArgs(Command cmd, int refFlowmtrNr, int totalRefPulses, int massRefPulses,
TestMethods testMethods, StopDevs stopDevs)
{
Cmd = cmd;
RefFlowmtrNr = refFlowmtrNr;
TotalRefPulses = totalRefPulses;
MassRefPulses = massRefPulses;
TestMethods = testMethods;
StopDevs = stopDevs;
}
}
}
@@ -0,0 +1,237 @@
///
/// Copyright (c) 2013-2020 Sensus Slovensko a.s.
///
using System;
using log4net;
using TBF.Rig.GenericDevices;
namespace TBF.Rig.ControlBoard.Legacy
{
public class StartMeasurementOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(StartMeasurementOp));
public override string ToString() { return string.Format("StartMeasurementOp(ref={0},pulses={1})", flowMeterNr, totalRefPulses); }
/// Set by the constructor
readonly CBoard controlBoard;
readonly IRegValve regulValve;
readonly int regulValveNr;
readonly int regulValveStableTime;
readonly int flowMeterNr;
readonly double nominalFlow;
readonly double maximalFlow;
readonly double reqFlowLo;
readonly double reqFlowHi;
readonly int totalRefPulses; /// Number of reference pulses for a complete test
readonly int massRefPulses; /// Number of reference pulses for mass collection
readonly int delayBeforeFlowRegulation; /// Delay before flow control starts in seconds
readonly TestMethods testMethod;
readonly int diverterNr;
///
/// Internal states of this operation
///
enum OpState
{
StartingTest,
ResendCommand,
WaitingBeforeValveMove,
StartingFlowRegulation,
OpCompleted,
}
OpState opState;
int delayStartTime; /// StateMachine.Time snapshot when delay before flow regulation starts
/// <summary>
/// Starts the measurement.
/// Events: MeasurementStarted
/// </summary>
/// <param name="controlBoard">Control board component reference</param>
/// <param name="outputPath">Specifies used components</param>
/// <param name="method">Test method</param>
/// <param name="totalRefPulses">Test duration in number of reference flowmeter pulses</param>
/// <param name="filterConstant">Specifies filter for watermeter pulses</param>
public StartMeasurementOp(CBoard controlBoard, OutputPath outputPath, TestMethods method,
double requiredFlowLo, double requiredFlowHi, int refPulses, int delayBeforeFlowRegulation = 0)
: this(controlBoard, outputPath, method, requiredFlowLo, requiredFlowHi, refPulses, refPulses, delayBeforeFlowRegulation)
{
}
/// <summary>
/// Starts the measurement.
/// Events: MeasurementStarted
/// </summary>
/// <param name="controlBoard">Control board component reference</param>
/// <param name="outputPath">Specifies used components</param>
/// <param name="method">Test method</param>
/// <param name="refPulses">Test duration in number of reference flowmeter pulses</param>
/// <param name="filterConstant">Specifies filter for watermeter pulses</param>
public StartMeasurementOp(CBoard controlBoard, OutputPath outputPath, TestMethods method,
double requiredFlowLo, double requiredFlowHi, int totalRefPulses, int massRefPulses, int delayBeforeFlowRegulation = 0)
{
if (controlBoard == null) throw new ArgumentNullException("controlBoardDev");
this.controlBoard = controlBoard;
if (outputPath.FlowMeter == null) throw new ArgumentNullException("Flow meter is missing");
flowMeterNr = outputPath.FlowMeter.Idx1;
this.regulValve = outputPath.RegValve;
if (regulValve is Elde.RegulValve.RegulValve)
{
Elde.RegulValve.RegulValve rv = outputPath.RegValve as Elde.RegulValve.RegulValve;
regulValveNr = rv.Idx1;
regulValveStableTime = rv.StableTime;
}
else if (regulValve is Elde.RegulValveCoax.RegulValve)
{
Elde.RegulValveCoax.RegulValve rv = outputPath.RegValve as Elde.RegulValveCoax.RegulValve;
regulValveNr = rv.Idx1;
regulValveStableTime = rv.StableTime;
}
else if (!(regulValve is Dummy.RegulValve.RegulValve))
{
throw new ArgumentNullException("Regulation valve is not compatible with Elde Control Board");
}
if (outputPath.Diverter is Elde.Diverter.Diverter)
{
diverterNr = (outputPath.Diverter as Elde.Diverter.Diverter).DiverterNr;
}
nominalFlow = outputPath.FlowMeter.NominalFlow;
maximalFlow = 1.25 * nominalFlow;
this.testMethod = method;
this.reqFlowLo = requiredFlowLo;
this.reqFlowHi = requiredFlowHi;
this.totalRefPulses = totalRefPulses;
this.massRefPulses = massRefPulses;
this.delayBeforeFlowRegulation = delayBeforeFlowRegulation;
log.Debug(this.ToString());
}
void SendStartCommand()
{
controlBoard.SyncRoute();
#if TURA_IPERL || TURA_IPERL_NEW || TURA_SPECIAL || BADGER_VELKA_TRAT || SLM_50
int flowMeterIdxAndDiv = flowMeterNr + 16 * diverterNr;
#elif BADGER_STREDNA_TRAT
int flowMeterIdxAndDiv = flowMeterNr + 8 * (diverterNr - 1);
#elif FILIPINY_50
int flowMeterIdxAndDiv = flowMeterNr + ((flowMeterNr == 3) ? (4 * (diverterNr - 1)) : 0);
#elif GELSENWASSER
int flowMeterIdxAndDiv = flowMeterNr + ((diverterNr == 2) ? 16 : 0);
#else
int flowMeterIdxAndDiv = flowMeterNr;
#endif
log.InfoFormat("Start() : SendCommand(Cmd.Start, {0}, route, {1}, {1}, {2}, Stop.None)",
flowMeterIdxAndDiv, totalRefPulses, testMethod);
controlBoard.SendCommand(Command.Start, flowMeterIdxAndDiv, totalRefPulses, massRefPulses, testMethod, StopDevs.None);
}
/// <summary>Start this operation</summary>
public void Start()
{
SendStartCommand();
opState = OpState.StartingTest;
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.FlowInDone or Event.FlowOutDone
/// </returns>
public Event Run()
{
if (opState == OpState.StartingTest)
{
StatusP statusP = controlBoard.StatusP;
log.DebugFormat("statusP = {0} {1} {2} {3}",
(((ulong)statusP >> 48) & 0xFFFF).ToString("X4"),
(((ulong)statusP >> 32) & 0xFFFF).ToString("X4"),
(((ulong)statusP >> 16) & 0xFFFF).ToString("X4"),
((ulong)statusP & 0xFFFF).ToString("X4"));
if ((statusP & StatusP.TestInProgress) != 0)
{
log.Info("Test started");
if (delayBeforeFlowRegulation > 0)
{
delayStartTime = StateMachine.Time;
opState = OpState.WaitingBeforeValveMove;
}
else
{
opState = OpState.StartingFlowRegulation;
}
}
else
{
//opState = OpState.ResendCommand;
}
return Event.None;
}
else if (opState == OpState.ResendCommand)
{
SendStartCommand();
opState = OpState.StartingTest;
return Event.None;
}
else if (opState == OpState.WaitingBeforeValveMove)
{
if (StateMachine.Time - delayStartTime >= delayBeforeFlowRegulation)
{
opState = OpState.StartingFlowRegulation;
}
return Event.None;
}
else if (opState == OpState.StartingFlowRegulation)
{
///
/// Done once, issues an appropriate ValveMove(...) command
///
if ((reqFlowLo >= reqFlowHi) || (reqFlowLo > maximalFlow) || (reqFlowHi <= 0))
{
return Event.OpArgumentError;
}
log.InfoFormat("Run(): rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3}",
regulValveNr, flowMeterNr, reqFlowLo, reqFlowHi);
double freqLo = 2000.0 * reqFlowLo / nominalFlow;
double freqHi = 2000.0 * reqFlowHi / nominalFlow;
if (regulValve.IsCoax)
{
controlBoard.ValveMove(regulValveNr, RegulValveMode.TargetFrequency,
new double[2] { (freqLo + freqHi) / 2, (freqLo + freqHi) / 2 },
regulValveStableTime);
}
else
{
controlBoard.ValveMove(regulValveNr, RegulValveMode.TargetFrequency,
new double[2] { freqLo, freqHi },
regulValveStableTime);
}
opState = OpState.OpCompleted;
return Event.None;
}
else if (opState == OpState.OpCompleted)
{
return Event.MeasurementStarted;
}
return Event.None;
}
/// <summary>Stop this operation</summary>
public void Stop()
{
}
}
}
@@ -0,0 +1,62 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
///
using System;
using log4net;
namespace TBF.Rig.ControlBoard.Legacy
{
class StopFlowRegulationOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(StopFlowRegulationOp));
public override string ToString() { return string.Format("StopFlowRegulationOp(.)"); }
/// Set by the constructor
readonly CBoard controlBoard;
readonly int flowMeterNr;
/// <summary>
/// Stop the previous control board operation (diverter, gate, etc.)
/// Events: None or PreviousStopped
/// </summary>
/// <param name="controlBoardDev">Control board component reference</param>
public StopFlowRegulationOp(CBoard controlBoardDev)
{
if (controlBoardDev == null) throw new ArgumentNullException("controlBoardDev");
this.controlBoard = controlBoardDev;
if (controlBoardDev.Devices.FlowMeter == null) throw new ArgumentNullException("Flow meter is missing");
flowMeterNr = controlBoardDev.Devices.FlowMeter.Idx1;
log.Debug(this.ToString());
}
void SendStopFlowRegulationCommand()
{
controlBoard.SyncRoute();
controlBoard.SendCommand(Command.Stop, flowMeterNr, 0, 0, 0, StopDevs.RegValveRegulation);
}
/// <summary>Start this operation</summary>
public void Start()
{
SendStopFlowRegulationCommand();
}
/// <summary>Run this operation</summary>
/// <returns>Event.FlowRegulationStopped</returns>
public Event Run()
{
return Event.FlowRegulationStopped;
}
/// <summary>Stop this operation</summary>
public void Stop()
{
}
}
}
@@ -0,0 +1,107 @@
///
/// Copyright (c) 2013-2015 Sensus Metering Systems
///
using System;
using log4net;
namespace TBF.Rig.ControlBoard.Legacy
{
public class StopPreviousOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(StopPreviousOp));
public override string ToString() { return string.Format("StopPreviousOp(.)"); }
/// Set by the constructor
readonly CBoard controlBoard;
///
/// Internal states of this operation
///
enum OpState
{
Idle = 0,
CheckIfStopped,
ResendCommand,
Stopped,
}
OpState opState;
/// <summary>
/// Stop the previous control board operation (diverter, gate, etc.)
/// Events: None or PreviousStopped
/// </summary>
/// <param name="controlBoardDev">Control board component reference</param>
public StopPreviousOp(CBoard controlBoardDev)
{
if (controlBoardDev == null) throw new ArgumentNullException("controlBoardDev");
this.controlBoard = controlBoardDev;
log.Debug(this.ToString());
}
void SendStopCommand()
{
controlBoard.SyncRoute();
controlBoard.SendCommand(Command.Stop, 0, 0, 0, TestMethods.Diverter,
StopDevs.Diverter | StopDevs.GatePulse | StopDevs.Reference | StopDevs.RegValveRegulation);
}
/// <summary>Start this operation</summary>
public void Start()
{
SendStopCommand();
opState = OpState.CheckIfStopped;
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.None or Event.PreviousStopped
/// </returns>
public Event Run()
{
if (opState == OpState.CheckIfStopped)
{
if ((controlBoard.StatusP & (StatusP.TestCompleted | StatusP.TestInProgress)) == 0)
{
opState = OpState.Stopped;
return Event.PreviousStopped;
}
else
{
opState = OpState.ResendCommand;
return Event.None;
}
}
else if (opState == OpState.ResendCommand)
{
if ((controlBoard.StatusP & (StatusP.TestCompleted | StatusP.TestInProgress)) == 0)
{
opState = OpState.Stopped;
return Event.PreviousStopped;
}
else
{
SendStopCommand();
opState = OpState.CheckIfStopped;
return Event.None;
}
}
else if (opState == OpState.Stopped)
{
return Event.PreviousStopped;
}
return Event.None;
}
/// <summary>Stop this operation</summary>
public void Stop()
{
opState = OpState.Idle;
}
}
}
+774
View File
@@ -0,0 +1,774 @@
///
/// Copyright (c) 2013-2020 Sensus Slovensko a.s.
///
using System;
using Dirichlet.Numerics;
using log4net;
namespace TBF.Rig.ControlBoard.Legacy
{
/// <summary>
/// Test bench model inherited by all classes for the simulation of devices.
/// Define DN100, MUNICH or nothing.
/// </summary>
public static class TestBenchSim
{
private static readonly ILog log = LogManager.GetLogger(typeof(TestBenchSim));
///
/// Incremented in RunDevice() depending on diverters and valves
///
public static double Mass1sim; /// Volume in [ltr] or mass in [kg] in the tank1 on the balance1, filled by the diverter1
public static double Mass2sim; /// Volume in [ltr] or mass in [kg] in the tank2 on the balance2, filled by the diverter2
///
/// Set by regulation valves
///
public static double Flow1sim; /// flow in [m3/h] through RV1
public static double Flow2sim; /// flow in [m3/h] through RV2
public static double Flow3sim; /// flow in [m3/h] through RV3
public static double Flow4sim; /// flow in [m3/h] through RV4
public static double Flow5sim; /// flow in [m3/h] through RV5
public static double Flow6sim; /// flow in [m3/h] through RV5
///
/// Valves and diverters
///
public static UInt128 SimRoute;
public static bool Div1sim;
public static bool Div2sim;
public static bool Div3sim;
static int regulValveNo; /// 0=undefined, 1..5
static int refFlowmtrNo; /// 0=undefined, 1..4
public static void Initialize()
{
Mass1sim = 0; /// Initialize tanks
Mass2sim = 0;
Flow1sim = 0; /// Initialize regulation valves
Flow2sim = 0;
Flow3sim = 0;
Flow4sim = 0;
Flow5sim = 0;
Flow6sim = 0;
SimRoute = 0; /// Initialize other valves
Div1sim = false;
Div2sim = false;
Div3sim = false;
}
#if DN100
/// Paths modulating the flows
const ulong K5 = (1L << 0);
const ulong K7 = (1L << 1);
const ulong K10 = (1L << 2);
const ulong K13 = (1L << 3);
const ulong K16 = (1L << 4);
const ulong K2 = (1L << 5);
const ulong EmptyValve1 = (1L << 17);
const ulong EmptyValve2 = (1L << 18);
const ulong Vl5 = (1L << 21);
const ulong Path1 = K2 | K5 | K7;
const ulong Path2 = K2 | K5 | K10;
const ulong Path3 = K2 | K5 | K13;
const ulong Path4 = K2 | K5 | K16;
const ulong Path5 = K2 | K5 | Vl5;
#elif MUNICH
const ulong VL11 = (1L << 0);
const ulong VL13 = (1L << 1);
const ulong VL21 = (1L << 2);
const ulong VL23 = (1L << 3);
const ulong VZ1 = (1L << 4);
const ulong VP2 = (1L << 5);
const ulong VP4 = (1L << 6);
const ulong VP5 = (1L << 7);
const ulong VP6 = (1L << 8);
const ulong VL12 = (1L << 9);
const ulong VL22 = (1L << 10);
const ulong VI11 = (1L << 11);
const ulong VI12 = (1L << 12);
const ulong VI13 = (1L << 13);
const ulong VI21 = (1L << 14);
const ulong VI22 = (1L << 15);
const ulong VI2P = (1L << 16);
const ulong VI31 = (1L << 17);
const ulong VI32 = (1L << 18);
const ulong VI3P = (1L << 19);
const ulong VI41 = (1L << 20);
const ulong VI42 = (1L << 21);
const ulong VI43 = (1L << 22);
const ulong VI4P = (1L << 23);
const ulong VB1 = (1L << 24);
const ulong VB1a = (1L << 25);
const ulong VB2 = (1L << 26);
const ulong VB2a = (1L << 27);
const ulong VM1 = (1L << 28);
const ulong VM2 = (1L << 29);
const ulong VM3 = (1L << 30);
const ulong VM4 = ((ulong)1 << 31);
const ulong Pump1 = ((ulong)1 << 32);
const ulong Block = ((ulong)1 << 33);
const ulong VZ8 = ((ulong)1 << 37);
const ulong EmptyValve1 = VB1 | VB1a;
const ulong EmptyValve2 = VB2 | VB2a;
const ulong Path1 = VZ1 | VL12 | VI11 | VI13;
const ulong Path2 = VZ1 | VL11 | VL12 | VI21 | VI22 | VI13;
const ulong Path3 = VZ1 | VL11 | VL12 | VI31 | VI32;
const ulong Path4 = VZ1 | VL11 | VL12 | VI41 | VI42;
const ulong Path5 = VZ1 | VL11 | VL12 | VI41 | VI43;
#elif FUZHOU_150
const ulong VL11 = (1L << 2);
const ulong VL13 = (1L << 3);
const ulong VL4 = (1L << 4);
const ulong VZ6 = (1L << 5);
const ulong VZ7 = (1L << 6);
const ulong VP5 = (1L << 7);
const ulong VP6 = (1L << 8);
const ulong VL12 = (1L << 9);
const ulong VZ14 = (1L << 10);
const ulong VI11 = (1L << 11);
const ulong VI12 = (1L << 12);
const ulong VI13 = (1L << 13);
const ulong VI21 = (1L << 14);
const ulong VI22 = (1L << 15);
const ulong VI2p = (1L << 16);
const ulong VI31 = (1L << 17);
const ulong VI32 = (1L << 18);
const ulong VI3p = (1L << 19);
const ulong VI41 = (1L << 20);
const ulong VI42 = (1L << 21);
const ulong VI43 = (1L << 22);
const ulong VI4p = (1L << 23);
const ulong VB1 = (1L << 24);
const ulong VB1a = (1L << 25);
const ulong VB2 = (1L << 26);
const ulong VB2a = (1L << 27);
const ulong VM1 = (1L << 28);
const ulong VM2 = (1L << 29);
const ulong VM3 = (1L << 20);
const ulong Pump1 = ((ulong)1 << 32);
const ulong Pump4 = ((ulong)1 << 33);
const ulong Pump2 = ((ulong)1 << 37);
const ulong Pump3 = ((ulong)1 << 38);
const ulong Pump5 = ((ulong)1 << 39);
const ulong EmptyValve1 = VB1 | VB1a;
const ulong EmptyValve2 = VB2 | VB2a;
const ulong Path1 = VL12 | VI11 | VI13;
const ulong Path2 = VL12 | VI21 | VI22 | VI13;
const ulong Path3 = VL12 | VI31 | VI32;
const ulong Path4 = VL12 | VI41 | VI42;
const ulong Path5 = VL12 | VI41 | VI43;
#elif FUZHOU_300
const ulong VL11 = (1L << 2);
const ulong VL13 = (1L << 3);
const ulong VL4 = (1L << 4);
const ulong VZ6 = (1L << 5);
const ulong VZ7 = (1L << 6);
const ulong VP5 = (1L << 7);
const ulong VP6 = (1L << 8);
const ulong VL12 = (1L << 9);
const ulong VZ14 = (1L << 10);
const ulong VI11 = (1L << 11);
const ulong VI12 = (1L << 12);
const ulong VI13 = (1L << 13);
const ulong VI21 = (1L << 14);
const ulong VI22 = (1L << 15);
const ulong VI2p = (1L << 16);
const ulong VI31 = (1L << 17);
const ulong VI32 = (1L << 18);
const ulong VI3p = (1L << 19);
const ulong VI41 = (1L << 20);
const ulong VI42 = (1L << 21);
const ulong VI43 = (1L << 22);
const ulong VI4p = (1L << 23);
const ulong VB1 = (1L << 24);
const ulong VB1a = (1L << 25);
const ulong VB2 = (1L << 26);
const ulong VB2a = (1L << 27);
const ulong VM1 = (1L << 28);
const ulong VM2 = (1L << 29);
const ulong VM3 = (1L << 20);
const ulong Pump1 = ((ulong)1 << 32);
const ulong Pump4 = ((ulong)1 << 33);
const ulong Pump2 = ((ulong)1 << 37);
const ulong Pump3 = ((ulong)1 << 38);
const ulong Pump5 = ((ulong)1 << 39);
const ulong EmptyValve1 = VB1 | VB1a;
const ulong EmptyValve2 = VB2 | VB2a;
const ulong Path1 = VL12 | VI11 | VI13;
const ulong Path2 = VL12 | VI21 | VI22 | VI13;
const ulong Path3 = VL12 | VI31 | VI32;
const ulong Path4 = VL12 | VI41 | VI42;
const ulong Path5 = VL12 | VI41 | VI43;
#elif IZRAEL_200 || PUCHONG_200 || GENESIS || BERLIN || GELSENWASSER
const ulong VM11 = (1L << 4);
const ulong VM12 = (1L << 5);
const ulong VM21 = (1L << 6);
const ulong VM22 = (1L << 7);
const ulong VZ14 = (1L << 8);
const ulong VZ13 = (1L << 9);
const ulong VL11 = (1L << 10);
const ulong VL13 = (1L << 11);
const ulong VL4 = (1L << 12);
const ulong VZ6 = (1L << 13);
const ulong VZ7 = (1L << 14);
const ulong VP5 = (1L << 15);
const ulong VP6 = (1L << 16);
const ulong VL12 = (1L << 17);
const ulong VL51 = (1L << 18);
const ulong VL53 = (1L << 19);
const ulong VI11 = (1L << 20);
const ulong VI12 = (1L << 21);
const ulong VI13 = (1L << 22);
const ulong VV1 = (1L << 23);
const ulong VI21 = (1L << 25);
const ulong VI22 = (1L << 26);
const ulong VI2p = (1L << 27);
const ulong VI31 = (1L << 28);
const ulong VI32 = (1L << 29);
const ulong VI3p = (1L << 30);
const ulong VI41 = (1L << 31);
const ulong VI42 = (1L << 32);
const ulong VI4p = (1L << 33);
const ulong VI43 = (1L << 37);
const ulong VM1 = (1L << 50);
const ulong VM2 = (1L << 51);
const ulong VM3 = (1L << 52);
const ulong VB1 = (1L << 41);
const ulong VB1a = (1L << 42);
const ulong VB2 = (1L << 43);
const ulong VB2a = (1L << 44);
const ulong Pump1 = (1L << 48);
const ulong Pump4 = (1L << 49);
const ulong Pump2 = (1L << 38);
const ulong Pump3 = (1L << 39);
const ulong Pump5 = (1L << 40);
const ulong EmptyValve1 = VB1 | VB1a;
const ulong EmptyValve2 = VB2 | VB2a;
const ulong Path1 = VL12 | VI11 | VI13;
const ulong Path2 = VL12 | VI21 | VI22 | VI13;
const ulong Path3 = VL12 | VI31 | VI32;
const ulong Path4 = VL12 | VI41 | VI42;
const ulong Path5 = VL12 | VI41 | VI43;
#elif BADGER_MALA_TRAT || BADGER_STREDNA_TRAT || BADGER_VELKA_TRAT
const ulong VZ34 = (1L << 0);
const ulong VZ35 = (1L << 1);
const ulong VZ39 = (1L << 2);
const ulong VZ37 = (1L << 3);
const ulong VZ38 = (1L << 4);
const ulong VL31 = (1L << 5);
const ulong VV1 = (1L << 6);
const ulong VS33 = (1L << 7);
const ulong VS31 = (1L << 8);
const ulong VS32 = (1L << 9);
const ulong VV2 = (1L << 10);
const ulong VL32 = (1L << 11);
const ulong VI31 = (1L << 12);
const ulong VI32 = (1L << 13);
const ulong VI33 = (1L << 14);
const ulong VI34 = (1L << 15);
const ulong DIV1 = (1L << 16);
const ulong DIV2 = (1L << 17);
const ulong VB1 = (1L << 18);
const ulong VB1a = (1L << 19);
const ulong VB2 = (1L << 20);
const ulong VB2a = (1L << 21);
const ulong P1 = (1L << 22);
const ulong P2 = (1L << 23);
const ulong EmptyValve1 = VB1 | VB1a;
const ulong EmptyValve2 = VB2 | VB2a;
const ulong Path1 = VI31;
const ulong Path2 = VI32;
const ulong Path3 = VI33;
const ulong Path4 = VI34;
const ulong Path5 = 0;
#elif CEVAK_40 || MURES_40 || FUZHOU_50 || SLM_50 || MALTA_WSD25
const ulong VL11 = (1L << 0);
const ulong VL13 = (1L << 1);
const ulong VL18 = (1L << 2);
const ulong VZ12 = (1L << 3);
const ulong VL15 = (1L << 4);
const ulong VL21 = (1L << 5);
const ulong VL23 = (1L << 6);
const ulong VL28 = (1L << 7);
const ulong VZ5 = (1L << 8);
const ulong VI1 = (1L << 9);
const ulong VI2 = (1L << 10);
const ulong VI3 = (1L << 11);
const ulong VZ9 = (1L << 12);
const ulong VBa = (1L << 13);
const ulong VB = (1L << 14);
const ulong DIV1 = (1L << 15);
const ulong P1 = (1L << 16);
const ulong P2 = (1L << 17);
const ulong VL9 = (1L << 18);
const ulong VV1 = (1L << 19);
const ulong VV2 = (1L << 20);
const ulong VZ6 = (1L << 21);
const ulong VV3 = (1L << 22);
const ulong Gate = (1L << 23);
const ulong EmptyValve1 = VB | VBa;
const ulong EmptyValve2 = 0x0000FFFFFFFFFFFF;
const ulong Path1 = VI1;
const ulong Path2 = VI2;
const ulong Path3 = VI3;
const ulong Path4 = 0;
const ulong Path5 = 0;
#elif TORINO_50
const ulong nic1 = (1L << 0);
const ulong nic2 = (1L << 1);
const ulong VL11 = (1L << 2);
const ulong VL13 = (1L << 3);
const ulong VL18 = (1L << 4);
const ulong VZ13 = (1L << 5);
const ulong VL15 = (1L << 6);
const ulong VZ10 = (1L << 7);
const ulong VZ6 = (1L << 8);
const ulong VV1 = (1L << 9);
const ulong VV4 = (1L << 10);
const ulong VL12 = (1L << 11);
const ulong VI1 = (1L << 12);
const ulong VI2 = (1L << 13);
const ulong VI3 = (1L << 14);
const ulong VI4 = (1L << 15);
const ulong VB1 = (1L << 16);
const ulong VB1a = (1L << 17);
const ulong VB2 = (1L << 18);
const ulong VB2a = (1L << 19);
const ulong DIV1 = (1L << 20);
const ulong DIV2 = (1L << 21);
const ulong P1 = (1L << 22);
const ulong P3 = (1L << 23);
const ulong P2 = (1L << 24);
const ulong EmptyValve1 = VB1 | VB1a;
const ulong EmptyValve2 = VB2 | VB2a;
const ulong Path1 = VI1;
const ulong Path2 = VI2;
const ulong Path3 = VI3;
const ulong Path4 = VI4;
const ulong Path5 = 0;
#elif TORUN_50 || TURA_IPERL || TURA_IPERL_NEW
const ulong VL11 = (1L << 0);
const ulong VL13 = (1L << 1);
const ulong VL15 = (1L << 2);
const ulong VL21 = (1L << 3);
const ulong VL23 = (1L << 4);
const ulong VL18 = (1L << 5);
const ulong VL28 = (1L << 6);
const ulong VZ5 = (1L << 7);
const ulong VZ6 = (1L << 8);
const ulong DIV1 = (1L << 9);
const ulong DIV2 = (1L << 10);
const ulong P1 = (1L << 11);
const ulong P2 = (1L << 12);
const ulong P3 = (1L << 13);
const ulong DIV3 = (1L << 14);
const ulong rez1 = (1L << 15);
const ulong nic1 = (1L << 16);
const ulong nic2 = (1L << 17);
const ulong VI1 = (1L << 18);
const ulong VI2 = (1L << 19);
const ulong VI3 = (1L << 20);
const ulong VI4 = (1L << 21);
const ulong VI5 = (1L << 22);
const ulong VB1 = (1L << 23);
const ulong VV12 = (1L << 24);
const ulong VV22 = (1L << 25);
const ulong VI6 = (1L << 26);
const ulong VV3 = (1L << 27);
const ulong VB2 = (1L << 28);
const ulong EmptyValve1 = VB1;
const ulong EmptyValve2 = VB2;
const ulong Path1 = VI1;
const ulong Path2 = VI2;
const ulong Path3 = VI3;
const ulong Path4 = VI4;
const ulong Path5 = VI5;
const ulong Path6 = VI6;
#elif TURA_SPECIAL
const ulong VL11 = (1L << 0);
const ulong VL13 = (1L << 1);
const ulong VL15 = (1L << 2);
const ulong VL21 = (1L << 3);
const ulong VL23 = (1L << 4);
const ulong VL18 = (1L << 5);
const ulong VL28 = (1L << 6);
const ulong VZ5 = (1L << 7);
const ulong VZ6 = (1L << 8);
const ulong DIV1 = (1L << 9);
const ulong DIV2 = (1L << 10);
const ulong P1 = (1L << 11);
const ulong P2 = (1L << 12);
const ulong P3 = (1L << 13);
const ulong DIV3 = (1L << 14);
const ulong rez1 = (1L << 15);
const ulong nic1 = (1L << 16);
const ulong nic2 = (1L << 17);
const ulong VI1 = (1L << 18);
const ulong VI2 = (1L << 19);
const ulong VI3 = (1L << 20);
const ulong VI4 = (1L << 21);
const ulong VI5 = (1L << 22);
const ulong VB1 = (1L << 23);
const ulong VV12 = (1L << 24);
const ulong VV22 = (1L << 25);
const ulong VI6 = (1L << 26);
const ulong VV3 = (1L << 27);
const ulong VB2 = (1L << 28);
const ulong EmptyValve1 = VB1;
const ulong EmptyValve2 = VB2;
const ulong Path1 = VI1;
const ulong Path2 = VI2;
const ulong Path3 = VI3;
const ulong Path4 = VI4;
const ulong Path5 = VI5;
const ulong Path6 = VI6;
#else
/// Paths modulating the flows
const ulong V1 = (1L << 1);
const ulong V2 = (1L << 2);
const ulong V3 = (1L << 3);
const ulong V3b = (1L << 4);
const ulong V4 = (1L << 5);
const ulong V4b = (1L << 6);
const ulong V5 = (1L << 7);
const ulong V5b = (1L << 8);
const ulong EmptyValve1 = (1L << 9); // =Ve1
const ulong EmptyValve2 = (1L << 10); // =Ve2
const ulong Path1 = V1 | V3 | V3b | V4 | V4b;
const ulong Path2 = V2 | V3 | V3b | V5 | V5b;
const ulong Path3 = 0;
const ulong Path4 = 0;
const ulong Path5 = 0;
#endif
/// <summary>Run this device</summary>
public static void RunDevice(int regulValveNo, int refFlowmtrNo, StatusP statusP)
{
TestBenchSim.regulValveNo = regulValveNo;
TestBenchSim.refFlowmtrNo = refFlowmtrNo;
double time = 1.0;
#if DN100
if (Div1sim && (SimRoute & Path1) == Path1) Mass1sim += DiffKg(Flow1sim, time);
if (Div1sim && (SimRoute & Path2) == Path2) Mass1sim += DiffKg(Flow2sim, time);
if (Div2sim && (SimRoute & Path3) == Path3) Mass2sim += DiffKg(Flow3sim, time);
if (Div2sim && (SimRoute & Path4) == Path4) Mass2sim += DiffKg(Flow4sim, time);
if (Div1sim && (SimRoute & Path5) == Path5) Mass1sim += DiffKg(Flow5sim, time);
#elif MUNICH || FUZHOU_150 || FUZHOU_300 || IZRAEL_200 || PUCHONG_200 || GENESIS || BERLIN || GELSENWASSER
if (Div1sim && (SimRoute & Path1) == Path1)
{
double diff = DiffKg(Flow1sim, time);
Mass1sim += diff;
log.WarnFormat("Path1: Div1, Mass1+={0}kg, flow={1}m3/h, Mass1={2}kg", diff, Flow1sim, Mass1sim);
}
if (Div1sim && (SimRoute & Path2) == Path2)
{
double diff = DiffKg(Flow2sim, time);
Mass1sim += diff;
log.WarnFormat("Path2: Div1, Mass1 += {0}kg, flow={1}m3/h, Mass1={2}kg", diff, Flow1sim, Mass1sim);
}
if (Div2sim && (SimRoute & Path3) == Path3)
{
double diff = DiffKg(Flow3sim, time);
Mass2sim += diff;
log.WarnFormat("Path3: Div2, Mass2 += {0}kg, flow={1}m3/h, Mass2={2}kg", diff, Flow1sim, Mass2sim);
}
if (Div3sim && (SimRoute & Path4) == Path4)
{
double diff = DiffKg(Flow4sim, time);
Mass2sim += diff;
log.WarnFormat("Path4: Div3, Mass2 += {0}kg, flow={1}m3/h, Mass2={2}kg", diff, Flow1sim, Mass2sim);
}
if (Div3sim && (SimRoute & Path5) == Path5)
{
double diff = DiffKg(Flow5sim, time);
Mass2sim += diff;
log.WarnFormat("Path5: Div3, Mass2 += {0}kg, flow={1}m3/h, Mass2={2}kg", diff, Flow1sim, Mass2sim);
}
#elif BADGER_MALA_TRAT || BADGER_STREDNA_TRAT || BADGER_VELKA_TRAT || TORINO_50 /// Path1,2 do WT1, Path3,4 do WT2
if (Div1sim && (SimRoute & Path1) == Path1) Mass1sim += DiffKg(Flow1sim, time);
if (Div1sim && (SimRoute & Path2) == Path2) Mass1sim += DiffKg(Flow2sim, time);
if (Div2sim && (SimRoute & Path3) == Path3) Mass2sim += DiffKg(Flow3sim, time);
if (Div2sim && (SimRoute & Path4) == Path4) Mass2sim += DiffKg(Flow4sim, time);
#elif CEVAK_40 || MURES_40 || FUZHOU_50 || SLM_50 || MALTA_WSD25 /// Path1,2,3 do WT1
if (Div1sim && (SimRoute & Path1) == Path1) Mass1sim += DiffKg(Flow1sim, time);
if (Div1sim && (SimRoute & Path2) == Path2) Mass1sim += DiffKg(Flow2sim, time);
if (Div1sim && (SimRoute & Path3) == Path3) Mass1sim += DiffKg(Flow3sim, time);
#elif TORUN_50 || TURA_IPERL || TURA_IPERL_NEW /// Path1,2,3,4,5 do WT1, Path6 do WT2
if (Div1sim && (SimRoute & Path1) == Path1) Mass1sim += DiffKg(Flow1sim, time);
if (Div1sim && (SimRoute & Path2) == Path2) Mass1sim += DiffKg(Flow2sim, time);
if (Div1sim && (SimRoute & Path3) == Path3) Mass1sim += DiffKg(Flow3sim, time);
if (Div2sim && (SimRoute & Path4) == Path4) Mass1sim += DiffKg(Flow4sim, time);
if (Div2sim && (SimRoute & Path5) == Path5) Mass1sim += DiffKg(Flow5sim, time);
if (Div3sim && (SimRoute & Path6) == Path6) Mass2sim += DiffKg(Flow4sim, time);
#elif TURA_SPECIAL
if (Div1sim && (SimRoute & Path1) == Path1) Mass1sim += DiffKg(Flow1sim, time);
if (Div1sim && (SimRoute & Path2) == Path2) Mass1sim += DiffKg(Flow2sim, time);
if (Div1sim && (SimRoute & Path3) == Path3) Mass1sim += DiffKg(Flow3sim, time);
if (Div2sim && (SimRoute & Path4) == Path4) Mass1sim += DiffKg(Flow4sim, time);
if (Div2sim && (SimRoute & Path5) == Path5) Mass1sim += DiffKg(Flow5sim, time);
if (Div3sim && (SimRoute & Path6) == Path6) Mass2sim += DiffKg(Flow4sim, time);
#else
if (Div1sim && (SimRoute & Path1) == Path1) Mass1sim += DiffKg(Flow1sim, time);
if (Div2sim && (SimRoute & Path2) == Path2) Mass2sim += DiffKg(Flow2sim, time);
#endif
if ((SimRoute & EmptyValve1) == EmptyValve1) Mass1sim -= DiffKg(100.0, time);
if (Mass1sim < 0) Mass1sim = 0;
if ((SimRoute & EmptyValve2) == EmptyValve2) Mass2sim -= DiffKg(10.0, time);
if (Mass2sim < 0) Mass2sim = 0;
}
/// <summary>
/// Calculate the mass change from the flow and the time period
/// </summary>
/// <param name="flowM3H">Flow in [m3/h]</param>
/// <param name="timeSec">Time period in [s]</param>
/// <returns>Mass change in [kg]</returns>
static double DiffKg(double flowM3H, double timeSec)
{
return timeSec * flowM3H / 3.6;
}
/// <summary>
/// Get the simulated mass. Use the balance range to distinguish the balances.
/// </summary>
/// <param name="balanceNr">0-based balance number</param>
/// <returns>Simulated mass reading [kg]</returns>
public static double GetSimMass(int balanceNr)
{
if (balanceNr == 0) return Mass1sim;
else if (balanceNr == 1) return Mass2sim;
else return 0;
}
/// <summary>
/// Set the simulated diverter. Use the nominal flow to distinguish the path.
/// </summary>
/// <param name="toTank">Diverter state: true = to the tank</param>
/// <param name="nominalFlow">Nominal flow of the path [m3/h]</param>
public static void SetSimDiverter(bool toTank)
{
#if DN100
switch (regulValveNo)
{
case 1:
case 2:
case 5:
Div1sim = toTank;
break;
case 3:
case 4:
Div2sim = toTank;
break;
default:
if (toTank) { throw (new Exception()); }
break;
}
#elif MUNICH || FUZHOU_150 || FUZHOU_300 || IZRAEL_200 || PUCHONG_200 || GENESIS || BERLIN || GELSENWASSER
switch (regulValveNo)
{
case 1:
case 2:
Div1sim = toTank;
break;
case 3:
Div2sim = toTank;
break;
case 4:
case 5:
Div3sim = toTank;
break;
default:
//if (toTank) { throw (new Exception()); }
break;
}
#elif BADGER_MALA_TRAT || BADGER_STREDNA_TRAT || TORINO_50
switch (regulValveNo)
{
case 1:
case 2:
Div1sim = toTank;
break;
case 3:
case 4:
Div2sim = toTank;
break;
default:
if (toTank) { throw (new Exception()); }
break;
}
#elif BADGER_VELKA_TRAT
switch (regulValveNo)
{
case 7:
case 2:
Div1sim = toTank;
break;
case 3:
Div2sim = toTank;
break;
default:
if (toTank) { throw (new Exception()); }
break;
}
#elif CEVAK_40 || MURES_40 || FUZHOU_50 || SLM_50 || MALTA_WSD25
switch (regulValveNo)
{
case 1:
case 2:
case 3:
Div1sim = toTank;
break;
default:
if (toTank) { /* throw (new Exception()); */ }
break;
}
#elif TORUN_50 || TURA_IPERL || TURA_IPERL_NEW
switch (regulValveNo)
{
case 1:
case 2:
case 3:
Div1sim = toTank;
break;
case 4:
case 5:
Div2sim = toTank;
break;
case 6:
Div3sim = toTank;
break;
default:
if (toTank) { throw (new Exception()); }
break;
}
#elif TURA_SPECIAL
switch (regulValveNo)
{
case 1:
case 2:
case 3:
Div1sim = toTank;
break;
case 4:
case 5:
Div2sim = toTank;
break;
case 6:
Div3sim = toTank;
break;
default:
if (toTank) { throw (new Exception()); }
break;
}
#else
switch (regulValveNo)
{
case 1: Div1sim = toTank; break;
case 2: Div2sim = toTank; break;
default:
if (toTank) { throw (new Exception()); }
break;
}
#endif
return;
}
/// <summary>
/// Get the simulated flow in [m3/h].
/// </summary>
/// <returns>Simulated flow [m3/h]</returns>
public static double GetSimFlow()
{
switch (refFlowmtrNo)
{
case 1: return ((SimRoute & Path1) == Path1) ? Flow1sim : 0;
case 2: return ((SimRoute & Path2) == Path2) ? Flow2sim : 0;
case 3: return ((SimRoute & Path3) == Path3) ? Flow3sim : 0;
case 4: return (((SimRoute & Path4) == Path4) ? Flow4sim : 0) +
(((SimRoute & Path5) == Path5) ? Flow5sim : 0);
default: return 0;
}
}
/// <summary>
/// Update simulated flow. Use the nominal flow to distinguish the path.
/// </summary>
/// <param name="targetFlow">Target flow [m3/h]</param>
/// <param name="nominalFlow">Nominal flow of the path [m3/h]</param>
public static void UpdateSimFlow(double targetFlow)
{
double A = 0.7; /// higher value -> slower regulation
double B = 1.0 - A;
switch (regulValveNo)
{
case 1: Flow1sim = A * Flow1sim + B * targetFlow; break;
case 2: Flow2sim = A * Flow2sim + B * targetFlow; break;
case 3: Flow3sim = A * Flow3sim + B * targetFlow; break;
case 4: Flow4sim = A * Flow4sim + B * targetFlow; break;
case 5: Flow5sim = A * Flow5sim + B * targetFlow; break;
case 6: Flow6sim = A * Flow6sim + B * targetFlow; break;
default: break;
}
}
}
}
+203
View File
@@ -0,0 +1,203 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
namespace TBF.Rig.ControlBoard.Papouch
{
partial class CBoardCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.classNameLabel = new System.Windows.Forms.Label();
this.nameLabel = new System.Windows.Forms.Label();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.vValveRangeLoTextBox = new System.Windows.Forms.TextBox();
this.vValveRangeLoLabel = new System.Windows.Forms.Label();
this.vValveRangeHiTextBox = new System.Windows.Forms.TextBox();
this.vValveRangeHiLabel = new System.Windows.Forms.Label();
this.parentNameComboBox = new System.Windows.Forms.ComboBox();
this.modbusAddressTextBox = new System.Windows.Forms.TextBox();
this.modbusAddressLabel = new System.Windows.Forms.Label();
this.parentNameLabel = new System.Windows.Forms.Label();
this.variantComboBox = new System.Windows.Forms.ComboBox();
this.variantLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(175, 26);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
this.classNameLabel.TabIndex = 2;
this.classNameLabel.Text = "ComonentName";
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(42, 60);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 3;
this.nameLabel.Text = "Name";
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(178, 57);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(130, 20);
this.nameTextBox.TabIndex = 4;
//
// vValveRangeLoTextBox
//
this.vValveRangeLoTextBox.Enabled = false;
this.vValveRangeLoTextBox.Location = new System.Drawing.Point(178, 161);
this.vValveRangeLoTextBox.Name = "vValveRangeLoTextBox";
this.vValveRangeLoTextBox.Size = new System.Drawing.Size(46, 20);
this.vValveRangeLoTextBox.TabIndex = 6;
//
// vValveRangeLoLabel
//
this.vValveRangeLoLabel.AutoSize = true;
this.vValveRangeLoLabel.Location = new System.Drawing.Point(42, 164);
this.vValveRangeLoLabel.Name = "vValveRangeLoLabel";
this.vValveRangeLoLabel.Size = new System.Drawing.Size(118, 13);
this.vValveRangeLoLabel.TabIndex = 5;
this.vValveRangeLoLabel.Text = "Virtual valves range Lo:";
//
// vValveRangeHiTextBox
//
this.vValveRangeHiTextBox.Enabled = false;
this.vValveRangeHiTextBox.Location = new System.Drawing.Point(178, 186);
this.vValveRangeHiTextBox.Name = "vValveRangeHiTextBox";
this.vValveRangeHiTextBox.Size = new System.Drawing.Size(46, 20);
this.vValveRangeHiTextBox.TabIndex = 8;
//
// vValveRangeHiLabel
//
this.vValveRangeHiLabel.AutoSize = true;
this.vValveRangeHiLabel.Location = new System.Drawing.Point(42, 189);
this.vValveRangeHiLabel.Name = "vValveRangeHiLabel";
this.vValveRangeHiLabel.Size = new System.Drawing.Size(116, 13);
this.vValveRangeHiLabel.TabIndex = 7;
this.vValveRangeHiLabel.Text = "Virtual valves range Hi:";
//
// parentNameComboBox
//
this.parentNameComboBox.Enabled = false;
this.parentNameComboBox.FormattingEnabled = true;
this.parentNameComboBox.Location = new System.Drawing.Point(178, 83);
this.parentNameComboBox.Name = "parentNameComboBox";
this.parentNameComboBox.Size = new System.Drawing.Size(130, 21);
this.parentNameComboBox.TabIndex = 10;
//
// modbusAddressTextBox
//
this.modbusAddressTextBox.Enabled = false;
this.modbusAddressTextBox.Location = new System.Drawing.Point(178, 136);
this.modbusAddressTextBox.Name = "modbusAddressTextBox";
this.modbusAddressTextBox.Size = new System.Drawing.Size(46, 20);
this.modbusAddressTextBox.TabIndex = 12;
//
// modbusAddressLabel
//
this.modbusAddressLabel.AutoSize = true;
this.modbusAddressLabel.Location = new System.Drawing.Point(42, 140);
this.modbusAddressLabel.Name = "modbusAddressLabel";
this.modbusAddressLabel.Size = new System.Drawing.Size(86, 13);
this.modbusAddressLabel.TabIndex = 11;
this.modbusAddressLabel.Text = "Modbus Address";
//
// parentNameLabel
//
this.parentNameLabel.AutoSize = true;
this.parentNameLabel.Location = new System.Drawing.Point(42, 86);
this.parentNameLabel.Name = "parentNameLabel";
this.parentNameLabel.Size = new System.Drawing.Size(69, 13);
this.parentNameLabel.TabIndex = 9;
this.parentNameLabel.Text = "Parent Name";
//
// variantComboBox
//
this.variantComboBox.Enabled = false;
this.variantComboBox.FormattingEnabled = true;
this.variantComboBox.Location = new System.Drawing.Point(178, 110);
this.variantComboBox.Name = "variantComboBox";
this.variantComboBox.Size = new System.Drawing.Size(130, 21);
this.variantComboBox.TabIndex = 14;
//
// variantLabel
//
this.variantLabel.AutoSize = true;
this.variantLabel.Location = new System.Drawing.Point(42, 113);
this.variantLabel.Name = "variantLabel";
this.variantLabel.Size = new System.Drawing.Size(40, 13);
this.variantLabel.TabIndex = 13;
this.variantLabel.Text = "Variant";
//
// CBoardCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.variantComboBox);
this.Controls.Add(this.variantLabel);
this.Controls.Add(this.parentNameComboBox);
this.Controls.Add(this.modbusAddressTextBox);
this.Controls.Add(this.modbusAddressLabel);
this.Controls.Add(this.parentNameLabel);
this.Controls.Add(this.vValveRangeHiTextBox);
this.Controls.Add(this.vValveRangeHiLabel);
this.Controls.Add(this.vValveRangeLoTextBox);
this.Controls.Add(this.vValveRangeLoLabel);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "CBoardCfgCtrl";
this.Size = new System.Drawing.Size(400, 300);
this.Load += new System.EventHandler(this.ControlBoardCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label classNameLabel;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.TextBox vValveRangeLoTextBox;
private System.Windows.Forms.Label vValveRangeLoLabel;
private System.Windows.Forms.TextBox vValveRangeHiTextBox;
private System.Windows.Forms.Label vValveRangeHiLabel;
private System.Windows.Forms.ComboBox parentNameComboBox;
private System.Windows.Forms.TextBox modbusAddressTextBox;
private System.Windows.Forms.Label modbusAddressLabel;
private System.Windows.Forms.Label parentNameLabel;
private System.Windows.Forms.ComboBox variantComboBox;
private System.Windows.Forms.Label variantLabel;
}
}
@@ -0,0 +1,143 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using System.Windows.Forms;
using Config.Entities;
using TBF.Rig.Generic;
using TBF.UI.Bench.Components;
namespace TBF.Rig.ControlBoard.Papouch
{
public partial class CBoardCfgCtrl : UserControl, IComponentCfgCtrl
{
ComponentParametersDlg parent;
public bool ShowMore { get { return false; } }
PapouchCBCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as PapouchCBCfg;
Redraw();
}
}
public CBoardCfgCtrl()
{
InitializeComponent();
}
private void ControlBoardCfgCtrl_Load(object sender, EventArgs e)
{
parent = ParentForm as ComponentParametersDlg;
if (parent == null) return;
if (parent.CmpntEntities != null)
{
foreach (var cmpnt in parent.CmpntEntities)
{
if (TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is Modbus.Common.Factory)
{
parentNameComboBox.Items.Add(cmpnt.Name);
}
}
}
for (QuidoVariant v = 0; v < QuidoVariant.Count; v++) variantComboBox.Items.Add(v.ToString());
Redraw();
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
parentNameComboBox.Text = string.IsNullOrEmpty(config.ParentName) ? "---" : config.ParentName;
variantComboBox.Text = config.Variant.ToString();
modbusAddressTextBox.Text = config.ModbusAddress.ToString();
vValveRangeLoTextBox.Text = config.VirtualValvesRangeLo.ToString();
vValveRangeHiTextBox.Text = config.VirtualValvesRangeHi.ToString();
}
public void Unlock()
{
nameTextBox.Enabled = true;
parentNameComboBox.Enabled = true;
variantComboBox.Enabled = true;
modbusAddressTextBox.Enabled = true;
vValveRangeLoTextBox.Enabled = true;
vValveRangeHiTextBox.Enabled = true;
}
/// <summary>
/// Verify current user controls for validity.
/// Called when user wants to close/save the configuration.
/// </summary>
/// <returns>See VerifyFlags</returns>
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
int dummy;
if (!parentNameComboBox.Items.Contains(parentNameComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Parent Name'";
}
if (!variantComboBox.Items.Contains(variantComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Variant'";
}
if (!int.TryParse(modbusAddressTextBox.Text, out dummy) || dummy < 0 || dummy > 255)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Modbus Address' should be between 0 and 255";
}
if (!int.TryParse(vValveRangeLoTextBox.Text, out dummy) || dummy < 0 || dummy > 63)
{
message += "Virtual valves range Lo is invalid";
flags |= CfgUpdateFlags.Error;
}
if (!int.TryParse(vValveRangeHiTextBox.Text, out dummy) || dummy < 0 || dummy > 63)
{
message += "Virtual valves range Hi is invalid";
flags |= CfgUpdateFlags.Error;
}
return flags;
}
/// <summary>
/// Save settings to the configuration class.
/// </summary>
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
this.Name = nameTextBox.Text;
config.ParentName = parentNameComboBox.Text.Equals("---") ? string.Empty : parentNameComboBox.Text;
for (QuidoVariant v = 0; v < QuidoVariant.Count; v++)
{
if (variantComboBox.Text == v.ToString()) { config.Variant = v; break; }
}
config.ModbusAddress = (byte)int.Parse(modbusAddressTextBox.Text);
config.VirtualValvesRangeLo = int.Parse(vValveRangeLoTextBox.Text);
config.VirtualValvesRangeHi = int.Parse(vValveRangeHiTextBox.Text);
return flags;
}
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+30
View File
@@ -0,0 +1,30 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.ControlBoard.Papouch
{
public class Factory : IComponentFactory
{
public string ClassName { get { return this.GetType().Namespace.Substring(8); } }
public override string ToString() { return ClassName; }
public void ResetStaticProperties() { PapouchCB.ResetStaticProperties(); }
/// <summary>Max. number of components of this class in the system</summary>
public int MaxCount { get { return 1; } }
public IComponent DummyComponent() { return new PapouchCB(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new PapouchCB(cfg, components); }
public IComponentCfg DefaultConfig() { return new PapouchCBCfg(this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(PapouchCBCfg.Serializer, component, this);
}
}
}
+489
View File
@@ -0,0 +1,489 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using log4net;
using Config.Entities;
using Dirichlet.Numerics;
using TBF.Rig.Generic;
using TBF.Rig.GenericDevices;
using TBF.Rig.Modbus;
using TBF.Rig.Sequences;
namespace TBF.Rig.ControlBoard.Papouch
{
public class PapouchCB : ComponentBase, IControlBoard, IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(PapouchCB));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(1)); }
readonly PapouchCBCfg cbCfg;
readonly GenericDevices.IModbus modbus;
UInt32 currentOutputs;
bool outputsInitialized;
DateTime lastOutputsChange;
int lastStateMachineTime = 0;
///
UInt128 benchModelRoute;
UInt128 valvesToInvert; /// Route = valesToInvert ^ RequiredRouteWithoutInvertedVlaves
readonly UInt128 routeMask; /// This mask masks out virtual valves, routeMask is set in the constructor
///
OutputPath devices;
enum SelectedOp
{
None,
SetFlow,
QueryMeasurementEnd,
}
SelectedOp scheduledOp;
SelectedOp runningOp;
///
bool opCompleted; /// true = Operation was completed and waits for Stop();
public PapouchCB()
{
}
/// <summary>
/// Constructor
/// </summary>
public PapouchCB(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
: base(cfg)
{
cbCfg = cfg as PapouchCBCfg;
modbus = (GenericDevices.IModbus)TbfComponents.FindComponent(cfg.ParentName, components);
if (modbus == null) throw new Exception("Cannot find " + Name + " parent");
routeMask = 0;
for (int i = 0; i < 128; i++)
{
if (i < cbCfg.VirtualValvesRangeLo || i > cbCfg.VirtualValvesRangeHi)
{
routeMask = routeMask | ((UInt128)1 << i);
}
}
TBF.UiBridge.Bridge.RouteChangeHandler += delegate(object sndr, TBF.UiBridge.RouteChangeArgs args)
{
UInt128 mask = ((UInt128)1) << args.BitNr;
if ((benchModelRoute & mask) == 0)
{
benchModelRoute |= mask;
}
else
{
benchModelRoute &= (~mask);
}
};
log.Warn(this.ToString());
}
public void SpecifyInvertedValves(UInt128 valvesToInvert)
{
this.valvesToInvert = valvesToInvert;
this.benchModelRoute = valvesToInvert;
}
///
/// IDevice interface
///
public void Initialize()
{
outputsInitialized = false;
runningOp = SelectedOp.None;
}
public void RunDeviceBefore()
{
if (cbCfg.DebugLevel == Config.Entities.DebugMode.Simulate) return;
if (modbus.ReceivedTelegrams[cbCfg.ModbusAddress].Count > 0)
{
byte[] telegram = modbus.ReceivedTelegrams[cbCfg.ModbusAddress].Dequeue();
if ((telegram.Length >= 8) && (telegram[1] == 0x11) && (telegram[2] == telegram.Length - 5))
{
int msgLen = telegram.Length - 7;
byte modbusAddress = telegram[3];
string msg = Encoding.ASCII.GetString(telegram, 5, msgLen);
string s = string.Format("QuidoRS detected: Address={0}, Message={1}", modbusAddress, msg);
Debug.WriteLine(s);
log.Warn(s);
}
if ((telegram.Length == 6) && (telegram[1] == 0x02) && (telegram[2] == telegram.Length - 5))
{
int inputData = telegram[3];
string s = string.Format("QuidoRS inputs: {0}", inputData);
Debug.WriteLine(s);
log.Warn(s);
}
}
}
public void RunDeviceAfter()
{
if (currentOutputs != (UInt32)(benchModelRoute & 0xFFFFFFFF) || !outputsInitialized || (StateMachine.Time - lastStateMachineTime) >= 3)
{
SetOutputs((UInt32)(benchModelRoute & 0xFFFFFFFF));
}
else
{
RequestInputs();
}
ProcessData.UpdateMeasuredValuesAndSetpoints();
TBF.UiBridge.Bridge.OnStateMachineTick(this, new TBF.UiBridge.StateMachineTickEventArgs(benchModelRoute,
ProcessData.MsrmntAvailableFlags,
ProcessData.MeasuredValues,
ProcessData.AltStrings,
ProcessData.Setpoints));
}
public void StopDevice()
{
SendOutputs(0);
}
public void StopDevice2() { }
/// <summary>
/// Set outputs of QuidoRS board
/// </summary>
/// <param name="outputs">output value</param>
public void SetOutputs(UInt32 outputs)
{
lock (this)
{
currentOutputs = outputs;
}
SendOutputs(currentOutputs);
}
/// <summary>
/// Set bit(s) specified by a bitMask. Leave other bits unaffeced.
/// </summary>
/// <param name="bitMask">Specifies bit(s) to set</param>
/// <param name="outputs">output value</param>
public void SetBit(UInt32 bitMask)
{
lock (this)
{
currentOutputs = currentOutputs | bitMask;
}
SendOutputs(currentOutputs);
}
/// <summary>
/// Reset bit(s) specified by a bitMask. Leave other bits unaffeced.
/// </summary>
/// <param name="bitMask">Specifies bit(s) to reset</param>
/// <param name="outputs">output value</param>
public void ResetBit(UInt32 bitMask)
{
lock (this)
{
currentOutputs = currentOutputs & (~bitMask);
}
SendOutputs(currentOutputs);
}
private void RequestInputs()
{
byte addr = cbCfg.ModbusAddress;
byte cmd = (byte)Function.ReadSingleInput;
modbus.SendMessage(new byte[] { addr, cmd, 0, 0, 0, 2, 0, 0 });
}
private void SendOutputs(UInt32 outputs)
{
byte addr = cbCfg.ModbusAddress;
byte cmd = (byte)Function.ForceMultipleCoils;
byte dataLo = (byte)(outputs & 0xFF);
byte data2 = (byte)(outputs >> 8);
byte data3 = (byte)(outputs >> 16);
byte dataHi = (byte)(outputs >> 24);
if (cbCfg.Variant == QuidoVariant.QuidoRS_4_4)
{
modbus.SendMessage(new byte[] { addr, cmd, 0, 0, 0, 4, 1, dataLo, 0, 0 });
}
else if (cbCfg.Variant == QuidoVariant.QuidoRS_8_8)
{
modbus.SendMessage(new byte[] { addr, cmd, 0, 0, 0, 8, 1, dataLo, 0, 0 });
}
else if (cbCfg.Variant == QuidoVariant.QuidoRS_2_16)
{
modbus.SendMessage(new byte[] { addr, cmd, 0, 0, 0, 16, 2, dataLo, data2, 0, 0 });
}
else if (cbCfg.Variant == QuidoVariant.QuidoRS_2_32)
{
modbus.SendMessage(new byte[] { addr, cmd, 0, 0, 0, 32, 4, dataLo, data2, data3, dataHi, 0, 0 });
}
outputsInitialized = true;
lastOutputsChange = DateTime.Now;
lastStateMachineTime = StateMachine.Time;
}
///
/// IControlBoard interface
///
public OutputPath Devices
{
set { devices = value; }
get { return devices; }
}
/// <summary>
/// Route: 128-bit word representing the current state of all valves and pumps
/// </summary>
public UInt128 Route { get { return benchModelRoute; } }
public UInt64 DigitalInputs { get { return 0; } }
public double RefFrequency { get { return 0; } }
public double RefFlow { get { return 0; } }
///
/// Last test result
///
public int RefPulses { get { return 0; } }
public double TestTime { get { return 1.0; } }
public int RefPulsesWM(int wmNr1) { return (wmNr1 > 0 && wmNr1 <= Config.Data.WMsCount) ? 0 : 0; }
public int PulsesWM(int wmNr1) { return (wmNr1 > 0 && wmNr1 <= Config.Data.WMsCount) ? 0 : 0; }
public double TestTimeWM(int wmNr1) { return (wmNr1 > 0 && wmNr1 <= Config.Data.WMsCount) ? 1.0 : 1.0; }
public void ClearProcessValues() { }
/// <summary>
/// Set valves to new positions.
/// </summary>
/// <param name="valvesToOpen">'UInt128' with bits of valves to open set to '1'</param>
/// <param name="valvesToClose">'UInt128' with bits of valves to close set to '1'</param>
/// <returns>'UInt128' with bits of valves that have changed set to '1'</returns>
public UInt128 SetValves(UInt128 valvesToOpen, UInt128 valvesToClose, IList<BuiltIn.ValveEx.Valve> extendedValves)
{
UInt128 oldRoute = benchModelRoute;
benchModelRoute = (((benchModelRoute ^ valvesToInvert) | valvesToOpen) & (~valvesToClose)) ^ valvesToInvert;
foreach (var extV in extendedValves) extV.UpdateRoute(ref benchModelRoute);
log.DebugFormat("SetValves(x,x), new route = {0}", Utils.RouteToStr(benchModelRoute));
UInt128 retVal = oldRoute ^ benchModelRoute;
log.DebugFormat("{0}.SetValves({1}, {2}) returns {3}", Name, valvesToOpen.ToString("X"), valvesToClose.ToString("X"), retVal.ToString("X"));
return retVal;
}
/// <summary>
/// Open one valve and/or close one valve.
/// Events: ValvesSet
/// </summary>
/// <param name="valveOpen">Valve to be opened</param>
/// <param name="valveClose">Valve to be closed</param>
/// <returns>Created operation</returns>
public IOperation SetValvesOp(IValve valveOpen, IValve valveClose)
{
IOperation op = new BuiltIn.SetValvesOp(this, valveOpen, valveClose);
log.DebugFormat("{0}.SetValvesOp(vO, vC) returns {1}", Name, (op != null) ? op.ToString() : "null");
return op;
}
/// <summary>
/// Open and/or close multiple valves.
/// Events: ValvesSet
/// </summary>
/// <param name="valvesOpen">A list of valves to be opened</param>
/// <param name="valvesClose">A list of valves to be closed</param>
/// <returns>Created operation</returns>
public IOperation SetValvesOp(IList<IValve> valvesOpen, IList<IValve> valvesClose)
{
IOperation op = new BuiltIn.SetValvesOp(this, valvesOpen, valvesClose);
log.DebugFormat("{0}.SetValvesOp(vlvsO, vlvsC) returns {1}", Name, (op != null) ? op.ToString() : "null");
return op;
}
/// <summary>
/// Open start/stop valve.
/// Events: ValvesSet, ValvesBusy, Error
/// </summary>
/// <returns>Created operation</returns>
public IOperation OpenStartValveOp()
{
IOperation op = new BuiltIn.SetValvesOp(this, true, devices);
log.DebugFormat("{0}.OpenStartValveOp({1}) returns {2}", Name, devices.StartValve1.Name, (op != null) ? op.ToString() : "null");
return op;
}
/// <summary>
/// Close start/stop valve.
/// Events: ValvesSet, ValvesBusy, Error
/// </summary>
/// <returns>Created operation</returns>
public IOperation CloseStartValveOp()
{
IOperation op = new BuiltIn.SetValvesOp(this, false, devices);
log.DebugFormat("{0}.CloseStartValveOp({1}) returns {2}", Name, devices.StartValve1.Name, (op != null) ? op.ToString() : "null");
return op;
}
public float ValveOpenCloseTime { get { return 0.1f; } }
/// <summary>
/// Returns operation to display a prompt message to set the flow.
/// </summary>
/// <param name="reqrdFlowLo">Lower limit</param>
/// <param name="reqrdFlowHi">Upper limit</param>
/// <param name="measuredFlow">Reference to a box for the measured flow or null</param>
/// <param name="timeout">Flow set timeout</param>
/// <returns>Operation</returns>
public IOperation SetFlowOp(double reqrdFlowLo, double reqrdFlowHi, TBF.Boxes.DoubleBox measuredFlow, int timeout)
{
string loLimStr = reqrdFlowLo.ToString(Config.Utils.SignificantDigitsToFmt(reqrdFlowLo, 2));
string hiLimStr = reqrdFlowHi.ToString(Config.Utils.SignificantDigitsToFmt(reqrdFlowHi, 2));
this.promptMsg = string.Format("Set flow measured by {0} withing {1} and {2} m3/h by regulation valve {3}",
devices.FlowMeter.Name, loLimStr, hiLimStr, devices.RegValve.Name);
this.backColor = System.Drawing.Color.LightSalmon;
scheduledOp = SelectedOp.SetFlow;
return this;
}
public IOperation StopFlowRegulationOp()
{
return new Operations.ReturnGivenEventOp(Event.FlowRegulationStopped);
}
/// <summary>
/// Start a test, Events: MeasurementStarted
/// </summary>
/// <param name="iParam">Int32 parameter 1</param>
/// <param name="dParam1">Double parameter 1 (alternative lower flow limit)</param>
/// <param name="dParam2">Double parameter 2 (alternative upper flow limit)</param>
/// <returns>Operation</returns>
public IOperation StartTestOp(Test test, int iParam = 0, double dParam1 = 0, double dParam2 = 0)
{
currentTest = test;
return new Operations.ReturnGivenEventOp(Event.MeasurementStarted);
}
public IOperation QueryMeasurementEndOp()
{
scheduledOp = SelectedOp.QueryMeasurementEnd;
return this;
}
public IOperation ReadDiverterTransitionOp(bool isStart, Sequences.Statistics plotter, int batchNr, string testName, int repetition)
{
return null;
}
public IOperation StopPreviousOp()
{
return new Operations.ReturnGivenEventOp(Event.PreviousStopped);
}
Test currentTest;
string promptMsg;
System.Drawing.Color backColor;
TBF.Rig.Operations.MessageBoxForm messageBoxForm;
///
delegate void MessageBoxFormDlgt(PapouchCB myRef);
///
void OpenFormDlg(PapouchCB myRef)
{
myRef.messageBoxForm = new TBF.Rig.Operations.MessageBoxForm(promptMsg, backColor);
messageBoxForm.Show();
}
/// <summary>
/// Start selected operation
/// </summary>
public void Start()
{
if (scheduledOp == SelectedOp.None || runningOp != SelectedOp.None)
{
throw new Exception("Sequence error");
}
runningOp = scheduledOp;
scheduledOp = SelectedOp.None;
if (runningOp == SelectedOp.SetFlow)
{
Program.MainWnd.Invoke(new MessageBoxFormDlgt(OpenFormDlg), this);
}
else if (runningOp == SelectedOp.QueryMeasurementEnd)
{
}
}
/// <summary>
/// Run selected operation
/// </summary>
/// <returns>Event.None or Event.FlowReached or Event.MeasurementCompleted </returns>
public Event Run()
{
if (runningOp == SelectedOp.SetFlow)
{
if (opCompleted || messageBoxForm.Completed)
{
opCompleted = true;
messageBoxForm = null;
return Event.FlowReached;
}
}
else if (runningOp == SelectedOp.QueryMeasurementEnd)
{
if (opCompleted) return Event.MeasurementCompleted;
double currentMass = TBF.Rig.Sequences.ProcessData.Mass.Val;
if (currentMass - TBF.Rig.Sequences.ProcessData.StartMass.Val >= currentTest.Volume)
{
opCompleted = true;
return Event.MeasurementCompleted;
}
}
return Event.None;
}
/// <summary>
/// Stop this operation
/// </summary>
public void Stop()
{
if (runningOp == SelectedOp.SetFlow)
{
if (messageBoxForm != null)
{
messageBoxForm.OnCloseThisForm(this, null);
messageBoxForm = null;
}
}
runningOp = SelectedOp.None;
opCompleted = false;
}
}
}
@@ -0,0 +1,62 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using System.Xml.Serialization;
using TBF.Rig.Generic;
namespace TBF.Rig.ControlBoard.Papouch
{
public enum QuidoVariant
{
QuidoRS_4_4,
QuidoRS_8_8,
QuidoRS_2_16,
QuidoRS_2_32,
Count
}
public class PapouchCBCfg : ComponentCfgBase, Generic.IChildComponentCfg
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(PapouchCBCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new CBoardCfgCtrl(); }
///
/// Serialized parameters
///
public byte ModbusAddress; /// 1..254
public QuidoVariant Variant; /// QuidoRS_2_16, QuidoRS_4_4 or QuidoRS_8_8
public int VirtualValvesRangeLo;
public int VirtualValvesRangeHi;
/// Private parameterless constructor invoked by all other (public) constructors
PapouchCBCfg()
{
Name = "CB";
ParentName = "Modbus";
ModbusAddress = 1;
Variant = QuidoVariant.QuidoRS_2_32;
VirtualValvesRangeLo = 50;
VirtualValvesRangeHi = 59;
}
public PapouchCBCfg(IComponentFactory factory)
: this()
{
this.Factory = factory;
}
public string ToString(int i)
{
return string.Format("name={0}({1}) address={2} variant={3} vvLo={4} vvHi={5}",
Name,
(string.IsNullOrEmpty(ParentName) ? "-" : ParentName),
ModbusAddress,
Variant,
VirtualValvesRangeLo,
VirtualValvesRangeHi);
}
}
}
+436
View File
@@ -0,0 +1,436 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using Dirichlet.Numerics;
namespace TBF.Rig.ControlBoard.Uni
{
public enum ActionID
{
/// Basic
ChangeRoute = 1, /// Change digital outputs (route)
MeasureFlow = 2, /// Activate a flow meter to measure the flow
SetFlow = 4, /// Set flow
StartTest = 8, /// Start a test
StopTest = 0x10, /// Stop a test or a flow regulation
RegVlvIncrMove = 0x20,
RegVlvMoveToPos = 0x40,
RegVlvStop = 0x80,
SwitchDiverter = 0x100, /// Switch diverter to tank/sink
/// Advanced
GetDiverterTransitionData,
GetScopeAnalyzerData,
ResetScopeAnalyzer,
GetSwitchCounterData,
}
public class Action
{
private static readonly ILog log = LogManager.GetLogger(typeof(Action));
public ActionID ActionId { get; set; }
public ulong Route { get; set; } /// ChangeRoute argument
public int FlowMId { get; set; } /// SetFlow, MeasureFlow and StartTest argument
public int RegVId { get; set; } /// SetFlow and StartTest argument
public int DivId { get; set; } /// StartTest and SwitchDiverter argument
public bool IsSyncMethod { get; set; } /// StartTest argument
public bool IsDivUsed { get; set; } /// StartTest argument
public bool ToTank { get; set; } /// SwitchDiverter argument
public int TotalPulsesCount { get; set; } /// StartTest argument
public int MassPulsesCount { get; set; } /// StartTest argument
public RegValveMode RegVMode { get; set; } /// SetFlow, RegVlvIncrMove, RegVlvMoveToPos, RegVlvStop
public int RVMovePar1 { get; set; } /// SetFlow, RegVlvIncrMove, RegVlvMoveToPos
public int RVMovePar2 { get; set; } /// SetFlow, RegVlvIncrMove, RegVlvMoveToPos
public int PID { get; set; } /// SetFlow
public int TolerRV { get; set; } /// SetFlow
public int StabTime { get; set; } /// SetFlow
public int DivThreshold { get; set; } /// StartTest argument
int StartStop { get; set; } /// Implicitly used by StartTest and StopTest: -1=not defined, 0=stop, 1=start
public Action()
{
/// Values -1 indicate the related arguments are not used yet
FlowMId = -1;
RegVId = -1;
DivId = -1;
RegVMode = RegValveMode.None;
StartStop = -1;
/// These values are used by one action type only. No conflicts possible
Route = 0;
TotalPulsesCount = 0;
MassPulsesCount = 0;
RVMovePar1 = 0;
RVMovePar2 = 0;
}
public bool IsStart()
{
return (ActionId & (ActionID.SetFlow | ActionID.StartTest)) != 0;
}
public bool IsStop()
{
return (ActionId & ActionID.StopTest) != 0;
}
///----------------------------------------------------------------------------------------------
public static Action ChangeRoute(ulong route)
{
return new Action
{
ActionId = ActionID.ChangeRoute,
Route = route,
};
}
void SetChangeRouteArgs(Action action)
{
Route = action.Route;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedChangeRouteArgs(Action newAction)
{
return Route == newAction.Route;
}
///----------------------------------------------------------------------------------------------
public static Action MeasureFlow(int flowMeterId)
{
return new Action
{
ActionId = ActionID.MeasureFlow,
FlowMId = flowMeterId,
};
}
void SetMeasureFlowArgs(Action action)
{
FlowMId = action.FlowMId;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedMeasureFlowArgs(Action newAction)
{
return (FlowMId == -1 || FlowMId == newAction.FlowMId);
}
///----------------------------------------------------------------------------------------------
public static Action SetFlow(int flowMeterId, int regValveId, double freqLo, double freqHi,
int pid, int tolerRV, int stabTime)
{
int rvMovePar1 = Convert.ToInt32(Math.Round(13.1072 * freqLo));
int rvMovePar2 = Convert.ToInt32(Math.Round(13.1072 * freqHi));
return new Action
{
ActionId = ActionID.SetFlow,
FlowMId = flowMeterId,
RegVId = regValveId,
RegVMode = RegValveMode.TargetFrequency,
RVMovePar1 = rvMovePar1,
RVMovePar2 = rvMovePar2,
PID = pid,
TolerRV = tolerRV,
StabTime = stabTime,
};
}
void SetSetFlowArgs(Action action)
{
FlowMId = action.FlowMId;
RegVId = action.RegVId;
RegVMode = action.RegVMode;
RVMovePar1 = action.RVMovePar1;
RVMovePar2 = action.RVMovePar2;
PID = action.PID;
TolerRV = action.TolerRV;
StabTime = action.StabTime;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedSetFlowArgs(Action newAction)
{
return (FlowMId == -1 || FlowMId == newAction.FlowMId) &&
(RegVId == -1 || RegVId == newAction.RegVId) &&
(RegVMode == RegValveMode.None || RegVMode == newAction.RegVMode) &&
(RVMovePar1 == -1 || RVMovePar1 == newAction.RVMovePar1) &&
(RVMovePar2 == -1 || RVMovePar2 == newAction.RVMovePar2);
}
///----------------------------------------------------------------------------------------------
public static Action StartTest(int flowMId, int divId, int divThreshold, bool isSyncMethod,
bool isDivUsed, int totalPulsesCount, int massPulsesCount = -1)
{
return new Action
{
ActionId = ActionID.StartTest,
FlowMId = flowMId,
DivId = divId,
DivThreshold = divThreshold,
IsSyncMethod = isSyncMethod,
IsDivUsed = isDivUsed,
TotalPulsesCount = totalPulsesCount,
MassPulsesCount = (massPulsesCount == -1) ? totalPulsesCount : massPulsesCount,
StartStop = 1,
};
}
void SetStartTestArgs(Action action)
{
FlowMId = action.FlowMId;
DivId = action.DivId;
DivThreshold = action.DivThreshold;
IsSyncMethod = action.IsSyncMethod;
IsDivUsed = action.IsDivUsed;
TotalPulsesCount = action.TotalPulsesCount;
MassPulsesCount = action.MassPulsesCount;
StartStop = 1;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedStartTestArgs(Action newAction)
{
return (FlowMId == -1 || FlowMId == newAction.FlowMId) &&
(DivId == -1 || DivId == newAction.DivId) &&
(StartStop == -1 || StartStop == 1);
}
///----------------------------------------------------------------------------------------------
public static Action StopTest()
{
return new Action()
{
ActionId = ActionID.StopTest,
StartStop = 0,
};
}
void SetStopTestArgs(Action action)
{
StartStop = 0;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedStopTestArgs(Action action)
{
return (StartStop == -1 || StartStop == 0);
}
///----------------------------------------------------------------------------------------------
public static Action RegVlvIncrMove(int regValveId, double timeSec)
{
int rvMovePar = Math.Abs(Convert.ToInt32(Math.Round(timeSec / 0.050))); /// Step is 50 ms
return new Action
{
ActionId = ActionID.RegVlvIncrMove,
RegVId = regValveId,
RegVMode = (timeSec >= 0) ? RegValveMode.PulseWidth : (RegValveMode.PulseWidth | RegValveMode.NegPulseWidth),
RVMovePar1 = rvMovePar,
RVMovePar2 = rvMovePar,
};
}
void SetRegVlvIncrMoveArgs(Action action)
{
RegVId = action.RegVId;
RegVMode = action.RegVMode;
RVMovePar1 = action.RVMovePar1;
RVMovePar2 = action.RVMovePar2;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedRegVlvIncrMoveArgs(Action newAction)
{
return (RegVId == -1 || RegVId == newAction.RegVId) &&
(RegVMode == RegValveMode.None || RegVMode == newAction.RegVMode);
}
///----------------------------------------------------------------------------------------------
public static Action RegVlvMoveToPos(int regValveId, double positionLo, double positionHi = -1)
{
int rvMovePar1, rvMovePar2; /// TODO
///
if (positionHi < 0)
{
/// Center position specified, calculate a range
rvMovePar1 = 0; // TODO
rvMovePar2 = 0; // TODO
}
else
{
/// Lower and upper range of position specified
rvMovePar1 = 0; // TODO
rvMovePar2 = 0; // TODO
}
return new Action
{
ActionId = ActionID.RegVlvMoveToPos,
RegVId = regValveId,
RegVMode = RegValveMode.TargetPosition,
RVMovePar1 = rvMovePar1,
RVMovePar2 = rvMovePar2,
};
}
void SetRegVlvMoveToPosArgs(Action action)
{
RegVId = action.RegVId;
RegVMode = action.RegVMode;
RVMovePar1 = action.RVMovePar1;
RVMovePar2 = action.RVMovePar2;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedRegVlvMoveToPosArgs(Action newAction)
{
return (RegVId == -1 || RegVId == newAction.RegVId) &&
(RegVMode == RegValveMode.None || RegVMode == newAction.RegVMode);
}
///----------------------------------------------------------------------------------------------
public static Action RegVlvStop(int regValveId)
{
return new Action
{
ActionId = ActionID.RegVlvStop,
RegVId = regValveId,
RegVMode = RegValveMode.Stop,
RVMovePar1 = 0,
RVMovePar2 = 0,
};
}
void SetRegVlvStopArgs(Action action)
{
RegVId = action.RegVId;
RegVMode = action.RegVMode;
RVMovePar1 = action.RVMovePar1;
RVMovePar2 = action.RVMovePar2;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedRegVlvStopArgs(Action newAction)
{
return (RegVId == -1 || RegVId == newAction.RegVId) &&
(RegVMode == RegValveMode.None || RegVMode == newAction.RegVMode);
}
///----------------------------------------------------------------------------------------------
public static Action SwitchDiverter(int divId, bool toTank)
{
return new Action
{
ActionId = ActionID.SwitchDiverter,
DivId = divId,
ToTank = toTank,
};
}
void SetSwitchDiverterArgs(Action action)
{
DivId = action.DivId;
ToTank = action.ToTank;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedSwitchDiverterArgs(Action action)
{
return (DivId == -1 || DivId == action.DivId);
}
///----------------------------------------------------------------------------------------------
void SetArgs(Action action)
{
ActionId |= action.ActionId;
switch (action.ActionId)
{
case ActionID.ChangeRoute: SetChangeRouteArgs(action); return;
case ActionID.MeasureFlow: SetMeasureFlowArgs(action); return;
case ActionID.SetFlow: SetSetFlowArgs(action); return;
case ActionID.StartTest: SetStartTestArgs(action); return;
case ActionID.StopTest: SetStopTestArgs(action); return;
case ActionID.RegVlvIncrMove: SetRegVlvIncrMoveArgs(action); return;
case ActionID.RegVlvMoveToPos: SetRegVlvMoveToPosArgs(action); return;
case ActionID.RegVlvStop: SetRegVlvStopArgs(action); return;
case ActionID.SwitchDiverter: SetSwitchDiverterArgs(action); return;
default: return;
}
}
/// <summary>
/// Check whether new action arguments are compatible with alredy collected arguments
/// </summary>
/// <param name="action">Action to be executed together with already collected actions</param>
/// <returns>true when compatible</returns>
bool CheckSharedArgs(Action action)
{
switch (action.ActionId)
{
case ActionID.ChangeRoute: return CheckSharedChangeRouteArgs(action);
case ActionID.MeasureFlow: return CheckSharedMeasureFlowArgs(action);
case ActionID.SetFlow: return CheckSharedSetFlowArgs(action);
case ActionID.StartTest: return CheckSharedStartTestArgs(action);
case ActionID.StopTest: return CheckSharedStopTestArgs(action);
case ActionID.RegVlvIncrMove: return CheckSharedRegVlvIncrMoveArgs(action);
case ActionID.RegVlvMoveToPos: return CheckSharedRegVlvMoveToPosArgs(action);
case ActionID.RegVlvStop: return CheckSharedRegVlvStopArgs(action);
case ActionID.SwitchDiverter: return CheckSharedSwitchDiverterArgs(action);
default: return false;
}
}
///----------------------------------------------------------------------------------------------
public static Action FetchNonConflictingActions(Queue<Action> queue)
{
log.Debug("Fetching non conflicting actions:");
if (queue == null || queue.Count == 0) return null;
Action resultA = queue.Dequeue();
log.Debug(resultA.ToString());
while (queue.Count > 0)
{
var peekA = queue.Peek();
if ((resultA.ActionId & peekA.ActionId) == 0 && resultA.CheckSharedArgs(peekA) == true)
{
/// ActionId would not be repeated and arguments are compatible => apply the new action
resultA.SetArgs(peekA);
log.Debug(peekA.ToString());
queue.Dequeue();
}
else
{
/// Leave actions in the queue and quit the loop as the next scheduled action is incompatible
break;
}
}
return resultA;
}
public override string ToString()
{
string args;
switch (ActionId)
{
case ActionID.ChangeRoute:
args = string.Format("Route={0}", Route.ToString("X16"));
break;
case ActionID.MeasureFlow:
args = string.Format("Etalon={0}", FlowMId);
break;
case ActionID.SetFlow:
args = string.Format("Etalon={0} RV={1} Par1={2} Par2={3}", FlowMId, RegVId, RVMovePar1, RVMovePar2);
break;
case ActionID.StartTest:
args = string.Format("Etalon={0} TotalP={1} MassP={2}", FlowMId, TotalPulsesCount, MassPulsesCount);
break;
case ActionID.RegVlvIncrMove:
args = string.Format("Time={0}ms", (RegVMode & RegValveMode.NegPulseWidth) != 0 ? -50 * RVMovePar1 : 50 * RVMovePar1);
break;
case ActionID.RegVlvMoveToPos:
args = string.Format("Position={0}%", 0); /// TODO
break;
default:
args = string.Empty;
break;
}
return string.Format(" {0} {1}", ActionId, args);
}
}
}
@@ -0,0 +1,59 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
namespace TBF.Rig.ControlBoard.Uni
{
public class DivTransitionData
{
public const int MessageLen = 255;
public const byte MessageCode = (byte)'K';
/// Diverter transition data
const int samplesCount = 245;
int DiverterTime_ms;
byte[] CurveRaw;
DivTransitionData()
{
CurveRaw = new byte[samplesCount];
}
/// <summary>
/// Returns tru when receive data fit the message frame
/// </summary>
/// <param name="rcvdData">Received data</param>
/// <param name="cumulativeSums">Cumulative sums of received data bytes</param>
/// <param name="rcvdBytesCount">Received bytes count</param>
/// <param name="offset">Offset of the message</param>
/// <returns>true when frame fits data</returns>
public static bool FrameFitsData(byte[] rcvdData, int[] cumulativeSums, int rcvdBytesCount, int offset)
{
if (offset + MessageLen > rcvdBytesCount) return false;
int checksum = cumulativeSums[offset + MessageLen - 3] - cumulativeSums[offset];
return rcvdData[offset] == Const.STX &&
rcvdData[offset + 1] == 0x01 &&
rcvdData[offset + 2] == ((MessageLen - 5) & 0xFF) &&
rcvdData[offset + 3] == MessageCode &&
rcvdData[offset + MessageLen - 2] == (checksum & 0xFF) &&
rcvdData[offset + MessageLen - 1] == ((checksum >> 8) & 0xFF);
}
/// <summary>
/// Proces received data
/// </summary>
/// <param name="rcvdData">Received data</param>
/// <param name="offset">Offset of the message</param>
public static DivTransitionData GetData(byte[] rcvdData, int offset)
{
var data = new DivTransitionData();
data.DiverterTime_ms = Const.DivTimeResolution * rcvdData[offset + 4];
for (int i = 0; i < samplesCount; i++)
{
data.CurveRaw[i] = rcvdData[offset + 6 + i];
}
return data;
}
}
}
+51
View File
@@ -0,0 +1,51 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
namespace TBF.Rig.ControlBoard.Uni
{
public class Const
{
public const byte STX = 0x10;
public const int WMsCount = 20; /// water meters count
public const int ADCsCount = 16; /// ADCs count: feedback from RV-s and diverters
public const int RVsCount = 8; /// 0..7
public const int FlowmtrsCount = 7; /// ID=1..7, ID=0 ... flowmeters 1,2,3 parallel
public const int DivertersCount = 5; /// 1..5
public const int DivTimeResolution = 2; /// [ms]
public const double TimeResolution = 0.0002; /// [s]
}
public enum StatusP : ulong
{
/// byte 0
FlowmtrNrMask = 0x7, /// bits 0,1,2
TestInProgress = 0x8, /// bit 3
TestCompleted = 0x10, /// bit 4
ReadingCounters = 0x20, /// bit 5
WaitingForDiverter = 0x40, /// bit 6
TestWithDiverter = 0x80, /// bit 7
/// byte 1
TestWithRefFlowmtr = 0x100, /// bit 8
DirectionOfDiverer = 0x200, /// bit 9
SynchroMethod = 0x800, /// bit 11
WaterMeterCalib = 0x1000, /// bit 12
EmgcyStopActive = 0x2000, /// bit 13
GateOn = 0x4000, /// bit 14
TimeMeasurementEn = 0x8000, /// bit 15
/// byte 2
FrequencyMeasured = 0x80000, /// bit 19
CoaxRegValveBusy = 0x200000, /// bit 21
/// byte 3
ADCError = 0x80000000, /// bit 31
/// byte 4
TimeoutOccured = 0x100000000, /// bit 32 (after 40s without communication)
MeretAddresses = 0x200000000, /// bit 33
ScopeBufferFull = 0x400000000, /// bit 34
/// byte 5
/// byte 6
Flowmtr1Active = 0x1000000000000, /// bit 48
Flowmtr2Active = 0x2000000000000, /// bit 49
Flowmtr3Active = 0x4000000000000, /// bit 50
}
}
+53
View File
@@ -0,0 +1,53 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
namespace TBF.Rig.ControlBoard.Uni
{
public class ExtremaData
{
public const int MessageLen = 253;
public const byte MessageCode = (byte)'E';
// TODO: Implement member variables
ExtremaData()
{
}
/// <summary>
/// Returns tru when receive data fit the message frame
/// </summary>
/// <param name="rcvdData">Received data</param>
/// <param name="cumulativeSums">Cumulative sums of received data bytes</param>
/// <param name="rcvdBytesCount">Received bytes count</param>
/// <param name="offset">Offset of the message</param>
/// <returns>true when frame fits data</returns>
public static bool FrameFitsData(byte[] rcvdData, int[] cumulativeSums, int rcvdBytesCount, int offset)
{
if (offset + MessageLen > rcvdBytesCount) return false;
int checksum = cumulativeSums[offset + MessageLen - 3] - cumulativeSums[offset];
return rcvdData[offset] == Const.STX &&
rcvdData[offset + 1] == 0x01 &&
rcvdData[offset + 2] == ((MessageLen - 5) & 0xFF) &&
rcvdData[offset + 3] == MessageCode &&
rcvdData[offset + MessageLen - 2] == (checksum & 0xFF) &&
rcvdData[offset + MessageLen - 1] == ((checksum >> 8) & 0xFF);
}
/// <summary>
/// Proces received data
/// </summary>
/// <param name="rcvdData">Received data</param>
/// <param name="offset">Offset of the message</param>
public static ExtremaData GetData(byte[] rcvdData, int offset)
{
var data = new ExtremaData();
// TODO
return data;
}
}
}
+27
View File
@@ -0,0 +1,27 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.ControlBoard.Uni
{
public class Factory : IComponentFactory
{
public string ClassName { get { return this.GetType().Namespace.Substring(8); } }
public override string ToString() { return ClassName; }
public void ResetStaticProperties() { UniCB.ResetStaticProperties(); }
public IComponent DummyComponent() { return new UniCB(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new UniCB(cfg); }
public IComponentCfg DefaultConfig() { return new UniCBCfg("UniCB", this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(UniCBCfg.Serializer, component, this);
}
}
}
+231
View File
@@ -0,0 +1,231 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
namespace TBF.Rig.ControlBoard.Uni
{
public class GeneralData
{
public const int MessageLen = 303;
public const byte MessageCode = (byte)' ';
/// General data
public ulong State; /// bytes 5,6,7,8,9,80,81 = 7 bytes = 56 bits
public uint Chyby485;
public ulong Vystupy;
public uint[] StavDA = new uint[2];
public double[] ReferenceFreq = new double[4];
public int[] EtPulses = new int[Const.WMsCount + 1]; /// EtPulses[0]=total pulses, EtPulses[1..WMsCount] gated et.pulses for respective WM
public int EtPulsesK;
public int EtPulses2;
public int EtPulses3;
public int[] WMeterPuls = new int[Const.WMsCount + 1]; /// WMsCount = 20
public double[] ImpulseTime = new double[Const.WMsCount + 1]; /// WMsCount = 20
public uint[] RegVStatus = new uint[Const.RVsCount + 1 + 1]; /// RVsCount = 8, posledny rValveStatus[9] je prudovy
public float[] RegVMoveTime = new float[Const.RVsCount];
public int DivTime;
public double Ttime; /// s
public double TimeRef; /// s
public ulong Vstupy;
public Int16[] AnalogInput = new Int16[Const.ADCsCount];
public int[] TemperatureRaw = new int[8];
public GeneralData()
{
}
/// <summary>
/// Returns tru when receive data fit the message frame
/// </summary>
/// <param name="data">Received data</param>
/// <param name="cumulativeSums">Cumulative sums of received data bytes</param>
/// <param name="rcvdBytesCount">Received bytes count</param>
/// <param name="offset">Offset of the message</param>
/// <returns>true when frame fits data</returns>
public static bool FrameFitsData(byte[] data, int[] cumulativeSums, int rcvdBytesCount, int offset)
{
if (offset + MessageLen > rcvdBytesCount) return false;
int checksum = cumulativeSums[offset + MessageLen - 3] - cumulativeSums[offset];
return data[offset] == Const.STX &&
data[offset + 1] == 0x01 &&
data[offset + 2] == ((MessageLen - 5) & 0xFF) &&
data[offset + 3] == MessageCode &&
data[offset + MessageLen - 2] == (checksum & 0xFF) &&
data[offset + MessageLen - 1] == ((checksum >> 8) & 0xFF);
}
/// <summary>
/// Auxiliary functions
/// </summary>
/// <param name="data">Received data</param>
/// <param name="offs">Offset to the files</param>
/// <returns></returns>
Int16 GetInt16(byte[] data, int offs) { return BitConverter.ToInt16(data, offs); }
UInt16 GetUInt16(byte[] data, int offs) { return BitConverter.ToUInt16(data, offs); }
UInt32 GetUInt24(byte[] data, int offs) { return BitConverter.ToUInt32(data, offs) & 0x00FFFFFF; }
UInt32 GetUInt32(byte[] data, int offs) { return BitConverter.ToUInt32(data, offs); }
UInt64 GetUInt40(byte[] data, int offs) { return BitConverter.ToUInt64(data, offs) & 0x000000FFFFFFFFFF; }
UInt64 GetUInt64(byte[] data, int offs) { return BitConverter.ToUInt64(data, offs); }
/// <summary>
/// Proces received data
/// </summary>
/// <param name="data">Received data</param>
/// <param name="offs">Offset of the message</param>
public void UpdateData(byte[] data, int offs)
{
State = GetUInt40(data, offs + (int)Poz.State) | /// Byte 5,6,7,8,9,80,81
((ulong)data[offs + (int)Poz.Stat5] << 40) |
((ulong)data[offs + (int)Poz.Stat6] << 48);
Vystupy = GetUInt64(data, offs + (int)Poz.Vyst); /// Byte 10 .. 17
StavDA[1] = GetUInt16(data, offs + (int)Poz.SDA2); /// Byte 18,19
Vstupy = GetUInt40(data, offs + (int)Poz.Vst); /// Byte 20,21,22,23,24
/// A/D converters: Feedback from RV-s and diverters
for (int i = 0; i < Const.ADCsCount; i++) /// Byte 25 .. 56
{
#if DEBUG
AnalogInput[Const.ADCsCount - 1 - i] = (short)(11 * (15 - i));
#else
AnalogInput[Const.ADCsCount - 1 - i] = GetInt16(data, offs + (int)Poz.Analogy + 2 * i);
#endif
}
/// Groch temperature meters
for (int i = 0; i < 8; i++) /// byte 57 .. 72
{
TemperatureRaw[i] = GetInt16(data, offs + (int)Poz.Groch + 2 * i);
}
EtPulses[0] = Convert.ToInt32(GetUInt24(data, offs + (int)Poz.Et1));/// Byte 73,74,75
EtPulsesK = Convert.ToInt32(GetUInt24(data, offs + (int)Poz.EtK)); /// Byte 76,77,78
byte spare1 = data[offs + (int)Poz.spare1]; /// byte 79
byte spare2 = data[offs + (int)Poz.spare2]; /// byte 82
for (int i = 0; i < Const.RVsCount; i++) /// Byte 83 .. 90
{
RegVStatus[i + 1] = ((uint)data[offs + (int)Poz.RVs + i] >> 3) & 7;
}
/// 4-20 mA reg. valve
uint stavRegQ = (uint)((State >> 16) & 0xFF);
RegVStatus[Const.RVsCount + 1] = (stavRegQ >> 4) & 2;
/// This must preceed processing bytes 91 .. 250 as Ttime is used there
uint ttimeRaw = GetUInt32(data, offs + (int)Poz.Ttime); /// Byte 251,252,253,254
Ttime = Convert.ToDouble(ttimeRaw) * Const.TimeResolution; /// convert to [s]
ImpulseTime[0] = Ttime;
/// Water meters (pulses count, gated test time, gated etalon pulses count)
int ix1 = offs + (int)Poz.CT1; /// Byte 91 .. 250
int ix2 = offs + (int)Poz.CTR1;
for (int wmNr = 1; wmNr <= Const.WMsCount; wmNr++, ix1 += 6, ix2 += 2)
{
if ((State & (ulong)StatusP.SynchroMethod) != 0)
{
ushort pulses = GetUInt16(data, ix2);
WMeterPuls[wmNr] = Convert.ToInt32(pulses);
EtPulses[wmNr] = (pulses == 0) ? 0 : Convert.ToInt32(GetUInt24(data, ix1));
ImpulseTime[wmNr] = (pulses == 0) ? 0 : Const.TimeResolution * Convert.ToDouble(GetUInt24(data, ix1 + 3));
}
else
{
WMeterPuls[wmNr] = Convert.ToInt32(GetUInt24(data, ix1));
EtPulses[wmNr] = EtPulses[0];
ImpulseTime[wmNr] = Ttime;
}
}
StavDA[0] = GetUInt16(data, offs + (int)Poz.SDA); /// Byte 255,256
byte spare3 = data[offs + (int)Poz.spare3]; /// Byte 257
/// Impulzy perioda (???)
uint[] par1 = new uint[3];
uint[] par2 = new uint[3];
par2[0] = GetUInt16(data, offs + (int)Poz.Per1); /// Byte 258,259
par1[0] = GetUInt16(data, offs + (int)Poz.Per1 + 2); /// Byte 260,261
par2[1] = GetUInt16(data, offs + (int)Poz.Per2); /// Byte 262.263
par1[1] = GetUInt16(data, offs + (int)Poz.Per2 + 2); /// Byte 264,265
par2[2] = GetUInt16(data, offs + (int)Poz.Per3); /// Byte 266,267
par1[2] = GetUInt16(data, offs + (int)Poz.Per3 + 2); /// Byte 268,269
///
ReferenceFreq[0] = (par2[0] != 0) ? (5.0f * par1[0] / par2[0]) : 0.0f;
ReferenceFreq[1] = ReferenceFreq[2] = ReferenceFreq[3] = 0;
///
if ((State & (ulong)StatusP.TestWithRefFlowmtr) != 0 && (State & (ulong)StatusP.FlowmtrNrMask) == 0)
{
/// Measurement with parallel flowmeters
if ((State & (ulong)StatusP.Flowmtr1Active) != 0)
{
ReferenceFreq[1] = ReferenceFreq[0];
}
if ((State & (ulong)StatusP.Flowmtr2Active) != 0)
{
ReferenceFreq[2] = (par2[1] != 0) ? (5.0f * par1[1] / par2[1]) : 0.0f;
}
if ((State & (ulong)StatusP.Flowmtr3Active) != 0)
{
ReferenceFreq[3] = (par2[2] != 0) ? (5.0f * par1[2] / par2[2]) : 0.0f;
}
ReferenceFreq[0] = ReferenceFreq[1] + ReferenceFreq[2] + ReferenceFreq[3];
}
DivTime = Const.DivTimeResolution * data[offs + (int)Poz.CasKl]; /// Byte 271
byte spare4 = data[offs + (int)Poz.spare4]; /// Byte 272
Chyby485 = GetUInt16(data, offs + (int)Poz.Chyb485); /// Byte 273, 274 !!!!!!!!!!!!!!!
uint timeRefRaw = GetUInt24(data, offs + (int)Poz.Tim2); /// Byte 274,275,276 !!!!!!!!!!!!!!!
TimeRef = Convert.ToDouble(timeRefRaw) / 1000.0; /// convert to [s]
for (int i = 0; i < Const.RVsCount; i++) /// Byte 278 .. 293
{
RegVMoveTime[i] = 10 * GetUInt16(data, offs + (int)Poz.CasKoh + 2*i);
}
EtPulses2 = Convert.ToInt32(GetUInt24(data, offs + (int)Poz.ETX2)); /// Byte 294,295,296
EtPulses3 = Convert.ToInt32(GetUInt24(data, offs + (int)Poz.ETX3)); /// Byte 297,298.299 !!!!!!!!!!!!!!!
}
}
/// <summary>
/// Byte positions in rcvdData buffer
/// </summary>
public enum Poz : int
{
State = 5, /// 5 .. 9
Vyst = State + 5, /// 10 .. 17
SDA2 = Vyst + 8, /// 18,19
Vst = SDA2 + 2, /// 20 .. 24
Analogy = Vst + 5, /// 25 .. 56
Groch = Analogy + 2 * Const.ADCsCount, /// 57 (16 analog inputs)
Et1 = Groch + 16, /// 73,74,75
EtK = Et1 + 3, /// 76,77,78
spare1 = EtK + 3, /// 79
Stat5 = spare1 + 1, /// 80
Stat6 = Stat5 + 1, /// 81
spare2 = Stat6 + 1, /// 82
RVs = spare2 + 1, /// 83
CT1 = RVs + 8, /// 91
CTR1 = CT1 + 6 * Const.WMsCount, /// 211
Ttime = CTR1 + 2 * Const.WMsCount, /// 251
SDA = Ttime + 4, /// 255
spare3 = SDA + 2, /// 257
Per1 = spare3 + 1, /// 258
Per2 = Per1 + 4, /// 262
Per3 = Per2 + 4, /// 266
CasKl = Per3 + 5, /// 271
spare4 = CasKl + 1, /// 272
Chyb485 = spare4 + 1, /// 273
Tim2 = Chyb485 + 1, /// 274
CasKoh = Tim2 + 4, /// 278
ETX2 = CasKoh + 2 * Const.RVsCount, /// 294
ETX3 = ETX2 + 3, /// 297
}
}
+186
View File
@@ -0,0 +1,186 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Diagnostics;
using Dirichlet.Numerics;
namespace TBF.Rig.ControlBoard.Uni
{
public static class OutputMessage
{
public const int PayloadLen = 38;
public const byte MessageCode = (byte)' ';
public static byte[] GetMessage(Action action, short config)
{
byte[] message = new byte[PayloadLen + 5]; /// headed 3 bytes, checksum 2 bytes
/// Header + message code (4 bytes)
message[0] = Const.STX;
message[1] = 1; /// Control board addres
message[2] = (byte)PayloadLen; /// Payload length
message[3] = MessageCode;
/// Command
message[4] = GetCommand(action);
message[5] = action.IsStart() ? GetStartParams(action) : action.IsStop() ? GetStopParams(action) : (byte)0;
message[6] = (action.DivId <= 0) ? (byte)0 : (byte)(action.DivId - 1);
int totalPulsesCount = (action.TotalPulsesCount < 0) ? 0 : action.TotalPulsesCount;
message[7] = (byte)(totalPulsesCount & 0xFF);
message[8] = (byte)((totalPulsesCount >> 8) & 0xFF);
message[9] = (byte)((totalPulsesCount >> 16) & 0xFF);
int massPulsesCount = (action.MassPulsesCount < 0) ? 0 : action.MassPulsesCount;
message[10] = (byte)(massPulsesCount & 0xFF);
message[11] = (byte)((massPulsesCount >> 8) & 0xFF);
message[12] = (byte)((massPulsesCount >> 16) & 0xFF);
message[13] = 0;
message[14] = (byte)(config & 0xff);
message[15] = (byte)((config >> 8) & 0xff);
/// Route
message[16] = ((action.ActionId & ActionID.ChangeRoute) != 0) ? (byte)1 : (byte)0; /// Route change flag
message[17] = (byte)(action.Route & 0xFF);
message[18] = (byte)((action.Route >> 8) & 0xFF);
message[19] = (byte)((action.Route >> 16) & 0xFF);
message[20] = (byte)((action.Route >> 24) & 0xFF);
message[21] = (byte)((action.Route >> 32) & 0xFF);
message[22] = (byte)((action.Route >> 40) & 0xFF);
message[23] = (byte)((action.Route >> 48) & 0xFF);
message[24] = (byte)((action.Route >> 56) & 0xFF);
/// DA2
message[25] = 0;
message[26] = 0;
/// Regulation valve
message[27] = (action.RegVId < 0) ? (byte)0 : (byte)(action.RegVId | (int)action.RegVMode);
message[28] = (byte)(action.RVMovePar1 & 0xFF);
message[29] = (byte)((action.RVMovePar1 >> 8) & 0xFF);
message[30] = (byte)(action.RVMovePar2 & 0xFF);
message[31] = (byte)((action.RVMovePar2 >> 8) & 0xFF);
message[32] = action.IsStop() ? (byte)0x20 : action.IsStart() ? (byte)0x42 : (byte)0; /// ZStavReg
/// DA1
message[33] = 0; /// PrudParL
message[34] = 0; /// PrudParH
message[35] = (byte)Math.Max(1, Math.Min(255, action.PID)); /// PIDRV
message[36] = (byte)Math.Max(4, Math.Min(255, action.TolerRV)); /// TolerRV (4..20 mA reg.valve only)
message[37] = (byte)Math.Max(0, Math.Min(255, action.StabTime)); /// StabRV
message[38] = (byte)((action.DivThreshold >> 2) & 0xFF); /// HranAK
message[39] = 0;
message[40] = 0;
Debug.Assert(40 == PayloadLen + 2);
/// Checksum (2 bytes)
int checksum = 0;
for (int i = 1; i < PayloadLen + 3; i++) checksum += message[i];
message[PayloadLen + 3] = (byte)(checksum & 0xFF);
message[PayloadLen + 4] = (byte)((checksum >> 8) & 0xFF);
return message;
}
static byte GetCommand(Action action)
{
int command = 0;
if (action.IsStart()) command |= (int)Command.Start;
if (action.IsStop()) command |= (int)Command.Stop;
return (byte)command;
}
static byte GetStartParams(Action action)
{
int param = action.FlowMId & (int)StartParam.EtalonMask;
if (action.IsDivUsed)
param |= (int)StartParam.DiverterStart;
if (action.IsSyncMethod)
param |= (int)StartParam.SynchroMethod;
else
param |= (int)StartParam.StartStopMethod;
return (byte)param;
}
static byte GetStopParams(Action action)
{
int param = 0;
return (byte)param;
}
}
public enum Command : byte
{
RequestData = 0,
Start = 1,
Stop = 2,
GetDiverterTransitionData = 4,
GetScopeAnalyzerData = 7,
ResetScopeAnalyzer = 8,
GetSwitchCounterData = 9,
}
public enum StartParam : byte
{
EtalonMask = 0x07,
DiverterStart = 0x08,
SynchroMethod = 0x10,
DirectGateStart = 0x20, /// ???
StartStopMethod = 0x40,
CalibrationMode = 0x80,
}
public enum StopDevs : byte
{
None = 0,
Reference = 0x01, /// bit 0
Diverter = 0x02, /// bit 1
GatePulse = 0x08, /// bit 3
TimeMeasurement = 0x10, /// bit 4
BypassDevCoupled2Div = 0x20, /// bit 5
RegValveRegulation = 0x80, /// bit 7
All = 0xFF,
}
public enum TestMethods
{
Diverter = 0x01, /// bit 0: 1=Mass method (diverters are used), 0=Volume method
FixedStart = 0x02, /// bit 1: 1=fixed start method, 0=flying start method
Synchro = 0x04, /// bit 2: 1=Synchro method, 0=Pulse counting
MassAndContinue = 0x10, /// bit 4: 1=Method with mass measurement followed by a volume method
}
public enum ValveChgFlag : byte
{
DoNotChange = 0,
Change = 1,
SendPressureMeterAddresses = 2,
}
public enum RegValveMode : byte
{
None = 0,
TargetFrequency = 0x10, /// Low and high frequency limits (0..2000Hz,0..2200Hz) are specified
TargetPosition = 0x20, /// Low and high position (=DAC value) limits (0..100%) are specified
Stop = 0x30, /// Stop regulation
PulseWidth = 0x40, /// Pulse width 0.05 .. 2 sec. ... opening and closing (opening=0x40, closing=0xC0)
NegPulseWidth = 0x80, /// Pulse width 0.05 .. 2 sec. ... closing (closing=0xC0)
}
public enum RegValveState : byte
{
Idle = 0,
PwOrFreqRegul = 2,
DacValueRegul = 3,
}
}
@@ -0,0 +1,57 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
namespace TBF.Rig.ControlBoard.Uni
{
public class ScopeAnalyzerData
{
public const int MessageLen = 1033;
public const byte MessageCode = (byte)'S';
/// Scope analyzer data
public int KonSc;
public int ZacSc;
ScopeAnalyzerData()
{
}
/// <summary>
/// Returns tru when receive data fit the message frame
/// </summary>
/// <param name="rcvdData">Received data</param>
/// <param name="cumulativeSums">Cumulative sums of received data bytes</param>
/// <param name="rcvdBytesCount">Received bytes count</param>
/// <param name="offset">Offset of the message</param>
/// <returns>true when frame fits data</returns>
public static bool FrameFitsData(byte[] rcvdData, int[] cumulativeSums, int rcvdBytesCount, int offset)
{
if (offset + MessageLen > rcvdBytesCount) return false;
int checksum = cumulativeSums[offset + MessageLen - 3] - cumulativeSums[offset];
return rcvdData[offset] == Const.STX &&
rcvdData[offset + 1] == 0x01 &&
rcvdData[offset + 2] == ((MessageLen - 5) & 0xFF) &&
rcvdData[offset + 3] == MessageCode &&
rcvdData[offset + MessageLen - 2] == (checksum & 0xFF) &&
rcvdData[offset + MessageLen - 1] == ((checksum >> 8) & 0xFF);
}
/// <summary>
/// Proces received data
/// </summary>
/// <param name="rcvdData">Received data</param>
/// <param name="offset">Offset of the message</param>
public static ScopeAnalyzerData GetData(byte[] rcvdData, int offset)
{
var data = new ScopeAnalyzerData();
data.KonSc = Convert.ToInt32(rcvdData[4]) + 256 * Convert.ToInt32(rcvdData[5]);
data.ZacSc = Convert.ToInt32(rcvdData[6]) + 256 * Convert.ToInt32(rcvdData[7]);
return data;
}
}
}
@@ -0,0 +1,53 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
namespace TBF.Rig.ControlBoard.Uni
{
public class SwitchCountersData
{
public const int MessageLen = 303;
public const byte MessageCode = (byte)'C';
// TODO: Implement member variables
SwitchCountersData()
{
}
/// <summary>
/// Returns tru when receive data fit the message frame
/// </summary>
/// <param name="rcvdData">Received data</param>
/// <param name="cumulativeSums">Cumulative sums of received data bytes</param>
/// <param name="rcvdBytesCount">Received bytes count</param>
/// <param name="offset">Offset of the message</param>
/// <returns>true when frame fits data</returns>
public static bool FrameFitsData(byte[] rcvdData, int[] cumulativeSums, int rcvdBytesCount, int offset)
{
if (offset + MessageLen > rcvdBytesCount) return false;
int checksum = cumulativeSums[offset + MessageLen - 3] - cumulativeSums[offset];
return rcvdData[offset] == Const.STX &&
rcvdData[offset + 1] == 0x01 &&
rcvdData[offset + 2] == ((MessageLen - 5) & 0xFF) &&
rcvdData[offset + 3] == MessageCode &&
rcvdData[offset + MessageLen - 2] == (checksum & 0xFF) &&
rcvdData[offset + MessageLen - 1] == ((checksum >> 8) & 0xFF);
}
/// <summary>
/// Proces received data
/// </summary>
/// <param name="rcvdData">Received data</param>
/// <param name="offset">Offset of the message</param>
public static SwitchCountersData GetData(byte[] rcvdData, int offset)
{
var data = new SwitchCountersData();
// TODO
return data;
}
}
}
+596
View File
@@ -0,0 +1,596 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.Text;
using log4net;
using Common;
using Config.Entities;
using Dirichlet.Numerics;
using TBF.Rig.GenericDevices;
using TBF.Rig.Sequences;
namespace TBF.Rig.ControlBoard.Uni
{
public class UniCB : ComponentBase, IControlBoard, SchematicDrawing.IDrawingItCmpntWithMeasuredVal
{
private static readonly ILog log = LogManager.GetLogger(typeof(UniCB));
public override string ToString() { return string.Format("CBoard({0})", cbCfg != null ? cbCfg.ToString(1) : string.Empty); }
/// TBF component configuration and useful wrappers
readonly UniCBCfg cbCfg;
string comPort { get { return string.Format("COM{0}", cbCfg.ComPortNr); } }
short config { get { return (short)((cbCfg.DrainValvesCount << 8) + ((cbCfg.DivertersCount - 1) << 3) + cbCfg.RegValvesCount - 4); } }
/// IDrawingItCmpnt interface implementation
public SchematicDrawing.IDrawingItem DrawingItem { get { return cbCfg as SchematicDrawing.IDrawingItem; } }
public bool MsrmntAvailable { get { return true; } }
public double MeasuredVal { get { return 0; } }
StringBuilder altString = new StringBuilder();
public string AltString
{
get {
altString.Clear();
altString.AppendFormat("DI: {0}\n", ToBin40(DigitalInputs));
altString.AppendFormat("DO: {0}\n", ToBin40((UInt64)Route));
altString.AppendFormat("AD 0:{0:D4} 1:{1:D4} 2:{2:D4} 3:{3:D4} 4:{4:D4} 5:{5:D4}\n",
AnalogInput(0), AnalogInput(1), AnalogInput(2), AnalogInput(3), AnalogInput(4), AnalogInput(5));
altString.AppendFormat("AD 8:{0:D4} 9:{1:D4} 10:{2:D4} 11:{3:D4}",
AnalogInput(8), AnalogInput(9), AnalogInput(10), AnalogInput(11));
return altString.ToString();
}
}
string ToBin40(UInt64 val)
{
return string.Format("{0}-{1}-{2}-{3}-{4}", ToBin8((val >> 32) & 0xFF), ToBin8((val >> 24) & 0xFF),
ToBin8((val >> 16) & 0xFF), ToBin8((val >> 8) & 0xFF), ToBin8(val & 0xFF));
}
string ToBin8(UInt64 val)
{
string str = Convert.ToString((byte)val, 2);
switch (str.Length)
{
case 1: return "0000000" + str;
case 2: return "000000" + str;
case 3: return "00000" + str;
case 4: return "0000" + str;
case 5: return "000" + str;
case 6: return "00" + str;
case 7: return "0" + str;
default: return str;
}
}
/// Uni CB state
UInt32 currentOutputs;
bool outputsInitialized;
DateTime lastOutputsChange;
int lastStateMachineTime = 0;
/// Propagated from configurations of other components
UInt128 benchModelRoute;
UInt128 valvesToInvert; /// Route = valesToInvert ^ RequiredRouteWithoutInvertedVlaves
readonly UInt128 routeMask; /// This mask masks out virtual valves, routeMask is set in the constructor
/// Serial communication
SerialPort serialPort; /// Seral port or null: Check serialPort.IsOpen before using the serial port
const int BUFFER_SIZE = 4000; /// Size of input buffers
byte[] buffer; /// Buffer for data received in one attempt in RunDeviceBefore()
byte[] rcvdData; /// Buffer for all recevied but nut processed data. May contain data from several read attempts
int[] cumulativeSums;
int rcvdBytesCount; /// Count of valid bytes in rcvdData buffer
/// Message queue
Queue<Action> scheduledActionQueue;
/// Received data
public GeneralData Data;
DivTransitionData divTransitionData;
ScopeAnalyzerData scopeAnalyzerData;
SwitchCountersData switchCounterData;
public UInt64 State { get { return Data.State; } } /// Control board state
public UInt64 DigitalInputs { get { return Data.Vstupy; } } /// Digital inputs
public Int16 AnalogInput(int channel)
{
if (Data.AnalogInput != null && channel >= 0 && channel < Data.AnalogInput.Length)
{
return Data.AnalogInput[channel];
}
return 0;
}
/// <summary>
/// Route: 128-bit word representing the current state of all valves and pumps
/// </summary>
public UInt128 Route { get { return benchModelRoute; } }
/// Values valid during a test
public double RefFrequency { get { return Data.ReferenceFreq[0]; } }
public double RefFlow
{
get { return (Devices != null && Devices.FlowMeter != null) ? Devices.FlowMeter.ReadFlow() : 0.0; }
}
/// Last test results
public double TestTime { set; get; }
public int RefPulses { set; get; }
public float ValveOpenCloseTime { set; get; } /// Start valve open or close time in sec
/// <summary>
/// Select devices used for control and measurement
/// </summary>
/// <param name="outPath"></param>
public OutputPath Devices
{
set { devices = value; }
get { return devices; }
}
OutputPath devices;
IFlowMeter flowMeter { get { return devices.FlowMeter; } }
IRegValve regValve { get { return devices.RegValve; } }
IDiverter diverter { get { return devices.Diverter; } }
/// <summary>
/// Constructor for user interfaces (change settings only).
/// Initialize(), RunDeviceXY() and StopDevice() methods of the created object will not be called.
/// </summary>
public UniCB()
{
devices = new OutputPath(string.Empty, 0);
}
/// <summary>
/// Constructor invoked when starting the test bench and creating components.
/// </summary>
public UniCB(Generic.IComponentCfg cfg)
: base(cfg)
{
#if DEBUG
Debug.WriteLine("");
Debug.WriteLine("Uni CB enums");
Debug.WriteLine("");
foreach (var e in Enum.GetValues(typeof(Poz)))
{
Debug.WriteLine(string.Format("{0} ... {1}", e, ((int)e)));
}
#endif
cbCfg = cfg as UniCBCfg;
devices = new OutputPath(string.Empty, 0);
scheduledActionQueue = new Queue<Action>();
Data = new GeneralData();
divTransitionData = null;
scopeAnalyzerData = null;
switchCounterData = null;
serialPort = null;
buffer = new byte[BUFFER_SIZE];
rcvdData = new byte[BUFFER_SIZE];
cumulativeSums = new int[BUFFER_SIZE];
rcvdBytesCount = 0;
routeMask = 0;
for (int i = 0; i < 128; i++)
{
if (i < cbCfg.VirtValvesRangeLo || i > cbCfg.VirtValvesRangeHi)
{
routeMask = routeMask | ((UInt128)1 << i);
}
}
TBF.UiBridge.Bridge.RouteChangeHandler += delegate(object sndr, TBF.UiBridge.RouteChangeArgs args)
{
UInt128 mask = ((UInt128)1) << args.BitNr;
if ((benchModelRoute & mask) == 0)
{
benchModelRoute |= mask;
}
else
{
benchModelRoute &= (~mask);
}
};
log.Warn(this.ToString());
}
/// <summary>
/// Specify inverted valves
/// </summary>
/// <param name="valvesToInvert"></param>
public void SpecifyInvertedValves(UInt128 valvesToInvert)
{
this.valvesToInvert = valvesToInvert;
this.benchModelRoute = valvesToInvert;
}
#region IDevice interface
/// <summary>
/// Initialize control board device hardware
/// </summary>
public void Initialize()
{
if (cbCfg.DebugLevel != DebugMode.Normal)
{
log.FatalFormat("{0} - Device simulated", Name);
return;
}
serialPort = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One);
serialPort.DtrEnable = true;
serialPort.WriteTimeout = 4000;
serialPort.ParityReplace = 0xFF;
serialPort.Open();
log.FatalFormat("{0} - Device successfully initialized", Name);
}
/// <summary>
/// Reecive and process data from the control board serial port
/// </summary>
public void RunDeviceBefore()
{
if (cbCfg.DebugLevel != DebugMode.Normal || serialPort == null || !serialPort.IsOpen) return;
/// Read new received bytes and append them to a buffer
int bytesCount = serialPort.BytesToRead;
if (bytesCount > 0)
{
bytesCount = serialPort.Read(buffer, 0, Math.Min(bytesCount, BUFFER_SIZE));
}
for (int i = 0; i < bytesCount && rcvdBytesCount < BUFFER_SIZE; i++, rcvdBytesCount++)
{
rcvdData[rcvdBytesCount] = buffer[i];
}
/// Calculate cumulative sums (to verify checksums easily)
int cumulativeSum = 0;
for (int i = 0; i < rcvdBytesCount; i++)
{
cumulativeSum += rcvdData[i];
cumulativeSums[i] = cumulativeSum;
}
/// Try to detect various kinds of data in rcvdData buffer in a loop, start at offset 0
int offset = 0;
int lastValidOffset = 0; /// Offset of the first byte after the last successfully parsed frame
do
{
bool anyProcessed = false;
if (ScopeAnalyzerData.FrameFitsData(rcvdData, cumulativeSums, rcvdBytesCount, offset))
{
/// Scope analyzer data received
scopeAnalyzerData = ScopeAnalyzerData.GetData(rcvdData, offset);
string s = Telegram.LogTelegram("Scope analyzer data ", rcvdData, offset, ScopeAnalyzerData.MessageLen);
Debug.WriteLine(s);
log.Debug(s);
offset += ScopeAnalyzerData.MessageLen;
lastValidOffset = offset;
anyProcessed = true;
}
else if (GeneralData.FrameFitsData(rcvdData, cumulativeSums, rcvdBytesCount, offset))
{
/// Regular data received
Data.UpdateData(rcvdData, offset);
string s = Telegram.LogTelegram("General data ", rcvdData, offset, GeneralData.MessageLen);
Debug.WriteLine(s);
log.Debug(s);
offset += GeneralData.MessageLen;
lastValidOffset = offset;
anyProcessed = true;
}
else if (SwitchCountersData.FrameFitsData(rcvdData, cumulativeSums, rcvdBytesCount, offset))
{
/// Switch counter data received
switchCounterData = SwitchCountersData.GetData(rcvdData, offset);
string s = Telegram.LogTelegram("Switch counter data ", rcvdData, offset, SwitchCountersData.MessageLen);
Debug.WriteLine(s);
log.Debug(s);
offset += SwitchCountersData.MessageLen;
lastValidOffset = offset;
anyProcessed = true;
}
else if (DivTransitionData.FrameFitsData(rcvdData, cumulativeSums, rcvdBytesCount, offset))
{
/// Diverter transition data received
divTransitionData = DivTransitionData.GetData(rcvdData, offset);
string s = Telegram.LogTelegram("Diverter transition data ", rcvdData, offset, DivTransitionData.MessageLen);
Debug.WriteLine(s);
log.Debug(s);
offset += DivTransitionData.MessageLen;
lastValidOffset = offset;
anyProcessed = true;
}
if (!anyProcessed) offset++;
}
while (offset < rcvdBytesCount);
/// Remove processed data from the receive buffer
for (int i = lastValidOffset; i < rcvdBytesCount; i++)
{
rcvdData[i - lastValidOffset] = rcvdData[i];
}
rcvdBytesCount -= lastValidOffset;
}
/// <summary>
/// Send data to the control board serial port
/// </summary>
public void RunDeviceAfter()
{
if (cbCfg.DebugLevel != DebugMode.Normal) return;
/// Make sure the serial port is open
if (serialPort == null || !serialPort.IsOpen)
{
/// Serial port is closed or does not exist => re-open the serial port
try
{
if (serialPort == null)
{
serialPort = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One);
}
serialPort.DtrEnable = true;
serialPort.WriteTimeout = 4000;
serialPort.ParityReplace = 0xFF;
serialPort.Open();
}
catch (Exception)
{
/// Re-opening serial port failed
return;
}
}
if (!outputsInitialized || Data.Vystupy != (ulong)benchModelRoute || (StateMachine.Time - lastStateMachineTime) >= 15)
{
scheduledActionQueue.Enqueue(Action.ChangeRoute((ulong)benchModelRoute));
log.InfoFormat("Enqueue( ChangeRoute(route={0:X}) )", benchModelRoute);
foreach (var a in scheduledActionQueue) log.DebugFormat(" {0}", a);
}
var combinedAction = Action.FetchNonConflictingActions(scheduledActionQueue);
byte[] outData = OutputMessage.GetMessage(combinedAction, config);
if (outData != null && outData.Length > 0)
{
serialPort.Write(outData, 0, outData.Length);
string s = Telegram.LogTelegram("Sent: ", outData);
Debug.WriteLine(s);
log.Debug(s);
}
ProcessData.UpdateMeasuredValuesAndSetpoints();
TBF.UiBridge.Bridge.OnStateMachineTick(this, new TBF.UiBridge.StateMachineTickEventArgs(Route, ProcessData.MsrmntAvailableFlags,
ProcessData.MeasuredValues,
ProcessData.AltStrings,
ProcessData.Setpoints));
}
public void StopDevice()
{
if (serialPort != null) serialPort.Close();
serialPort = null;
}
public void StopDevice2()
{
}
#endregion
#region IControlBoard interface
///
/// Interface functions
///
public void ClearProcessValues() { }
public double TestTimeWM(int wmNr1)
{
if (wmNr1 >= 1 && wmNr1 < Data.ImpulseTime.Length)
{
return Data.ImpulseTime[wmNr1];
}
return 0;
}
public int RefPulsesWM(int wmNr1)
{
if (wmNr1 >= 1 && wmNr1 < Data.EtPulses.Length)
{
return Data.EtPulses[wmNr1];
}
return 0;
}
public int PulsesWM(int wmNr1)
{
if (wmNr1 >= 1 && wmNr1 < Data.WMeterPuls.Length)
{
return Data.WMeterPuls[wmNr1];
}
return 0;
}
public UInt128 SetValves(UInt128 valvesToOpen, UInt128 valvesToClose, IList<BuiltIn.ValveEx.Valve> extendedValves)
{
UInt128 oldRoute = benchModelRoute;
benchModelRoute = (((benchModelRoute ^ valvesToInvert) | valvesToOpen) & (~valvesToClose)) ^ valvesToInvert;
foreach (var extV in extendedValves) extV.UpdateRoute(ref benchModelRoute);
log.DebugFormat("SetValves(x,x), new route = {0}", Utils.RouteToStr(benchModelRoute));
UInt128 retVal = oldRoute ^ benchModelRoute;
log.DebugFormat("{0}.SetValves({1}, {2}) returns {3}", Name, valvesToOpen.ToString("X"), valvesToClose.ToString("X"), retVal.ToString("X"));
return retVal;
}
///
/// Operations
///
public IOperation SetFlowOp(double flowLimLo, double flowLimHi, TBF.Boxes.DoubleBox measuredFlow, int timeout)
{
return Devices.RegValve.SetFlowOp(Devices.FlowMeter,flowLimLo, flowLimHi, measuredFlow, timeout);
}
public IOperation StopFlowRegulationOp()
{
//scheduledActionQueue.Enqueue(Action.Stop());
return null;
}
/// <summary>
/// Start a test, Events: MeasurementStarted
/// </summary>
/// <param name="iParam">Int32 parameter 1</param>
/// <param name="dParam1">Double parameter 1 (alternative lower flow limit)</param>
/// <param name="dParam2">Double parameter 2 (alternative upper flow limit)</param>
/// <returns>Operation</returns>
public IOperation StartTestOp(Test test, int iParam = 0, double dParam1 = 0, double dParam2 = 0)
{
return null;
}
public IOperation ReadDiverterTransitionOp(bool isStart, Sequences.Statistics plotter, int batchNr, string testName, int repetition)
{
return null;
}
/// <summary>
/// Returns operation with events: Event.MeasurementCompleted or Event.None
/// </summary>
/// <returns>Operation</returns>
public IOperation QueryMeasurementEndOp()
{
return null;
}
public IOperation StopPreviousOp()
{
return null;
}
#endregion
#region IValveControl interface
/// <summary>
/// Open/close one valve.
/// Events: ValvesSet, ValvesBusy, Error
/// </summary>
/// <param name="valveToOpen">Valve to be opened</param>
/// <param name="valveToClose">Valve to be closed</param>
/// <returns>Newly created operation instance reference casted to IOperaton</returns>
public IOperation SetValvesOp(IValve valveOpen, IValve valveClose)
{
return new BuiltIn.SetValvesOp(this, valveOpen, valveClose);
}
/// <summary>
/// Open/close multiple valves.
/// Events: ValvesSet, ValvesBusy, Error
/// </summary>
/// <param name="valvesToOpen">A list of valves to be opened</param>
/// <param name="valvesToClose">A list of valves to be closed</param>
/// <returns>Newly created operation instance reference casted to IOperaton</returns>
public IOperation SetValvesOp(IList<IValve> valvesOpen, IList<IValve> valvesClose)
{
return new BuiltIn.SetValvesOp(this, valvesOpen, valvesClose);
}
/// <summary>
/// Open start/stop valve.
/// Events: ValvesSet, ValvesBusy, Error
/// </summary>
/// <returns>Created operation</returns>
public IOperation OpenStartValveOp()
{
return new BuiltIn.SetValvesOp(this, true, devices);
}
/// <summary>
/// Close start/stop valve.
/// Events: ValvesSet, ValvesBusy, Error
/// </summary>
/// <returns>Created operation</returns>
public IOperation CloseStartValveOp()
{
return new BuiltIn.SetValvesOp(this, false, devices);
}
#endregion
public void MeasureFlow(int flowMeterId)
{
scheduledActionQueue.Enqueue(Action.MeasureFlow(flowMeterId));
log.InfoFormat("Enqueue( MeasureFlow(fm={0}) )", flowMeterId);
foreach (var a in scheduledActionQueue) log.DebugFormat(" {0}", a);
}
public void SetFlow(int flowMeterId, int regVId, double freqLo, double freqHi)
{
scheduledActionQueue.Enqueue(Action.SetFlow(flowMeterId, regVId, freqLo, freqHi, Convert.ToInt32(Math.Round(Devices.PidCoef)), 0, 200));
log.InfoFormat("Enqueue( SetFlow(fm={0}, rv={1}, fLo={2}, fHi={3}, pid={4}) )", flowMeterId, regVId, freqLo, freqHi, Convert.ToInt32(Math.Round(Devices.PidCoef)));
foreach (var a in scheduledActionQueue) log.DebugFormat(" {0}", a);
}
/// <summary>
/// Perform incremental movement of a regulation valve
/// </summary>
/// <param name="rvId">Reg. valve ID</param>
/// <param name="time">Time in seconds, positive value opens the reg. valve</param>
public void RegVlvIncrMove(int regVId, double time)
{
scheduledActionQueue.Enqueue(Action.RegVlvIncrMove(regVId, time));
log.InfoFormat("Enqueue( RegVlvIncrMove(rv={0}, time={1}) )", regVId, time);
foreach (var a in scheduledActionQueue) log.DebugFormat(" {0}", a);
}
/// <summary>
/// Move a regulation valve to specfied position
/// </summary>
/// <param name="rvId">Reg. valve ID</param>
/// <param name="position">Reg. valve position (0 .. 1.0)</param>
public void RegVlvMoveToPos(int regVId, double positionLo, double positionHi = -1)
{
scheduledActionQueue.Enqueue(Action.RegVlvMoveToPos(regVId, positionLo, positionHi));
log.InfoFormat("Enqueue( RegVlvMoveToPos(rv={0}, positionLo={1}, positionHi={2}) )", regVId, positionLo, positionHi);
foreach (var a in scheduledActionQueue) log.DebugFormat(" {0}", a);
}
public void DiverterToTank(int divNr1)
{
scheduledActionQueue.Enqueue(Action.SwitchDiverter(divNr1, true));
log.InfoFormat("Enqueue( SwitchDiverter(div={0}, true) )", divNr1);
foreach (var a in scheduledActionQueue) log.DebugFormat(" {0}", a);
}
public void DiverterToSink(int divNr1)
{
scheduledActionQueue.Enqueue(Action.SwitchDiverter(divNr1, false));
log.InfoFormat("Enqueue( SwitchDiverter(div={0}, false) )", divNr1);
foreach (var a in scheduledActionQueue) log.DebugFormat(" {0}", a);
}
public void ReadDiverterTransition(int divNr1)
{
/// TODO
}
}
}
+188
View File
@@ -0,0 +1,188 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using Config.Entities;
using SchematicDrawing;
using TBF.Rig.Generic;
namespace TBF.Rig.ControlBoard.Uni
{
/// <summary>
/// Holds backup and security options - serializable configuration.
/// </summary>
public class UniCBCfg : ComponentCfgBase, Generic.IComponentCfg, Config.Entities.IParamsProvider, IDrawingItemWithMeasuredVal
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(UniCBCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new Configs.ParamsProvider.ComponentCfgCtrl(this, null); }
///
/// Serialized parameters
///
public int ComPortNr;
public int DivertersCount;
public int DrainValvesCount;
public int RegValvesCount;
public int VirtValvesRangeLo;
public int VirtValvesRangeHi;
/// Schematic drawing info
public Shape Shape { get; set; }
public int X { get; set; }
public int Y { get; set; }
public Sz Sz { get; set; }
public Orient Orient { get; set; }
public bool Flip { get; set; }
public int LblX { get; set; }
public int LblY { get; set; }
public Orient LblOrient { get; set; }
public int MsrdX { get; set; }
public int MsrdY { get; set; }
public Orient MsrdOrient { get; set; }
public Config.Unit MsrdUnit { get; set; }
public string MsrdFormat { get; set; }
public double MsrdValLimLo { get; set; }
public double MsrdValLimHi { get; set; }
[XmlIgnore]
public IList<GNode> GNodes { get; set; }
[XmlIgnore]
public IList<GEdge> EdgesToSet { get; set; }
/// Private parameterless constructor invoked by all other (public) constructors
UniCBCfg()
{
GNodes = new List<GNode>();
EdgesToSet = new List<GEdge>();
}
public UniCBCfg(string name, IComponentFactory factory)
: this()
{
Shape = Shape.UniCB;
Sz = Sz.L;
Name = name;
Factory = factory;
ParentName = string.Empty;
InitializeAll();
}
public string ComponentName { get { return Name; } }
public void InitializeAll()
{
ComPortNr = 1;
VirtValvesRangeLo = 90;
VirtValvesRangeHi = 99;
}
string[] paramNames = new string[]
{
"Serial port number",
"Diverters count (1..5)",
"Drain valves count (0..8)",
"Regulation valves count (4..8)",
"Virtual valves range LO [bit#]",
"Virtual valves range HI [bit#]",
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
public ICollection<string> ParamValues(int i)
{
return null;
}
public string ToString(int i)
{
if (i == -1)
{
return string.Format("{0}: COM{1}, VirtValvesRngLO={2}, VirtValvesRngeHI={3}", Name, ComPortNr, VirtValvesRangeLo, VirtValvesRangeHi);
}
switch (i)
{
case 0: return ComPortNr.ToString();
case 1: return DivertersCount.ToString();
case 2: return DrainValvesCount.ToString();
case 3: return RegValvesCount.ToString();
case 4: return VirtValvesRangeLo.ToString();
case 5: return VirtValvesRangeHi.ToString();
default: return string.Empty;
}
}
public CfgUpdateFlags UpdateParam(int i, string strValue)
{
switch (i)
{
case 0: ComPortNr = int.Parse(strValue); return CfgUpdateFlags.RestartRqrd;
case 1: DivertersCount = int.Parse(strValue); return CfgUpdateFlags.RestartRqrd;
case 2: DrainValvesCount = int.Parse(strValue); return CfgUpdateFlags.RestartRqrd;
case 3: RegValvesCount = int.Parse(strValue); return CfgUpdateFlags.RestartRqrd;
case 4: VirtValvesRangeLo = int.Parse(strValue); return CfgUpdateFlags.RestartRqrd;
case 5: VirtValvesRangeHi = int.Parse(strValue); return CfgUpdateFlags.RestartRqrd;
default: return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string strValue, out string message)
{
message = string.Empty;
int n;
switch (i)
{
case 0:
if (int.TryParse(strValue, out n) && (n >= 1)) return true;
break;
case 1:
if (int.TryParse(strValue, out n) && (n >= 1) && n <= 5) return true;
break;
case 2:
if (int.TryParse(strValue, out n) && (n >= 0) && n <= 8) return true;
break;
case 3:
if (int.TryParse(strValue, out n) && (n >= 4) && n <= 8) return true;
break;
case 4:
case 5:
if (int.TryParse(strValue, out n) && (n >= 0) && n <= 127) return true;
break;
default:
message = "Invalid index";
return false;
}
message = ParamName(i) + " is invalid";
return false;
}
void CopyContentTo(UniCBCfg prms)
{
prms.ComPortNr = ComPortNr;
prms.DivertersCount = DivertersCount;
prms.DrainValvesCount = DrainValvesCount;
prms.RegValvesCount = RegValvesCount;
prms.VirtValvesRangeLo = VirtValvesRangeLo;
prms.VirtValvesRangeHi = VirtValvesRangeHi;
}
public Config.Entities.IParamsProvider Clone()
{
var pars = new UniCBCfg();
CopyContentTo(pars);
return pars;
}
public bool UpdateEmbeddedDbEntity()
{
return true; /// =OK, do nothing
}
}
}
+55
View File
@@ -0,0 +1,55 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Diagnostics;
namespace TBF.Rig.ControlBoard.Uni
{
class ValveMoveMsg
{
public int PayloadLen { get { return 38; } }
public byte MessageCode { get { return 0x20; } }
Command cmd;
int regValveNr;
public ValveMoveMsg(Command cmd, int regValveNr)
{
this.cmd = cmd;
this.regValveNr = regValveNr;
}
public byte[] GetMessage()
{
byte[] message = new byte[PayloadLen + 5]; /// headed 3 bytes, checksum 2 bytes
/// Header (3 bytes)
message[0] = Const.STX;
message[1] = 1; /// Control board addres
message[2] = (byte)PayloadLen; /// Payload length
/// Command
message[3] = MessageCode;
message[4] = (byte)cmd;
/// ...
message[40] = 0;
Debug.Assert(40 == PayloadLen + 2);
/// Checksum (2 bytes)
int checksum = 0;
for (int i = 1; i < PayloadLen + 3; i++) checksum += message[i];
message[PayloadLen + 3] = (byte)(checksum & 0xFF);
message[PayloadLen + 4] = (byte)((checksum >> 8) & 0xFF);
return message;
}
public override string ToString()
{
return string.Format("ValveMoveMsg : {0}", cmd);
}
}
}
+419
View File
@@ -0,0 +1,419 @@
///
/// Copyright (c) 2013-2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Text;
using log4net;
using Common;
using Config.Entities;
using Dirichlet.Numerics;
using SchematicDrawing;
using TBF.Rig.ControlBoard;
using TBF.Rig.Generic;
namespace TBF.Rig.Danfoss.VLT2800
{
/// <summary>
/// See page 20 of MG10S202 Operational Instructions Modbus RTU
/// </summary>
public enum CW : ushort
{
PresetRefLsb = (1 << 0),
PresetRefMsb = (1 << 1),
Not_DcBraking = (1 << 2),
Not_CoastingStop = (1 << 3),
Not_QuickStop = (1 << 4),
Not_FreezeFreq = (1 << 5),
Start_NotRampStop = (1 << 6),
Reset = (1 << 7),
Jog = (1 << 8),
Ramp2_NotRamp1 = (1 << 9),
DataValid = (1 << 10),
Relay01Activ = (1 << 11),
DOut46Activ = (1 << 12),
SelectSetupLsb = (1 << 13),
SelectSetupMsb = (1 << 14),
Reversing = (1 << 15),
}
/// <summary>
/// See page 22 of MG10S202 Operational Instructions Modbus RTU
/// </summary>
public enum SW : ushort
{
ControlReady = (1 << 0),
DriveReady = (1 << 1),
CoastingStop = (1 << 2),
Trip = (1 << 3),
TripLock = (1 << 6),
Warning = (1 << 7),
SpeedEqRef = (1 << 8),
RemoteCtrl = (1 << 9),
FreqLimitOK = (1 << 10),
MotorRunning = (1 << 11),
VoltageWarn = (1 << 13),
CurrentLimit = (1 << 14),
ThermalWarn = (1 << 15),
}
public enum Function : byte
{
ReadCoilStatus = 0x01,
ForceSingleCoil = 0x05,
ForceMultipleCoils = 0x0F,
ReadHoldingRegisters = 0x03,
PresetSingleRegister = 0x06,
PresetMultipleRegisters = 0x10,
}
public class Pump : ComponentBase, IDevice, IOperation, GenericDevices.IPumpFM, GenericDevices.IValve, IDrawingItCmpntWithSetpoint
{
private static readonly ILog log = LogManager.GetLogger(typeof(Pump));
public override string ToString() { return string.Format("Pump-Danfoss-VLT2800({0})", Cfg.ToString(1)); }
private readonly PumpCfg pumpCfg;
public IDrawingItem DrawingItem { get { return pumpCfg as IDrawingItem; } }
public int Delay { get { return pumpCfg.Delay; } }
public ValveCategory Category { get { return ValveCategory.Feeding; } } /// Pump category is Feeding
public GenericDevices.IValve CoupledTo { get { return null; } }
public bool InvertCouple { get { return false; } }
public int LagOpening { get { return 0; } }
public int LagClosing { get { return 0; } }
/// <summary>
/// Pump power in [%] in range 0 .. 100.0f
/// </summary>
private double power;
public double Power
{
get { return power; }
}
///
public double SetpointVal
{
get { return power; }
set
{
power = value;
if (power != 0) TurnOn(power);
}
}
///
public void IncreaseSetpoint()
{
power += 0.05;
if (power > 100.0) power = 100.0;
TurnOn(power);
}
///
public void DecreaseSetpoint()
{
power -= 0.05;
if (power <= 0)
{
power = 0;
TurnOff();
}
else
{
TurnOn(power);
}
}
readonly IControlBoard controlBoard;
readonly int bitNr; /// 0 .. 63
public readonly UInt128 Mask; /// derived from bitPosition in the constructor
public bool State
{
get { return (controlBoard.Route & Mask) != 0; }
}
/// Private fields
SerialPort serialPort;
bool dataToSendReady;
byte[] dataToSend;
StringBuilder responseBuilder;
public Pump()
{
}
/// <summary>
/// Ambient temperature / humidity / pressure meter 'Greco' connected via serial interface (RS232)
/// Connection settings: 19200 Bd 8-bits No-parity 1-stop-bit Flow control: none or hardware.
/// </summary>
public Pump(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
: base(cfg)
{
pumpCfg = cfg as PumpCfg;
controlBoard = TbfComponents.FindComponent("CB", components) as IControlBoard; /// TODO: replace "CB"
if (controlBoard == null) throw new Exception("Cannot find " + Name + " parent");
bitNr = pumpCfg.BitNr;
Mask = (((UInt128)1) << bitNr);
#if MUNICH
Mask |= (((UInt128)1) << (bitNr + 1));
#endif
TBF.UiBridge.Bridge.SetpointChangeHandler += delegate(object sndr, TBF.UiBridge.SetpointChangeArgs args)
{
if (args.Name == Name)
{
if (args.Increase)
{
IncreaseSetpoint();
}
else
{
DecreaseSetpoint();
}
}
};
log.Warn(this.ToString());
}
public void Initialize()
{
if (pumpCfg.DebugLevel == DebugMode.Simulate)
{
return;
}
string comPortName = "COM" + pumpCfg.ComPortNr.ToString();
serialPort = new SerialPort(comPortName, pumpCfg.BaudRate, pumpCfg.Parity, pumpCfg.DataBits, pumpCfg.StopBits);
serialPort.Handshake = Handshake.None;
serialPort.Open();
responseBuilder = new StringBuilder(40);
log.FatalFormat("Successfully initialized device {0}", ToString());
}
/// <summary>Run this device</summary>
public void RunDeviceBefore()
{
if (pumpCfg.DebugLevel == DebugMode.Simulate) return;
responseBuilder.Append(serialPort.ReadExisting());
/// Check if the response is complete
if (responseBuilder.Length >= 8)
{
string response = responseBuilder.ToString();
responseBuilder.Clear();
log.Info(Telegram.LogTelegram("Received ", response));
}
}
/// <summary>
/// Prepares data to be sent in RunDeviceAfter() function
/// </summary>
bool SendData(byte[] data)
{
if (dataToSendReady) return false;
dataToSend = data;
dataToSendReady = true;
log.Info(Telegram.LogTelegram("Sending ", data));
return true;
}
/// <summary>Run this device</summary>
public void RunDeviceAfter()
{
if (dataToSendReady)
{
if (pumpCfg.DebugLevel != DebugMode.Simulate)
{
serialPort.Write(dataToSend, 0, dataToSend.Length);
}
dataToSendReady = false;
}
}
/// <summary>Stop this device</summary>
public void StopDevice()
{
if (serialPort != null) serialPort.Close();
}
public void StopDevice2() { }
/// <summary>
/// Turn the pmp on using Modbus commad, use the variable frequency
/// </summary>
/// <param name="powerArg">Frequency in percent (-200.0 .. 200.0)</param>
public void TurnOn(double powerArg)
{
log.DebugFormat("{0}.TurnOn({1})", Name, powerArg);
this.power = powerArg;
//UInt16 controlWord = 0x047C;
UInt16 controlWord = (UInt16)(CW.Not_DcBraking |
CW.Not_CoastingStop |
CW.Not_QuickStop |
CW.Not_FreezeFreq |
CW.Start_NotRampStop |
CW.DataValid);
UInt16 serialComReference = (UInt16)(Int16)((float)0x4000 * powerArg / 100.0f + 0.5f);
byte[] msg;
if (pumpCfg.Protocol == PumpProtocol.Modbus)
{
msg = new byte[13];
msg[0] = (byte)pumpCfg.BusAddress;
msg[1] = (byte)Function.ForceMultipleCoils;
msg[2] = 0; /// Data Hi
msg[3] = 0; /// Data Lo
msg[4] = 0; /// Nr. of coils Hi
msg[5] = 0x20; /// Nr. of coils Lo
msg[6] = 4; /// Byte count
msg[7] = (byte)(controlWord & 0xFF); /// Control Word Lo
msg[8] = (byte)(controlWord >> 8); /// Control Word Hi
msg[9] = (byte)(serialComReference & 0xFF); /// Serial Com Reference Lo
msg[10] = (byte)(serialComReference >> 8); /// Serial Com Reference Hi
Telegram.UpdateTelegramCRC(msg);
}
else /// if (pumpCfg.Protocol == PumpProtocol.FC)
{
msg = new byte[8];
msg[0] = 0x02; /// STX
msg[1] = 6; /// lenght (6 bytes following this one)
msg[2] = (byte)pumpCfg.BusAddress;
msg[3] = (byte)(controlWord >> 8); /// Control Word Hi
msg[4] = (byte)(controlWord & 0xFF); /// Control Word Lo
msg[5] = (byte)(serialComReference >> 8); /// Serial Com Reference Hi
msg[6] = (byte)(serialComReference & 0xFF); /// Serial Com Reference Lo
Telegram.UpdateTelegramChecksum(msg);
}
SendData(msg);
}
/// <summary>
/// Turn the pmp off using Modbus command
/// </summary>
public void TurnOff()
{
log.DebugFormat("{0}.TurnOff()", Name);
this.power = 0;
UInt16 controlWord = (UInt16)(CW.Not_DcBraking |
CW.Not_CoastingStop |
CW.Not_QuickStop |
CW.Not_FreezeFreq |
//CW.Start_NotRampStop |
CW.DataValid);
UInt16 serialComReference = 0;
byte[] msg;
if (pumpCfg.Protocol == PumpProtocol.Modbus)
{
msg = new byte[13];
msg[0] = (byte)pumpCfg.BusAddress;
msg[1] = (byte)Function.ForceMultipleCoils;
msg[2] = 0; /// Data Hi
msg[3] = 0; /// Data Lo
msg[4] = 0; /// Nr. of coils Hi
msg[5] = 0x20; /// Nr. of coils Lo
msg[6] = 4; /// Byte count
msg[7] = (byte)(controlWord & 0xFF); /// Control Word Lo
msg[8] = (byte)(controlWord >> 8); /// Control Word Hi
msg[9] = (byte)(serialComReference & 0xFF); /// Serial Com Reference Lo
msg[10] = (byte)(serialComReference >> 8); /// Serial Com Reference Hi
Telegram.UpdateTelegramCRC(msg);
}
else /// if (pumpCfg.Protocol == PumpProtocol.FC)
{
msg = new byte[8];
msg[0] = 0x02; /// STX
msg[1] = 6; /// lenght (6 bytes following this one)
msg[2] = (byte)pumpCfg.BusAddress;
msg[3] = (byte)(controlWord >> 8); /// Control Word Hi
msg[4] = (byte)(controlWord & 0xFF); /// Control Word Lo
msg[5] = (byte)(serialComReference >> 8); /// Serial Com Reference Hi
msg[6] = (byte)(serialComReference & 0xFF); /// Serial Com Reference Lo
Telegram.UpdateTelegramChecksum(msg);
}
SendData(msg);
}
/// <summary>
/// The currently running operation.
/// </summary>
public enum CurrentOp
{
None,
TurnOn,
TurnOff,
}
///
CurrentOp currentOp;
double powerForOp;
/// <summary>
/// Turn the pump frequency inverter on.
/// </summary>
public IOperation TurnOnOp(double powerArg)
{
if (currentOp != CurrentOp.None) throw new Exception("Sequence error");
currentOp = CurrentOp.TurnOn;
powerForOp = powerArg;
return this;
}
/// <summary>
/// Turn the pump frequency inverter on.
/// </summary>
public IOperation TurnOffOp()
{
if (currentOp != CurrentOp.None) throw new Exception("Sequence error");
currentOp = CurrentOp.TurnOff;
return this;
}
/// <summary>Start the operation</summary>
public void Start()
{
switch (currentOp)
{
case CurrentOp.TurnOn:
TurnOn(powerForOp);
return;
case CurrentOp.TurnOff:
default:
TurnOff();
return;
}
}
/// <summary>Run the operation</summary>
public Event Run()
{
return Event.TurnPumpOnOffDone;
}
/// <summary>Stop the operation</summary>
public void Stop()
{
currentOp = CurrentOp.None;
}
}
}
+92
View File
@@ -0,0 +1,92 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
using System.Collections.Generic;
using System.IO.Ports;
using System.Xml.Serialization;
using SchematicDrawing;
using TBF.Rig.Generic;
namespace TBF.Rig.Danfoss.VLT2800
{
public class PumpCfg : ComponentCfgBase, Generic.IComponentCfg, IRouteBasedDrawingItem, IDrawingItemWithSetpoint
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(PumpCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new PumpCfgCtrl(); }
///
/// Serialized parameters
///
public int BitNr { get; set; }
public bool Inverted { get; set; } /// When true the pump function is inverted: 0 = on, 1 = off
public int Delay; /// Delay of the pump function in [s] (affects the duration of transition sequence steps)
public PumpProtocol Protocol; /// Modbus or FC with Siemens address
public int BusAddress; /// Modbus or FC address in range 1..247 (Modbus) or 1..31 (FC with Siemens address)
public int ComPortNr;
public int BaudRate;
public Parity Parity;
public int DataBits;
public StopBits StopBits;
/// Schematic drawing info
public Shape Shape { get; set; }
public int X { get; set; }
public int Y { get; set; }
public Sz Sz { get; set; }
public Orient Orient { get; set; }
public bool Flip { get; set; }
public int LblX { get; set; }
public int LblY { get; set; }
public Orient LblOrient { get; set; }
public int SetpX { get; set; }
public int SetpY { get; set; }
public Orient SetpOrient { get; set; }
public string SetpFormat { get; set; }
public Config.Unit SetpUnit { get; set; }
[XmlIgnore]
public IList<GNode> GNodes { get; set; }
[XmlIgnore]
public IList<GEdge> EdgesToSet { get; set; }
/// Private parameterless constructor invoked by all other (public) constructors
PumpCfg()
{
GNodes = new List<GNode>();
EdgesToSet = new List<GEdge>();
}
public PumpCfg(IComponentFactory factory)
: this()
{
Shape = Shape.PumpFM;
Sz = Sz.M;
SetpFormat = "{0:F0} %";
SetpUnit = Config.Unit.Pct;
Name = "Pump-Danfoss";
Factory = factory;
ParentName = string.Empty;
Delay = 1;
ComPortNr = 3;
/// Default protocol settings (the same as Danfoss VLT2800 factory settings)
Protocol = PumpProtocol.FC;
BusAddress = 1;
BaudRate = 9600;
DataBits = 8;
Parity = System.IO.Ports.Parity.Even; /// 'Parity.None' is the default value for Protocol = PumpProtocol.Modbus
StopBits = System.IO.Ports.StopBits.One;
}
public string ToString(int i)
{
return string.Format("Name={0}, Delay={1}s, Protocol={2}, BusAddress={3}, Com{4}, {5}Bd, {6}-bits, parity={7}, stopBits={8}",
Name, Delay, Protocol, BusAddress, ComPortNr, BaudRate, DataBits, Parity, StopBits);
}
}
}
+230
View File
@@ -0,0 +1,230 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
using System;
using System.Windows.Forms;
using System.IO.Ports;
using Config.Entities;
using TBF.Rig.Generic;
namespace TBF.Rig.Danfoss.VLT2800
{
public partial class PumpCfgCtrl : UserControl, IComponentCfgCtrl
{
public bool ShowMore { get { return false; } }
PumpCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as PumpCfg;
Redraw();
}
}
public PumpCfgCtrl()
{
InitializeComponent();
protocolComboBox.Items.Add(PumpProtocol.Modbus.ToString());
protocolComboBox.Items.Add(PumpProtocol.FC.ToString());
parityComboBox.Items.Add(Parity.None.ToString());
parityComboBox.Items.Add(Parity.Even.ToString());
parityComboBox.Items.Add(Parity.Odd.ToString());
stopBitsComboBox.Items.Add(StopBits.None.ToString());
stopBitsComboBox.Items.Add(StopBits.One.ToString());
stopBitsComboBox.Items.Add(StopBits.OnePointFive.ToString());
stopBitsComboBox.Items.Add(StopBits.Two.ToString());
}
int GetParityIx(Parity par)
{
if (par == Parity.None) return 0;
if (par == Parity.Even) return 0;
if (par == Parity.Odd) return 0;
return -1;
}
Parity GetParity(string str)
{
if (str.Equals(Parity.None.ToString())) return Parity.None;
if (str.Equals(Parity.Even.ToString())) return Parity.Even;
if (str.Equals(Parity.Odd.ToString())) return Parity.Odd;
return (Parity)(-1);
}
int GetStopBitsIx(StopBits sb)
{
if (sb == StopBits.None) return 0;
if (sb == StopBits.One) return 1;
if (sb == StopBits.OnePointFive) return 2;
if (sb == StopBits.Two) return 3;
return -1;
}
StopBits GetStopBits(string str)
{
if (str.Equals(StopBits.None.ToString())) return StopBits.None;
if (str.Equals(StopBits.One.ToString())) return StopBits.One;
if (str.Equals(StopBits.OnePointFive.ToString())) return StopBits.OnePointFive;
if (str.Equals(StopBits.Two.ToString())) return StopBits.Two;
return (StopBits)(-1);
}
int GetHandshakeIx(Handshake par)
{
if (par == Handshake.None) return 0;
if (par == Handshake.RequestToSend) return 0;
if (par == Handshake.XOnXOff) return 0;
return -1;
}
Handshake GetHandshake(string str)
{
if (str.Equals(Handshake.None.ToString())) return Handshake.None;
if (str.Equals(Handshake.RequestToSend.ToString())) return Handshake.RequestToSend;
if (str.Equals(Handshake.XOnXOff.ToString())) return Handshake.XOnXOff;
return (Handshake)(-1);
}
private void AbbientCfgCtrl_Load(object sender, EventArgs e)
{
for (Config.Unit units = 0; units < global::Config.Unit.Count; units++)
{
if (global::Config.Units.IsQuantity(units, global::Config.Quantity.Error))
{
unitsComboBox.Items.Add(units.ToString());
}
}
Redraw();
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
delayTextBox.Text = config.Delay.ToString();
bitPositionTextBox.Text = config.BitNr.ToString();
protocolComboBox.Text = config.Protocol.ToString();
busAddressTextBox.Text = config.BusAddress.ToString();
comPortNrTextBox.Text = config.ComPortNr.ToString();
baudRateTextBox.Text = config.BaudRate.ToString();
parityComboBox.Text = config.Parity.ToString();
dataBitsTextBox.Text = config.DataBits.ToString();
stopBitsComboBox.Text = config.StopBits.ToString();
formatTextBox.Text = config.SetpFormat;
unitsComboBox.Text = config.SetpUnit.ToString();
}
public void Unlock()
{
nameTextBox.Enabled = true;
delayTextBox.Enabled = true;
bitPositionTextBox.Enabled = true;
protocolComboBox.Enabled = true;
busAddressTextBox.Enabled = true;
comPortNrTextBox.Enabled = true;
baudRateTextBox.Enabled = true;
parityComboBox.Enabled = true;
dataBitsTextBox.Enabled = true;
stopBitsComboBox.Enabled = true;
formatTextBox.Enabled = true;
unitsComboBox.Enabled = true;
}
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
config.Name = nameTextBox.Text;
config.Delay = int.Parse(delayTextBox.Text);
config.BitNr = int.Parse(bitPositionTextBox.Text);
config.Protocol = protocolComboBox.Text.Equals(PumpProtocol.Modbus.ToString()) ? PumpProtocol.Modbus : PumpProtocol.FC;
config.BusAddress = int.Parse(busAddressTextBox.Text);
config.ComPortNr = int.Parse(comPortNrTextBox.Text);
config.BaudRate = int.Parse(baudRateTextBox.Text);
config.Parity = GetParity(parityComboBox.SelectedItem.ToString());
config.DataBits = int.Parse(dataBitsTextBox.Text);
config.StopBits = GetStopBits(stopBitsComboBox.SelectedItem.ToString());
config.SetpFormat = formatTextBox.Text;
config.SetpUnit = global::Config.Unit.None;
for (Config.Unit units = 0; units < global::Config.Unit.Count; units++)
{
if (unitsComboBox.Text == units.ToString())
{
config.SetpUnit = units;
break;
}
}
return flags;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
int dummy;
if (!int.TryParse(delayTextBox.Text, out dummy) || dummy < 0 || dummy > 300)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Delay' is not valid";
}
if (!int.TryParse(bitPositionTextBox.Text, out dummy) || dummy < 0 || dummy >= 128)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Bit Position' should be between 0 and 127";
}
if (!protocolComboBox.Items.Contains(protocolComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Protocol' should Modbus or FC";
}
if (!int.TryParse(busAddressTextBox.Text, out dummy) || dummy < 1 || dummy > 247)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Bus Address' should be in range 1..247";
}
if (!int.TryParse(comPortNrTextBox.Text, out dummy) || dummy < 1 || dummy > 999)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Serial Port Number' is not valid";
}
if (!int.TryParse(baudRateTextBox.Text, out dummy) || dummy < 150 || dummy > 115200)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Baud Rate' is not valid";
}
if (!int.TryParse(dataBitsTextBox.Text, out dummy) || dummy < 7 || dummy > 8)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Data Bits' is not valid";
}
if (!unitsComboBox.Items.Contains(unitsComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Units'";
}
return flags;
}
}
}
+345
View File
@@ -0,0 +1,345 @@
///
/// Copyright (c) 2013-2015 Sensus Metering Systems
///
namespace TBF.Rig.Danfoss.VLT2800
{
partial class PumpCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.comPortNrTextBox = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.baudRateLabel = new System.Windows.Forms.Label();
this.baudRateTextBox = new System.Windows.Forms.TextBox();
this.partityLabel = new System.Windows.Forms.Label();
this.dataBitsLabel = new System.Windows.Forms.Label();
this.dataBitsTextBox = new System.Windows.Forms.TextBox();
this.stopBitsLabel = new System.Windows.Forms.Label();
this.busAddressLabel = new System.Windows.Forms.Label();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
this.classNameLabel = new System.Windows.Forms.Label();
this.parityComboBox = new System.Windows.Forms.ComboBox();
this.stopBitsComboBox = new System.Windows.Forms.ComboBox();
this.busAddressTextBox = new System.Windows.Forms.TextBox();
this.delayTextBox = new System.Windows.Forms.TextBox();
this.delayLabel = new System.Windows.Forms.Label();
this.protocolLabel = new System.Windows.Forms.Label();
this.protocolComboBox = new System.Windows.Forms.ComboBox();
this.bitPositionTextBox = new System.Windows.Forms.TextBox();
this.bitPositionLabel = new System.Windows.Forms.Label();
this.unitsComboBox = new System.Windows.Forms.ComboBox();
this.unitsLabel = new System.Windows.Forms.Label();
this.formatTextBox = new System.Windows.Forms.TextBox();
this.formatLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// comPortNrTextBox
//
this.comPortNrTextBox.Enabled = false;
this.comPortNrTextBox.Location = new System.Drawing.Point(140, 129);
this.comPortNrTextBox.Name = "comPortNrTextBox";
this.comPortNrTextBox.Size = new System.Drawing.Size(34, 20);
this.comPortNrTextBox.TabIndex = 6;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(29, 132);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(98, 13);
this.label1.TabIndex = 5;
this.label1.Text = "Serial Port Number:";
//
// baudRateLabel
//
this.baudRateLabel.AutoSize = true;
this.baudRateLabel.Location = new System.Drawing.Point(29, 153);
this.baudRateLabel.Name = "baudRateLabel";
this.baudRateLabel.Size = new System.Drawing.Size(58, 13);
this.baudRateLabel.TabIndex = 7;
this.baudRateLabel.Text = "Baud Rate";
//
// baudRateTextBox
//
this.baudRateTextBox.Enabled = false;
this.baudRateTextBox.Location = new System.Drawing.Point(140, 150);
this.baudRateTextBox.Name = "baudRateTextBox";
this.baudRateTextBox.Size = new System.Drawing.Size(130, 20);
this.baudRateTextBox.TabIndex = 8;
//
// partityLabel
//
this.partityLabel.AutoSize = true;
this.partityLabel.Location = new System.Drawing.Point(29, 174);
this.partityLabel.Name = "partityLabel";
this.partityLabel.Size = new System.Drawing.Size(33, 13);
this.partityLabel.TabIndex = 9;
this.partityLabel.Text = "Parity";
//
// dataBitsLabel
//
this.dataBitsLabel.AutoSize = true;
this.dataBitsLabel.Location = new System.Drawing.Point(29, 196);
this.dataBitsLabel.Name = "dataBitsLabel";
this.dataBitsLabel.Size = new System.Drawing.Size(50, 13);
this.dataBitsLabel.TabIndex = 11;
this.dataBitsLabel.Text = "Data Bits";
//
// dataBitsTextBox
//
this.dataBitsTextBox.Enabled = false;
this.dataBitsTextBox.Location = new System.Drawing.Point(140, 193);
this.dataBitsTextBox.Name = "dataBitsTextBox";
this.dataBitsTextBox.Size = new System.Drawing.Size(34, 20);
this.dataBitsTextBox.TabIndex = 12;
//
// stopBitsLabel
//
this.stopBitsLabel.AutoSize = true;
this.stopBitsLabel.Location = new System.Drawing.Point(29, 217);
this.stopBitsLabel.Name = "stopBitsLabel";
this.stopBitsLabel.Size = new System.Drawing.Size(49, 13);
this.stopBitsLabel.TabIndex = 13;
this.stopBitsLabel.Text = "Stop Bits";
//
// busAddressLabel
//
this.busAddressLabel.AutoSize = true;
this.busAddressLabel.Location = new System.Drawing.Point(29, 110);
this.busAddressLabel.Name = "busAddressLabel";
this.busAddressLabel.Size = new System.Drawing.Size(66, 13);
this.busAddressLabel.TabIndex = 3;
this.busAddressLabel.Text = "Bus Address";
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(140, 23);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(130, 20);
this.nameTextBox.TabIndex = 2;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(30, 26);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 1;
this.nameLabel.Text = "Name";
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(137, 5);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
this.classNameLabel.TabIndex = 0;
this.classNameLabel.Text = "ComonentName";
//
// parityComboBox
//
this.parityComboBox.Enabled = false;
this.parityComboBox.FormattingEnabled = true;
this.parityComboBox.Location = new System.Drawing.Point(140, 171);
this.parityComboBox.Name = "parityComboBox";
this.parityComboBox.Size = new System.Drawing.Size(130, 21);
this.parityComboBox.TabIndex = 10;
//
// stopBitsComboBox
//
this.stopBitsComboBox.Enabled = false;
this.stopBitsComboBox.FormattingEnabled = true;
this.stopBitsComboBox.Location = new System.Drawing.Point(140, 214);
this.stopBitsComboBox.Name = "stopBitsComboBox";
this.stopBitsComboBox.Size = new System.Drawing.Size(130, 21);
this.stopBitsComboBox.TabIndex = 14;
//
// busAddressTextBox
//
this.busAddressTextBox.Enabled = false;
this.busAddressTextBox.Location = new System.Drawing.Point(140, 108);
this.busAddressTextBox.Name = "busAddressTextBox";
this.busAddressTextBox.Size = new System.Drawing.Size(34, 20);
this.busAddressTextBox.TabIndex = 4;
//
// delayTextBox
//
this.delayTextBox.Enabled = false;
this.delayTextBox.Location = new System.Drawing.Point(140, 44);
this.delayTextBox.Name = "delayTextBox";
this.delayTextBox.Size = new System.Drawing.Size(34, 20);
this.delayTextBox.TabIndex = 16;
//
// delayLabel
//
this.delayLabel.AutoSize = true;
this.delayLabel.Location = new System.Drawing.Point(29, 46);
this.delayLabel.Name = "delayLabel";
this.delayLabel.Size = new System.Drawing.Size(45, 13);
this.delayLabel.TabIndex = 15;
this.delayLabel.Text = "Delay[s]";
//
// protocolLabel
//
this.protocolLabel.AutoSize = true;
this.protocolLabel.Location = new System.Drawing.Point(29, 89);
this.protocolLabel.Name = "protocolLabel";
this.protocolLabel.Size = new System.Drawing.Size(46, 13);
this.protocolLabel.TabIndex = 17;
this.protocolLabel.Text = "Protocol";
//
// protocolComboBox
//
this.protocolComboBox.Enabled = false;
this.protocolComboBox.FormattingEnabled = true;
this.protocolComboBox.Location = new System.Drawing.Point(140, 86);
this.protocolComboBox.Name = "protocolComboBox";
this.protocolComboBox.Size = new System.Drawing.Size(130, 21);
this.protocolComboBox.TabIndex = 18;
//
// bitPositionTextBox
//
this.bitPositionTextBox.Enabled = false;
this.bitPositionTextBox.Location = new System.Drawing.Point(140, 65);
this.bitPositionTextBox.Name = "bitPositionTextBox";
this.bitPositionTextBox.Size = new System.Drawing.Size(34, 20);
this.bitPositionTextBox.TabIndex = 20;
//
// bitPositionLabel
//
this.bitPositionLabel.AutoSize = true;
this.bitPositionLabel.Location = new System.Drawing.Point(30, 68);
this.bitPositionLabel.Name = "bitPositionLabel";
this.bitPositionLabel.Size = new System.Drawing.Size(89, 13);
this.bitPositionLabel.TabIndex = 19;
this.bitPositionLabel.Text = "Valve Bit Position";
//
// unitsComboBox
//
this.unitsComboBox.Enabled = false;
this.unitsComboBox.FormattingEnabled = true;
this.unitsComboBox.Location = new System.Drawing.Point(140, 257);
this.unitsComboBox.Name = "unitsComboBox";
this.unitsComboBox.Size = new System.Drawing.Size(80, 21);
this.unitsComboBox.TabIndex = 32;
//
// unitsLabel
//
this.unitsLabel.AutoSize = true;
this.unitsLabel.Location = new System.Drawing.Point(29, 260);
this.unitsLabel.Name = "unitsLabel";
this.unitsLabel.Size = new System.Drawing.Size(71, 13);
this.unitsLabel.TabIndex = 31;
this.unitsLabel.Text = "Setpoint units";
//
// formatTextBox
//
this.formatTextBox.Enabled = false;
this.formatTextBox.Location = new System.Drawing.Point(140, 236);
this.formatTextBox.Name = "formatTextBox";
this.formatTextBox.Size = new System.Drawing.Size(130, 20);
this.formatTextBox.TabIndex = 30;
//
// formatLabel
//
this.formatLabel.AutoSize = true;
this.formatLabel.Location = new System.Drawing.Point(29, 239);
this.formatLabel.Name = "formatLabel";
this.formatLabel.Size = new System.Drawing.Size(78, 13);
this.formatLabel.TabIndex = 29;
this.formatLabel.Text = "Setpoint format";
//
// PumpCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.Control;
this.Controls.Add(this.unitsComboBox);
this.Controls.Add(this.unitsLabel);
this.Controls.Add(this.formatTextBox);
this.Controls.Add(this.formatLabel);
this.Controls.Add(this.bitPositionTextBox);
this.Controls.Add(this.bitPositionLabel);
this.Controls.Add(this.protocolComboBox);
this.Controls.Add(this.protocolLabel);
this.Controls.Add(this.delayTextBox);
this.Controls.Add(this.delayLabel);
this.Controls.Add(this.busAddressTextBox);
this.Controls.Add(this.stopBitsComboBox);
this.Controls.Add(this.parityComboBox);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Controls.Add(this.busAddressLabel);
this.Controls.Add(this.stopBitsLabel);
this.Controls.Add(this.dataBitsTextBox);
this.Controls.Add(this.dataBitsLabel);
this.Controls.Add(this.partityLabel);
this.Controls.Add(this.baudRateTextBox);
this.Controls.Add(this.baudRateLabel);
this.Controls.Add(this.comPortNrTextBox);
this.Controls.Add(this.label1);
this.Name = "PumpCfgCtrl";
this.Size = new System.Drawing.Size(400, 300);
this.Load += new System.EventHandler(this.AbbientCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox comPortNrTextBox;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label baudRateLabel;
private System.Windows.Forms.TextBox baudRateTextBox;
private System.Windows.Forms.Label partityLabel;
private System.Windows.Forms.Label dataBitsLabel;
private System.Windows.Forms.TextBox dataBitsTextBox;
private System.Windows.Forms.Label stopBitsLabel;
private System.Windows.Forms.Label busAddressLabel;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label classNameLabel;
private System.Windows.Forms.ComboBox parityComboBox;
private System.Windows.Forms.ComboBox stopBitsComboBox;
private System.Windows.Forms.TextBox busAddressTextBox;
private System.Windows.Forms.TextBox delayTextBox;
private System.Windows.Forms.Label delayLabel;
private System.Windows.Forms.Label protocolLabel;
private System.Windows.Forms.ComboBox protocolComboBox;
private System.Windows.Forms.TextBox bitPositionTextBox;
private System.Windows.Forms.Label bitPositionLabel;
private System.Windows.Forms.ComboBox unitsComboBox;
private System.Windows.Forms.Label unitsLabel;
private System.Windows.Forms.TextBox formatTextBox;
private System.Windows.Forms.Label formatLabel;
}
}
+120
View File
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+27
View File
@@ -0,0 +1,27 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.Danfoss.VLT2800
{
public class PumpFactory : IComponentFactory
{
public string ClassName { get { return "Pump-Danfoss-VLT2800"; } }
public override string ToString() { return ClassName; }
public void ResetStaticProperties() { Pump.ResetStaticProperties(); }
public IComponent DummyComponent() { return new Pump(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Pump(cfg, components); }
public IComponentCfg DefaultConfig() { return new PumpCfg(this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(PumpCfg.Serializer, component, this);
}
}
}
@@ -0,0 +1,37 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
///
using System;
using log4net;
namespace TBF.Rig.DataContainer.BackupAndSecurityOptions
{
/// <summary>
/// Holds backup and security options.
/// </summary>
public class Component : ComponentBase
{
private static readonly ILog log = LogManager.GetLogger(typeof(Component));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(1)); }
readonly ComponentCfg myCfg;
public int MinPasswdLength { get { return myCfg.MinPasswdLength; } }
public int PasswdExpirationPeriodDays { get { return myCfg.PasswdExpirationPeriodDays; } }
public Component()
{
}
public Component(Generic.IComponentCfg cfg)
: base(cfg)
{
myCfg = cfg as ComponentCfg;
Users.GlobalData.MinPasswdLength = myCfg.MinPasswdLength;
Users.GlobalData.PasswdExpirationPeriodDays = myCfg.PasswdExpirationPeriodDays;
log.Warn(this.ToString());
}
}
}
@@ -0,0 +1,121 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using Config.Entities;
using TBF.Rig.Generic;
namespace TBF.Rig.DataContainer.BackupAndSecurityOptions
{
/// <summary>
/// Holds backup and security options - serializable configuration.
/// </summary>
public class ComponentCfg : ComponentCfgBase, Generic.IComponentCfg, Config.Entities.IParamsProvider
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(ComponentCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new Configs.ParamsProvider.ComponentCfgCtrl(this, null); }
///
/// Serialized parameters
///
public int MinPasswdLength;
public int PasswdExpirationPeriodDays; /// 0 = validity is not limited
/// Private parameterless constructor invoked by all other (public) constructors
ComponentCfg() {}
public ComponentCfg(string name, IComponentFactory factory)
: this()
{
Factory = factory;
Name = name;
ParentName = string.Empty;
InitializeAll();
}
public string ComponentName { get { return Name; } }
public void InitializeAll()
{
MinPasswdLength = 6;
PasswdExpirationPeriodDays = 0;
}
string[] paramNames = new string[]
{
"Minimum password length (characters)",
"Password expiration period (days)",
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
public ICollection<string> ParamValues(int i) { return null; }
public string ToString(int i)
{
if (i == -1)
{
return string.Format("{0}: Min. password length = {1} characters, Password expiration period = {2} days", Name, MinPasswdLength, PasswdExpirationPeriodDays);
}
switch (i)
{
case 0: return MinPasswdLength.ToString();
case 1: return PasswdExpirationPeriodDays.ToString();;
default: return string.Empty;
}
}
public CfgUpdateFlags UpdateParam(int i, string strValue)
{
switch (i)
{
case 0: MinPasswdLength = int.Parse(strValue); return CfgUpdateFlags.RestartRqrd;
case 1: PasswdExpirationPeriodDays = int.Parse(strValue); return CfgUpdateFlags.RestartRqrd;
default: return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string strValue, out string message)
{
message = string.Empty;
int idummy;
switch (i)
{
case 0:
case 1:
/// Positive integers and zero are allowed
if (int.TryParse(strValue, out idummy) && (idummy >= 0)) return true;
break;
default:
message = "Invalid index";
return false;
}
message = ParamName(i) + " is invalid";
return false;
}
void CopyContentTo(ComponentCfg prms)
{
prms.MinPasswdLength = this.MinPasswdLength;
prms.PasswdExpirationPeriodDays = this.PasswdExpirationPeriodDays;
}
public Config.Entities.IParamsProvider Clone()
{
ComponentCfg pars = new ComponentCfg();
CopyContentTo(pars);
return pars;
}
public bool UpdateEmbeddedDbEntity()
{
return true; /// =OK, do nothing
}
}
}
@@ -0,0 +1,27 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.DataContainer.BackupAndSecurityOptions
{
public class Factory : IComponentFactory
{
public string ClassName { get { return GetType().Namespace.Substring(8); } }
public override string ToString() { return ClassName; }
public void ResetStaticProperties() { Component.ResetStaticProperties(); }
public IComponent DummyComponent() { return new Component(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Component(cfg); }
public IComponentCfg DefaultConfig() { return new ComponentCfg(GetType().Namespace.Substring(22), this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(ComponentCfg.Serializer, component, this);
}
}
}
@@ -0,0 +1,45 @@
///
/// Copyright (c) 2018-2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using log4net;
using Config.Entities;
using TBF.Rig;
using TBF.Rig.Generic;
namespace TBF.Rig.DataContainer.BenchInfo
{
/// <summary>
/// Holds information identifying the test bench.
/// </summary>
public class Component : ComponentBase, GenericDevices.IBenchInfo
{
private static readonly ILog log = LogManager.GetLogger(typeof(Component));
public override string ToString() { return string.Format("BenchInfo({0})", Cfg.ToString(1)); }
readonly ComponentCfg myCfg;
public string TestBenchName { get { return myCfg.TestBenchName; } }
public int TestBenchId { get { return myCfg.TestBenchId; } }
public string Address1 { get { return myCfg.Address1; } }
public string Address2 { get { return myCfg.Address2; } }
public string Address3 { get { return myCfg.Address3; } }
public string Address4 { get { return myCfg.Address4; } }
public string Address5 { get { return myCfg.Address5; } }
public RemoteDBUse RemoteDBUse { get { return myCfg.RemoteDBUse; } }
public Component()
{
}
public Component(Generic.IComponentCfg cfg)
: base(cfg)
{
myCfg = cfg as ComponentCfg;
Events.DB.SetBenchName(myCfg.TestBenchName);
log.Warn(this.ToString());
}
}
}
@@ -0,0 +1,222 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using Config.Entities;
using TBF.Rig.Generic;
namespace TBF.Rig.DataContainer.BenchInfo
{
/// <summary>
/// Holds information identifying the test bench - serializable configuration.
/// </summary>
public class ComponentCfg : ComponentCfgBase, Generic.IComponentCfg, Config.Entities.IParamsProvider
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(ComponentCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new Configs.ParamsProvider.ComponentCfgCtrl(this, null); }
///
/// Serialized parameters
///
public string TestBenchName;
public int TestBenchId;
public string Address1;
public string Address2;
public string Address3;
public string Address4;
public string Address5;
public string ApprovalId;
public string ApprovalDate;
public string ApprovedBy;
public RemoteDBUse RemoteDBUse;
/// Private parameterless constructor invoked by all other (public) constructors
ComponentCfg() {}
public ComponentCfg(string name, IComponentFactory factory)
: this()
{
Name = name;
Factory = factory;
ParentName = string.Empty;
InitializeAll();
}
public string ComponentName { get { return Name; } }
public void InitializeAll()
{
TestBenchName = "1";
TestBenchId = 1;
Address1 = string.Empty;
Address2 = string.Empty;
Address3 = string.Empty;
Address4 = string.Empty;
Address5 = string.Empty;
ApprovalId = string.Empty;
ApprovalDate = string.Empty;
ApprovedBy = string.Empty;
RemoteDBUse = RemoteDBUse.LocalDBOnly;
}
string[] paramNames = new string[]
{
"Test bench name",
"Test bench ID",
"Address 1",
"Address 2",
"Address 3",
"Address 4",
"Address 5",
"Approval",
"Approval date",
"Approved by",
"Remote DB use",
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
public ICollection<string> ParamValues(int i)
{
if (i == 10)
{
return new string[] { RemoteDBUse.LocalDBOnly.ToString(),
RemoteDBUse.RemoteDBOnly.ToString(),
RemoteDBUse.BothDBsLocalFirst.ToString(),
RemoteDBUse.BothDBsRemoteFirst.ToString() };
}
return null;
}
public string ToString(int i)
{
if (i == -1)
{
return string.Format("{0}: Bench name={1}, Bench Id={2}, Procedures={3}", Name, TestBenchName, TestBenchId, RemoteDBUse.ToDescription());
}
switch (i)
{
case 0: return TestBenchName;
case 1: return TestBenchId.ToString();
case 2: return Address1;
case 3: return Address2;
case 4: return Address3;
case 5: return Address4;
case 6: return Address5;
case 7: return ApprovalId;
case 8: return ApprovalDate;
case 9: return ApprovedBy;
case 10: return RemoteDBUse.ToDescription();
default: return string.Empty;
}
}
public CfgUpdateFlags UpdateParam(int i, string strValue)
{
switch (i)
{
case 0: TestBenchName = strValue; return CfgUpdateFlags.RestartRqrd;
case 1: TestBenchId = int.Parse(strValue); return CfgUpdateFlags.RestartRqrd;
case 2: Address1 = strValue; return CfgUpdateFlags.RestartRqrd;
case 3: Address2 = strValue; return CfgUpdateFlags.RestartRqrd;
case 4: Address3 = strValue; return CfgUpdateFlags.RestartRqrd;
case 5: Address4 = strValue; return CfgUpdateFlags.RestartRqrd;
case 6: Address5 = strValue; return CfgUpdateFlags.RestartRqrd;
case 7: ApprovalId = strValue; return CfgUpdateFlags.RestartRqrd;
case 8: ApprovalDate = strValue; return CfgUpdateFlags.RestartRqrd;
case 9: ApprovedBy = strValue; return CfgUpdateFlags.RestartRqrd;
case 10:
for (RemoteDBUse rdbu = 0; rdbu < RemoteDBUse.Count; rdbu++)
{
if (strValue == rdbu.ToDescription())
{
if (RemoteDBUse != rdbu)
{
RemoteDBUse = rdbu;
return CfgUpdateFlags.RestartRqrd;
}
else
{
return CfgUpdateFlags.None;
}
}
}
return CfgUpdateFlags.Error;
default: return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string strValue, out string message)
{
message = string.Empty;
int idummy;
switch (i)
{
case 0:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
return true;
case 1:
if (int.TryParse(strValue, out idummy) && (idummy >= 0)) return true;
break;
case 10:
for (RemoteDBUse rdbu = 0; rdbu < RemoteDBUse.Count; rdbu++)
{
if (strValue == rdbu.ToDescription()) return true;
}
return false;
default:
message = "Invalid index";
return false;
}
message = ParamName(i) + " is invalid";
return false;
}
void CopyContentTo(ComponentCfg prms)
{
prms.TestBenchName = this.TestBenchName;
prms.TestBenchId = this.TestBenchId;
prms.Address1 = this.Address1;
prms.Address2 = this.Address2;
prms.Address3 = this.Address3;
prms.Address4 = this.Address4;
prms.Address5 = this.Address5;
prms.ApprovalId = this.ApprovalId;
prms.ApprovalDate = this.ApprovalDate;
prms.ApprovedBy = this.ApprovedBy;
prms.RemoteDBUse = this.RemoteDBUse;
}
public Config.Entities.IParamsProvider Clone()
{
ComponentCfg pars = new ComponentCfg();
CopyContentTo(pars);
return pars;
}
public bool UpdateEmbeddedDbEntity()
{
return true; /// =OK, do nothing
}
}
}
@@ -0,0 +1,27 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.DataContainer.BenchInfo
{
public class Factory : IComponentFactory
{
public string ClassName { get { return GetType().Namespace.Substring(8); } }
public override string ToString() { return ClassName; }
public void ResetStaticProperties() { Component.ResetStaticProperties(); }
public IComponent DummyComponent() { return new Component(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Component(cfg); }
public IComponentCfg DefaultConfig() { return new ComponentCfg(GetType().Namespace.Substring(22), this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(ComponentCfg.Serializer, component, this);
}
}
}
@@ -0,0 +1,69 @@
///
/// Copyright (c) 2019-2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using TBF.Resources;
namespace TBF.Rig.DataContainer.Buoyancy
{
/// <summary>
/// Holds measured (true) buoyancy value.
/// </summary>
public class Component : ComponentBase, GenericDevices.IHasCalendarEvents
{
private static readonly ILog log = LogManager.GetLogger(typeof(Component));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(1)); }
readonly ComponentCfg myCfg;
public double Buoyancy { get { return myCfg.Buoyancy; } }
public Component()
{
}
public Component(Generic.IComponentCfg cfg)
: base(cfg)
{
myCfg = cfg as ComponentCfg;
/// This is to use data in formulas
Config.Data.Buoyancy = Buoyancy;
log.Warn(this.ToString());
}
public IList<Config.CalendarEvent.ICalendarEvent> GetCalendarEvents()
{
DateTime calibrationDue = myCfg.CalibValidDate;
IList<Config.CalendarEvent.ICalendarEvent> calendarEvents = new List<Config.CalendarEvent.ICalendarEvent>();
if (calibrationDue > TBF.UI.Constants.MinDate)
{
/// Calibration due date calendar event
calendarEvents.Add(new TBF.UI.Calendar.CalibrationDueDateEvent(calibrationDue.Date, Name,
string.Format(Strings.Calibration_due_date_is_0,
calibrationDue.Date.ToString(TBF.UI.Constants.DateFormat))));
if (DateTime.Now.Date <= calibrationDue.AddDays(-7))
{
/// Weekly reminders (last 5 weeks)
calendarEvents.Add(new TBF.UI.Calendar.CalibrationReminderEvent(calibrationDue.Date.AddDays(-35), Name,
string.Format(Strings.Calibration_due_date_is_0,
calibrationDue.Date.ToString(TBF.UI.Constants.DateFormat)),
false));
}
if (DateTime.Now.Date <= calibrationDue.Date)
{
/// Daily reminders (last 5 days)
calendarEvents.Add(new TBF.UI.Calendar.CalibrationReminderEvent(calibrationDue.AddDays(-5), Name,
string.Format(Strings.Calibration_due_date_is_0,
calibrationDue.Date.ToString(TBF.UI.Constants.DateFormat)),
true));
}
}
return calendarEvents;
}
}
}
@@ -0,0 +1,120 @@
///
/// Copyright (c) 2019-2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using Config.Entities;
using TBF.Rig.Generic;
namespace TBF.Rig.DataContainer.Buoyancy
{
/// <summary>
/// Holds backup and security options - serializable configuration.
/// </summary>
public class ComponentCfg : ComponentCfgBase, Generic.IComponentCfg, Config.Entities.IParamsProvider, TBF.Rig.GenericDevices.ICalibInfoCfg
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(ComponentCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new Configs.ParamsProvider.ComponentCfgCtrl(this, null); }
///
/// Serialized parameters
///
public double Buoyancy;
/// Calibration info serialized parameters displayed in Metrology tab page
public string CalibCertificateNr { get; set; }
public DateTime CalibDate { get; set; }
public DateTime CalibValidDate { get; set; }
/// Private parameterless constructor invoked by all other (public) constructors
ComponentCfg() {}
public ComponentCfg(string name, IComponentFactory factory)
: this()
{
Name = name;
Factory = factory;
ParentName = string.Empty;
InitializeAll();
}
public string ComponentName { get { return Name; } }
public void InitializeAll()
{
Buoyancy = 1.00103;
}
string[] paramNames = new string[]
{
"Buoyancy",
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
public ICollection<string> ParamValues(int i) { return null; }
public string ToString(int i)
{
if (i == -1)
{
return string.Format("{0}: Buoyancy = {1}", Name, Buoyancy);
}
switch (i)
{
case 0: return Buoyancy.ToString();
default: return string.Empty;
}
}
public CfgUpdateFlags UpdateParam(int i, string strValue)
{
switch (i)
{
case 0: Buoyancy = Utils.ParseUDouble(strValue); return CfgUpdateFlags.RestartRqrd;
default: return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string strValue, out string message)
{
message = string.Empty;
double dummy;
switch (i)
{
case 0:
/// Real number between 0.8 and 1.2 expected
if (Utils.TryParseUDouble(strValue, out dummy) && (dummy >= 0.8) && (dummy <= 1.2)) return true;
break;
default:
message = "Invalid index";
return false;
}
message = ParamName(i) + " is invalid";
return false;
}
void CopyContentTo(ComponentCfg prms)
{
prms.Buoyancy = this.Buoyancy;
}
public Config.Entities.IParamsProvider Clone()
{
ComponentCfg pars = new ComponentCfg();
CopyContentTo(pars);
return pars;
}
public bool UpdateEmbeddedDbEntity()
{
return true; /// =OK, do nothing
}
}
}
+27
View File
@@ -0,0 +1,27 @@
///
/// Copyright (c) 2019 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.DataContainer.Buoyancy
{
public class Factory : IComponentFactory
{
public string ClassName { get { return GetType().Namespace.Substring(8); } }
public override string ToString() { return ClassName; }
public void ResetStaticProperties() { Component.ResetStaticProperties(); }
public IComponent DummyComponent() { return new Component(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Component(cfg); }
public IComponentCfg DefaultConfig() { return new ComponentCfg(GetType().Namespace.Substring(22), this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(ComponentCfg.Serializer, component, this);
}
}
}
@@ -0,0 +1,71 @@
///
/// Copyright (c) 2019-2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using TBF.Resources;
namespace TBF.Rig.DataContainer.Density
{
/// <summary>
/// Holds measured (true) density value.
/// </summary>
public class Component : ComponentBase, GenericDevices.IHasCalendarEvents
{
private static readonly ILog log = LogManager.GetLogger(typeof(Component));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(1)); }
readonly ComponentCfg myCfg;
public double SampleDensity { get { return myCfg.SampleDensity; } }
public double SampleTemp { get { return myCfg.SampleTemp; } }
public Component()
{
}
public Component(Generic.IComponentCfg cfg)
: base(cfg)
{
myCfg = cfg as ComponentCfg;
/// This is to use data in formulas
Config.Data.SampleDensity = SampleDensity;
Config.Data.SampleTemp = SampleTemp;
log.Warn(this.ToString());
}
public IList<Config.CalendarEvent.ICalendarEvent> GetCalendarEvents()
{
DateTime calibrationDue = myCfg.CalibValidDate;
IList<Config.CalendarEvent.ICalendarEvent> calendarEvents = new List<Config.CalendarEvent.ICalendarEvent>();
if (calibrationDue > TBF.UI.Constants.MinDate)
{
/// Calibration due date calendar event
calendarEvents.Add(new TBF.UI.Calendar.CalibrationDueDateEvent(calibrationDue.Date, Name,
string.Format(Strings.Calibration_due_date_is_0,
calibrationDue.Date.ToString(TBF.UI.Constants.DateFormat))));
if (DateTime.Now.Date <= calibrationDue.AddDays(-7))
{
/// Weekly reminders (last 5 weeks)
calendarEvents.Add(new TBF.UI.Calendar.CalibrationReminderEvent(calibrationDue.Date.AddDays(-35), Name,
string.Format(Strings.Calibration_due_date_is_0,
calibrationDue.Date.ToString(TBF.UI.Constants.DateFormat)),
false));
}
if (DateTime.Now.Date <= calibrationDue.Date)
{
/// Daily reminders (last 5 days)
calendarEvents.Add(new TBF.UI.Calendar.CalibrationReminderEvent(calibrationDue.AddDays(-5), Name,
string.Format(Strings.Calibration_due_date_is_0,
calibrationDue.Date.ToString(TBF.UI.Constants.DateFormat)),
true));
}
}
return calendarEvents;
}
}
}
@@ -0,0 +1,130 @@
///
/// Copyright (c) 2019-2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using Config.Entities;
using TBF.Rig.Generic;
namespace TBF.Rig.DataContainer.Density
{
/// <summary>
/// Holds water density - serializable configuration.
/// </summary>
public class ComponentCfg : ComponentCfgBase, Generic.IComponentCfg, Config.Entities.IParamsProvider, TBF.Rig.GenericDevices.ICalibInfoCfg
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(ComponentCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new Configs.ParamsProvider.ComponentCfgCtrl(this, null); }
///
/// Serialized parameters
///
public double SampleDensity;
public double SampleTemp;
/// Calibration info serialized parameters displayed in Metrology tab page
public string CalibCertificateNr { get; set; }
public DateTime CalibDate { get; set; }
public DateTime CalibValidDate { get; set; }
/// Private parameterless constructor invoked by all other (public) constructors
ComponentCfg() {}
public ComponentCfg(string name, IComponentFactory factory)
: this()
{
Name = name;
Factory = factory;
ParentName = string.Empty;
InitializeAll();
}
public string ComponentName { get { return Name; } }
public void InitializeAll()
{
SampleDensity = 998.2008; /// kg/m3
SampleTemp = 20.0; /// °C
}
string[] paramNames = new string[]
{
"Sample density [kg/m3]",
"Sample temperature [°C]",
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
public ICollection<string> ParamValues(int i) { return null; }
public string ToString(int i)
{
if (i == -1)
{
return string.Format("{0}: Sample density = {1} kg/m3 measured at temperature {2} °C", Name, SampleDensity, SampleTemp);
}
switch (i)
{
case 0: return SampleDensity.ToString();
case 1: return SampleTemp.ToString();
default: return string.Empty;
}
}
public CfgUpdateFlags UpdateParam(int i, string strValue)
{
switch (i)
{
case 0: SampleDensity = Utils.ParseUDouble(strValue); return CfgUpdateFlags.RestartRqrd;
case 1: SampleTemp = Utils.ParseUDouble(strValue); return CfgUpdateFlags.RestartRqrd;
default: return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string strValue, out string message)
{
message = string.Empty;
double dummy;
switch (i)
{
case 0:
/// Real number between 800 and 1200 kg/m3 expected
if (Utils.TryParseUDouble(strValue, out dummy) && (dummy >= 800) && (dummy <= 1200)) return true;
break;
case 1:
/// Real number above 0 expected
if (Utils.TryParseUDouble(strValue, out dummy) && (dummy >= 0)) return true;
break;
default:
message = "Invalid index";
return false;
}
message = ParamName(i) + " is invalid";
return false;
}
void CopyContentTo(ComponentCfg prms)
{
prms.SampleDensity = this.SampleDensity;
prms.SampleTemp = this.SampleTemp;
}
public Config.Entities.IParamsProvider Clone()
{
ComponentCfg pars = new ComponentCfg();
CopyContentTo(pars);
return pars;
}
public bool UpdateEmbeddedDbEntity()
{
return true; /// =OK, do nothing
}
}
}

Some files were not shown because too many files have changed in this diff Show More