Compare commits

...

2 Commits

22 changed files with 3530 additions and 0 deletions

View File

@ -0,0 +1,238 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using log4net;
using Common;
using TBF.Rig.Generic;
namespace TBF.Rig.Modbus.ConductivityMeter
{
public class ConductivityMeter : ComponentBase, IDevice
{
private static readonly ILog log = LogManager.GetLogger(typeof(ConductivityMeter));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
readonly ConductivityMeterCfg cfg;
Common.Modbus modbus;
int ticketNumber;
ushort[] rawRegs;
DateTime lastUpdate;
double receivedCond;
double receivedmA;
bool msrmntAvailable;
byte[] lastTelegram;
public double MeasuredVal { get { return receivedCond; } }
public double MeasuredmA { get { return receivedmA; } }
public bool MsrmntAvailable { get { return msrmntAvailable; } }
public double MsrdValLimLo { get { return cfg.MsrdValLimLo; } }
public double MsrdValLimHi { get { return cfg.MsrdValLimHi; } }
public string MsrdUnit { get { return cfg.MsrdUnit.ToString(); } }
public string MsrdFormat { get { return cfg.MsrdFormat; } }
public ConductivityMeterDiagnostics Diagnostics { get; private set; }
public ConductivityMeter()
{
Diagnostics = new ConductivityMeterDiagnostics();
}
public ConductivityMeter(IComponentCfg cfg, IList<IComponent> components)
: base(cfg)
{
this.cfg = cfg as ConductivityMeterCfg;
ticketNumber = -1;
Diagnostics = new ConductivityMeterDiagnostics();
}
public override void Initialize()
{
int regCount = Math.Max(1, (int)cfg.RegisterCount);
rawRegs = new ushort[regCount];
if (DebugLevel == DebugMode.Normal)
{
modbus = TbfComponents.FindComponent(cfg.ParentName) as Common.Modbus;
if (modbus == null) throw new Exception("Cannot find " + Name + " parent");
modbus.ComponentNames[cfg.ModbusAddress] = Name;
if (cfg.EnablePolling)
ticketNumber = modbus.RegisterForPolling();
log.FatalFormat("{0} initialized: {1}", Name, this);
}
else
{
log.FatalFormat("{0} simulated: {1}", Name, this);
}
}
public void RunDeviceBefore()
{
if (DebugLevel != DebugMode.Normal)
{
msrmntAvailable = true;
receivedmA = 12.0;
receivedCond = ConvertMilliAmpsToConductivity(receivedmA);
return;
}
var queue = modbus.ReceivedTelegrams[cfg.ModbusAddress];
if (queue.Count > 0)
{
lastTelegram = queue.Dequeue();
ParseTelegram(lastTelegram);
}
msrmntAvailable = (DateTime.Now - lastUpdate).TotalMilliseconds <= cfg.FreshnessMs;
if (!msrmntAvailable) return;
int ch = cfg.Channel;
if (ch < 0 || ch >= rawRegs.Length)
{
msrmntAvailable = false;
return;
}
double raw = rawRegs[ch];
receivedmA = ConvertRawToMilliAmps(raw);
receivedCond = ConvertMilliAmpsToConductivity(receivedmA);
float floatValue = 0;
if (rawRegs != null && rawRegs.Length >= 4)
{
floatValue = ModbusFloat(rawRegs[2], rawRegs[3]);
}
Diagnostics.SetResponse(
lastTelegram,
rawRegs,
receivedmA,
receivedCond,
cfg.MsrdUnit.ToString(),
floatValue);
}
public void RunDeviceAfter()
{
if (DebugLevel == DebugMode.Normal && cfg.EnablePolling && modbus.IsMyTurn(ticketNumber))
{
byte func = (byte)((int)cfg.ReadFunction);
Diagnostics.SetRequest(
cfg.ModbusAddress,
func,
cfg.FirstRegister,
cfg.RegisterCount);
modbus.SendMessage(
cfg.ModbusAddress,
func,
cfg.FirstRegister,
cfg.RegisterCount,
Name);
}
}
public void StopDevice() { }
public void StopDevice2() { }
private void ParseTelegram(byte[] telegram)
{
try
{
if (telegram == null || telegram.Length < 5) return;
byte func = telegram[1];
if (func != (byte)((int)cfg.ReadFunction)) return;
int byteCount = telegram[2];
int expectedRegs = rawRegs.Length;
int expectedBytes = expectedRegs * 2;
if (byteCount < expectedBytes) return;
if (telegram.Length < 3 + expectedBytes) return;
for (int i = 0; i < expectedRegs; i++)
{
int ix = 3 + i * 2;
rawRegs[i] = (ushort)((telegram[ix] << 8) | telegram[ix + 1]);
}
lastUpdate = DateTime.Now;
float floatValue = 0;
if (rawRegs.Length >= 4)
{
floatValue = ModbusFloat(rawRegs[2], rawRegs[3]);
}
Diagnostics.SetResponse(
lastTelegram,
rawRegs,
receivedmA,
receivedCond,
cfg.MsrdUnit.ToString(),
floatValue);
}
catch (Exception ex)
{
Diagnostics.SetError(
ex.Message + Environment.NewLine +
"Telegram: " + BitConverter.ToString(telegram));
log.WarnFormat("{0}: Failed to parse telegram. {1}", Name, ex.Message);
Debug.WriteLine(ex);
}
}
private double ConvertRawToMilliAmps(double raw)
{
if (cfg.RawFormat == RawFormat.Milliamps_x1000)
return raw / 1000.0;
double denom = cfg.RawAt20mA - cfg.RawAt4mA;
if (Math.Abs(denom) < 1e-12) return 0;
return 4.0 + (raw - cfg.RawAt4mA) * (16.0 / denom);
}
private double ConvertMilliAmpsToConductivity(double mA)
{
return cfg.CondAt4mA + (mA - 4.0) / 16.0 * (cfg.CondAt20mA - cfg.CondAt4mA);
}
public void ShowDiagnostics()
{
ConductivityMeterDiagnosticsForm form =
new ConductivityMeterDiagnosticsForm(this);
form.Show();
}
private static float ModbusFloat(ushort hi, ushort lo)
{
byte[] bytes =
{
(byte)(hi >> 8),
(byte)hi,
(byte)(lo >> 8),
(byte)lo
};
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes);
return BitConverter.ToSingle(bytes, 0);
}
}
}

View File

@ -0,0 +1,108 @@
using System;
using System.Xml.Serialization;
using Config.Entities;
using TBF.Rig.Generic;
namespace TBF.Rig.Modbus.ConductivityMeter
{
public enum ModbusReadFunction
{
ReadHoldingRegisters_03 = 3,
ReadInputRegisters_04 = 4
}
public enum RawFormat
{
Counts16bit,
Milliamps_x1000
}
public class ConductivityMeterCfg : ComponentCfgBase, Generic.IChildComponentCfg
{
public static XmlSerializer Serializer =
XmlSerializer.FromTypes(new[] { typeof(ConductivityMeterCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(System.Collections.Generic.IList<Component> cmpntEntities)
{
return new ConductivityMeterCfgCtrl();
}
/// Modbus link (parent component is Common.Modbus)
public string ParentName; // Modbus component name
public byte ModbusAddress; // 1..247
public ModbusReadFunction ReadFunction; // 03 or 04
public ushort FirstRegister; // start register address on AD4RS
public ushort RegisterCount; // 1..4 typically
public bool EnablePolling;
/// Which channel to use for conductivity value
public int Channel; // 0..(RegisterCount-1)
/// Raw format and scaling
public RawFormat RawFormat;
public double RawAt4mA; // used when RawFormat == Counts16bit
public double RawAt20mA; // used when RawFormat == Counts16bit
public double CondAt4mA; // e.g. 0 uS/cm
public double CondAt20mA; // e.g. 2000 uS/cm
public string MsrdUnit; // "uS/cm"
public string MsrdFormat; // "{0:0}"
public double MsrdValLimLo;
public double MsrdValLimHi;
public int FreshnessMs;
ConductivityMeterCfg()
{
Name = "ConductivityMeter";
ParentName = "Modbus";
ModbusAddress = 50;
ReadFunction = ModbusReadFunction.ReadInputRegisters_04;
FirstRegister = 0;
RegisterCount = 1;
EnablePolling = true;
Channel = 0;
RawFormat = RawFormat.Counts16bit;
RawAt4mA = 13107;
RawAt20mA = 65535;
CondAt4mA = 0;
CondAt20mA = 2000;
MsrdUnit = "uS/cm";
MsrdFormat = "{0:0}";
MsrdValLimLo = 0;
MsrdValLimHi = 5000;
FreshnessMs = 3000;
}
public ConductivityMeterCfg(IComponentFactory factory) : this()
{
this.Factory = factory;
}
public string ToString(int i)
{
return string.Format(
"{0}: Parent={1}, Addr={2}, Fn={3}, Reg={4}, Cnt={5}, Ch={6}, RawFormat={7}, Cond={8}..{9} {10}",
Name,
string.IsNullOrEmpty(ParentName) ? "-" : ParentName,
ModbusAddress,
(int)ReadFunction,
FirstRegister,
RegisterCount,
Channel,
RawFormat,
CondAt4mA,
CondAt20mA,
MsrdUnit);
}
}
}

View File

@ -0,0 +1,469 @@
// ConductivityMeterCfgCtrl.Designer.cs
namespace TBF.Rig.Modbus.ConductivityMeter
{
partial class ConductivityMeterCfgCtrl
{
private System.ComponentModel.IContainer components = null;
private System.Windows.Forms.Label componentNameLabel;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label parentLabel;
private System.Windows.Forms.ComboBox parentNameComboBox;
private System.Windows.Forms.Label modbusAddressLabel;
private System.Windows.Forms.TextBox modbusAddressTextBox;
private System.Windows.Forms.Label fnLabel;
private System.Windows.Forms.ComboBox fnComboBox;
private System.Windows.Forms.Label firstRegisterLabel;
private System.Windows.Forms.TextBox firstRegisterTextBox;
private System.Windows.Forms.Label registerCountLabel;
private System.Windows.Forms.TextBox registerCountTextBox;
private System.Windows.Forms.CheckBox enablePollingCheckBox;
private System.Windows.Forms.Label channelLabel;
private System.Windows.Forms.TextBox channelTextBox;
private System.Windows.Forms.Label rawFormatLabel;
private System.Windows.Forms.ComboBox rawFormatComboBox;
private System.Windows.Forms.Label raw4Label;
private System.Windows.Forms.TextBox raw4TextBox;
private System.Windows.Forms.Label raw20Label;
private System.Windows.Forms.TextBox raw20TextBox;
private System.Windows.Forms.Label cond4Label;
private System.Windows.Forms.TextBox cond4TextBox;
private System.Windows.Forms.Label cond20Label;
private System.Windows.Forms.TextBox cond20TextBox;
private System.Windows.Forms.Label unitLabel;
private System.Windows.Forms.TextBox unitTextBox;
private System.Windows.Forms.Label formatLabel;
private System.Windows.Forms.TextBox formatTextBox;
private System.Windows.Forms.Label limLoLabel;
private System.Windows.Forms.TextBox limLoTextBox;
private System.Windows.Forms.Label limHiLabel;
private System.Windows.Forms.TextBox limHiTextBox;
private System.Windows.Forms.Label freshnessLabel;
private System.Windows.Forms.TextBox freshnessTextBox;
private System.Windows.Forms.Button diagnosticsButton;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
components.Dispose();
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.componentNameLabel = new System.Windows.Forms.Label();
this.nameLabel = new System.Windows.Forms.Label();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.parentLabel = new System.Windows.Forms.Label();
this.parentNameComboBox = new System.Windows.Forms.ComboBox();
this.modbusAddressLabel = new System.Windows.Forms.Label();
this.modbusAddressTextBox = new System.Windows.Forms.TextBox();
this.fnLabel = new System.Windows.Forms.Label();
this.fnComboBox = new System.Windows.Forms.ComboBox();
this.firstRegisterLabel = new System.Windows.Forms.Label();
this.firstRegisterTextBox = new System.Windows.Forms.TextBox();
this.registerCountLabel = new System.Windows.Forms.Label();
this.registerCountTextBox = new System.Windows.Forms.TextBox();
this.enablePollingCheckBox = new System.Windows.Forms.CheckBox();
this.channelLabel = new System.Windows.Forms.Label();
this.channelTextBox = new System.Windows.Forms.TextBox();
this.rawFormatLabel = new System.Windows.Forms.Label();
this.rawFormatComboBox = new System.Windows.Forms.ComboBox();
this.raw4Label = new System.Windows.Forms.Label();
this.raw4TextBox = new System.Windows.Forms.TextBox();
this.raw20Label = new System.Windows.Forms.Label();
this.raw20TextBox = new System.Windows.Forms.TextBox();
this.cond4Label = new System.Windows.Forms.Label();
this.cond4TextBox = new System.Windows.Forms.TextBox();
this.cond20Label = new System.Windows.Forms.Label();
this.cond20TextBox = new System.Windows.Forms.TextBox();
this.unitLabel = new System.Windows.Forms.Label();
this.unitTextBox = new System.Windows.Forms.TextBox();
this.formatLabel = new System.Windows.Forms.Label();
this.formatTextBox = new System.Windows.Forms.TextBox();
this.limLoLabel = new System.Windows.Forms.Label();
this.limLoTextBox = new System.Windows.Forms.TextBox();
this.limHiLabel = new System.Windows.Forms.Label();
this.limHiTextBox = new System.Windows.Forms.TextBox();
this.freshnessLabel = new System.Windows.Forms.Label();
this.freshnessTextBox = new System.Windows.Forms.TextBox();
this.diagnosticsButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// componentNameLabel
//
this.componentNameLabel.AutoSize = true;
this.componentNameLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold);
this.componentNameLabel.Location = new System.Drawing.Point(12, 10);
this.componentNameLabel.Name = "componentNameLabel";
this.componentNameLabel.Size = new System.Drawing.Size(120, 15);
this.componentNameLabel.TabIndex = 0;
this.componentNameLabel.Text = "ConductivityMeter";
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(12, 40);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 1;
this.nameLabel.Text = "Name";
//
// nameTextBox
//
this.nameTextBox.Location = new System.Drawing.Point(170, 37);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(220, 20);
this.nameTextBox.TabIndex = 2;
//
// parentLabel
//
this.parentLabel.AutoSize = true;
this.parentLabel.Location = new System.Drawing.Point(12, 66);
this.parentLabel.Name = "parentLabel";
this.parentLabel.Size = new System.Drawing.Size(95, 13);
this.parentLabel.TabIndex = 3;
this.parentLabel.Text = "Parent Component";
//
// parentNameComboBox
//
this.parentNameComboBox.FormattingEnabled = true;
this.parentNameComboBox.Location = new System.Drawing.Point(170, 63);
this.parentNameComboBox.Name = "parentNameComboBox";
this.parentNameComboBox.Size = new System.Drawing.Size(220, 21);
this.parentNameComboBox.TabIndex = 4;
//
// modbusAddressLabel
//
this.modbusAddressLabel.AutoSize = true;
this.modbusAddressLabel.Location = new System.Drawing.Point(12, 93);
this.modbusAddressLabel.Name = "modbusAddressLabel";
this.modbusAddressLabel.Size = new System.Drawing.Size(86, 13);
this.modbusAddressLabel.TabIndex = 5;
this.modbusAddressLabel.Text = "Modbus Address";
//
// modbusAddressTextBox
//
this.modbusAddressTextBox.Location = new System.Drawing.Point(170, 90);
this.modbusAddressTextBox.Name = "modbusAddressTextBox";
this.modbusAddressTextBox.Size = new System.Drawing.Size(80, 20);
this.modbusAddressTextBox.TabIndex = 6;
//
// fnLabel
//
this.fnLabel.AutoSize = true;
this.fnLabel.Location = new System.Drawing.Point(12, 119);
this.fnLabel.Name = "fnLabel";
this.fnLabel.Size = new System.Drawing.Size(92, 13);
this.fnLabel.TabIndex = 7;
this.fnLabel.Text = "Function (03 / 04)";
//
// fnComboBox
//
this.fnComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.fnComboBox.FormattingEnabled = true;
this.fnComboBox.Location = new System.Drawing.Point(170, 116);
this.fnComboBox.Name = "fnComboBox";
this.fnComboBox.Size = new System.Drawing.Size(220, 21);
this.fnComboBox.TabIndex = 8;
//
// firstRegisterLabel
//
this.firstRegisterLabel.AutoSize = true;
this.firstRegisterLabel.Location = new System.Drawing.Point(12, 146);
this.firstRegisterLabel.Name = "firstRegisterLabel";
this.firstRegisterLabel.Size = new System.Drawing.Size(68, 13);
this.firstRegisterLabel.TabIndex = 9;
this.firstRegisterLabel.Text = "First Register";
//
// firstRegisterTextBox
//
this.firstRegisterTextBox.Location = new System.Drawing.Point(170, 143);
this.firstRegisterTextBox.Name = "firstRegisterTextBox";
this.firstRegisterTextBox.Size = new System.Drawing.Size(120, 20);
this.firstRegisterTextBox.TabIndex = 10;
//
// registerCountLabel
//
this.registerCountLabel.AutoSize = true;
this.registerCountLabel.Location = new System.Drawing.Point(12, 172);
this.registerCountLabel.Name = "registerCountLabel";
this.registerCountLabel.Size = new System.Drawing.Size(77, 13);
this.registerCountLabel.TabIndex = 11;
this.registerCountLabel.Text = "Register Count";
//
// registerCountTextBox
//
this.registerCountTextBox.Location = new System.Drawing.Point(170, 169);
this.registerCountTextBox.Name = "registerCountTextBox";
this.registerCountTextBox.Size = new System.Drawing.Size(120, 20);
this.registerCountTextBox.TabIndex = 12;
//
// enablePollingCheckBox
//
this.enablePollingCheckBox.AutoSize = true;
this.enablePollingCheckBox.Location = new System.Drawing.Point(170, 197);
this.enablePollingCheckBox.Name = "enablePollingCheckBox";
this.enablePollingCheckBox.Size = new System.Drawing.Size(93, 17);
this.enablePollingCheckBox.TabIndex = 13;
this.enablePollingCheckBox.Text = "Enable Polling";
this.enablePollingCheckBox.UseVisualStyleBackColor = true;
//
// channelLabel
//
this.channelLabel.AutoSize = true;
this.channelLabel.Location = new System.Drawing.Point(12, 224);
this.channelLabel.Name = "channelLabel";
this.channelLabel.Size = new System.Drawing.Size(46, 13);
this.channelLabel.TabIndex = 14;
this.channelLabel.Text = "Channel";
//
// channelTextBox
//
this.channelTextBox.Location = new System.Drawing.Point(170, 221);
this.channelTextBox.Name = "channelTextBox";
this.channelTextBox.Size = new System.Drawing.Size(80, 20);
this.channelTextBox.TabIndex = 15;
//
// rawFormatLabel
//
this.rawFormatLabel.AutoSize = true;
this.rawFormatLabel.Location = new System.Drawing.Point(12, 250);
this.rawFormatLabel.Name = "rawFormatLabel";
this.rawFormatLabel.Size = new System.Drawing.Size(64, 13);
this.rawFormatLabel.TabIndex = 16;
this.rawFormatLabel.Text = "Raw Format";
//
// rawFormatComboBox
//
this.rawFormatComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.rawFormatComboBox.FormattingEnabled = true;
this.rawFormatComboBox.Location = new System.Drawing.Point(170, 247);
this.rawFormatComboBox.Name = "rawFormatComboBox";
this.rawFormatComboBox.Size = new System.Drawing.Size(220, 21);
this.rawFormatComboBox.TabIndex = 17;
//
// raw4Label
//
this.raw4Label.AutoSize = true;
this.raw4Label.Location = new System.Drawing.Point(12, 277);
this.raw4Label.Name = "raw4Label";
this.raw4Label.Size = new System.Drawing.Size(100, 13);
this.raw4Label.TabIndex = 18;
this.raw4Label.Text = "Raw Value @ 4 mA";
//
// raw4TextBox
//
this.raw4TextBox.Location = new System.Drawing.Point(170, 274);
this.raw4TextBox.Name = "raw4TextBox";
this.raw4TextBox.Size = new System.Drawing.Size(120, 20);
this.raw4TextBox.TabIndex = 19;
//
// raw20Label
//
this.raw20Label.AutoSize = true;
this.raw20Label.Location = new System.Drawing.Point(12, 303);
this.raw20Label.Name = "raw20Label";
this.raw20Label.Size = new System.Drawing.Size(106, 13);
this.raw20Label.TabIndex = 20;
this.raw20Label.Text = "Raw Value @ 20 mA";
//
// raw20TextBox
//
this.raw20TextBox.Location = new System.Drawing.Point(170, 300);
this.raw20TextBox.Name = "raw20TextBox";
this.raw20TextBox.Size = new System.Drawing.Size(120, 20);
this.raw20TextBox.TabIndex = 21;
//
// cond4Label
//
this.cond4Label.AutoSize = true;
this.cond4Label.Location = new System.Drawing.Point(12, 329);
this.cond4Label.Name = "cond4Label";
this.cond4Label.Size = new System.Drawing.Size(106, 13);
this.cond4Label.TabIndex = 22;
this.cond4Label.Text = "Conductivity @ 4 mA";
//
// cond4TextBox
//
this.cond4TextBox.Location = new System.Drawing.Point(170, 326);
this.cond4TextBox.Name = "cond4TextBox";
this.cond4TextBox.Size = new System.Drawing.Size(120, 20);
this.cond4TextBox.TabIndex = 23;
//
// cond20Label
//
this.cond20Label.AutoSize = true;
this.cond20Label.Location = new System.Drawing.Point(12, 355);
this.cond20Label.Name = "cond20Label";
this.cond20Label.Size = new System.Drawing.Size(112, 13);
this.cond20Label.TabIndex = 24;
this.cond20Label.Text = "Conductivity @ 20 mA";
//
// cond20TextBox
//
this.cond20TextBox.Location = new System.Drawing.Point(170, 352);
this.cond20TextBox.Name = "cond20TextBox";
this.cond20TextBox.Size = new System.Drawing.Size(120, 20);
this.cond20TextBox.TabIndex = 25;
//
// unitLabel
//
this.unitLabel.AutoSize = true;
this.unitLabel.Location = new System.Drawing.Point(12, 381);
this.unitLabel.Name = "unitLabel";
this.unitLabel.Size = new System.Drawing.Size(26, 13);
this.unitLabel.TabIndex = 26;
this.unitLabel.Text = "Unit";
//
// unitTextBox
//
this.unitTextBox.Location = new System.Drawing.Point(170, 378);
this.unitTextBox.Name = "unitTextBox";
this.unitTextBox.Size = new System.Drawing.Size(120, 20);
this.unitTextBox.TabIndex = 27;
//
// formatLabel
//
this.formatLabel.AutoSize = true;
this.formatLabel.Location = new System.Drawing.Point(12, 407);
this.formatLabel.Name = "formatLabel";
this.formatLabel.Size = new System.Drawing.Size(76, 13);
this.formatLabel.TabIndex = 28;
this.formatLabel.Text = "Display Format";
//
// formatTextBox
//
this.formatTextBox.Location = new System.Drawing.Point(170, 404);
this.formatTextBox.Name = "formatTextBox";
this.formatTextBox.Size = new System.Drawing.Size(220, 20);
this.formatTextBox.TabIndex = 29;
//
// limLoLabel
//
this.limLoLabel.AutoSize = true;
this.limLoLabel.Location = new System.Drawing.Point(12, 433);
this.limLoLabel.Name = "limLoLabel";
this.limLoLabel.Size = new System.Drawing.Size(51, 13);
this.limLoLabel.TabIndex = 30;
this.limLoLabel.Text = "Low Limit";
//
// limLoTextBox
//
this.limLoTextBox.Location = new System.Drawing.Point(170, 430);
this.limLoTextBox.Name = "limLoTextBox";
this.limLoTextBox.Size = new System.Drawing.Size(120, 20);
this.limLoTextBox.TabIndex = 31;
//
// limHiLabel
//
this.limHiLabel.AutoSize = true;
this.limHiLabel.Location = new System.Drawing.Point(12, 459);
this.limHiLabel.Name = "limHiLabel";
this.limHiLabel.Size = new System.Drawing.Size(53, 13);
this.limHiLabel.TabIndex = 32;
this.limHiLabel.Text = "High Limit";
//
// limHiTextBox
//
this.limHiTextBox.Location = new System.Drawing.Point(170, 456);
this.limHiTextBox.Name = "limHiTextBox";
this.limHiTextBox.Size = new System.Drawing.Size(120, 20);
this.limHiTextBox.TabIndex = 33;
//
// freshnessLabel
//
this.freshnessLabel.AutoSize = true;
this.freshnessLabel.Location = new System.Drawing.Point(12, 485);
this.freshnessLabel.Name = "freshnessLabel";
this.freshnessLabel.Size = new System.Drawing.Size(93, 13);
this.freshnessLabel.TabIndex = 34;
this.freshnessLabel.Text = "Data Timeout (ms)";
//
// freshnessTextBox
//
this.freshnessTextBox.Location = new System.Drawing.Point(170, 482);
this.freshnessTextBox.Name = "freshnessTextBox";
this.freshnessTextBox.Size = new System.Drawing.Size(120, 20);
this.freshnessTextBox.TabIndex = 35;
//
// diagnosticsButton
//
this.diagnosticsButton.Location = new System.Drawing.Point(170, 512);
this.diagnosticsButton.Name = "diagnosticsButton";
this.diagnosticsButton.Size = new System.Drawing.Size(120, 27);
this.diagnosticsButton.TabIndex = 36;
this.diagnosticsButton.Text = "Diagnostics...";
this.diagnosticsButton.UseVisualStyleBackColor = true;
this.diagnosticsButton.Click += new System.EventHandler(this.diagnosticsButton_Click);
//
// ConductivityMeterCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.componentNameLabel);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.parentLabel);
this.Controls.Add(this.parentNameComboBox);
this.Controls.Add(this.modbusAddressLabel);
this.Controls.Add(this.modbusAddressTextBox);
this.Controls.Add(this.fnLabel);
this.Controls.Add(this.fnComboBox);
this.Controls.Add(this.firstRegisterLabel);
this.Controls.Add(this.firstRegisterTextBox);
this.Controls.Add(this.registerCountLabel);
this.Controls.Add(this.registerCountTextBox);
this.Controls.Add(this.enablePollingCheckBox);
this.Controls.Add(this.channelLabel);
this.Controls.Add(this.channelTextBox);
this.Controls.Add(this.rawFormatLabel);
this.Controls.Add(this.rawFormatComboBox);
this.Controls.Add(this.raw4Label);
this.Controls.Add(this.raw4TextBox);
this.Controls.Add(this.raw20Label);
this.Controls.Add(this.raw20TextBox);
this.Controls.Add(this.cond4Label);
this.Controls.Add(this.cond4TextBox);
this.Controls.Add(this.cond20Label);
this.Controls.Add(this.cond20TextBox);
this.Controls.Add(this.unitLabel);
this.Controls.Add(this.unitTextBox);
this.Controls.Add(this.formatLabel);
this.Controls.Add(this.formatTextBox);
this.Controls.Add(this.limLoLabel);
this.Controls.Add(this.limLoTextBox);
this.Controls.Add(this.limHiLabel);
this.Controls.Add(this.limHiTextBox);
this.Controls.Add(this.freshnessLabel);
this.Controls.Add(this.freshnessTextBox);
this.Controls.Add(this.diagnosticsButton);
this.Name = "ConductivityMeterCfgCtrl";
this.Size = new System.Drawing.Size(420, 551);
this.Load += new System.EventHandler(this.ConductivityMeterCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
}
}

View File

@ -0,0 +1,258 @@
using Common;
using Config.Entities;
using System;
using System.Windows.Forms;
using TBF.Rig.Generic;
using TBF.UI.Bench.Components;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
namespace TBF.Rig.Modbus.ConductivityMeter
{
public partial class ConductivityMeterCfgCtrl : UserControl, IComponentCfgCtrl
{
ComponentParametersDlg parent;
public bool ShowMore { get { return false; } }
ConductivityMeterCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as ConductivityMeterCfg;
Redraw();
}
}
public ConductivityMeterCfgCtrl()
{
InitializeComponent();
}
private void ConductivityMeterCfgCtrl_Load(object sender, EventArgs e)
{
parent = ParentForm as ComponentParametersDlg;
if (parent == null) return;
// Parent selection: Modbus component
if (parent.CmpntEntities != null)
{
foreach (var cmpnt in parent.CmpntEntities)
{
if (TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is Modbus.Common.Factory)
{
parentNameComboBox.Items.Add(cmpnt.Name);
}
}
}
// Function 03/04
fnComboBox.Items.Add(ModbusReadFunction.ReadHoldingRegisters_03.ToString());
fnComboBox.Items.Add(ModbusReadFunction.ReadInputRegisters_04.ToString());
// Raw format
rawFormatComboBox.Items.Add(RawFormat.Counts16bit.ToString());
rawFormatComboBox.Items.Add(RawFormat.Milliamps_x1000.ToString());
Redraw();
}
public void Closing() { }
void Redraw()
{
if (config == null) return;
componentNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
parentNameComboBox.Text = string.IsNullOrEmpty(config.ParentName) ? "---" : config.ParentName;
modbusAddressTextBox.Text = config.ModbusAddress.ToString();
fnComboBox.Text = config.ReadFunction.ToString();
firstRegisterTextBox.Text = config.FirstRegister.ToString();
registerCountTextBox.Text = config.RegisterCount.ToString();
enablePollingCheckBox.Checked = config.EnablePolling;
channelTextBox.Text = config.Channel.ToString();
rawFormatComboBox.Text = config.RawFormat.ToString();
raw4TextBox.Text = config.RawAt4mA.ToString();
raw20TextBox.Text = config.RawAt20mA.ToString();
cond4TextBox.Text = config.CondAt4mA.ToString();
cond20TextBox.Text = config.CondAt20mA.ToString();
unitTextBox.Text = config.MsrdUnit;
formatTextBox.Text = config.MsrdFormat;
limLoTextBox.Text = config.MsrdValLimLo.ToString();
limHiTextBox.Text = config.MsrdValLimHi.ToString();
freshnessTextBox.Text = config.FreshnessMs.ToString();
}
public void Unlock()
{
nameTextBox.Enabled = true;
parentNameComboBox.Enabled = true;
modbusAddressTextBox.Enabled = true;
fnComboBox.Enabled = true;
firstRegisterTextBox.Enabled = true;
registerCountTextBox.Enabled = true;
enablePollingCheckBox.Enabled = true;
channelTextBox.Enabled = true;
rawFormatComboBox.Enabled = true;
raw4TextBox.Enabled = true;
raw20TextBox.Enabled = true;
cond4TextBox.Enabled = true;
cond20TextBox.Enabled = true;
unitTextBox.Enabled = true;
formatTextBox.Enabled = true;
limLoTextBox.Enabled = true;
limHiTextBox.Enabled = true;
freshnessTextBox.Enabled = true;
diagnosticsButton.Enabled = true;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
int iVal;
double dVal;
if (!parentNameComboBox.Items.Contains(parentNameComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Parent Component'";
}
if (!int.TryParse(modbusAddressTextBox.Text, out iVal) || iVal < 1 || iVal > 247)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Modbus Address' must be between 1 and 247";
}
if (!fnComboBox.Items.Contains(fnComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Function (03/04)'";
}
if (!int.TryParse(firstRegisterTextBox.Text, out iVal) || iVal < 0 || iVal > 65535)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'First Register' must be between 0 and 65535";
}
if (!int.TryParse(registerCountTextBox.Text, out iVal) || iVal < 1 || iVal > 4)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Register Count' must be between 1 and 4";
}
if (!int.TryParse(channelTextBox.Text, out iVal) || iVal < 0)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Channel'";
}
if (!rawFormatComboBox.Items.Contains(rawFormatComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Raw Format'";
}
if (!double.TryParse(raw4TextBox.Text, out dVal) || !double.TryParse(raw20TextBox.Text, out dVal))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid raw calibration values (Raw @ 4 mA / Raw @ 20 mA)";
}
if (!double.TryParse(cond4TextBox.Text, out dVal) || !double.TryParse(cond20TextBox.Text, out dVal))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid conductivity scaling values (Cond @ 4 mA / Cond @ 20 mA)";
}
if (!int.TryParse(freshnessTextBox.Text, out iVal) || iVal < 100)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Data Timeout (ms)' must be at least 100";
}
return flags;
}
public CfgUpdateFlags UpdateCfg()
{
if (config == null) return CfgUpdateFlags.Error;
config.Name = nameTextBox.Text;
config.ParentName = parentNameComboBox.Text.Equals("---") ? string.Empty : parentNameComboBox.Text;
config.ModbusAddress = (byte)int.Parse(modbusAddressTextBox.Text);
foreach (ModbusReadFunction fn in Enum.GetValues(typeof(ModbusReadFunction)))
{
if (fnComboBox.Text == fn.ToString()) { config.ReadFunction = fn; break; }
}
config.FirstRegister = (ushort)int.Parse(firstRegisterTextBox.Text);
config.RegisterCount = (ushort)int.Parse(registerCountTextBox.Text);
config.EnablePolling = enablePollingCheckBox.Checked;
config.Channel = int.Parse(channelTextBox.Text);
foreach (RawFormat rf in Enum.GetValues(typeof(RawFormat)))
{
if (rawFormatComboBox.Text == rf.ToString()) { config.RawFormat = rf; break; }
}
config.RawAt4mA = double.Parse(raw4TextBox.Text);
config.RawAt20mA = double.Parse(raw20TextBox.Text);
config.CondAt4mA = double.Parse(cond4TextBox.Text);
config.CondAt20mA = double.Parse(cond20TextBox.Text);
config.MsrdUnit = unitTextBox.Text;
config.MsrdFormat = formatTextBox.Text;
config.MsrdValLimLo = double.Parse(limLoTextBox.Text);
config.MsrdValLimHi = double.Parse(limHiTextBox.Text);
config.FreshnessMs = int.Parse(freshnessTextBox.Text);
return CfgUpdateFlags.RestartRqrd;
}
private void diagnosticsButton_Click(object sender, EventArgs e)
{
if (config == null) return;
ConductivityMeter cmpnt =
TbfComponents.FindComponent(config.Name) as ConductivityMeter;
if (cmpnt == null)
{
MessageBox.Show(
"Runtime component was not found. Diagnostics are available only while the component is initialized.",
"Diagnostics",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
return;
}
cmpnt.ShowDiagnostics();
}
}
}

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>

View File

@ -0,0 +1,164 @@
// ConductivityMeterDiagnostics.cs
using System;
using System.Text;
namespace TBF.Rig.Modbus.ConductivityMeter
{
public class ConductivityMeterDiagnostics
{
public DateTime LastRequestTime { get; private set; }
public DateTime LastResponseTime { get; private set; }
public string LastRequest { get; private set; }
public string LastResponse { get; private set; }
public string LastError { get; private set; }
public int RequestCount { get; private set; }
public int ResponseCount { get; private set; }
public int ErrorCount { get; private set; }
public ConductivityMeterDiagnostics()
{
LastRequest = string.Empty;
LastResponse = string.Empty;
LastError = string.Empty;
}
public void Clear()
{
LastRequestTime = DateTime.MinValue;
LastResponseTime = DateTime.MinValue;
LastRequest = string.Empty;
LastResponse = string.Empty;
LastError = string.Empty;
RequestCount = 0;
ResponseCount = 0;
ErrorCount = 0;
}
public void SetRequest(
byte address,
byte function,
ushort firstRegister,
ushort registerCount)
{
RequestCount++;
LastRequestTime = DateTime.Now;
LastRequest = string.Format(
"TX {0:HH:mm:ss.fff}{1}" +
"Address: {2}{1}" +
"Function: 0x{3:X2}{1}" +
"First register: {4}{1}" +
"Register count: {5}",
LastRequestTime,
Environment.NewLine,
address,
function,
firstRegister,
registerCount);
}
public void SetResponse(
byte[] telegram,
ushort[] rawRegisters,
double milliAmps,
double conductivity,
string unit,
float floatValue)
{
ResponseCount++;
LastResponseTime = DateTime.Now;
var sb = new StringBuilder();
sb.AppendFormat("RX {0:HH:mm:ss.fff}", LastResponseTime);
sb.AppendLine();
sb.Append("Telegram: ");
sb.AppendLine(ToHex(telegram));
if (rawRegisters != null)
{
for (int i = 0; i < rawRegisters.Length; i++)
{
sb.AppendFormat("Raw[{0}]: {1}", i, rawRegisters[i]);
sb.AppendLine();
}
}
sb.AppendFormat("Float value: {0:0.###}", floatValue);
sb.AppendLine();
sb.AppendFormat("Current: {0:0.000} mA", milliAmps);
sb.AppendLine();
sb.AppendFormat("Conductivity: {0:0.###} {1}", conductivity, unit);
LastResponse = sb.ToString();
LastError = string.Empty;
}
public void SetError(string message)
{
ErrorCount++;
LastError = string.Format(
"{0:HH:mm:ss.fff} {1}",
DateTime.Now,
message);
}
public string GetText()
{
var sb = new StringBuilder();
sb.AppendLine("Conductivity Meter Diagnostics");
sb.AppendLine("--------------------------------");
sb.AppendFormat("Requests: {0}", RequestCount);
sb.AppendLine();
sb.AppendFormat("Responses: {0}", ResponseCount);
sb.AppendLine();
sb.AppendFormat("Errors: {0}", ErrorCount);
sb.AppendLine();
sb.AppendLine();
if (!string.IsNullOrEmpty(LastRequest))
{
sb.AppendLine(LastRequest);
sb.AppendLine();
}
if (!string.IsNullOrEmpty(LastResponse))
{
sb.AppendLine(LastResponse);
sb.AppendLine();
}
if (!string.IsNullOrEmpty(LastError))
{
sb.AppendLine("Last error:");
sb.AppendLine(LastError);
}
return sb.ToString();
}
static string ToHex(byte[] data)
{
if (data == null || data.Length == 0)
return string.Empty;
var sb = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
if (i > 0) sb.Append(" ");
sb.Append(data[i].ToString("X2"));
}
return sb.ToString();
}
}
}

View File

@ -0,0 +1,91 @@
namespace TBF.Rig.Modbus.ConductivityMeter
{
partial class ConductivityMeterDiagnosticsForm
{
private System.ComponentModel.IContainer components = null;
private System.Windows.Forms.TextBox diagnosticsTextBox;
private System.Windows.Forms.Button clearButton;
private System.Windows.Forms.Button closeButton;
private System.Windows.Forms.Timer refreshTimer;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
components.Dispose();
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.diagnosticsTextBox = new System.Windows.Forms.TextBox();
this.clearButton = new System.Windows.Forms.Button();
this.closeButton = new System.Windows.Forms.Button();
this.refreshTimer = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// diagnosticsTextBox
//
this.diagnosticsTextBox.Anchor =
((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top |
System.Windows.Forms.AnchorStyles.Bottom) |
System.Windows.Forms.AnchorStyles.Left) |
System.Windows.Forms.AnchorStyles.Right)));
this.diagnosticsTextBox.Font = new System.Drawing.Font("Consolas", 9F);
this.diagnosticsTextBox.Location = new System.Drawing.Point(12, 12);
this.diagnosticsTextBox.Multiline = true;
this.diagnosticsTextBox.Name = "diagnosticsTextBox";
this.diagnosticsTextBox.ReadOnly = true;
this.diagnosticsTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.diagnosticsTextBox.Size = new System.Drawing.Size(660, 390);
this.diagnosticsTextBox.TabIndex = 0;
this.diagnosticsTextBox.WordWrap = false;
//
// clearButton
//
this.clearButton.Anchor =
((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom |
System.Windows.Forms.AnchorStyles.Left)));
this.clearButton.Location = new System.Drawing.Point(12, 415);
this.clearButton.Name = "clearButton";
this.clearButton.Size = new System.Drawing.Size(90, 27);
this.clearButton.TabIndex = 1;
this.clearButton.Text = "Clear";
this.clearButton.UseVisualStyleBackColor = true;
this.clearButton.Click += new System.EventHandler(this.clearButton_Click);
//
// closeButton
//
this.closeButton.Anchor =
((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom |
System.Windows.Forms.AnchorStyles.Right)));
this.closeButton.Location = new System.Drawing.Point(582, 415);
this.closeButton.Name = "closeButton";
this.closeButton.Size = new System.Drawing.Size(90, 27);
this.closeButton.TabIndex = 2;
this.closeButton.Text = "Close";
this.closeButton.UseVisualStyleBackColor = true;
this.closeButton.Click += new System.EventHandler(this.closeButton_Click);
//
// refreshTimer
//
this.refreshTimer.Interval = 500;
this.refreshTimer.Tick += new System.EventHandler(this.refreshTimer_Tick);
//
// ConductivityMeterDiagnosticsForm
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(684, 454);
this.Controls.Add(this.diagnosticsTextBox);
this.Controls.Add(this.clearButton);
this.Controls.Add(this.closeButton);
this.Name = "ConductivityMeterDiagnosticsForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Conductivity Meter - Modbus Diagnostics";
this.Load += new System.EventHandler(this.ConductivityMeterDiagnosticsForm_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
}
}

View File

@ -0,0 +1,61 @@
using System;
using System.Windows.Forms;
namespace TBF.Rig.Modbus.ConductivityMeter
{
public partial class ConductivityMeterDiagnosticsForm : Form
{
readonly ConductivityMeter conductivityMeter;
public ConductivityMeterDiagnosticsForm(ConductivityMeter conductivityMeter)
{
if (conductivityMeter == null)
throw new ArgumentNullException("conductivityMeter");
this.conductivityMeter = conductivityMeter;
InitializeComponent();
}
private void ConductivityMeterDiagnosticsForm_Load(object sender, EventArgs e)
{
refreshTimer.Start();
RefreshDiagnostics();
}
private void refreshTimer_Tick(object sender, EventArgs e)
{
RefreshDiagnostics();
}
private void RefreshDiagnostics()
{
if (conductivityMeter.Diagnostics == null)
{
diagnosticsTextBox.Text = "Diagnostics are not available.";
return;
}
diagnosticsTextBox.Text = conductivityMeter.Diagnostics.GetText();
}
private void clearButton_Click(object sender, EventArgs e)
{
if (conductivityMeter.Diagnostics != null)
conductivityMeter.Diagnostics.Clear();
RefreshDiagnostics();
}
private void closeButton_Click(object sender, EventArgs e)
{
Close();
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
refreshTimer.Stop();
base.OnFormClosing(e);
}
}
}

View File

@ -0,0 +1,35 @@
using System.Collections.Generic;
using TBF.Rig.Generic;
using TBF.Rig.Modbus.ConductivityMeter;
namespace TBF.Rig.Modbus.ConductivityMeter
{
public class Factory : IComponentFactory
{
public string ClassName { get { return this.GetType().Namespace.Substring(8); } }
public override string ToString() { return ClassName; }
public IComponent DummyComponent()
{
return new ConductivityMeter();
}
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components)
{
return new ConductivityMeter(cfg, components);
}
public IComponentCfg DefaultConfig()
{
return new ConductivityMeterCfg(this);
}
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(
ConductivityMeterCfg.Serializer,
component,
this);
}
}
}

View File

@ -0,0 +1,359 @@
using Common;
using log4net;
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Diagnostics;
using TBF.Boxes;
using TBF.Rig.Generic;
using TBF.Rig.Modbus.WaterAnalyzerUni;
namespace TBF.Rig.Modbus.WaterAnalyzerUni
{
public class Analyzer : ComponentBase, IDevice
{
private static readonly ILog log = LogManager.GetLogger(typeof(Analyzer));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
readonly AnalyzerCfg myCfg;
Common.Modbus modbus;
float conductivity; // [uS/cm]
double temperature; // [°C]
int msrmntTimeStamp;
int ticketNumber;
ushort[] rawRegs;
DateTime lastUpdate;
byte[] lastTelegram;
public float Conductivity { get { return conductivity; } }
public AnalyzerDiagnostics Diagnostics { get; private set; }
public Analyzer()
{
Diagnostics = new AnalyzerDiagnostics();
}
public Analyzer(IComponentCfg cfg, IList<IComponent> components)
: base(cfg)
{
myCfg = cfg as AnalyzerCfg;
Diagnostics = new AnalyzerDiagnostics();
}
public override void Initialize()
{
modbus = TbfComponents.FindComponent(myCfg.ParentName) as Common.Modbus;
if (modbus == null) throw new Exception("Cannot find " + Name + " parent");
conductivity = 0.0F;
temperature = 0.0;
msrmntTimeStamp = 0;
ticketNumber = -1;
rawRegs = new ushort[Math.Max(1, (int)myCfg.ConverterRegisterCount)];
modbus.ComponentNames[myCfg.ModbusAddress] = Name;
ticketNumber = modbus.RegisterForPolling();
log.FatalFormat("{0} initialized: {1}", Name, this);
}
public float ReadConductivity()
{
return conductivity;
}
public double ReadTemperature()
{
return temperature;
}
public ReadConductivityOp ReadConductivityOp(ref FloatBox conduct)
{
return new ReadConductivityOp(this, ref conduct);
}
public IOperation ReadTempOp(ref DoubleBox temperature)
{
return new ReadTempOp(this, ref temperature);
}
public IOperation ReadTempOp(ref DoubleBox temperature, Event eventDone)
{
return new ReadTempOp(this, ref temperature, eventDone);
}
public void RunDeviceBefore()
{
if (myCfg.DebugLevel == DebugMode.Simulate ||
myCfg.DebugLevel == DebugMode.FailureDuringOperation)
{
msrmntTimeStamp = StateMachine.Time;
return;
}
var queue = modbus.ReceivedTelegrams[myCfg.ModbusAddress];
if (queue.Count == 0) return;
lastTelegram = queue.Dequeue();
if (myCfg.ConnectionType == AnalyzerConnectionType.DirectConductivityMeter)
{
ParseDirectAnalyzerTelegram(lastTelegram);
}
else
{
ParseConverterTelegram(lastTelegram);
}
}
public void RunDeviceAfter()
{
if (myCfg.DebugLevel == DebugMode.Simulate ||
myCfg.DebugLevel == DebugMode.FailureDuringOperation ||
!modbus.IsMyTurn(ticketNumber))
{
return;
}
if (myCfg.ConnectionType == AnalyzerConnectionType.DirectConductivityMeter)
{
SendDirectAnalyzerRequest();
}
else
{
SendConverterRequest();
}
}
public void StopDevice() { }
public void StopDevice2() { }
void SendDirectAnalyzerRequest()
{
ushort regAddr = myCfg.DirectRegisterAddress;
ushort count = 2;
byte[] msg = new byte[8];
msg[0] = myCfg.ModbusAddress;
msg[1] = 3;
msg[2] = (byte)(regAddr >> 8);
msg[3] = (byte)(regAddr & 0xFF);
msg[4] = (byte)(count >> 8);
msg[5] = (byte)(count & 0xFF);
Diagnostics.SetRequest(myCfg.ModbusAddress, 3, regAddr, count);
modbus.SendMessage(msg, Name);
}
void SendConverterRequest()
{
Diagnostics.SetRequest(
myCfg.ModbusAddress,
myCfg.ConverterReadFunction,
myCfg.ConverterFirstRegister,
myCfg.ConverterRegisterCount);
modbus.SendMessage(
myCfg.ModbusAddress,
myCfg.ConverterReadFunction,
myCfg.ConverterFirstRegister,
myCfg.ConverterRegisterCount,
Name);
}
void ParseDirectAnalyzerTelegram(byte[] telegram)
{
if (telegram == null) return;
if (telegram.Length == 9 && telegram[1] == 3 && telegram[2] == 4)
{
byte[] conductBytes = CreateFloatBytes(
telegram[3],
telegram[4],
telegram[5],
telegram[6],
myCfg.DirectFloatByteOrder);
conductivity = BitConverter.ToSingle(conductBytes, 0);
lastUpdate = DateTime.Now;
UpdateProcessData(conductivity);
Diagnostics.SetResponse(
telegram,
null,
conductivity,
0,
conductivity,
myCfg.Unit);
string line = string.Format("conductivity = {0} {1}", conductivity, myCfg.Unit);
log.Debug(line);
Debug.WriteLine(line);
}
}
void ParseConverterTelegram(byte[] telegram)
{
try
{
if (telegram == null || telegram.Length < 5) return;
if (telegram[1] != myCfg.ConverterReadFunction) return;
int byteCount = telegram[2];
int expectedBytes = myCfg.ConverterRegisterCount * 2;
if (byteCount < expectedBytes) return;
if (telegram.Length < 3 + expectedBytes) return;
if (rawRegs == null || rawRegs.Length != myCfg.ConverterRegisterCount)
rawRegs = new ushort[Math.Max(1, (int)myCfg.ConverterRegisterCount)];
for (int i = 0; i < myCfg.ConverterRegisterCount; i++)
{
int ix = 3 + i * 2;
rawRegs[i] = (ushort)((telegram[ix] << 8) | telegram[ix + 1]);
}
double raw = ReadConverterRawValue();
double current = ConvertRawToMilliAmps(raw);
conductivity = (float)ConvertRawToConductivity(raw);
lastUpdate = DateTime.Now;
UpdateProcessData(conductivity);
Diagnostics.SetResponse(
telegram,
rawRegs,
raw,
current,
conductivity,
myCfg.Unit);
string line = string.Format(
"converter raw = {0:0.###}, conductivity = {1:0.###} {2}",
raw,
conductivity,
myCfg.Unit);
log.Debug(line);
Debug.WriteLine(line);
}
catch (Exception ex)
{
Diagnostics.SetError(
ex.Message + Environment.NewLine +
"Telegram: " + BitConverter.ToString(telegram));
log.WarnFormat("{0}: Failed to parse converter telegram. {1}", Name, ex.Message);
Debug.WriteLine(ex);
}
}
double ReadConverterRawValue()
{
if (myCfg.ConverterValueSource == AnalyzerValueSource.IntegerRegister)
{
int ch = myCfg.ConverterChannel;
if (rawRegs == null || ch < 0 || ch >= rawRegs.Length)
return 0.0;
return rawRegs[ch];
}
if (rawRegs == null || rawRegs.Length < 4)
return 0.0;
return ModbusFloat(
rawRegs[2],
rawRegs[3],
myCfg.ConverterFloatByteOrder);
}
double ConvertRawToConductivity(double raw)
{
double denom = myCfg.RawValueAt20mA - myCfg.RawValueAt4mA;
if (Math.Abs(denom) < 1e-12) return 0;
return myCfg.ConductivityAt4mA +
(raw - myCfg.RawValueAt4mA) / denom *
(myCfg.ConductivityAt20mA - myCfg.ConductivityAt4mA);
}
double ConvertRawToMilliAmps(double raw)
{
double denom = myCfg.RawValueAt20mA - myCfg.RawValueAt4mA;
if (Math.Abs(denom) < 1e-12) return 0;
return 4.0 + (raw - myCfg.RawValueAt4mA) * (16.0 / denom);
}
static byte[] CreateFloatBytes(
byte b0,
byte b1,
byte b2,
byte b3,
AnalyzerFloatByteOrder order)
{
switch (order)
{
case AnalyzerFloatByteOrder.ABCD:
return BitConverter.IsLittleEndian
? new byte[] { b3, b2, b1, b0 }
: new byte[] { b0, b1, b2, b3 };
case AnalyzerFloatByteOrder.BADC:
return BitConverter.IsLittleEndian
? new byte[] { b2, b3, b0, b1 }
: new byte[] { b1, b0, b3, b2 };
case AnalyzerFloatByteOrder.CDAB:
return BitConverter.IsLittleEndian
? new byte[] { b1, b0, b3, b2 }
: new byte[] { b2, b3, b0, b1 };
case AnalyzerFloatByteOrder.DCBA:
return BitConverter.IsLittleEndian
? new byte[] { b0, b1, b2, b3 }
: new byte[] { b3, b2, b1, b0 };
default:
return BitConverter.IsLittleEndian
? new byte[] { b3, b2, b1, b0 }
: new byte[] { b0, b1, b2, b3 };
}
}
static float ModbusFloat(
ushort hi,
ushort lo,
AnalyzerFloatByteOrder order)
{
byte a = (byte)(hi >> 8);
byte b = (byte)(hi & 0xFF);
byte c = (byte)(lo >> 8);
byte d = (byte)(lo & 0xFF);
byte[] bytes = CreateFloatBytes(a, b, c, d, order);
return BitConverter.ToSingle(bytes, 0);
}
void UpdateProcessData(float conduct)
{
TBF.Rig.Sequences.ProcessData.Conductivity.Val = conduct;
}
public void ShowDiagnostics()
{
new AnalyzerDiagnosticsForm(this).Show();
}
}
}

View File

@ -0,0 +1,242 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using Common;
using Config.Entities;
using TBF.Rig.Generic;
namespace TBF.Rig.Modbus.WaterAnalyzerUni
{
public enum AnalyzerConnectionType
{
DirectConductivityMeter,
CurrentLoop420mA
}
public enum AnalyzerValueSource
{
IntegerRegister,
FloatRegisters
}
public enum AnalyzerFloatByteOrder
{
ABCD,
BADC,
CDAB,
DCBA
}
public class AnalyzerCfg : ComponentCfgBase, Generic.IChildComponentCfg, IParamsProvider
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(AnalyzerCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Component> cmpntEntities)
{
return new AnalyzerCfgCtrl();
}
public AnalyzerConnectionType ConnectionType;
public byte ModbusAddress;
/// Direct analyzer
public ushort DirectRegisterAddress;
public AnalyzerFloatByteOrder DirectFloatByteOrder;
/// Papouch converter
public byte ConverterReadFunction;
public ushort ConverterFirstRegister;
public ushort ConverterRegisterCount;
public int ConverterChannel;
public AnalyzerValueSource ConverterValueSource;
public AnalyzerFloatByteOrder ConverterFloatByteOrder;
/// Raw scaling
public double RawValueAt4mA;
public double RawValueAt20mA;
/// Conductivity scaling
public double ConductivityAt4mA;
public double ConductivityAt20mA;
/// Display
public string Unit;
public string DisplayFormat;
public double LowLimit;
public double HighLimit;
/// Timeout
public int DataTimeoutMs;
public double ConverterIntegerScale;
AnalyzerCfg() { }
public AnalyzerCfg(string name, IComponentFactory factory)
: this()
{
Factory = factory;
Name = name;
ParentName = "ModbusUSB";
InitializeAll();
}
public string ComponentName { get { return Name; } }
public void InitializeAll()
{
ModbusAddress = 49;
ConnectionType = AnalyzerConnectionType.CurrentLoop420mA;
DirectRegisterAddress = 0x50;
DirectFloatByteOrder = AnalyzerFloatByteOrder.BADC;
ConverterReadFunction = 4;
ConverterFirstRegister = 0;
ConverterRegisterCount = 4;
ConverterChannel = 1;
ConverterValueSource = AnalyzerValueSource.IntegerRegister;
ConverterFloatByteOrder = AnalyzerFloatByteOrder.ABCD;
RawValueAt4mA = 0;
RawValueAt20mA = 9990;
ConductivityAt4mA = 10;
ConductivityAt20mA = 20000;
Unit = "uS/cm";
DisplayFormat = "{0:0}";
LowLimit = 0;
HighLimit = 5000;
DataTimeoutMs = 3000;
}
string[] paramNames = new string[]
{
"Connection type",
"Modbus address"
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
public ICollection<string> ParamValues(int i)
{
switch (i)
{
case 0:
return Enum.GetNames(typeof(AnalyzerConnectionType));
default:
return null;
}
}
public string ToString(int i)
{
if (i == -1)
{
return string.Format(
"ConnectionType={0}, ModbusAddr={1}",
ConnectionType,
ModbusAddress);
}
switch (i)
{
case 0: return ConnectionType.ToString();
case 1: return ModbusAddress.ToString();
default: return string.Empty;
}
}
public CfgUpdateFlags UpdateParam(int i, string strValue)
{
switch (i)
{
case 0:
ConnectionType = (AnalyzerConnectionType)Enum.Parse(typeof(AnalyzerConnectionType), strValue);
return CfgUpdateFlags.RestartRqrd;
case 1:
ModbusAddress = byte.Parse(strValue);
return CfgUpdateFlags.RestartRqrd;
default:
return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string strValue, out string message)
{
message = string.Empty;
int dummy;
switch (i)
{
case 0:
if (Enum.IsDefined(typeof(AnalyzerConnectionType), strValue)) return true;
message = ParamName(i) + " is invalid";
return false;
case 1:
if (int.TryParse(strValue, out dummy) && dummy >= 1 && dummy <= 247) return true;
message = ParamName(i) + " is invalid. Address range is 1 .. 247";
return false;
default:
message = "Invalid index";
return false;
}
}
void CopyContentTo(AnalyzerCfg prms)
{
prms.ParentName = ParentName;
prms.ModbusAddress = ModbusAddress;
prms.ConnectionType = ConnectionType;
prms.DirectRegisterAddress = DirectRegisterAddress;
prms.DirectFloatByteOrder = DirectFloatByteOrder;
prms.ConverterReadFunction = ConverterReadFunction;
prms.ConverterFirstRegister = ConverterFirstRegister;
prms.ConverterRegisterCount = ConverterRegisterCount;
prms.ConverterChannel = ConverterChannel;
prms.ConverterValueSource = ConverterValueSource;
prms.ConverterFloatByteOrder = ConverterFloatByteOrder;
prms.RawValueAt4mA = RawValueAt4mA;
prms.RawValueAt20mA = RawValueAt20mA;
prms.ConductivityAt4mA = ConductivityAt4mA;
prms.ConductivityAt20mA = ConductivityAt20mA;
prms.Unit = Unit;
prms.DisplayFormat = DisplayFormat;
prms.LowLimit = LowLimit;
prms.HighLimit = HighLimit;
prms.DataTimeoutMs = DataTimeoutMs;
}
public IParamsProvider Clone()
{
AnalyzerCfg pars = new AnalyzerCfg();
CopyContentTo(pars);
return pars;
}
public bool UpdateEmbeddedDbEntity()
{
return true;
}
}
}

View File

@ -0,0 +1,394 @@
namespace TBF.Rig.Modbus.WaterAnalyzerUni
{
partial class AnalyzerCfgCtrl
{
private System.ComponentModel.IContainer components = null;
private System.Windows.Forms.Label componentNameLabel;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label parentLabel;
private System.Windows.Forms.ComboBox parentNameComboBox;
private System.Windows.Forms.Label connectionTypeLabel;
private System.Windows.Forms.ComboBox connectionTypeComboBox;
private System.Windows.Forms.Label modbusAddressLabel;
private System.Windows.Forms.TextBox modbusAddressTextBox;
private System.Windows.Forms.GroupBox directGroupBox;
private System.Windows.Forms.Label directRegisterLabel;
private System.Windows.Forms.TextBox directRegisterTextBox;
private System.Windows.Forms.Label directFloatByteOrderLabel;
private System.Windows.Forms.ComboBox directFloatByteOrderComboBox;
private System.Windows.Forms.GroupBox converterGroupBox;
private System.Windows.Forms.Label converterFunctionLabel;
private System.Windows.Forms.TextBox converterFunctionTextBox;
private System.Windows.Forms.Label converterFirstRegisterLabel;
private System.Windows.Forms.TextBox converterFirstRegisterTextBox;
private System.Windows.Forms.Label converterRegisterCountLabel;
private System.Windows.Forms.TextBox converterRegisterCountTextBox;
private System.Windows.Forms.Label converterChannelLabel;
private System.Windows.Forms.TextBox converterChannelTextBox;
private System.Windows.Forms.Label valueSourceLabel;
private System.Windows.Forms.ComboBox valueSourceComboBox;
private System.Windows.Forms.Label floatByteOrderLabel;
private System.Windows.Forms.ComboBox floatByteOrderComboBox;
private System.Windows.Forms.Label raw4Label;
private System.Windows.Forms.TextBox raw4TextBox;
private System.Windows.Forms.Label raw20Label;
private System.Windows.Forms.TextBox raw20TextBox;
private System.Windows.Forms.Label cond4Label;
private System.Windows.Forms.TextBox cond4TextBox;
private System.Windows.Forms.Label cond20Label;
private System.Windows.Forms.TextBox cond20TextBox;
private System.Windows.Forms.Label unitLabel;
private System.Windows.Forms.TextBox unitTextBox;
private System.Windows.Forms.Label formatLabel;
private System.Windows.Forms.TextBox formatTextBox;
private System.Windows.Forms.Label lowLimitLabel;
private System.Windows.Forms.TextBox lowLimitTextBox;
private System.Windows.Forms.Label highLimitLabel;
private System.Windows.Forms.TextBox highLimitTextBox;
private System.Windows.Forms.Label dataTimeoutLabel;
private System.Windows.Forms.TextBox dataTimeoutTextBox;
private System.Windows.Forms.Button diagnosticsButton;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null)) components.Dispose();
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.componentNameLabel = new System.Windows.Forms.Label();
this.nameLabel = new System.Windows.Forms.Label();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.parentLabel = new System.Windows.Forms.Label();
this.parentNameComboBox = new System.Windows.Forms.ComboBox();
this.connectionTypeLabel = new System.Windows.Forms.Label();
this.connectionTypeComboBox = new System.Windows.Forms.ComboBox();
this.modbusAddressLabel = new System.Windows.Forms.Label();
this.modbusAddressTextBox = new System.Windows.Forms.TextBox();
this.directGroupBox = new System.Windows.Forms.GroupBox();
this.directRegisterLabel = new System.Windows.Forms.Label();
this.directRegisterTextBox = new System.Windows.Forms.TextBox();
this.directFloatByteOrderLabel = new System.Windows.Forms.Label();
this.directFloatByteOrderComboBox = new System.Windows.Forms.ComboBox();
this.converterGroupBox = new System.Windows.Forms.GroupBox();
this.converterFunctionLabel = new System.Windows.Forms.Label();
this.converterFunctionTextBox = new System.Windows.Forms.TextBox();
this.converterFirstRegisterLabel = new System.Windows.Forms.Label();
this.converterFirstRegisterTextBox = new System.Windows.Forms.TextBox();
this.converterRegisterCountLabel = new System.Windows.Forms.Label();
this.converterRegisterCountTextBox = new System.Windows.Forms.TextBox();
this.converterChannelLabel = new System.Windows.Forms.Label();
this.converterChannelTextBox = new System.Windows.Forms.TextBox();
this.valueSourceLabel = new System.Windows.Forms.Label();
this.valueSourceComboBox = new System.Windows.Forms.ComboBox();
this.floatByteOrderLabel = new System.Windows.Forms.Label();
this.floatByteOrderComboBox = new System.Windows.Forms.ComboBox();
this.raw4Label = new System.Windows.Forms.Label();
this.raw4TextBox = new System.Windows.Forms.TextBox();
this.raw20Label = new System.Windows.Forms.Label();
this.raw20TextBox = new System.Windows.Forms.TextBox();
this.cond4Label = new System.Windows.Forms.Label();
this.cond4TextBox = new System.Windows.Forms.TextBox();
this.cond20Label = new System.Windows.Forms.Label();
this.cond20TextBox = new System.Windows.Forms.TextBox();
this.unitLabel = new System.Windows.Forms.Label();
this.unitTextBox = new System.Windows.Forms.TextBox();
this.formatLabel = new System.Windows.Forms.Label();
this.formatTextBox = new System.Windows.Forms.TextBox();
this.lowLimitLabel = new System.Windows.Forms.Label();
this.lowLimitTextBox = new System.Windows.Forms.TextBox();
this.highLimitLabel = new System.Windows.Forms.Label();
this.highLimitTextBox = new System.Windows.Forms.TextBox();
this.dataTimeoutLabel = new System.Windows.Forms.Label();
this.dataTimeoutTextBox = new System.Windows.Forms.TextBox();
this.diagnosticsButton = new System.Windows.Forms.Button();
this.directGroupBox.SuspendLayout();
this.converterGroupBox.SuspendLayout();
this.SuspendLayout();
// componentNameLabel
this.componentNameLabel.AutoSize = true;
this.componentNameLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold);
this.componentNameLabel.Location = new System.Drawing.Point(12, 10);
this.componentNameLabel.Name = "componentNameLabel";
this.componentNameLabel.Size = new System.Drawing.Size(95, 15);
this.componentNameLabel.TabIndex = 0;
this.componentNameLabel.Text = "WaterAnalyzer";
// nameLabel
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(12, 40);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 1;
this.nameLabel.Text = "Name";
// nameTextBox
this.nameTextBox.Location = new System.Drawing.Point(170, 37);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(220, 20);
this.nameTextBox.TabIndex = 2;
// parentLabel
this.parentLabel.AutoSize = true;
this.parentLabel.Location = new System.Drawing.Point(12, 66);
this.parentLabel.Name = "parentLabel";
this.parentLabel.Size = new System.Drawing.Size(95, 13);
this.parentLabel.TabIndex = 3;
this.parentLabel.Text = "Parent Component";
// parentNameComboBox
this.parentNameComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDown;
this.parentNameComboBox.FormattingEnabled = true;
this.parentNameComboBox.Location = new System.Drawing.Point(170, 63);
this.parentNameComboBox.Name = "parentNameComboBox";
this.parentNameComboBox.Size = new System.Drawing.Size(220, 21);
this.parentNameComboBox.TabIndex = 4;
// connectionTypeLabel
this.connectionTypeLabel.AutoSize = true;
this.connectionTypeLabel.Location = new System.Drawing.Point(12, 93);
this.connectionTypeLabel.Name = "connectionTypeLabel";
this.connectionTypeLabel.Size = new System.Drawing.Size(86, 13);
this.connectionTypeLabel.TabIndex = 5;
this.connectionTypeLabel.Text = "Connection Type";
// connectionTypeComboBox
this.connectionTypeComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.connectionTypeComboBox.FormattingEnabled = true;
this.connectionTypeComboBox.Location = new System.Drawing.Point(170, 90);
this.connectionTypeComboBox.Name = "connectionTypeComboBox";
this.connectionTypeComboBox.Size = new System.Drawing.Size(220, 21);
this.connectionTypeComboBox.TabIndex = 6;
this.connectionTypeComboBox.SelectedIndexChanged += new System.EventHandler(this.connectionTypeComboBox_SelectedIndexChanged);
// modbusAddressLabel
this.modbusAddressLabel.AutoSize = true;
this.modbusAddressLabel.Location = new System.Drawing.Point(12, 120);
this.modbusAddressLabel.Name = "modbusAddressLabel";
this.modbusAddressLabel.Size = new System.Drawing.Size(84, 13);
this.modbusAddressLabel.TabIndex = 7;
this.modbusAddressLabel.Text = "Modbus Address";
// modbusAddressTextBox
this.modbusAddressTextBox.Location = new System.Drawing.Point(170, 117);
this.modbusAddressTextBox.Name = "modbusAddressTextBox";
this.modbusAddressTextBox.Size = new System.Drawing.Size(80, 20);
this.modbusAddressTextBox.TabIndex = 8;
// directGroupBox
this.directGroupBox.Controls.Add(this.directRegisterLabel);
this.directGroupBox.Controls.Add(this.directRegisterTextBox);
this.directGroupBox.Controls.Add(this.directFloatByteOrderLabel);
this.directGroupBox.Controls.Add(this.directFloatByteOrderComboBox);
this.directGroupBox.Location = new System.Drawing.Point(15, 150);
this.directGroupBox.Name = "directGroupBox";
this.directGroupBox.Size = new System.Drawing.Size(375, 90);
this.directGroupBox.TabIndex = 9;
this.directGroupBox.TabStop = false;
this.directGroupBox.Text = "Direct conductivity meter";
this.directRegisterLabel.AutoSize = true;
this.directRegisterLabel.Location = new System.Drawing.Point(12, 28);
this.directRegisterLabel.Name = "directRegisterLabel";
this.directRegisterLabel.Size = new System.Drawing.Size(82, 13);
this.directRegisterLabel.TabIndex = 0;
this.directRegisterLabel.Text = "Register Address";
this.directRegisterTextBox.Location = new System.Drawing.Point(155, 25);
this.directRegisterTextBox.Name = "directRegisterTextBox";
this.directRegisterTextBox.Size = new System.Drawing.Size(120, 20);
this.directRegisterTextBox.TabIndex = 1;
this.directFloatByteOrderLabel.AutoSize = true;
this.directFloatByteOrderLabel.Location = new System.Drawing.Point(12, 55);
this.directFloatByteOrderLabel.Name = "directFloatByteOrderLabel";
this.directFloatByteOrderLabel.Size = new System.Drawing.Size(84, 13);
this.directFloatByteOrderLabel.TabIndex = 2;
this.directFloatByteOrderLabel.Text = "Float Byte Order";
this.directFloatByteOrderComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.directFloatByteOrderComboBox.FormattingEnabled = true;
this.directFloatByteOrderComboBox.Location = new System.Drawing.Point(155, 52);
this.directFloatByteOrderComboBox.Name = "directFloatByteOrderComboBox";
this.directFloatByteOrderComboBox.Size = new System.Drawing.Size(200, 21);
this.directFloatByteOrderComboBox.TabIndex = 3;
// converterGroupBox
this.converterGroupBox.Controls.Add(this.converterFunctionLabel);
this.converterGroupBox.Controls.Add(this.converterFunctionTextBox);
this.converterGroupBox.Controls.Add(this.converterFirstRegisterLabel);
this.converterGroupBox.Controls.Add(this.converterFirstRegisterTextBox);
this.converterGroupBox.Controls.Add(this.converterRegisterCountLabel);
this.converterGroupBox.Controls.Add(this.converterRegisterCountTextBox);
this.converterGroupBox.Controls.Add(this.converterChannelLabel);
this.converterGroupBox.Controls.Add(this.converterChannelTextBox);
this.converterGroupBox.Controls.Add(this.valueSourceLabel);
this.converterGroupBox.Controls.Add(this.valueSourceComboBox);
this.converterGroupBox.Controls.Add(this.floatByteOrderLabel);
this.converterGroupBox.Controls.Add(this.floatByteOrderComboBox);
this.converterGroupBox.Controls.Add(this.raw4Label);
this.converterGroupBox.Controls.Add(this.raw4TextBox);
this.converterGroupBox.Controls.Add(this.raw20Label);
this.converterGroupBox.Controls.Add(this.raw20TextBox);
this.converterGroupBox.Controls.Add(this.cond4Label);
this.converterGroupBox.Controls.Add(this.cond4TextBox);
this.converterGroupBox.Controls.Add(this.cond20Label);
this.converterGroupBox.Controls.Add(this.cond20TextBox);
this.converterGroupBox.Controls.Add(this.unitLabel);
this.converterGroupBox.Controls.Add(this.unitTextBox);
this.converterGroupBox.Controls.Add(this.formatLabel);
this.converterGroupBox.Controls.Add(this.formatTextBox);
this.converterGroupBox.Controls.Add(this.lowLimitLabel);
this.converterGroupBox.Controls.Add(this.lowLimitTextBox);
this.converterGroupBox.Controls.Add(this.highLimitLabel);
this.converterGroupBox.Controls.Add(this.highLimitTextBox);
this.converterGroupBox.Controls.Add(this.dataTimeoutLabel);
this.converterGroupBox.Controls.Add(this.dataTimeoutTextBox);
this.converterGroupBox.Location = new System.Drawing.Point(15, 250);
this.converterGroupBox.Name = "converterGroupBox";
this.converterGroupBox.Size = new System.Drawing.Size(375, 430);
this.converterGroupBox.TabIndex = 10;
this.converterGroupBox.TabStop = false;
this.converterGroupBox.Text = "4-20 mA converter";
this.converterFunctionLabel.AutoSize = true;
this.converterFunctionLabel.Location = new System.Drawing.Point(12, 25);
this.converterFunctionLabel.Text = "Function (3 or 4)";
this.converterFunctionTextBox.Location = new System.Drawing.Point(155, 22);
this.converterFunctionTextBox.Size = new System.Drawing.Size(80, 20);
this.converterFirstRegisterLabel.AutoSize = true;
this.converterFirstRegisterLabel.Location = new System.Drawing.Point(12, 51);
this.converterFirstRegisterLabel.Text = "First Register";
this.converterFirstRegisterTextBox.Location = new System.Drawing.Point(155, 48);
this.converterFirstRegisterTextBox.Size = new System.Drawing.Size(120, 20);
this.converterRegisterCountLabel.AutoSize = true;
this.converterRegisterCountLabel.Location = new System.Drawing.Point(12, 77);
this.converterRegisterCountLabel.Text = "Register Count";
this.converterRegisterCountTextBox.Location = new System.Drawing.Point(155, 74);
this.converterRegisterCountTextBox.Size = new System.Drawing.Size(120, 20);
this.converterChannelLabel.AutoSize = true;
this.converterChannelLabel.Location = new System.Drawing.Point(12, 103);
this.converterChannelLabel.Text = "Channel";
this.converterChannelTextBox.Location = new System.Drawing.Point(155, 100);
this.converterChannelTextBox.Size = new System.Drawing.Size(80, 20);
this.valueSourceLabel.AutoSize = true;
this.valueSourceLabel.Location = new System.Drawing.Point(12, 130);
this.valueSourceLabel.Text = "Value Source";
this.valueSourceComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.valueSourceComboBox.Location = new System.Drawing.Point(155, 127);
this.valueSourceComboBox.Size = new System.Drawing.Size(200, 21);
this.floatByteOrderLabel.AutoSize = true;
this.floatByteOrderLabel.Location = new System.Drawing.Point(12, 157);
this.floatByteOrderLabel.Text = "Float Byte Order";
this.floatByteOrderComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.floatByteOrderComboBox.Location = new System.Drawing.Point(155, 154);
this.floatByteOrderComboBox.Size = new System.Drawing.Size(200, 21);
this.raw4Label.AutoSize = true;
this.raw4Label.Location = new System.Drawing.Point(12, 190);
this.raw4Label.Text = "Raw Value @ 4 mA";
this.raw4TextBox.Location = new System.Drawing.Point(155, 187);
this.raw4TextBox.Size = new System.Drawing.Size(120, 20);
this.raw20Label.AutoSize = true;
this.raw20Label.Location = new System.Drawing.Point(12, 216);
this.raw20Label.Text = "Raw Value @ 20 mA";
this.raw20TextBox.Location = new System.Drawing.Point(155, 213);
this.raw20TextBox.Size = new System.Drawing.Size(120, 20);
this.cond4Label.AutoSize = true;
this.cond4Label.Location = new System.Drawing.Point(12, 242);
this.cond4Label.Text = "Conductivity @ 4 mA";
this.cond4TextBox.Location = new System.Drawing.Point(155, 239);
this.cond4TextBox.Size = new System.Drawing.Size(120, 20);
this.cond20Label.AutoSize = true;
this.cond20Label.Location = new System.Drawing.Point(12, 268);
this.cond20Label.Text = "Conductivity @ 20 mA";
this.cond20TextBox.Location = new System.Drawing.Point(155, 265);
this.cond20TextBox.Size = new System.Drawing.Size(120, 20);
this.unitLabel.AutoSize = true;
this.unitLabel.Location = new System.Drawing.Point(12, 294);
this.unitLabel.Text = "Unit";
this.unitTextBox.Location = new System.Drawing.Point(155, 291);
this.unitTextBox.Size = new System.Drawing.Size(120, 20);
this.formatLabel.AutoSize = true;
this.formatLabel.Location = new System.Drawing.Point(12, 320);
this.formatLabel.Text = "Display Format";
this.formatTextBox.Location = new System.Drawing.Point(155, 317);
this.formatTextBox.Size = new System.Drawing.Size(200, 20);
this.lowLimitLabel.AutoSize = true;
this.lowLimitLabel.Location = new System.Drawing.Point(12, 346);
this.lowLimitLabel.Text = "Low Limit";
this.lowLimitTextBox.Location = new System.Drawing.Point(155, 343);
this.lowLimitTextBox.Size = new System.Drawing.Size(120, 20);
this.highLimitLabel.AutoSize = true;
this.highLimitLabel.Location = new System.Drawing.Point(12, 372);
this.highLimitLabel.Text = "High Limit";
this.highLimitTextBox.Location = new System.Drawing.Point(155, 369);
this.highLimitTextBox.Size = new System.Drawing.Size(120, 20);
this.dataTimeoutLabel.AutoSize = true;
this.dataTimeoutLabel.Location = new System.Drawing.Point(12, 398);
this.dataTimeoutLabel.Text = "Data Timeout (ms)";
this.dataTimeoutTextBox.Location = new System.Drawing.Point(155, 395);
this.dataTimeoutTextBox.Size = new System.Drawing.Size(120, 20);
// diagnosticsButton
this.diagnosticsButton.Location = new System.Drawing.Point(170, 700);
this.diagnosticsButton.Name = "diagnosticsButton";
this.diagnosticsButton.Size = new System.Drawing.Size(120, 27);
this.diagnosticsButton.TabIndex = 11;
this.diagnosticsButton.Text = "Diagnostics...";
this.diagnosticsButton.UseVisualStyleBackColor = true;
this.diagnosticsButton.Click += new System.EventHandler(this.diagnosticsButton_Click);
// AnalyzerCfgCtrl
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.componentNameLabel);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.parentLabel);
this.Controls.Add(this.parentNameComboBox);
this.Controls.Add(this.connectionTypeLabel);
this.Controls.Add(this.connectionTypeComboBox);
this.Controls.Add(this.modbusAddressLabel);
this.Controls.Add(this.modbusAddressTextBox);
this.Controls.Add(this.directGroupBox);
this.Controls.Add(this.converterGroupBox);
this.Controls.Add(this.diagnosticsButton);
this.Name = "AnalyzerCfgCtrl";
this.Size = new System.Drawing.Size(420, 740);
this.Load += new System.EventHandler(this.AnalyzerCfgCtrl_Load);
this.directGroupBox.ResumeLayout(false);
this.directGroupBox.PerformLayout();
this.converterGroupBox.ResumeLayout(false);
this.converterGroupBox.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
}
}

View File

@ -0,0 +1,379 @@
using Common;
using Config.Entities;
using System;
using System.Drawing;
using System.Windows.Forms;
using TBF.Rig.Generic;
using TBF.UI.Bench.Components;
namespace TBF.Rig.Modbus.WaterAnalyzerUni
{
public partial class AnalyzerCfgCtrl : UserControl, IComponentCfgCtrl
{
ComponentParametersDlg parent;
AnalyzerCfg config;
public bool ShowMore { get { return false; } }
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as AnalyzerCfg;
Redraw();
}
}
public AnalyzerCfgCtrl()
{
InitializeComponent();
}
private void AnalyzerCfgCtrl_Load(object sender, EventArgs e)
{
parent = ParentForm as ComponentParametersDlg;
if (parent != null && parent.CmpntEntities != null)
{
foreach (var cmpnt in parent.CmpntEntities)
{
if (TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is Modbus.Common.Factory)
{
parentNameComboBox.Items.Add(cmpnt.Name);
}
}
}
connectionTypeComboBox.Items.Clear();
connectionTypeComboBox.Items.Add(AnalyzerConnectionType.DirectConductivityMeter.ToString());
connectionTypeComboBox.Items.Add(AnalyzerConnectionType.CurrentLoop420mA.ToString());
directFloatByteOrderComboBox.Items.Clear();
directFloatByteOrderComboBox.Items.Add(AnalyzerFloatByteOrder.ABCD.ToString());
directFloatByteOrderComboBox.Items.Add(AnalyzerFloatByteOrder.BADC.ToString());
directFloatByteOrderComboBox.Items.Add(AnalyzerFloatByteOrder.CDAB.ToString());
directFloatByteOrderComboBox.Items.Add(AnalyzerFloatByteOrder.DCBA.ToString());
valueSourceComboBox.Items.Clear();
valueSourceComboBox.Items.Add(AnalyzerValueSource.IntegerRegister.ToString());
valueSourceComboBox.Items.Add(AnalyzerValueSource.FloatRegisters.ToString());
floatByteOrderComboBox.Items.Clear();
floatByteOrderComboBox.Items.Add(AnalyzerFloatByteOrder.ABCD.ToString());
floatByteOrderComboBox.Items.Add(AnalyzerFloatByteOrder.BADC.ToString());
floatByteOrderComboBox.Items.Add(AnalyzerFloatByteOrder.CDAB.ToString());
floatByteOrderComboBox.Items.Add(AnalyzerFloatByteOrder.DCBA.ToString());
Lock();
Redraw();
}
public void Closing() { }
void Redraw()
{
if (config == null) return;
componentNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
parentNameComboBox.Text = string.IsNullOrEmpty(config.ParentName) ? "---" : config.ParentName;
connectionTypeComboBox.Text = config.ConnectionType.ToString();
modbusAddressTextBox.Text = config.ModbusAddress.ToString();
directRegisterTextBox.Text = config.DirectRegisterAddress.ToString();
directFloatByteOrderComboBox.Text = config.DirectFloatByteOrder.ToString();
converterFunctionTextBox.Text = config.ConverterReadFunction.ToString();
converterFirstRegisterTextBox.Text = config.ConverterFirstRegister.ToString();
converterRegisterCountTextBox.Text = config.ConverterRegisterCount.ToString();
converterChannelTextBox.Text = config.ConverterChannel.ToString();
valueSourceComboBox.Text = config.ConverterValueSource.ToString();
floatByteOrderComboBox.Text = config.ConverterFloatByteOrder.ToString();
raw4TextBox.Text = config.RawValueAt4mA.ToString();
raw20TextBox.Text = config.RawValueAt20mA.ToString();
cond4TextBox.Text = config.ConductivityAt4mA.ToString();
cond20TextBox.Text = config.ConductivityAt20mA.ToString();
unitTextBox.Text = config.Unit;
formatTextBox.Text = config.DisplayFormat;
lowLimitTextBox.Text = config.LowLimit.ToString();
highLimitTextBox.Text = config.HighLimit.ToString();
dataTimeoutTextBox.Text = config.DataTimeoutMs.ToString();
UpdateGroupVisibility();
}
int formChromeHeight = -1;
void UpdateGroupVisibility()
{
bool direct =
connectionTypeComboBox.Text ==
AnalyzerConnectionType.DirectConductivityMeter.ToString();
directGroupBox.Visible = false;
converterGroupBox.Visible = !direct;
if (direct)
{
diagnosticsButton.Top = modbusAddressTextBox.Bottom + 20;
}
else
{
converterGroupBox.Top = modbusAddressTextBox.Bottom + 20;
diagnosticsButton.Top = converterGroupBox.Bottom + 15;
}
int requiredControlHeight = diagnosticsButton.Bottom + 15;
this.Height = requiredControlHeight;
Form form = FindForm();
if (form != null)
{
form.ClientSize = new System.Drawing.Size(
form.ClientSize.Width,
requiredControlHeight + 20);
}
}
private void connectionTypeComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
UpdateGroupVisibility();
}
public void Unlock()
{
nameTextBox.Enabled = true;
parentNameComboBox.Enabled = true;
connectionTypeComboBox.Enabled = true;
modbusAddressTextBox.Enabled = true;
directRegisterTextBox.Enabled = true;
directFloatByteOrderComboBox.Enabled = true;
converterFunctionTextBox.Enabled = true;
converterFirstRegisterTextBox.Enabled = true;
converterRegisterCountTextBox.Enabled = true;
converterChannelTextBox.Enabled = true;
valueSourceComboBox.Enabled = true;
floatByteOrderComboBox.Enabled = true;
raw4TextBox.Enabled = true;
raw20TextBox.Enabled = true;
cond4TextBox.Enabled = true;
cond20TextBox.Enabled = true;
unitTextBox.Enabled = true;
formatTextBox.Enabled = true;
lowLimitTextBox.Enabled = true;
highLimitTextBox.Enabled = true;
dataTimeoutTextBox.Enabled = true;
diagnosticsButton.Enabled = true;
UpdateGroupVisibility();
}
public void Lock()
{
nameTextBox.Enabled = false;
parentNameComboBox.Enabled = false;
connectionTypeComboBox.Enabled = false;
modbusAddressTextBox.Enabled = false;
directRegisterTextBox.Enabled = false;
directFloatByteOrderComboBox.Enabled = false;
converterFunctionTextBox.Enabled = false;
converterFirstRegisterTextBox.Enabled = false;
converterRegisterCountTextBox.Enabled = false;
converterChannelTextBox.Enabled = false;
valueSourceComboBox.Enabled = false;
floatByteOrderComboBox.Enabled = false;
raw4TextBox.Enabled = false;
raw20TextBox.Enabled = false;
cond4TextBox.Enabled = false;
cond20TextBox.Enabled = false;
unitTextBox.Enabled = false;
formatTextBox.Enabled = false;
lowLimitTextBox.Enabled = false;
highLimitTextBox.Enabled = false;
dataTimeoutTextBox.Enabled = false;
diagnosticsButton.Enabled = false;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
int iVal;
double dVal;
bool direct =
connectionTypeComboBox.Text ==
AnalyzerConnectionType.DirectConductivityMeter.ToString();
if (!parentNameComboBox.Items.Contains(parentNameComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Parent Component'";
}
if (!connectionTypeComboBox.Items.Contains(connectionTypeComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Connection Type'";
}
if (!int.TryParse(modbusAddressTextBox.Text, out iVal) || iVal < 1 || iVal > 247)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Modbus Address' must be between 1 and 247";
}
if (!int.TryParse(converterFunctionTextBox.Text, out iVal) || (iVal != 3 && iVal != 4))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Converter Function' must be 3 or 4";
}
if (!int.TryParse(converterFirstRegisterTextBox.Text, out iVal) || iVal < 0 || iVal > 65535)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Converter First Register' must be between 0 and 65535";
}
if (!int.TryParse(converterRegisterCountTextBox.Text, out iVal) || iVal < 1 || iVal > 8)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Converter Register Count' must be between 1 and 8";
}
if (!int.TryParse(converterChannelTextBox.Text, out iVal) || iVal < 0)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Converter Channel'";
}
if (!valueSourceComboBox.Items.Contains(valueSourceComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Value Source'";
}
if (!floatByteOrderComboBox.Items.Contains(floatByteOrderComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Float Byte Order'";
}
if (!double.TryParse(raw4TextBox.Text, out dVal) ||
!double.TryParse(raw20TextBox.Text, out dVal))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid raw scaling values";
}
if (!double.TryParse(cond4TextBox.Text, out dVal) ||
!double.TryParse(cond20TextBox.Text, out dVal))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid conductivity scaling values";
}
if (!double.TryParse(lowLimitTextBox.Text, out dVal) ||
!double.TryParse(highLimitTextBox.Text, out dVal))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid limit values";
}
if (!int.TryParse(dataTimeoutTextBox.Text, out iVal) || iVal < 100)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Data Timeout (ms)' must be at least 100";
}
return flags;
}
public CfgUpdateFlags UpdateCfg()
{
if (config == null) return CfgUpdateFlags.Error;
config.Name = nameTextBox.Text;
config.ParentName = parentNameComboBox.Text.Equals("---") ? string.Empty : parentNameComboBox.Text;
config.ConnectionType =
(AnalyzerConnectionType)Enum.Parse(
typeof(AnalyzerConnectionType),
connectionTypeComboBox.Text);
config.ModbusAddress = (byte)int.Parse(modbusAddressTextBox.Text);
config.DirectRegisterAddress = (ushort)int.Parse(directRegisterTextBox.Text);
config.DirectFloatByteOrder =
(AnalyzerFloatByteOrder)Enum.Parse(
typeof(AnalyzerFloatByteOrder),
directFloatByteOrderComboBox.Text);
config.ConverterReadFunction = (byte)int.Parse(converterFunctionTextBox.Text);
config.ConverterFirstRegister = (ushort)int.Parse(converterFirstRegisterTextBox.Text);
config.ConverterRegisterCount = (ushort)int.Parse(converterRegisterCountTextBox.Text);
config.ConverterChannel = int.Parse(converterChannelTextBox.Text);
config.ConverterValueSource =
(AnalyzerValueSource)Enum.Parse(
typeof(AnalyzerValueSource),
valueSourceComboBox.Text);
config.ConverterFloatByteOrder =
(AnalyzerFloatByteOrder)Enum.Parse(
typeof(AnalyzerFloatByteOrder),
floatByteOrderComboBox.Text);
config.RawValueAt4mA = Utils.ParseSDouble(raw4TextBox.Text);
config.RawValueAt20mA = Utils.ParseSDouble(raw20TextBox.Text);
config.ConductivityAt4mA = Utils.ParseSDouble(cond4TextBox.Text);
config.ConductivityAt20mA = Utils.ParseSDouble(cond20TextBox.Text);
config.Unit = unitTextBox.Text;
config.DisplayFormat = formatTextBox.Text;
config.LowLimit = Utils.ParseSDouble(lowLimitTextBox.Text);
config.HighLimit = Utils.ParseSDouble(highLimitTextBox.Text);
config.DataTimeoutMs = int.Parse(dataTimeoutTextBox.Text);
return CfgUpdateFlags.RestartRqrd;
}
private void diagnosticsButton_Click(object sender, EventArgs e)
{
if (config == null) return;
Analyzer analyzer = TbfComponents.FindComponent(config.Name) as Analyzer;
if (analyzer == null)
{
MessageBox.Show(
"Runtime component was not found. Diagnostics are available only while the component is initialized.",
"Diagnostics",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
return;
}
analyzer.ShowDiagnostics();
}
}
}

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>

View File

@ -0,0 +1,167 @@
using System;
using System.Text;
using TBF.Rig.Modbus.WaterAnalyzerUni;
namespace TBF.Rig.Modbus.WaterAnalyzerUni
{
public class AnalyzerDiagnostics
{
public string LastRequest { get; private set; }
public string LastResponse { get; private set; }
public string LastError { get; private set; }
public int RequestCount { get; private set; }
public int ResponseCount { get; private set; }
public int ErrorCount { get; private set; }
public void Clear()
{
LastRequest = string.Empty;
LastResponse = string.Empty;
LastError = string.Empty;
RequestCount = 0;
ResponseCount = 0;
ErrorCount = 0;
}
public void SetRequest(byte address, byte function, ushort firstRegister, ushort registerCount)
{
RequestCount++;
LastRequest = string.Format(
"TX {0:HH:mm:ss.fff}{1}Address: {2}{1}Function: 0x{3:X2}{1}First register: {4}{1}Register count: {5}",
DateTime.Now,
Environment.NewLine,
address,
function,
firstRegister,
registerCount);
}
public void SetResponse(
byte[] telegram,
ushort[] rawRegisters,
double rawValue,
double milliAmps,
double conductivity,
string unit)
{
ResponseCount++;
var sb = new StringBuilder();
sb.AppendFormat("RX {0:HH:mm:ss.fff}", DateTime.Now);
sb.AppendLine();
sb.Append("Telegram: ");
sb.AppendLine(ToHex(telegram));
if (rawRegisters != null)
{
for (int i = 0; i < rawRegisters.Length; i++)
{
sb.AppendFormat("Raw[{0}]: {1} / 0x{1:X4}", i, rawRegisters[i]);
sb.AppendLine();
}
if (rawRegisters.Length >= 4)
{
sb.AppendFormat("Float ABCD: {0}", ToFloat(rawRegisters[2], rawRegisters[3], AnalyzerFloatByteOrder.ABCD));
sb.AppendLine();
sb.AppendFormat("Float BADC: {0}", ToFloat(rawRegisters[2], rawRegisters[3], AnalyzerFloatByteOrder.BADC));
sb.AppendLine();
sb.AppendFormat("Float CDAB: {0}", ToFloat(rawRegisters[2], rawRegisters[3], AnalyzerFloatByteOrder.CDAB));
sb.AppendLine();
sb.AppendFormat("Float DCBA: {0}", ToFloat(rawRegisters[2], rawRegisters[3], AnalyzerFloatByteOrder.DCBA));
sb.AppendLine();
}
}
sb.AppendFormat("Raw value: {0:0.###}", rawValue);
sb.AppendLine();
sb.AppendFormat("Current: {0:0.000} mA", milliAmps);
sb.AppendLine();
sb.AppendFormat("Conductivity: {0:0.###} {1}", conductivity, unit);
LastResponse = sb.ToString();
LastError = string.Empty;
}
public void SetError(string message)
{
ErrorCount++;
LastError = string.Format("{0:HH:mm:ss.fff} {1}", DateTime.Now, message);
}
public string GetText()
{
var sb = new StringBuilder();
sb.AppendLine("Water Analyzer Diagnostics");
sb.AppendLine("--------------------------------");
sb.AppendFormat("Requests: {0}", RequestCount);
sb.AppendLine();
sb.AppendFormat("Responses: {0}", ResponseCount);
sb.AppendLine();
sb.AppendFormat("Errors: {0}", ErrorCount);
sb.AppendLine();
sb.AppendLine();
if (!string.IsNullOrEmpty(LastRequest))
{
sb.AppendLine(LastRequest);
sb.AppendLine();
}
if (!string.IsNullOrEmpty(LastResponse))
{
sb.AppendLine(LastResponse);
sb.AppendLine();
}
if (!string.IsNullOrEmpty(LastError))
{
sb.AppendLine("Last error:");
sb.AppendLine(LastError);
}
return sb.ToString();
}
static string ToHex(byte[] data)
{
if (data == null) return string.Empty;
var sb = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
if (i > 0) sb.Append(" ");
sb.Append(data[i].ToString("X2"));
}
return sb.ToString();
}
static float ToFloat(ushort hi, ushort lo, AnalyzerFloatByteOrder order)
{
byte a = (byte)(hi >> 8);
byte b = (byte)(hi & 0xFF);
byte c = (byte)(lo >> 8);
byte d = (byte)(lo & 0xFF);
byte[] bytes;
switch (order)
{
case AnalyzerFloatByteOrder.ABCD: bytes = new byte[] { d, c, b, a }; break;
case AnalyzerFloatByteOrder.BADC: bytes = new byte[] { c, d, a, b }; break;
case AnalyzerFloatByteOrder.CDAB: bytes = new byte[] { b, a, d, c }; break;
case AnalyzerFloatByteOrder.DCBA: bytes = new byte[] { a, b, c, d }; break;
default: bytes = new byte[] { d, c, b, a }; break;
}
return BitConverter.ToSingle(bytes, 0);
}
}
}

View File

@ -0,0 +1,91 @@
namespace TBF.Rig.Modbus.WaterAnalyzerUni
{
partial class AnalyzerDiagnosticsForm
{
private System.ComponentModel.IContainer components = null;
private System.Windows.Forms.TextBox diagnosticsTextBox;
private System.Windows.Forms.Button clearButton;
private System.Windows.Forms.Button closeButton;
private System.Windows.Forms.Timer refreshTimer;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
components.Dispose();
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.diagnosticsTextBox = new System.Windows.Forms.TextBox();
this.clearButton = new System.Windows.Forms.Button();
this.closeButton = new System.Windows.Forms.Button();
this.refreshTimer = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// diagnosticsTextBox
//
this.diagnosticsTextBox.Anchor =
((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top |
System.Windows.Forms.AnchorStyles.Bottom) |
System.Windows.Forms.AnchorStyles.Left) |
System.Windows.Forms.AnchorStyles.Right)));
this.diagnosticsTextBox.Font = new System.Drawing.Font("Consolas", 9F);
this.diagnosticsTextBox.Location = new System.Drawing.Point(12, 12);
this.diagnosticsTextBox.Multiline = true;
this.diagnosticsTextBox.Name = "diagnosticsTextBox";
this.diagnosticsTextBox.ReadOnly = true;
this.diagnosticsTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.diagnosticsTextBox.Size = new System.Drawing.Size(660, 390);
this.diagnosticsTextBox.TabIndex = 0;
this.diagnosticsTextBox.WordWrap = false;
//
// clearButton
//
this.clearButton.Anchor =
((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom |
System.Windows.Forms.AnchorStyles.Left)));
this.clearButton.Location = new System.Drawing.Point(12, 415);
this.clearButton.Name = "clearButton";
this.clearButton.Size = new System.Drawing.Size(90, 27);
this.clearButton.TabIndex = 1;
this.clearButton.Text = "Clear";
this.clearButton.UseVisualStyleBackColor = true;
this.clearButton.Click += new System.EventHandler(this.clearButton_Click);
//
// closeButton
//
this.closeButton.Anchor =
((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom |
System.Windows.Forms.AnchorStyles.Right)));
this.closeButton.Location = new System.Drawing.Point(582, 415);
this.closeButton.Name = "closeButton";
this.closeButton.Size = new System.Drawing.Size(90, 27);
this.closeButton.TabIndex = 2;
this.closeButton.Text = "Close";
this.closeButton.UseVisualStyleBackColor = true;
this.closeButton.Click += new System.EventHandler(this.closeButton_Click);
//
// refreshTimer
//
this.refreshTimer.Interval = 500;
this.refreshTimer.Tick += new System.EventHandler(this.refreshTimer_Tick);
//
// AnalyzerDiagnosticsForm
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(684, 454);
this.Controls.Add(this.diagnosticsTextBox);
this.Controls.Add(this.clearButton);
this.Controls.Add(this.closeButton);
this.Name = "AnalyzerDiagnosticsForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Water Analyzer - Modbus Diagnostics";
this.Load += new System.EventHandler(this.AnalyzerDiagnosticsForm_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
}
}

View File

@ -0,0 +1,56 @@
using System;
using System.Windows.Forms;
namespace TBF.Rig.Modbus.WaterAnalyzerUni
{
public partial class AnalyzerDiagnosticsForm : Form
{
readonly Analyzer analyzer;
public AnalyzerDiagnosticsForm(Analyzer analyzer)
{
if (analyzer == null) throw new ArgumentNullException("analyzer");
this.analyzer = analyzer;
InitializeComponent();
}
private void AnalyzerDiagnosticsForm_Load(object sender, EventArgs e)
{
refreshTimer.Start();
RefreshDiagnostics();
}
private void refreshTimer_Tick(object sender, EventArgs e)
{
RefreshDiagnostics();
}
private void RefreshDiagnostics()
{
diagnosticsTextBox.Text =
analyzer.Diagnostics != null
? analyzer.Diagnostics.GetText()
: "Diagnostics are not available.";
}
private void clearButton_Click(object sender, EventArgs e)
{
if (analyzer.Diagnostics != null)
analyzer.Diagnostics.Clear();
RefreshDiagnostics();
}
private void closeButton_Click(object sender, EventArgs e)
{
Close();
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
refreshTimer.Stop();
base.OnFormClosing(e);
}
}
}

View File

@ -0,0 +1,31 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.Modbus.WaterAnalyzerUni
{
public class Factory : IComponentFactory
{
public string ClassName { get { return this.GetType().Namespace.Substring(8); } }
public override string ToString() { return ClassName; }
public IComponent DummyComponent() { return new Analyzer(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components)
{
return new Analyzer(cfg, components);
}
public IComponentCfg DefaultConfig()
{
return new AnalyzerCfg(this.GetType().Namespace.Substring(24), this);
}
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(AnalyzerCfg.Serializer, component, this);
}
}
}

View File

@ -0,0 +1,40 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using log4net;
using TBF.Boxes;
namespace TBF.Rig.Modbus.WaterAnalyzerUni
{
public class ReadConductivityOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(ReadConductivityOp));
public override string ToString() { return "ReadConductivityOp(.,.)"; }
readonly Analyzer analyzer;
FloatBox conductivity;
public ReadConductivityOp(Analyzer analyzer, ref FloatBox conduct)
{
if (analyzer == null) throw new ArgumentNullException("analyzer");
this.analyzer = analyzer;
this.conductivity = conduct;
log.Debug(this.ToString());
}
public void Start()
{
conductivity.Val = analyzer.ReadConductivity();
}
public Event Run()
{
conductivity.Val = analyzer.ReadConductivity();
return Event.ConductivityDone;
}
public void Stop() { }
}
}

View File

@ -0,0 +1,64 @@
///
/// Copyright (c) 2020 Sensus Slovensko a.s.
///
using System;
using log4net;
using TBF.Boxes;
namespace TBF.Rig.Modbus.WaterAnalyzerUni
{
public class ReadTempOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(ReadTempOp));
public override string ToString() { return string.Format("ReadTempOp(.,{0},.)", eventDone); }
/// Set by the constructor
readonly Analyzer analyzer;
readonly Event eventDone;
/// Measured value
DoubleBox temperature;
/// <summary>
/// Events: eventDone or Error
/// </summary>
/// <param name="analyzer">Water temperature meter reference</param>
/// <param name="temperature">Reference to the measured temperature variable, value is in l</param>
/// <param name="eventDone">Event to be returned by Run() when completed OK</param>
public ReadTempOp(Analyzer analyzer, ref DoubleBox temperature, Event eventDone)
{
if (analyzer == null) throw new ArgumentNullException("analyzer");
this.analyzer = analyzer;
this.temperature = temperature;
this.eventDone = eventDone;
log.Debug(this.ToString());
}
public ReadTempOp(Analyzer levelMeter, ref DoubleBox temperature)
: this(levelMeter, ref temperature, Event.TempDone)
{
}
/// <summary>Start this operation</summary>
public void Start()
{
temperature.Val = analyzer.ReadTemperature();
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.temperatureDone
/// </returns>
public Event Run()
{
temperature.Val = analyzer.ReadTemperature();
return eventDone;
}
/// <summary>Stop this operation</summary>
public void Stop()
{
}
}
}

View File

@ -80,6 +80,8 @@ namespace TBF.Rig
new Modbus.TempMeter.Meret.Factory(), /// Meret temperature meter connected via a modbus on a PC
new Modbus.UltrasoundLevelMeter.Factory(),
new Modbus.WaterAnalyzer.Factory(),
new Modbus.WaterAnalyzerUni.Factory(),
new Modbus.ConductivityMeter.Factory(),
new Network.Adapter.Factory(),
new Network.AdapterFTP.Factory(),
new Network.AdapterJMS.Factory(),

View File

@ -873,6 +873,22 @@
<Compile Include="Rig\Modbus\Ambient\Comet\AmbientCfg.cs" />
<Compile Include="Rig\Modbus\Ambient\Comet\Factory.cs" />
<Compile Include="Rig\Modbus\Common\TelegramMeno.cs" />
<Compile Include="Rig\Modbus\ConductivityMeter\ConductivityMeter.cs" />
<Compile Include="Rig\Modbus\ConductivityMeter\ConductivityMeterCfg.cs" />
<Compile Include="Rig\Modbus\ConductivityMeter\ConductivityMeterCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\Modbus\ConductivityMeter\ConductivityMeterCfgCtrl.Designer.cs">
<DependentUpon>ConductivityMeterCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\Modbus\ConductivityMeter\ConductivityMeterDiagnostics.cs" />
<Compile Include="Rig\Modbus\ConductivityMeter\ConductivityMeterDiagnosticsForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Rig\Modbus\ConductivityMeter\ConductivityMeterDiagnosticsForm.Designer.cs">
<DependentUpon>ConductivityMeterDiagnosticsForm.cs</DependentUpon>
</Compile>
<Compile Include="Rig\Modbus\ConductivityMeter\Factory.cs" />
<Compile Include="Rig\Modbus\Enums.cs" />
<Compile Include="Rig\Modbus\Common\Modbus.cs" />
<Compile Include="Rig\Modbus\Common\ModbusCfg.cs" />
@ -963,6 +979,24 @@
<Compile Include="Rig\Modbus\UltrasoundLevelMeter\ReadLevelOp.cs" />
<Compile Include="Rig\Modbus\UltrasoundLevelMeter\ReadStableLevelOp.cs" />
<Compile Include="Rig\Modbus\UltrasoundLevelMeter\ReadTempOp.cs" />
<Compile Include="Rig\Modbus\WaterAnalyzerUni\Analyzer.cs" />
<Compile Include="Rig\Modbus\WaterAnalyzerUni\AnalyzerCfg.cs" />
<Compile Include="Rig\Modbus\WaterAnalyzerUni\AnalyzerCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\Modbus\WaterAnalyzerUni\AnalyzerCfgCtrl.Designer.cs">
<DependentUpon>AnalyzerCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\Modbus\WaterAnalyzerUni\AnalyzerDiagnostics.cs" />
<Compile Include="Rig\Modbus\WaterAnalyzerUni\AnalyzerDiagnosticsForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Rig\Modbus\WaterAnalyzerUni\AnalyzerDiagnosticsForm.Designer.cs">
<DependentUpon>AnalyzerDiagnosticsForm.cs</DependentUpon>
</Compile>
<Compile Include="Rig\Modbus\WaterAnalyzerUni\Factory.cs" />
<Compile Include="Rig\Modbus\WaterAnalyzerUni\ReadConductivityOp.cs" />
<Compile Include="Rig\Modbus\WaterAnalyzerUni\ReadTempOp.cs" />
<Compile Include="Rig\Modbus\WaterAnalyzer\Factory.cs" />
<Compile Include="Rig\Modbus\WaterAnalyzer\Analyzer.cs" />
<Compile Include="Rig\Modbus\WaterAnalyzer\AnalyzerCfg.cs" />
@ -3577,6 +3611,9 @@
<EmbeddedResource Include="Rig\MettlerToledo\Standard\BalanceCfgCtrl.resx">
<DependentUpon>BalanceCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\Modbus\ConductivityMeter\ConductivityMeterCfgCtrl.resx">
<DependentUpon>ConductivityMeterCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\Modbus\PumpFM\DanfossVLT\PumpCfgCtrl.resx">
<DependentUpon>PumpCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
@ -3592,6 +3629,9 @@
<EmbeddedResource Include="Rig\Modbus\TankSelector\TankSelectorCfgCtrl.resx">
<DependentUpon>TankSelectorCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\Modbus\WaterAnalyzerUni\AnalyzerCfgCtrl.resx">
<DependentUpon>AnalyzerCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\Network\AdapterFTP\NetadapterCfgCtrl.resx">
<DependentUpon>NetadapterCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
@ -4499,6 +4539,7 @@
<Name>Results</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="Build\CopyGci.targets.xml" />
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.